From: dan Date: Tue, 26 Dec 2017 20:39:58 +0000 (+0000) Subject: Add new file ext/misc/zipfile.c, containing a virtual table for read-only X-Git-Tag: version-3.22.0~108^2~20 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=9ebfaad25db43869ccfae50c02e0fd3310a95e9b;p=thirdparty%2Fsqlite.git Add new file ext/misc/zipfile.c, containing a virtual table for read-only access to simple zip archives. FossilOrigin-Name: 8e366b99b13d765d8bf000a7ec5919e582702e51dc07c27a746b6002898a2302 --- diff --git a/ext/misc/zipfile.c b/ext/misc/zipfile.c new file mode 100644 index 0000000000..bcee873044 --- /dev/null +++ b/ext/misc/zipfile.c @@ -0,0 +1,696 @@ +/* +** 2017-12-26 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +*/ +#include "sqlite3ext.h" +SQLITE_EXTENSION_INIT1 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef SQLITE_OMIT_VIRTUALTABLE + +#ifndef SQLITE_AMALGAMATION +typedef sqlite3_int64 i64; +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned long u32; +#define MIN(a,b) ((a)<(b) ? (a) : (b)) +#endif + +#define ZIPFILE_SCHEMA "CREATE TABLE y(" \ + "name, /* Name of file in zip archive */" \ + "mode, /* POSIX mode for file */" \ + "mtime, /* Last modification time in seconds since epoch */" \ + "sz, /* Size of object */" \ + "data, /* Data stored in zip file (possibly compressed) */" \ + "method, /* Compression method (integer) */" \ + "f HIDDEN /* Name of zip file */" \ +");" + +#define ZIPFILE_F_COLUMN_IDX 6 /* Index of column "f" in the above */ + +#define ZIPFILE_BUFFER_SIZE (64*1024) + +/* +** Set the error message contained in context ctx to the results of +** vprintf(zFmt, ...). +*/ +static void zipfileCtxErrorMsg(sqlite3_context *ctx, const char *zFmt, ...){ + char *zMsg = 0; + va_list ap; + va_start(ap, zFmt); + zMsg = sqlite3_vmprintf(zFmt, ap); + sqlite3_result_error(ctx, zMsg, -1); + sqlite3_free(zMsg); + va_end(ap); +} + + +/* +*** 4.3.16 End of central directory record: +*** +*** end of central dir signature 4 bytes (0x06054b50) +*** number of this disk 2 bytes +*** number of the disk with the +*** start of the central directory 2 bytes +*** total number of entries in the +*** central directory on this disk 2 bytes +*** total number of entries in +*** the central directory 2 bytes +*** size of the central directory 4 bytes +*** offset of start of central +*** directory with respect to +*** the starting disk number 4 bytes +*** .ZIP file comment length 2 bytes +*** .ZIP file comment (variable size) +*/ +typedef struct ZipfileEOCD ZipfileEOCD; +struct ZipfileEOCD { + u16 iDisk; + u16 iFirstDisk; + u16 nEntry; + u16 nEntryTotal; + u32 nSize; + u32 iOffset; +}; + +/* +*** 4.3.12 Central directory structure: +*** +*** ... +*** +*** central file header signature 4 bytes (0x02014b50) +*** version made by 2 bytes +*** version needed to extract 2 bytes +*** general purpose bit flag 2 bytes +*** compression method 2 bytes +*** last mod file time 2 bytes +*** last mod file date 2 bytes +*** crc-32 4 bytes +*** compressed size 4 bytes +*** uncompressed size 4 bytes +*** file name length 2 bytes +*** extra field length 2 bytes +*** file comment length 2 bytes +*** disk number start 2 bytes +*** internal file attributes 2 bytes +*** external file attributes 4 bytes +*** relative offset of local header 4 bytes +*/ +typedef struct ZipfileCDS ZipfileCDS; +struct ZipfileCDS { + u16 iVersionMadeBy; + u16 iVersionExtract; + u16 flags; + u16 iCompression; + u16 mTime; + u16 mDate; + u32 crc32; + u32 szCompressed; + u32 szUncompressed; + u16 nFile; + u16 nExtra; + u16 nComment; + u16 iDiskStart; + u16 iInternalAttr; + u32 iExternalAttr; + u32 iOffset; + char *zFile; /* Filename (sqlite3_malloc()) */ +}; + +/* +*** 4.3.7 Local file header: +*** +*** local file header signature 4 bytes (0x04034b50) +*** version needed to extract 2 bytes +*** general purpose bit flag 2 bytes +*** compression method 2 bytes +*** last mod file time 2 bytes +*** last mod file date 2 bytes +*** crc-32 4 bytes +*** compressed size 4 bytes +*** uncompressed size 4 bytes +*** file name length 2 bytes +*** extra field length 2 bytes +*** +*/ +typedef struct ZipfileLFH ZipfileLFH; +struct ZipfileLFH { + u16 iVersionExtract; + u16 flags; + u16 iCompression; + u16 mTime; + u16 mDate; + u32 crc32; + u32 szCompressed; + u32 szUncompressed; + u16 nFile; + u16 nExtra; +}; + +/* +** Cursor type for recursively iterating through a directory structure. +*/ +typedef struct ZipfileCsr ZipfileCsr; + +struct ZipfileCsr { + sqlite3_vtab_cursor base; /* Base class - must be first */ + i64 iRowid; /* Rowid for current row */ + FILE *pFile; /* Zip file */ + i64 nByte; /* Size of zip file on disk */ + int bEof; /* True when at EOF */ + i64 iNextOff; /* Offset of next record in central directory */ + ZipfileEOCD eocd; /* Parse of central directory record */ + ZipfileCDS cds; /* Central Directory Structure */ + ZipfileLFH lfh; /* Local File Header for current entry */ + i64 iDataOff; /* Offset in zipfile to data */ + u32 mTime; /* Extended mtime value */ + int flags; + u8 *aBuffer; /* Buffer used for various tasks */ +}; + +#define ZIPFILE_MTIME_VALID 0x0001 + +typedef struct ZipfileTab ZipfileTab; +struct ZipfileTab { + sqlite3_vtab base; /* Base class - must be first */ +}; + +/* +** Construct a new ZipfileTab virtual table object. +*/ +static int zipfileConnect( + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVtab, + char **pzErr +){ + ZipfileTab *pNew = 0; + int rc; + + rc = sqlite3_declare_vtab(db, ZIPFILE_SCHEMA); + if( rc==SQLITE_OK ){ + pNew = (ZipfileTab*)sqlite3_malloc( sizeof(*pNew) ); + if( pNew==0 ) return SQLITE_NOMEM; + memset(pNew, 0, sizeof(*pNew)); + } + *ppVtab = (sqlite3_vtab*)pNew; + return rc; +} + +/* +** This method is the destructor for zipfile vtab objects. +*/ +static int zipfileDisconnect(sqlite3_vtab *pVtab){ + sqlite3_free(pVtab); + return SQLITE_OK; +} + +/* +** Constructor for a new ZipfileCsr object. +*/ +static int zipfileOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCsr){ + ZipfileCsr *pCsr; + pCsr = sqlite3_malloc( sizeof(*pCsr) + ZIPFILE_BUFFER_SIZE); + if( pCsr==0 ) return SQLITE_NOMEM; + memset(pCsr, 0, sizeof(*pCsr)); + pCsr->aBuffer = (u8*)&pCsr[1]; + *ppCsr = &pCsr->base; + return SQLITE_OK; +} + +/* +** Reset a cursor back to the state it was in when first returned +** by zipfileOpen(). +*/ +static void zipfileResetCursor(ZipfileCsr *pCsr){ + pCsr->iRowid = 0; + pCsr->bEof = 0; + if( pCsr->pFile ){ + fclose(pCsr->pFile); + pCsr->pFile = 0; + } +} + +/* +** Destructor for an ZipfileCsr. +*/ +static int zipfileClose(sqlite3_vtab_cursor *cur){ + ZipfileCsr *pCsr = (ZipfileCsr*)cur; + zipfileResetCursor(pCsr); + sqlite3_free(pCsr); + return SQLITE_OK; +} + +/* +** Set the error message for the virtual table associated with cursor +** pCsr to the results of vprintf(zFmt, ...). +*/ +static void zipfileSetErrmsg(ZipfileCsr *pCsr, const char *zFmt, ...){ + va_list ap; + va_start(ap, zFmt); + pCsr->base.pVtab->zErrMsg = sqlite3_vmprintf(zFmt, ap); + va_end(ap); +} + +static int zipfileReadData(ZipfileCsr *pCsr, u8 *aRead, int nRead, i64 iOff){ + size_t n; + fseek(pCsr->pFile, iOff, SEEK_SET); + n = fread(aRead, 1, nRead, pCsr->pFile); + if( n!=nRead ){ + zipfileSetErrmsg(pCsr, "error in fread()"); + return SQLITE_ERROR; + } + return SQLITE_OK; +} + +static u16 zipfileGetU16(const u8 *aBuf){ + return (aBuf[1] << 8) + aBuf[0]; +} +static u32 zipfileGetU32(const u8 *aBuf){ + return ((u32)(aBuf[3]) << 24) + + ((u32)(aBuf[2]) << 16) + + ((u32)(aBuf[1]) << 8) + + ((u32)(aBuf[0]) << 0); +} + +#define zipfileRead32(aBuf) ( aBuf+=4, zipfileGetU32(aBuf-4) ) +#define zipfileRead16(aBuf) ( aBuf+=2, zipfileGetU16(aBuf-2) ) + +static int zipfileReadCDS(ZipfileCsr *pCsr){ + static const int szFix = 46; /* Size of fixed-size part of CDS */ + u8 *aRead = pCsr->aBuffer; + int rc; + + rc = zipfileReadData(pCsr, aRead, szFix, pCsr->iNextOff); + if( rc==SQLITE_OK ){ + u32 sig = zipfileRead32(aRead); + if( sig!=0x02014b50 ){ + zipfileSetErrmsg(pCsr,"failed to read CDS at offset %lld",pCsr->iNextOff); + rc = SQLITE_ERROR; + }else{ + int nRead; + pCsr->cds.iVersionMadeBy = zipfileRead16(aRead); + pCsr->cds.iVersionExtract = zipfileRead16(aRead); + pCsr->cds.flags = zipfileRead16(aRead); + pCsr->cds.iCompression = zipfileRead16(aRead); + pCsr->cds.mTime = zipfileRead16(aRead); + pCsr->cds.mDate = zipfileRead16(aRead); + pCsr->cds.crc32 = zipfileRead32(aRead); + pCsr->cds.szCompressed = zipfileRead32(aRead); + pCsr->cds.szUncompressed = zipfileRead32(aRead); + pCsr->cds.nFile = zipfileRead16(aRead); + pCsr->cds.nExtra = zipfileRead16(aRead); + pCsr->cds.nComment = zipfileRead16(aRead); + pCsr->cds.iDiskStart = zipfileRead16(aRead); + pCsr->cds.iInternalAttr = zipfileRead16(aRead); + pCsr->cds.iExternalAttr = zipfileRead32(aRead); + pCsr->cds.iOffset = zipfileRead32(aRead); + + assert( aRead==&pCsr->aBuffer[szFix] ); + + nRead = pCsr->cds.nFile + pCsr->cds.nExtra; + aRead = pCsr->aBuffer; + rc = zipfileReadData(pCsr, aRead, nRead, pCsr->iNextOff+szFix); + + if( rc==SQLITE_OK ){ + pCsr->cds.zFile = sqlite3_mprintf("%.*s", (int)pCsr->cds.nFile, aRead); + pCsr->iNextOff += szFix; + pCsr->iNextOff += pCsr->cds.nFile; + pCsr->iNextOff += pCsr->cds.nExtra; + pCsr->iNextOff += pCsr->cds.nComment; + } + + /* Scan the "extra" fields */ + if( rc==SQLITE_OK ){ + u8 *p = &aRead[pCsr->cds.nFile]; + u8 *pEnd = &p[pCsr->cds.nExtra]; + + while( p modtime is present */ + pCsr->mTime = zipfileGetU32(&p[1]); + pCsr->flags |= ZIPFILE_MTIME_VALID; + } + break; + } + + case 0x7875: /* Info-ZIP Unix (new) */ + break; + } + + p += nByte; + } + } + } + } + + return rc; +} + +static int zipfileReadLFH(ZipfileCsr *pCsr){ + static const int szFix = 30; /* Size of fixed-size part of LFH */ + u8 *aRead = pCsr->aBuffer; + int rc; + + rc = zipfileReadData(pCsr, aRead, szFix, pCsr->cds.iOffset); + if( rc==SQLITE_OK ){ + u32 sig = zipfileRead32(aRead); + if( sig!=0x04034b50 ){ + zipfileSetErrmsg(pCsr, "failed to read LFH at offset %d", + (int)pCsr->cds.iOffset + ); + rc = SQLITE_ERROR; + }else{ + pCsr->lfh.iVersionExtract = zipfileRead16(aRead); + pCsr->lfh.flags = zipfileRead16(aRead); + pCsr->lfh.iCompression = zipfileRead16(aRead); + pCsr->lfh.mTime = zipfileRead16(aRead); + pCsr->lfh.mDate = zipfileRead16(aRead); + pCsr->lfh.crc32 = zipfileRead32(aRead); + pCsr->lfh.szCompressed = zipfileRead32(aRead); + pCsr->lfh.szUncompressed = zipfileRead32(aRead); + pCsr->lfh.nFile = zipfileRead16(aRead); + pCsr->lfh.nExtra = zipfileRead16(aRead); + assert( aRead==&pCsr->aBuffer[szFix] ); + pCsr->iDataOff = pCsr->cds.iOffset+szFix+pCsr->lfh.nFile+pCsr->lfh.nExtra; + } + } + + return rc; +} + + +/* +** Advance an ZipfileCsr to its next row of output. +*/ +static int zipfileNext(sqlite3_vtab_cursor *cur){ + ZipfileCsr *pCsr = (ZipfileCsr*)cur; + i64 iEof = pCsr->eocd.iOffset + pCsr->eocd.nSize; + int rc = SQLITE_OK; + + if( pCsr->iNextOff>=iEof ){ + pCsr->bEof = 1; + }else{ + pCsr->iRowid++; + pCsr->flags = 0; + rc = zipfileReadCDS(pCsr); + if( rc==SQLITE_OK ){ + rc = zipfileReadLFH(pCsr); + } + } + return rc; +} + +/* +** "Standard" MS-DOS time format: +** +** File modification time: +** Bits 00-04: seconds divided by 2 +** Bits 05-10: minute +** Bits 11-15: hour +** File modification date: +** Bits 00-04: day +** Bits 05-08: month (1-12) +** Bits 09-15: years from 1980 +*/ +static time_t zipfileMtime(ZipfileCsr *pCsr){ + struct tm t; + memset(&t, 0, sizeof(t)); + t.tm_sec = (pCsr->cds.mTime & 0x1F)*2; + t.tm_min = (pCsr->cds.mTime >> 5) & 0x2F; + t.tm_hour = (pCsr->cds.mTime >> 11) & 0x1F; + + t.tm_mday = (pCsr->cds.mDate & 0x1F); + t.tm_mon = ((pCsr->cds.mDate >> 5) & 0x0F) - 1; + t.tm_year = 80 + ((pCsr->cds.mDate >> 9) & 0x7F); + + return mktime(&t); +} + +/* +** Return values of columns for the row at which the series_cursor +** is currently pointing. +*/ +static int zipfileColumn( + sqlite3_vtab_cursor *cur, /* The cursor */ + sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ + int i /* Which column to return */ +){ + ZipfileCsr *pCsr = (ZipfileCsr*)cur; + int rc = SQLITE_OK; + switch( i ){ + case 0: /* name */ + sqlite3_result_text(ctx, pCsr->cds.zFile, -1, SQLITE_TRANSIENT); + break; + case 1: /* mode */ + /* TODO: Whether or not the following is correct surely depends on + ** the platform on which the archive was created. */ + sqlite3_result_int(ctx, pCsr->cds.iExternalAttr >> 16); + break; + case 2: { /* mtime */ + if( pCsr->flags & ZIPFILE_MTIME_VALID ){ + sqlite3_result_int64(ctx, pCsr->mTime); + }else{ + sqlite3_result_int64(ctx, zipfileMtime(pCsr)); + } + break; + } + case 3: { /* sz */ + sqlite3_result_int64(ctx, pCsr->cds.szUncompressed); + break; + } + case 4: { /* data */ + int sz = pCsr->cds.szCompressed; + if( sz>0 ){ + u8 *aBuf = sqlite3_malloc(sz); + if( aBuf==0 ){ + rc = SQLITE_NOMEM; + }else{ + rc = zipfileReadData(pCsr, aBuf, sz, pCsr->iDataOff); + } + if( rc==SQLITE_OK ){ + sqlite3_result_blob(ctx, aBuf, sz, SQLITE_TRANSIENT); + sqlite3_free(aBuf); + } + } + break; + } + case 5: /* method */ + sqlite3_result_int(ctx, pCsr->cds.iCompression); + break; + } + + return SQLITE_OK; +} + +/* +** Return the rowid for the current row. In this implementation, the +** first row returned is assigned rowid value 1, and each subsequent +** row a value 1 more than that of the previous. +*/ +static int zipfileRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ + ZipfileCsr *pCsr = (ZipfileCsr*)cur; + *pRowid = pCsr->iRowid; + return SQLITE_OK; +} + +/* +** Return TRUE if the cursor has been moved off of the last +** row of output. +*/ +static int zipfileEof(sqlite3_vtab_cursor *cur){ + ZipfileCsr *pCsr = (ZipfileCsr*)cur; + return pCsr->bEof; +} + +/* +** The zip file has been successfully opened (so pCsr->pFile is valid). +** This function attempts to locate and read the End of central +** directory record from the file. +** +*/ +static int zipfileReadEOCD(ZipfileCsr *pCsr, ZipfileEOCD *pEOCD){ + u8 *aRead = pCsr->aBuffer; + int nRead = (int)(MIN(pCsr->nByte, ZIPFILE_BUFFER_SIZE)); + i64 iOff = pCsr->nByte - nRead; + + int rc = zipfileReadData(pCsr, aRead, nRead, iOff); + if( rc==SQLITE_OK ){ + int i; + + /* Scan backwards looking for the signature bytes */ + for(i=nRead-20; i>=0; i--){ + if( aRead[i]==0x50 && aRead[i+1]==0x4b + && aRead[i+2]==0x05 && aRead[i+3]==0x06 + ){ + break; + } + } + if( i<0 ){ + zipfileSetErrmsg(pCsr, "cannot find end of central directory record"); + return SQLITE_ERROR; + } + + aRead += i+4; + pEOCD->iDisk = zipfileRead16(aRead); + pEOCD->iFirstDisk = zipfileRead16(aRead); + pEOCD->nEntry = zipfileRead16(aRead); + pEOCD->nEntryTotal = zipfileRead16(aRead); + pEOCD->nSize = zipfileRead32(aRead); + pEOCD->iOffset = zipfileRead32(aRead); + +#if 0 + printf("iDisk=%d iFirstDisk=%d nEntry=%d " + "nEntryTotal=%d nSize=%d iOffset=%d", + (int)pEOCD->iDisk, (int)pEOCD->iFirstDisk, (int)pEOCD->nEntry, + (int)pEOCD->nEntryTotal, (int)pEOCD->nSize, (int)pEOCD->iOffset + ); +#endif + } + + return SQLITE_OK; +} + +/* +** xFilter callback. +*/ +static int zipfileFilter( + sqlite3_vtab_cursor *cur, + int idxNum, const char *idxStr, + int argc, sqlite3_value **argv +){ + ZipfileCsr *pCsr = (ZipfileCsr*)cur; + const char *zFile; /* Zip file to scan */ + int rc = SQLITE_OK; /* Return Code */ + + zipfileResetCursor(pCsr); + + assert( idxNum==argc && (idxNum==0 || idxNum==1) ); + if( idxNum==0 ){ + /* Error. User did not supply a file name. */ + zipfileSetErrmsg(pCsr, "table function zipfile() requires an argument"); + return SQLITE_ERROR; + } + + zFile = sqlite3_value_text(argv[0]); + pCsr->pFile = fopen(zFile, "rb"); + if( pCsr->pFile==0 ){ + zipfileSetErrmsg(pCsr, "cannot open file: %s", zFile); + rc = SQLITE_ERROR; + }else{ + fseek(pCsr->pFile, 0, SEEK_END); + pCsr->nByte = (i64)ftell(pCsr->pFile); + rc = zipfileReadEOCD(pCsr, &pCsr->eocd); + if( rc==SQLITE_OK ){ + pCsr->iNextOff = pCsr->eocd.iOffset; + rc = zipfileNext(cur); + } + } + + return rc; +} + +/* +** xBestIndex callback. +*/ +static int zipfileBestIndex( + sqlite3_vtab *tab, + sqlite3_index_info *pIdxInfo +){ + int i; + + for(i=0; inConstraint; i++){ + const struct sqlite3_index_constraint *pCons = &pIdxInfo->aConstraint[i]; + if( pCons->usable==0 ) continue; + if( pCons->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue; + if( pCons->iColumn!=ZIPFILE_F_COLUMN_IDX ) continue; + break; + } + + if( inConstraint ){ + pIdxInfo->aConstraintUsage[i].argvIndex = 1; + pIdxInfo->aConstraintUsage[i].omit = 1; + pIdxInfo->estimatedCost = 1000.0; + pIdxInfo->idxNum = 1; + }else{ + pIdxInfo->estimatedCost = (double)(((sqlite3_int64)1) << 50); + pIdxInfo->idxNum = 0; + } + + return SQLITE_OK; +} + +/* +** Register the "zipfile" virtual table. +*/ +static int zipfileRegister(sqlite3 *db){ + static sqlite3_module zipfileModule = { + 0, /* iVersion */ + 0, /* xCreate */ + zipfileConnect, /* xConnect */ + zipfileBestIndex, /* xBestIndex */ + zipfileDisconnect, /* xDisconnect */ + 0, /* xDestroy */ + zipfileOpen, /* xOpen - open a cursor */ + zipfileClose, /* xClose - close a cursor */ + zipfileFilter, /* xFilter - configure scan constraints */ + zipfileNext, /* xNext - advance a cursor */ + zipfileEof, /* xEof - check for end of scan */ + zipfileColumn, /* xColumn - read data */ + zipfileRowid, /* xRowid - read data */ + 0, /* xUpdate */ + 0, /* xBegin */ + 0, /* xSync */ + 0, /* xCommit */ + 0, /* xRollback */ + 0, /* xFindMethod */ + 0, /* xRename */ + }; + + int rc = sqlite3_create_module(db, "zipfile" , &zipfileModule, 0); + return rc; +} +#else /* SQLITE_OMIT_VIRTUALTABLE */ +# define zipfileRegister(x) SQLITE_OK +#endif + +#ifdef _WIN32 +__declspec(dllexport) +#endif +int sqlite3_zipfile_init( + sqlite3 *db, + char **pzErrMsg, + const sqlite3_api_routines *pApi +){ + int rc = SQLITE_OK; + SQLITE_EXTENSION_INIT2(pApi); + (void)pzErrMsg; /* Unused parameter */ + return zipfileRegister(db); +} + diff --git a/main.mk b/main.mk index ea0ff8bc2e..ff379da861 100644 --- a/main.mk +++ b/main.mk @@ -695,7 +695,8 @@ SHELL_SRC = \ $(TOP)/ext/misc/completion.c \ $(TOP)/ext/misc/sqlar.c \ $(TOP)/ext/expert/sqlite3expert.c \ - $(TOP)/ext/expert/sqlite3expert.h + $(TOP)/ext/expert/sqlite3expert.h \ + $(TOP)/ext/misc/zipfile.c shell.c: $(SHELL_SRC) $(TOP)/tool/mkshellc.tcl tclsh $(TOP)/tool/mkshellc.tcl >shell.c diff --git a/manifest b/manifest index 0293660ba4..a788cbbd26 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\senhancements\sfrom\strunk. -D 2017-12-23T18:34:49.545 +C Add\snew\sfile\sext/misc/zipfile.c,\scontaining\sa\svirtual\stable\sfor\sread-only\naccess\sto\ssimple\szip\sarchives. +D 2017-12-26T20:39:58.777 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in ceb40bfcb30ebba8e1202b34c56ff7e13e112f9809e2381d99be32c2726058f5 @@ -302,6 +302,7 @@ F ext/misc/vfsstat.c bf10ef0bc51e1ad6756629e1edb142f7a8db1178 F ext/misc/vtablog.c 31d0d8f4406795679dcd3a67917c213d3a2a5fb3ea5de35f6e773491ed7e13c9 F ext/misc/vtshim.c 1976e6dd68dd0d64508c91a6dfab8e75f8aaf6cd F ext/misc/wholenumber.c 784b12543d60702ebdd47da936e278aa03076212 +F ext/misc/zipfile.c 9736694a5eb029397e769f06517250be8b8e3836f4869246bfb60942a4047227 F ext/rbu/rbu.c ea7d1b7eb44c123a2a619332e19fe5313500705c4a58aaa1887905c0d83ffc2e F ext/rbu/rbu1.test 43836fac8c7179a358eaf38a8a1ef3d6e6285842 F ext/rbu/rbu10.test 1846519a438697f45e9dcb246908af81b551c29e1078d0304fae83f1fed7e9ee @@ -404,7 +405,7 @@ F ext/userauth/userauth.c 3410be31283abba70255d71fd24734e017a4497f F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8 F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60 -F main.mk eef9a9918485b5df70d7a69ed3d0e1dd182bf714740122a144905a59d42da5c6 +F main.mk fc13303745f7a06e2eac69406ee0e7ba481f6df37a528ceb6ebacc03e310a020 F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83 F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271 F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504 @@ -482,7 +483,7 @@ F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 F src/resolve.c bbee7e31d369a18a2f4836644769882e9c5d40ef4a3af911db06410b65cb3730 F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac F src/select.c 8b22abe193e4d8243befa2038e4ae2405802fed1c446e5e502d11f652e09ba74 -F src/shell.c.in e739db2809b9ad38ac389a89bead6986542a679ca33b153aef5850856998b525 +F src/shell.c.in 1c927f9407fa4e58ed114577971525209ea12a293d25fe689d1973d9fef17f74 F src/sqlite.h.in 2126192945019d4cdce335cb236b440a05ec75c93e4cd94c9c6d6e7fcc654cc4 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h c02d628cca67f3889c689d82d25c3eb45e2c155db08e4c6089b5840d64687d34 @@ -1691,7 +1692,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 7652b3c2374084047b6c1da3e525e0cac34fe220597f81e793bc4fd9f33358da 07c773148d8db185fa54991df09298b64f4fef28879e6c9395759265e8183977 -R 0cdaf396f246262d8fd00807c02fe094 -U drh -Z d44ebee6c3c37877974b2b88daec7bfe +P 150f07fec1e6d1fc0601820d717d8712fc513fe0d4bed67c8679eb51bca30d53 +R ab04bfd243997fb0b46867b0347c7799 +U dan +Z 06eecfc1ea586319973b447240342e1d diff --git a/manifest.uuid b/manifest.uuid index 3fe37939e4..85c9e9cdf5 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -150f07fec1e6d1fc0601820d717d8712fc513fe0d4bed67c8679eb51bca30d53 \ No newline at end of file +8e366b99b13d765d8bf000a7ec5919e582702e51dc07c27a746b6002898a2302 \ No newline at end of file diff --git a/src/shell.c.in b/src/shell.c.in index 444df58899..b3ef375c0b 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -797,6 +797,7 @@ INCLUDE ../ext/misc/shathree.c INCLUDE ../ext/misc/fileio.c INCLUDE ../ext/misc/completion.c #ifdef SQLITE_HAVE_ZLIB +INCLUDE ../ext/misc/zipfile.c INCLUDE ../ext/misc/sqlar.c #endif INCLUDE ../ext/expert/sqlite3expert.h @@ -3002,6 +3003,7 @@ static void open_db(ShellState *p, int keepAlive){ sqlite3_shathree_init(p->db, 0, 0); sqlite3_completion_init(p->db, 0, 0); #ifdef SQLITE_HAVE_ZLIB + sqlite3_zipfile_init(p->db, 0, 0); sqlite3_sqlar_init(p->db, 0, 0); #endif sqlite3_create_function(p->db, "shell_add_schema", 2, SQLITE_UTF8, 0,