9b780d220b 2007-07-31 drh: /* 9b780d220b 2007-07-31 drh: ** Copyright (c) 2007 D. Richard Hipp 9b780d220b 2007-07-31 drh: ** 9b780d220b 2007-07-31 drh: ** This program is free software; you can redistribute it and/or 9b780d220b 2007-07-31 drh: ** modify it under the terms of the GNU General Public 9b780d220b 2007-07-31 drh: ** License version 2 as published by the Free Software Foundation. 9b780d220b 2007-07-31 drh: ** 9b780d220b 2007-07-31 drh: ** This program is distributed in the hope that it will be useful, 9b780d220b 2007-07-31 drh: ** but WITHOUT ANY WARRANTY; without even the implied warranty of 9b780d220b 2007-07-31 drh: ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 9b780d220b 2007-07-31 drh: ** General Public License for more details. 9b780d220b 2007-07-31 drh: ** 9b780d220b 2007-07-31 drh: ** You should have received a copy of the GNU General Public 9b780d220b 2007-07-31 drh: ** License along with this library; if not, write to the 9b780d220b 2007-07-31 drh: ** Free Software Foundation, Inc., 59 Temple Place - Suite 330, 9b780d220b 2007-07-31 drh: ** Boston, MA 02111-1307, USA. 9b780d220b 2007-07-31 drh: ** 9b780d220b 2007-07-31 drh: ** Author contact information: 9b780d220b 2007-07-31 drh: ** drh@hwaci.com 9b780d220b 2007-07-31 drh: ** http://www.hwaci.com/drh/ 9b780d220b 2007-07-31 drh: ** 9b780d220b 2007-07-31 drh: ******************************************************************************* 9b780d220b 2007-07-31 drh: ** 9b780d220b 2007-07-31 drh: ** This file contains code used to generate ZIP archives. 9b780d220b 2007-07-31 drh: */ 9b780d220b 2007-07-31 drh: #include <assert.h> 9b780d220b 2007-07-31 drh: #include <zlib.h> 9b780d220b 2007-07-31 drh: #include "config.h" 9b780d220b 2007-07-31 drh: #include "zip.h" 9b780d220b 2007-07-31 drh: 9b780d220b 2007-07-31 drh: /* 9b780d220b 2007-07-31 drh: ** Write a 16- or 32-bit integer as little-endian into the given buffer. 9b780d220b 2007-07-31 drh: */ 9b780d220b 2007-07-31 drh: static void put16(char *z, int v){ 9b780d220b 2007-07-31 drh: z[0] = v & 0xff; 9b780d220b 2007-07-31 drh: z[1] = (v>>8) & 0xff; 9b780d220b 2007-07-31 drh: } 9b780d220b 2007-07-31 drh: static void put32(char *z, int v){ 9b780d220b 2007-07-31 drh: z[0] = v & 0xff; 9b780d220b 2007-07-31 drh: z[1] = (v>>8) & 0xff; 9b780d220b 2007-07-31 drh: z[2] = (v>>16) & 0xff; 9b780d220b 2007-07-31 drh: z[3] = (v>>24) & 0xff; 9b780d220b 2007-07-31 drh: } 9b780d220b 2007-07-31 drh: 9b780d220b 2007-07-31 drh: /* 9b780d220b 2007-07-31 drh: ** Variables in which to accumulate a growing ZIP archive. 9b780d220b 2007-07-31 drh: */ 9b780d220b 2007-07-31 drh: static Blob body; /* The body of the ZIP archive */ 9b780d220b 2007-07-31 drh: static Blob toc; /* The table of contents */ 9b780d220b 2007-07-31 drh: static int nEntry; /* Number of files */ dead090c0b 2007-07-31 drh: static int dosTime; /* DOS-format time */ dead090c0b 2007-07-31 drh: static int dosDate; /* DOS-format date */ 9b780d220b 2007-07-31 drh: 9b780d220b 2007-07-31 drh: /* 9b780d220b 2007-07-31 drh: ** Initialize a new ZIP archive. 9b780d220b 2007-07-31 drh: */ 9b780d220b 2007-07-31 drh: void zip_open(void){ 9b780d220b 2007-07-31 drh: blob_zero(&body); 9b780d220b 2007-07-31 drh: blob_zero(&toc); 9b780d220b 2007-07-31 drh: nEntry = 0; dead090c0b 2007-07-31 drh: dosTime = 0; dead090c0b 2007-07-31 drh: dosDate = 0; dead090c0b 2007-07-31 drh: } dead090c0b 2007-07-31 drh: dead090c0b 2007-07-31 drh: /* dead090c0b 2007-07-31 drh: ** Set the date and time values from an ISO8601 date string. dead090c0b 2007-07-31 drh: */ dead090c0b 2007-07-31 drh: void zip_set_timedate_from_str(const char *zDate){ dead090c0b 2007-07-31 drh: int y, m, d; dead090c0b 2007-07-31 drh: int H, M, S; dead090c0b 2007-07-31 drh: dead090c0b 2007-07-31 drh: y = atoi(zDate); dead090c0b 2007-07-31 drh: m = atoi(&zDate[5]); dead090c0b 2007-07-31 drh: d = atoi(&zDate[8]); dead090c0b 2007-07-31 drh: H = atoi(&zDate[11]); dead090c0b 2007-07-31 drh: M = atoi(&zDate[14]); dead090c0b 2007-07-31 drh: S = atoi(&zDate[17]); dead090c0b 2007-07-31 drh: dosTime = (H<<11) + (M<<5) + S; dead090c0b 2007-07-31 drh: dosDate = ((y-1980)<<9) + (m<<5) + d; dead090c0b 2007-07-31 drh: } dead090c0b 2007-07-31 drh: dead090c0b 2007-07-31 drh: /* dead090c0b 2007-07-31 drh: ** Set the date and time from a julian day number. dead090c0b 2007-07-31 drh: */ dead090c0b 2007-07-31 drh: void zip_set_timedate(double rDate){ dead090c0b 2007-07-31 drh: char *zDate = db_text(0, "SELECT datetime(%.17g)", rDate); dead090c0b 2007-07-31 drh: zip_set_timedate_from_str(zDate); dead090c0b 2007-07-31 drh: free(zDate); 9b780d220b 2007-07-31 drh: } 9b780d220b 2007-07-31 drh: 9b780d220b 2007-07-31 drh: /* 9b780d220b 2007-07-31 drh: ** Append a single file to a growing ZIP archive. 9b780d220b 2007-07-31 drh: ** 9b780d220b 2007-07-31 drh: ** pFile is the file to be appended. zName is the name 9b780d220b 2007-07-31 drh: ** that the file should be saved as. 9b780d220b 2007-07-31 drh: */ dead090c0b 2007-07-31 drh: void zip_add_file(const char *zName, const Blob *pFile){ 9b780d220b 2007-07-31 drh: z_stream stream; 9b780d220b 2007-07-31 drh: int nameLen; 9b780d220b 2007-07-31 drh: int skip; 9b780d220b 2007-07-31 drh: int toOut; 9b780d220b 2007-07-31 drh: int iStart; 9b780d220b 2007-07-31 drh: int iCRC; 9b780d220b 2007-07-31 drh: int nByte; 9b780d220b 2007-07-31 drh: int nByteCompr; 9b780d220b 2007-07-31 drh: char *z; 9b780d220b 2007-07-31 drh: char zHdr[30]; 9b780d220b 2007-07-31 drh: char zBuf[100]; 9b780d220b 2007-07-31 drh: char zOutBuf[100000]; 9b780d220b 2007-07-31 drh: 9b780d220b 2007-07-31 drh: /* Fill in as much of the header as we know. 9b780d220b 2007-07-31 drh: */ 9b780d220b 2007-07-31 drh: nameLen = strlen(zName); 9b780d220b 2007-07-31 drh: put32(&zHdr[0], 0x04034b50); 9b780d220b 2007-07-31 drh: put16(&zHdr[4], 0x0014); 9b780d220b 2007-07-31 drh: put16(&zHdr[6], 0); 9b780d220b 2007-07-31 drh: put16(&zHdr[8], 8); dead090c0b 2007-07-31 drh: put16(&zHdr[10], dosTime); dead090c0b 2007-07-31 drh: put16(&zHdr[12], dosDate); 9b780d220b 2007-07-31 drh: put16(&zHdr[26], nameLen); 9b780d220b 2007-07-31 drh: put16(&zHdr[28], 0); 9b780d220b 2007-07-31 drh: 9b780d220b 2007-07-31 drh: /* Write the header and filename. 9b780d220b 2007-07-31 drh: */ 9b780d220b 2007-07-31 drh: iStart = blob_size(&body); 9b780d220b 2007-07-31 drh: blob_append(&body, zHdr, 30); 9b780d220b 2007-07-31 drh: blob_append(&body, zName, nameLen); 9b780d220b 2007-07-31 drh: 9b780d220b 2007-07-31 drh: /* The first two bytes that come out of the deflate compressor are 9b780d220b 2007-07-31 drh: ** some kind of header that ZIP does not use. So skip the first two 9b780d220b 2007-07-31 drh: ** output bytes. 9b780d220b 2007-07-31 drh: */ 9b780d220b 2007-07-31 drh: skip = 2; 9b780d220b 2007-07-31 drh: 9b780d220b 2007-07-31 drh: /* Write the compressed file. Compute the CRC as we progress. 9b780d220b 2007-07-31 drh: */ 9b780d220b 2007-07-31 drh: stream.zalloc = (alloc_func)0; 9b780d220b 2007-07-31 drh: stream.zfree = (free_func)0; 9b780d220b 2007-07-31 drh: stream.opaque = 0; 9b780d220b 2007-07-31 drh: stream.avail_in = blob_size(pFile); 9b780d220b 2007-07-31 drh: stream.next_in = (unsigned char*)blob_buffer(pFile); 9b780d220b 2007-07-31 drh: stream.avail_out = sizeof(zOutBuf); 9b780d220b 2007-07-31 drh: stream.next_out = (unsigned char*)zOutBuf; 9b780d220b 2007-07-31 drh: deflateInit(&stream, 9); 9b780d220b 2007-07-31 drh: iCRC = crc32(0, stream.next_in, stream.avail_in); 9b780d220b 2007-07-31 drh: while( stream.avail_in>0 ){ 9b780d220b 2007-07-31 drh: deflate(&stream, 0); 9b780d220b 2007-07-31 drh: toOut = sizeof(zOutBuf) - stream.avail_out; 9b780d220b 2007-07-31 drh: if( toOut>skip ){ 9b780d220b 2007-07-31 drh: blob_append(&body, &zOutBuf[skip], toOut - skip); 9b780d220b 2007-07-31 drh: skip = 0; 9b780d220b 2007-07-31 drh: }else{ 9b780d220b 2007-07-31 drh: skip -= toOut; 9b780d220b 2007-07-31 drh: } 9b780d220b 2007-07-31 drh: stream.avail_out = sizeof(zOutBuf); 9b780d220b 2007-07-31 drh: stream.next_out = (unsigned char*)zOutBuf; 9b780d220b 2007-07-31 drh: } 9b780d220b 2007-07-31 drh: do{ 9b780d220b 2007-07-31 drh: stream.avail_out = sizeof(zOutBuf); 9b780d220b 2007-07-31 drh: stream.next_out = (unsigned char*)zOutBuf; 9b780d220b 2007-07-31 drh: deflate(&stream, Z_FINISH); 9b780d220b 2007-07-31 drh: toOut = sizeof(zOutBuf) - stream.avail_out; 9b780d220b 2007-07-31 drh: if( toOut>skip ){ 9b780d220b 2007-07-31 drh: blob_append(&body, &zOutBuf[skip], toOut - skip); 9b780d220b 2007-07-31 drh: skip = 0; 9b780d220b 2007-07-31 drh: }else{ 9b780d220b 2007-07-31 drh: skip -= toOut; 9b780d220b 2007-07-31 drh: } 9b780d220b 2007-07-31 drh: }while( stream.avail_out==0 ); 9b780d220b 2007-07-31 drh: nByte = stream.total_in; 9b780d220b 2007-07-31 drh: nByteCompr = stream.total_out - 2; 9b780d220b 2007-07-31 drh: deflateEnd(&stream); 9b780d220b 2007-07-31 drh: 9b780d220b 2007-07-31 drh: /* Go back and write the header, now that we know the compressed file size. 9b780d220b 2007-07-31 drh: */ 9b780d220b 2007-07-31 drh: z = &blob_buffer(&body)[iStart]; 9b780d220b 2007-07-31 drh: put32(&z[14], iCRC); 9b780d220b 2007-07-31 drh: put32(&z[18], nByteCompr); 9b780d220b 2007-07-31 drh: put32(&z[22], nByte); 9b780d220b 2007-07-31 drh: 9b780d220b 2007-07-31 drh: /* Make an entry in the tables of contents 9b780d220b 2007-07-31 drh: */ 9b780d220b 2007-07-31 drh: memset(zBuf, 0, sizeof(zBuf)); 9b780d220b 2007-07-31 drh: put32(&zBuf[0], 0x02014b50); 9b780d220b 2007-07-31 drh: put16(&zBuf[4], 0x0317); 9b780d220b 2007-07-31 drh: put16(&zBuf[6], 0x0014); 9b780d220b 2007-07-31 drh: put16(&zBuf[8], 0); 9b780d220b 2007-07-31 drh: put16(&zBuf[10], 0x0008); dead090c0b 2007-07-31 drh: put16(&zBuf[12], dosTime); dead090c0b 2007-07-31 drh: put16(&zBuf[14], dosDate); 9b780d220b 2007-07-31 drh: put32(&zBuf[16], iCRC); 9b780d220b 2007-07-31 drh: put32(&zBuf[20], nByteCompr); 9b780d220b 2007-07-31 drh: put32(&zBuf[24], nByte); 9b780d220b 2007-07-31 drh: put16(&zBuf[28], nameLen); 9b780d220b 2007-07-31 drh: put16(&zBuf[30], 0); 9b780d220b 2007-07-31 drh: put16(&zBuf[32], 0); 9b780d220b 2007-07-31 drh: put16(&zBuf[34], 1); 9b780d220b 2007-07-31 drh: put16(&zBuf[36], 0); 9b780d220b 2007-07-31 drh: put32(&zBuf[38], (0100000 | 0644)<<16); 9b780d220b 2007-07-31 drh: put32(&zBuf[42], iStart); 9b780d220b 2007-07-31 drh: blob_append(&toc, zBuf, 46); 9b780d220b 2007-07-31 drh: blob_append(&toc, zName, nameLen); 9b780d220b 2007-07-31 drh: nEntry++; 9b780d220b 2007-07-31 drh: } 9b780d220b 2007-07-31 drh: 9b780d220b 2007-07-31 drh: 9b780d220b 2007-07-31 drh: /* 9b780d220b 2007-07-31 drh: ** Write the ZIP archive into the given BLOB. 9b780d220b 2007-07-31 drh: */ dead090c0b 2007-07-31 drh: void zip_close(Blob *pZip){ 9b780d220b 2007-07-31 drh: int iTocStart; 9b780d220b 2007-07-31 drh: int iTocEnd; 9b780d220b 2007-07-31 drh: char zBuf[30]; 9b780d220b 2007-07-31 drh: 9b780d220b 2007-07-31 drh: iTocStart = blob_size(&body); 9b780d220b 2007-07-31 drh: blob_append(&body, blob_buffer(&toc), blob_size(&toc)); 9b780d220b 2007-07-31 drh: iTocEnd = blob_size(&body); 9b780d220b 2007-07-31 drh: 9b780d220b 2007-07-31 drh: memset(zBuf, 0, sizeof(zBuf)); 9b780d220b 2007-07-31 drh: put32(&zBuf[0], 0x06054b50); 9b780d220b 2007-07-31 drh: put16(&zBuf[4], 0); 9b780d220b 2007-07-31 drh: put16(&zBuf[6], 0); 9b780d220b 2007-07-31 drh: put16(&zBuf[8], nEntry); 9b780d220b 2007-07-31 drh: put16(&zBuf[10], nEntry); 9b780d220b 2007-07-31 drh: put32(&zBuf[12], iTocEnd - iTocStart); 9b780d220b 2007-07-31 drh: put32(&zBuf[16], iTocStart); 9b780d220b 2007-07-31 drh: put16(&zBuf[20], 0); 9b780d220b 2007-07-31 drh: blob_append(&body, zBuf, 22); 9b780d220b 2007-07-31 drh: blob_reset(&toc); 9b780d220b 2007-07-31 drh: *pZip = body; 9b780d220b 2007-07-31 drh: blob_zero(&body); 9b780d220b 2007-07-31 drh: nEntry = 0; 9b780d220b 2007-07-31 drh: } 9b780d220b 2007-07-31 drh: 9b780d220b 2007-07-31 drh: /* 9b780d220b 2007-07-31 drh: ** COMMAND: test-filezip 9b780d220b 2007-07-31 drh: ** 9b780d220b 2007-07-31 drh: ** Generate a ZIP archive specified by the first argument that 9b780d220b 2007-07-31 drh: ** contains files given in the second and subsequent arguments. 9b780d220b 2007-07-31 drh: */ 9b780d220b 2007-07-31 drh: void filezip_cmd(void){ 9b780d220b 2007-07-31 drh: int i; 9b780d220b 2007-07-31 drh: Blob zip; 9b780d220b 2007-07-31 drh: Blob file; 9b780d220b 2007-07-31 drh: if( g.argc<3 ){ 9b780d220b 2007-07-31 drh: usage("ARCHIVE FILE...."); 9b780d220b 2007-07-31 drh: } 9b780d220b 2007-07-31 drh: zip_open(); 9b780d220b 2007-07-31 drh: for(i=3; i<g.argc; i++){ 9b780d220b 2007-07-31 drh: blob_zero(&file); 9b780d220b 2007-07-31 drh: blob_read_from_file(&file, g.argv[i]); 9b780d220b 2007-07-31 drh: zip_add_file(g.argv[i], &file); 9b780d220b 2007-07-31 drh: blob_reset(&file); 9b780d220b 2007-07-31 drh: } 9b780d220b 2007-07-31 drh: zip_close(&zip); 9b780d220b 2007-07-31 drh: blob_write_to_file(&zip, g.argv[2]); dead090c0b 2007-07-31 drh: } dead090c0b 2007-07-31 drh: dead090c0b 2007-07-31 drh: /* dead090c0b 2007-07-31 drh: ** Given the RID for a manifest, construct a ZIP archive containing dead090c0b 2007-07-31 drh: ** all files in the corresponding baseline. dead090c0b 2007-07-31 drh: ** dead090c0b 2007-07-31 drh: ** If RID is for an object that is not a real manifest, then the dead090c0b 2007-07-31 drh: ** resulting ZIP archive contains a single file which is the RID dead090c0b 2007-07-31 drh: ** object. dead090c0b 2007-07-31 drh: ** dead090c0b 2007-07-31 drh: ** If the RID object does not exist in the repository, then dead090c0b 2007-07-31 drh: ** pZip is zeroed. 974fd92330 2008-02-08 stephan: ** 4bbb00a8c8 2008-02-08 drh: ** zDir is a "synthetic" subdirectory which all zipped files get 974fd92330 2008-02-08 stephan: ** added to as part of the zip file. It may be 0 or an empty string, 974fd92330 2008-02-08 stephan: ** in which case it is ignored. The intention is to create a zip which 974fd92330 2008-02-08 stephan: ** politely expands into a subdir instead of filling your current dir 974fd92330 2008-02-08 stephan: ** with source files. For example, pass a UUID or "ProjectName". 974fd92330 2008-02-08 stephan: ** dead090c0b 2007-07-31 drh: */ 4bbb00a8c8 2008-02-08 drh: void zip_of_baseline(int rid, Blob *pZip, const char *zDir){ dead090c0b 2007-07-31 drh: int i; 95e17f4e3f 2007-08-25 drh: Blob mfile, file, hash; dead090c0b 2007-07-31 drh: Manifest m; 4bbb00a8c8 2008-02-08 drh: Blob filename; 4bbb00a8c8 2008-02-08 drh: int nPrefix; dead090c0b 2007-07-31 drh: dead090c0b 2007-07-31 drh: content_get(rid, &mfile); dead090c0b 2007-07-31 drh: if( blob_size(&mfile)==0 ){ dead090c0b 2007-07-31 drh: blob_zero(pZip); dead090c0b 2007-07-31 drh: return; dead090c0b 2007-07-31 drh: } dead090c0b 2007-07-31 drh: blob_zero(&file); 95e17f4e3f 2007-08-25 drh: blob_zero(&hash); dead090c0b 2007-07-31 drh: blob_copy(&file, &mfile); 4bbb00a8c8 2008-02-08 drh: blob_zero(&filename); dead090c0b 2007-07-31 drh: zip_open(); 974fd92330 2008-02-08 stephan: 4bbb00a8c8 2008-02-08 drh: if( zDir && zDir[0] ){ 4bbb00a8c8 2008-02-08 drh: blob_appendf(&filename, "%s/", zDir); 974fd92330 2008-02-08 stephan: } 4bbb00a8c8 2008-02-08 drh: nPrefix = blob_size(&filename); 4bbb00a8c8 2008-02-08 drh: dead090c0b 2007-07-31 drh: if( manifest_parse(&m, &mfile) ){ dead090c0b 2007-07-31 drh: zip_set_timedate(m.rDate); 4bbb00a8c8 2008-02-08 drh: blob_append(&filename, "manifest", -1); 4bbb00a8c8 2008-02-08 drh: zip_add_file(blob_str(&filename), &file); 95e17f4e3f 2007-08-25 drh: sha1sum_blob(&file, &hash); dead090c0b 2007-07-31 drh: blob_reset(&file); 95e17f4e3f 2007-08-25 drh: blob_append(&hash, "\n", 1); 4bbb00a8c8 2008-02-08 drh: blob_resize(&filename, nPrefix); 4bbb00a8c8 2008-02-08 drh: blob_append(&filename, "manifest.uuid", -1); 4bbb00a8c8 2008-02-08 drh: zip_add_file(blob_str(&filename), &hash); 95e17f4e3f 2007-08-25 drh: blob_reset(&hash); dead090c0b 2007-07-31 drh: for(i=0; i<m.nFile; i++){ dead090c0b 2007-07-31 drh: int fid = uuid_to_rid(m.aFile[i].zUuid, 0); dead090c0b 2007-07-31 drh: if( fid ){ dead090c0b 2007-07-31 drh: content_get(fid, &file); 4bbb00a8c8 2008-02-08 drh: blob_resize(&filename, nPrefix); 4bbb00a8c8 2008-02-08 drh: blob_append(&filename, m.aFile[i].zName, -1); 4bbb00a8c8 2008-02-08 drh: zip_add_file(blob_str(&filename), &file); dead090c0b 2007-07-31 drh: blob_reset(&file); dead090c0b 2007-07-31 drh: } dead090c0b 2007-07-31 drh: } dead090c0b 2007-07-31 drh: manifest_clear(&m); dead090c0b 2007-07-31 drh: }else{ dead090c0b 2007-07-31 drh: blob_reset(&mfile); dead090c0b 2007-07-31 drh: blob_reset(&file); dead090c0b 2007-07-31 drh: } 4bbb00a8c8 2008-02-08 drh: blob_reset(&filename); dead090c0b 2007-07-31 drh: zip_close(pZip); dead090c0b 2007-07-31 drh: } dead090c0b 2007-07-31 drh: dead090c0b 2007-07-31 drh: /* dead090c0b 2007-07-31 drh: ** COMMAND: test-baseline-zip dead090c0b 2007-07-31 drh: ** dead090c0b 2007-07-31 drh: ** Generate a ZIP archive for a specified baseline. dead090c0b 2007-07-31 drh: */ dead090c0b 2007-07-31 drh: void baseline_zip_cmd(void){ dead090c0b 2007-07-31 drh: int rid; dead090c0b 2007-07-31 drh: Blob zip; dead090c0b 2007-07-31 drh: if( g.argc!=4 ){ dead090c0b 2007-07-31 drh: usage("UUID ZIPFILE"); dead090c0b 2007-07-31 drh: } dead090c0b 2007-07-31 drh: db_must_be_within_tree(); dead090c0b 2007-07-31 drh: rid = name_to_rid(g.argv[2]); 974fd92330 2008-02-08 stephan: zip_of_baseline(rid, &zip, g.argv[2]); dead090c0b 2007-07-31 drh: blob_write_to_file(&zip, g.argv[3]); 6dab6149b1 2007-08-01 drh: } 6dab6149b1 2007-08-01 drh: 6dab6149b1 2007-08-01 drh: /* 6dab6149b1 2007-08-01 drh: ** WEBPAGE: zip 677aa71bca 2007-10-12 drh: ** URL: /zip/RID.zip 6dab6149b1 2007-08-01 drh: ** 677aa71bca 2007-10-12 drh: ** Generate a ZIP archive for the baseline. 677aa71bca 2007-10-12 drh: ** Return that ZIP archive as the HTTP reply content. 6dab6149b1 2007-08-01 drh: */ 6dab6149b1 2007-08-01 drh: void baseline_zip_page(void){ 6dab6149b1 2007-08-01 drh: int rid; 6dab6149b1 2007-08-01 drh: char *zName; 6dab6149b1 2007-08-01 drh: int i; 6dab6149b1 2007-08-01 drh: Blob zip; 6dab6149b1 2007-08-01 drh: 6dab6149b1 2007-08-01 drh: login_check_credentials(); 6dab6149b1 2007-08-01 drh: if( !g.okRead || !g.okHistory ){ login_needed(); return; } 677aa71bca 2007-10-12 drh: zName = mprintf("%s", PD("name","")); 6dab6149b1 2007-08-01 drh: i = strlen(zName); 6dab6149b1 2007-08-01 drh: for(i=strlen(zName)-1; i>5; i--){ 6dab6149b1 2007-08-01 drh: if( zName[i]=='.' ){ 6dab6149b1 2007-08-01 drh: zName[i] = 0; 6dab6149b1 2007-08-01 drh: break; 6dab6149b1 2007-08-01 drh: } 6dab6149b1 2007-08-01 drh: } 6dab6149b1 2007-08-01 drh: rid = name_to_rid(zName); 6dab6149b1 2007-08-01 drh: if( rid==0 ){ 6dab6149b1 2007-08-01 drh: @ Not found 6dab6149b1 2007-08-01 drh: return; 6dab6149b1 2007-08-01 drh: } 974fd92330 2008-02-08 stephan: zip_of_baseline(rid, &zip, zName); 6dab6149b1 2007-08-01 drh: cgi_set_content(&zip); 6dab6149b1 2007-08-01 drh: cgi_set_content_type("application/zip"); 6dab6149b1 2007-08-01 drh: cgi_reply(); 9b780d220b 2007-07-31 drh: }