/ Check-in [029ebcd3]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:If the argument to table function zipfile() is a blob (not text), assume that it contains a zip file image to interpret, not the name of a file on disk.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 029ebcd30cb261d949f7587ac54c23d7479796b6716fd4ca7512361b8f32de3e
User & Date: dan 2018-01-26 18:59:25
Context
2018-01-26
22:41
Fix the query planner so that it takes into account dependencies in the arguments to table-valued functions in subexpressions in the WHERE clause. Fix for ticket [80177f0c226ff54f6dd]. check-in: 7daa6873 user: drh tags: trunk
18:59
If the argument to table function zipfile() is a blob (not text), assume that it contains a zip file image to interpret, not the name of a file on disk. check-in: 029ebcd3 user: dan tags: trunk
18:37
Improve text-to-integer conversion in boundary cases. The sqlite3Atoi64() function always returns the minimum or maximum integer if the magnitude of the text value is too large. Trailing whitespace is now ignored. check-in: ace0644a user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to ext/misc/zipfile.c.

   221    221   };
   222    222   
   223    223   typedef struct ZipfileEntry ZipfileEntry;
   224    224   struct ZipfileEntry {
   225    225     ZipfileCDS cds;            /* Parsed CDS record */
   226    226     u32 mUnixTime;             /* Modification time, in UNIX format */
   227    227     u8 *aExtra;                /* cds.nExtra+cds.nComment bytes of extra data */
          228  +  i64 iDataOff;
          229  +  u8 *aData;                 /* cds.szCompressed bytes of compressed data */
   228    230     ZipfileEntry *pNext;       /* Next element in in-memory CDS */
   229    231   };
   230    232   
   231    233   /* 
   232    234   ** Cursor type for recursively iterating through a directory structure.
   233    235   */
   234    236   typedef struct ZipfileCsr ZipfileCsr;
................................................................................
   238    240     u8 bEof;                   /* True when at EOF */
   239    241     u8 bNoop;                  /* If next xNext() call is no-op */
   240    242   
   241    243     /* Used outside of write transactions */
   242    244     FILE *pFile;               /* Zip file */
   243    245     i64 iNextOff;              /* Offset of next record in central directory */
   244    246     ZipfileEOCD eocd;          /* Parse of central directory record */
          247  +
          248  +  ZipfileEntry *pFreeEntry;
   245    249   
   246    250     ZipfileEntry *pCurrent;    /* Current entry */
   247         -  ZipfileLFH lfh;            /* Local File Header for current entry */
   248         -  i64 iDataOff;              /* Offset in zipfile to data */
   249    251     ZipfileCsr *pCsrNext;      /* Next cursor on same virtual table */
   250    252   };
   251    253   
   252    254   /*
   253    255   ** Possible values for ZipfileCsr.eType. Set in zipfileFilter().
   254    256   */
   255    257   #define ZIPFILE_CSR_LIST 1        /* Cursor reads from ZipfileTab.pFirstEntry */
................................................................................
   389    391   }
   390    392   
   391    393   /*
   392    394   ** Reset a cursor back to the state it was in when first returned
   393    395   ** by zipfileOpen().
   394    396   */
   395    397   static void zipfileResetCursor(ZipfileCsr *pCsr){
          398  +  ZipfileEntry *p;
          399  +  ZipfileEntry *pNext;
          400  +
   396    401     pCsr->bEof = 0;
   397    402     if( pCsr->pFile ){
   398    403       fclose(pCsr->pFile);
   399    404       pCsr->pFile = 0;
   400    405       zipfileEntryFree(pCsr->pCurrent);
   401    406       pCsr->pCurrent = 0;
   402    407     }
          408  +
          409  +  for(p=pCsr->pFreeEntry; p; p=pNext){
          410  +    pNext = p->pNext;
          411  +    zipfileEntryFree(p);
          412  +  }
   403    413   }
   404    414   
   405    415   /*
   406    416   ** Destructor for an ZipfileCsr.
   407    417   */
   408    418   static int zipfileClose(sqlite3_vtab_cursor *cur){
   409    419     ZipfileCsr *pCsr = (ZipfileCsr*)cur;
................................................................................
   499    509   }
   500    510   
   501    511   /*
   502    512   ** Magic numbers used to read CDS records.
   503    513   */
   504    514   #define ZIPFILE_CDS_FIXED_SZ         46
   505    515   #define ZIPFILE_CDS_NFILE_OFF        28
          516  +#define ZIPFILE_CDS_SZCOMPRESSED_OFF 20
   506    517   
   507    518   /*
   508    519   ** Decode the CDS record in buffer aBuf into (*pCDS). Return SQLITE_ERROR
   509    520   ** if the record is not well-formed, or SQLITE_OK otherwise.
   510    521   */
   511    522   static int zipfileReadCDS(u8 *aBuf, ZipfileCDS *pCDS){
   512    523     u8 *aRead = aBuf;
................................................................................
   591    602   
   592    603     t.tm_mday = (pCDS->mDate & 0x1F);
   593    604     t.tm_mon = ((pCDS->mDate >> 5) & 0x0F) - 1;
   594    605     t.tm_year = 80 + ((pCDS->mDate >> 9) & 0x7F);
   595    606   
   596    607     return mktime(&t);
   597    608   }
          609  +
          610  +static int zipfileReadLFH(
          611  +  u8 *aBuffer,
          612  +  ZipfileLFH *pLFH
          613  +){
          614  +  u8 *aRead = aBuffer;
          615  +  int rc = SQLITE_OK;
          616  +
          617  +  u32 sig = zipfileRead32(aRead);
          618  +  if( sig!=ZIPFILE_SIGNATURE_LFH ){
          619  +    rc = SQLITE_ERROR;
          620  +  }else{
          621  +    pLFH->iVersionExtract = zipfileRead16(aRead);
          622  +    pLFH->flags = zipfileRead16(aRead);
          623  +    pLFH->iCompression = zipfileRead16(aRead);
          624  +    pLFH->mTime = zipfileRead16(aRead);
          625  +    pLFH->mDate = zipfileRead16(aRead);
          626  +    pLFH->crc32 = zipfileRead32(aRead);
          627  +    pLFH->szCompressed = zipfileRead32(aRead);
          628  +    pLFH->szUncompressed = zipfileRead32(aRead);
          629  +    pLFH->nFile = zipfileRead16(aRead);
          630  +    pLFH->nExtra = zipfileRead16(aRead);
          631  +  }
          632  +  return rc;
          633  +}
   598    634   
   599    635   /*
   600    636   ** Read a Zip archive CDS header from offset iOff of file pFile. Return
   601    637   ** SQLITE_OK if successful, or an SQLite error code otherwise.
   602    638   */
   603    639   static int zipfileGetEntry(
   604    640     ZipfileTab *pTab,               /* Store any error message here */
   605         -  FILE *pFile,
          641  +  const u8 *aBlob,                /* Pointer to in-memory file image */
          642  +  int nBlob,                      /* Size of aBlob[] in bytes */
          643  +  FILE *pFile,                    /* If aBlob==0, read from this file */
   606    644     i64 iOff,
   607    645     ZipfileEntry **ppEntry
   608    646   ){
   609         -  u8 *aRead = pTab->aBuffer;
          647  +  u8 *aRead;
   610    648     char **pzErr = &pTab->base.zErrMsg;
   611         -  int rc;
          649  +  int rc = SQLITE_OK;
   612    650   
   613         -  rc = zipfileReadData(pFile, aRead, ZIPFILE_CDS_FIXED_SZ, iOff, pzErr);
          651  +  if( aBlob==0 ){
          652  +    aRead = pTab->aBuffer;
          653  +    rc = zipfileReadData(pFile, aRead, ZIPFILE_CDS_FIXED_SZ, iOff, pzErr);
          654  +  }else{
          655  +    aRead = (u8*)&aBlob[iOff];
          656  +  }
          657  +
   614    658     if( rc==SQLITE_OK ){
   615         -    if( rc!=SQLITE_OK ){
   616         -      *pzErr = sqlite3_mprintf("failed to read CDS at offset %lld", iOff);
          659  +    int nAlloc;
          660  +    ZipfileEntry *pNew;
          661  +
          662  +    int nFile = zipfileGetU16(&aRead[ZIPFILE_CDS_NFILE_OFF]);
          663  +    int nExtra = zipfileGetU16(&aRead[ZIPFILE_CDS_NFILE_OFF+2]);
          664  +    nExtra += zipfileGetU16(&aRead[ZIPFILE_CDS_NFILE_OFF+4]);
          665  +
          666  +    nAlloc = sizeof(ZipfileEntry) + nExtra;
          667  +    if( aBlob ){
          668  +      nAlloc += zipfileGetU32(&aRead[ZIPFILE_CDS_SZCOMPRESSED_OFF]);
          669  +    }
          670  +
          671  +    pNew = (ZipfileEntry*)sqlite3_malloc(nAlloc);
          672  +    if( pNew==0 ){
          673  +      rc = SQLITE_NOMEM;
   617    674       }else{
   618         -      ZipfileEntry *pNew;
   619         -
   620         -      int nFile = zipfileGetU16(&aRead[ZIPFILE_CDS_NFILE_OFF]);
   621         -      int nExtra = zipfileGetU16(&aRead[ZIPFILE_CDS_NFILE_OFF+2]);
   622         -      nExtra += zipfileGetU16(&aRead[ZIPFILE_CDS_NFILE_OFF+4]);
   623         -
   624         -      pNew = (ZipfileEntry*)sqlite3_malloc(sizeof(ZipfileEntry) + nExtra);
   625         -      if( pNew==0 ){
   626         -        rc = SQLITE_NOMEM;
   627         -      }else{
   628         -        memset(pNew, 0, sizeof(ZipfileEntry));
   629         -        rc = zipfileReadCDS(aRead, &pNew->cds);
   630         -        if( rc!=SQLITE_OK ){
   631         -          *pzErr = sqlite3_mprintf("failed to read CDS at offset %lld", iOff);
   632         -        }else{
   633         -          rc = zipfileReadData(
   634         -              pFile, aRead, nExtra+nFile, iOff+ZIPFILE_CDS_FIXED_SZ, pzErr
   635         -          );
   636         -        }
   637         -      }
   638         -
   639         -      if( rc==SQLITE_OK ){
   640         -        u32 *pt = &pNew->mUnixTime;
   641         -        pNew->cds.zFile = sqlite3_mprintf("%.*s", nFile, aRead); 
   642         -        if( pNew->cds.zFile==0 ){
   643         -          rc = SQLITE_NOMEM;
   644         -        }else if( 0==zipfileScanExtra(&aRead[nFile], pNew->cds.nExtra, pt) ){
   645         -          pNew->mUnixTime = zipfileMtime(&pNew->cds);
   646         -        }
   647         -      }
   648         -
          675  +      memset(pNew, 0, sizeof(ZipfileEntry));
          676  +      rc = zipfileReadCDS(aRead, &pNew->cds);
   649    677         if( rc!=SQLITE_OK ){
   650         -        zipfileEntryFree(pNew);
          678  +        *pzErr = sqlite3_mprintf("failed to read CDS at offset %lld", iOff);
          679  +      }else if( aBlob==0 ){
          680  +        rc = zipfileReadData(
          681  +            pFile, aRead, nExtra+nFile, iOff+ZIPFILE_CDS_FIXED_SZ, pzErr
          682  +        );
          683  +      }else{
          684  +        aRead = (u8*)&aBlob[iOff + ZIPFILE_CDS_FIXED_SZ];
          685  +      }
          686  +    }
          687  +
          688  +    if( rc==SQLITE_OK ){
          689  +      u32 *pt = &pNew->mUnixTime;
          690  +      pNew->cds.zFile = sqlite3_mprintf("%.*s", nFile, aRead); 
          691  +      pNew->aExtra = (u8*)&pNew[1];
          692  +      memcpy(pNew->aExtra, &aRead[nFile], nExtra);
          693  +      if( pNew->cds.zFile==0 ){
          694  +        rc = SQLITE_NOMEM;
          695  +      }else if( 0==zipfileScanExtra(&aRead[nFile], pNew->cds.nExtra, pt) ){
          696  +        pNew->mUnixTime = zipfileMtime(&pNew->cds);
          697  +      }
          698  +    }
          699  +
          700  +    if( rc==SQLITE_OK ){
          701  +      static const int szFix = ZIPFILE_LFH_FIXED_SZ;
          702  +      ZipfileLFH lfh;
          703  +      if( pFile ){
          704  +        rc = zipfileReadData(pFile, aRead, szFix, pNew->cds.iOffset, pzErr);
          705  +      }else{
          706  +        aRead = &aBlob[pNew->cds.iOffset];
          707  +      }
          708  +
          709  +      rc = zipfileReadLFH(aRead, &lfh);
          710  +      if( rc==SQLITE_OK ){
          711  +        pNew->iDataOff =  pNew->cds.iOffset + ZIPFILE_LFH_FIXED_SZ;
          712  +        pNew->iDataOff += lfh.nFile + lfh.nExtra;
          713  +        if( aBlob && pNew->cds.szCompressed ){
          714  +          pNew->aData = &pNew->aExtra[nExtra];
          715  +          memcpy(pNew->aData, &aBlob[pNew->iDataOff], pNew->cds.szCompressed);
          716  +        }
   651    717         }else{
   652         -        *ppEntry = pNew;
          718  +        *pzErr = sqlite3_mprintf("failed to read LFH at offset %d", 
          719  +            (int)pNew->cds.iOffset
          720  +        );
   653    721         }
   654    722       }
          723  +
          724  +    if( rc!=SQLITE_OK ){
          725  +      zipfileEntryFree(pNew);
          726  +    }else{
          727  +      *ppEntry = pNew;
          728  +    }
   655    729     }
   656    730   
   657    731     return rc;
   658    732   }
   659    733   
   660    734   static FILE *zipfileGetFd(ZipfileCsr *pCsr){
   661    735     if( pCsr->pFile ) return pCsr->pFile;
   662    736     return ((ZipfileTab*)(pCsr->base.pVtab))->pWriteFd;
   663    737   }
   664    738   
   665         -static int zipfileReadLFH(
   666         -  FILE *pFd, 
   667         -  i64 iOffset,
   668         -  u8 *aTmp, 
   669         -  ZipfileLFH *pLFH, 
   670         -  char **pzErr
   671         -){
   672         -  u8 *aRead = aTmp;
   673         -  static const int szFix = ZIPFILE_LFH_FIXED_SZ;
   674         -  int rc;
   675         -
   676         -  rc = zipfileReadData(pFd, aRead, szFix, iOffset, pzErr);
   677         -  if( rc==SQLITE_OK ){
   678         -    u32 sig = zipfileRead32(aRead);
   679         -    if( sig!=ZIPFILE_SIGNATURE_LFH ){
   680         -      *pzErr = sqlite3_mprintf("failed to read LFH at offset %d", (int)iOffset);
   681         -      rc = SQLITE_ERROR;
   682         -    }else{
   683         -      pLFH->iVersionExtract = zipfileRead16(aRead);
   684         -      pLFH->flags = zipfileRead16(aRead);
   685         -      pLFH->iCompression = zipfileRead16(aRead);
   686         -      pLFH->mTime = zipfileRead16(aRead);
   687         -      pLFH->mDate = zipfileRead16(aRead);
   688         -      pLFH->crc32 = zipfileRead32(aRead);
   689         -      pLFH->szCompressed = zipfileRead32(aRead);
   690         -      pLFH->szUncompressed = zipfileRead32(aRead);
   691         -      pLFH->nFile = zipfileRead16(aRead);
   692         -      pLFH->nExtra = zipfileRead16(aRead);
   693         -      assert( aRead==&aTmp[szFix] );
   694         -    }
   695         -  }
   696         -  return rc;
   697         -}
   698         -
   699         -static int zipfileCsrReadLFH(ZipfileCsr *pCsr){
   700         -  FILE *pFile = zipfileGetFd(pCsr);
   701         -  char **pzErr = &pCsr->base.pVtab->zErrMsg;
   702         -  u8 *aRead = zipfileCsrBuffer(pCsr);
   703         -  ZipfileCDS *pCDS = &pCsr->pCurrent->cds;
   704         -  int rc = zipfileReadLFH(pFile, pCDS->iOffset, aRead, &pCsr->lfh, pzErr);
   705         -  pCsr->iDataOff =  pCDS->iOffset + ZIPFILE_LFH_FIXED_SZ;
   706         -  pCsr->iDataOff += pCsr->lfh.nFile+pCsr->lfh.nExtra;
   707         -  return rc;
   708         -}
   709         -
   710    739   
   711    740   /*
   712    741   ** Advance an ZipfileCsr to its next row of output.
   713    742   */
   714    743   static int zipfileNext(sqlite3_vtab_cursor *cur){
   715    744     ZipfileCsr *pCsr = (ZipfileCsr*)cur;
   716    745     int rc = SQLITE_OK;
................................................................................
   720    749       zipfileEntryFree(pCsr->pCurrent);
   721    750       pCsr->pCurrent = 0;
   722    751       if( pCsr->iNextOff>=iEof ){
   723    752         pCsr->bEof = 1;
   724    753       }else{
   725    754         ZipfileEntry *p = 0;
   726    755         ZipfileTab *pTab = (ZipfileTab*)(cur->pVtab);
   727         -      rc = zipfileGetEntry(pTab, pCsr->pFile, pCsr->iNextOff, &p);
          756  +      rc = zipfileGetEntry(pTab, 0, 0, pCsr->pFile, pCsr->iNextOff, &p);
   728    757         if( rc==SQLITE_OK ){
   729    758           pCsr->iNextOff += ZIPFILE_CDS_FIXED_SZ;
   730    759           pCsr->iNextOff += (int)p->cds.nExtra + p->cds.nFile + p->cds.nComment;
   731    760         }
   732    761         pCsr->pCurrent = p;
   733    762       }
   734    763     }else{
................................................................................
   737    766       }
   738    767       if( pCsr->pCurrent==0 ){
   739    768         pCsr->bEof = 1;
   740    769       }
   741    770     }
   742    771   
   743    772     pCsr->bNoop = 0;
   744         -  if( rc==SQLITE_OK && pCsr->bEof==0 ){
   745         -    rc = zipfileCsrReadLFH(pCsr);
   746         -  }
   747         -
   748    773     return rc;
   749    774   }
   750    775   
   751    776   static void zipfileMtimeToDos(ZipfileCDS *pCds, u32 mTime){
   752    777     time_t t = (time_t)mTime;
   753    778     struct tm res;
   754    779   
................................................................................
   877    902       case 4:   /* rawdata */
   878    903         if( sqlite3_vtab_nochange(ctx) ) break;
   879    904       case 5: { /* data */
   880    905         if( i==4 || pCDS->iCompression==0 || pCDS->iCompression==8 ){
   881    906           int sz = pCDS->szCompressed;
   882    907           int szFinal = pCDS->szUncompressed;
   883    908           if( szFinal>0 ){
   884         -          u8 *aBuf = sqlite3_malloc(sz);
   885         -          if( aBuf==0 ){
   886         -            rc = SQLITE_NOMEM;
          909  +          u8 *aBuf;
          910  +          u8 *aFree = 0;
          911  +          if( pCsr->pCurrent->aData ){
          912  +            aBuf = pCsr->pCurrent->aData;
   887    913             }else{
   888         -            FILE *pFile = zipfileGetFd(pCsr);
   889         -            rc = zipfileReadData(pFile, aBuf, sz, pCsr->iDataOff,
   890         -                &pCsr->base.pVtab->zErrMsg
   891         -            );
          914  +            aBuf = aFree = sqlite3_malloc(sz);
          915  +            if( aBuf==0 ){
          916  +              rc = SQLITE_NOMEM;
          917  +            }else{
          918  +              FILE *pFile = zipfileGetFd(pCsr);
          919  +              if( rc==SQLITE_OK ){
          920  +                rc = zipfileReadData(pFile, aBuf, sz, pCsr->pCurrent->iDataOff,
          921  +                    &pCsr->base.pVtab->zErrMsg
          922  +                );
          923  +              }
          924  +            }
   892    925             }
   893    926             if( rc==SQLITE_OK ){
   894    927               if( i==5 && pCDS->iCompression ){
   895    928                 zipfileInflate(ctx, aBuf, sz, szFinal);
   896    929               }else{
   897    930                 sqlite3_result_blob(ctx, aBuf, sz, SQLITE_TRANSIENT);
   898    931               }
   899         -            sqlite3_free(aBuf);
   900    932             }
          933  +          sqlite3_free(aFree);
   901    934           }else{
   902    935             /* Figure out if this is a directory or a zero-sized file. Consider
   903    936             ** it to be a directory either if the mode suggests so, or if
   904    937             ** the final character in the name is '/'.  */
   905    938             u32 mode = pCDS->iExternalAttr >> 16;
   906    939             if( !(mode & S_IFDIR) && pCDS->zFile[pCDS->nFile-1]!='/' ){
   907    940               sqlite3_result_blob(ctx, "", 0, SQLITE_STATIC);
................................................................................
   938    971     return pCsr->bEof;
   939    972   }
   940    973   
   941    974   /*
   942    975   */
   943    976   static int zipfileReadEOCD(
   944    977     ZipfileTab *pTab,               /* Return errors here */
   945         -  FILE *pFile,                    /* Read from this file */
          978  +  const u8 *aBlob,                /* Pointer to in-memory file image */
          979  +  int nBlob,                      /* Size of aBlob[] in bytes */
          980  +  FILE *pFile,                    /* Read from this file if aBlob==0 */
   946    981     ZipfileEOCD *pEOCD              /* Object to populate */
   947    982   ){
   948    983     u8 *aRead = pTab->aBuffer;      /* Temporary buffer */
   949         -  i64 szFile;                     /* Total size of file in bytes */
   950    984     int nRead;                      /* Bytes to read from file */
   951         -  i64 iOff;                       /* Offset to read from */
   952         -  int rc;
          985  +  int rc = SQLITE_OK;
   953    986   
   954         -  fseek(pFile, 0, SEEK_END);
   955         -  szFile = (i64)ftell(pFile);
   956         -  if( szFile==0 ){
   957         -    memset(pEOCD, 0, sizeof(ZipfileEOCD));
   958         -    return SQLITE_OK;
          987  +  if( aBlob==0 ){
          988  +    i64 iOff;                     /* Offset to read from */
          989  +    i64 szFile;                   /* Total size of file in bytes */
          990  +    fseek(pFile, 0, SEEK_END);
          991  +    szFile = (i64)ftell(pFile);
          992  +    if( szFile==0 ){
          993  +      memset(pEOCD, 0, sizeof(ZipfileEOCD));
          994  +      return SQLITE_OK;
          995  +    }
          996  +    nRead = (int)(MIN(szFile, ZIPFILE_BUFFER_SIZE));
          997  +    iOff = szFile - nRead;
          998  +    rc = zipfileReadData(pFile, aRead, nRead, iOff, &pTab->base.zErrMsg);
          999  +  }else{
         1000  +    nRead = (int)(MIN(nBlob, ZIPFILE_BUFFER_SIZE));
         1001  +    aRead = (u8*)&aBlob[nBlob-nRead];
   959   1002     }
   960         -  nRead = (int)(MIN(szFile, ZIPFILE_BUFFER_SIZE));
   961         -  iOff = szFile - nRead;
   962   1003   
   963         -  rc = zipfileReadData(pFile, aRead, nRead, iOff, &pTab->base.zErrMsg);
   964   1004     if( rc==SQLITE_OK ){
   965   1005       int i;
   966   1006   
   967   1007       /* Scan backwards looking for the signature bytes */
   968   1008       for(i=nRead-20; i>=0; i--){
   969   1009         if( aRead[i]==0x50 && aRead[i+1]==0x4b 
   970   1010          && aRead[i+2]==0x05 && aRead[i+3]==0x06 
................................................................................
   982   1022       aRead += i+4;
   983   1023       pEOCD->iDisk = zipfileRead16(aRead);
   984   1024       pEOCD->iFirstDisk = zipfileRead16(aRead);
   985   1025       pEOCD->nEntry = zipfileRead16(aRead);
   986   1026       pEOCD->nEntryTotal = zipfileRead16(aRead);
   987   1027       pEOCD->nSize = zipfileRead32(aRead);
   988   1028       pEOCD->iOffset = zipfileRead32(aRead);
   989         -
   990         -#if 0
   991         -    printf("iDisk=%d  iFirstDisk=%d  nEntry=%d  "
   992         -           "nEntryTotal=%d  nSize=%d  iOffset=%d", 
   993         -           (int)pEOCD->iDisk, (int)pEOCD->iFirstDisk, (int)pEOCD->nEntry,
   994         -           (int)pEOCD->nEntryTotal, (int)pEOCD->nSize, (int)pEOCD->iOffset
   995         -    );
   996         -#endif
   997   1029     }
   998   1030   
   999   1031     return SQLITE_OK;
  1000   1032   }
         1033  +
         1034  +/*
         1035  +** Add object pNew to the end of the linked list that begins at
         1036  +** ZipfileTab.pFirstEntry and ends with pLastEntry.
         1037  +*/
         1038  +static void zipfileAddEntry(
         1039  +  ZipfileTab *pTab, 
         1040  +  ZipfileEntry *pBefore, 
         1041  +  ZipfileEntry *pNew
         1042  +){
         1043  +  assert( (pTab->pFirstEntry==0)==(pTab->pLastEntry==0) );
         1044  +  assert( pNew->pNext==0 );
         1045  +  if( pBefore==0 ){
         1046  +    if( pTab->pFirstEntry==0 ){
         1047  +      pTab->pFirstEntry = pTab->pLastEntry = pNew;
         1048  +    }else{
         1049  +      assert( pTab->pLastEntry->pNext==0 );
         1050  +      pTab->pLastEntry->pNext = pNew;
         1051  +      pTab->pLastEntry = pNew;
         1052  +    }
         1053  +  }else{
         1054  +    ZipfileEntry **pp;
         1055  +    for(pp=&pTab->pFirstEntry; *pp!=pBefore; pp=&((*pp)->pNext));
         1056  +    pNew->pNext = pBefore;
         1057  +    *pp = pNew;
         1058  +  }
         1059  +}
         1060  +
         1061  +static int zipfileLoadDirectory(ZipfileTab *pTab, const u8 *aBlob, int nBlob){
         1062  +  ZipfileEOCD eocd;
         1063  +  int rc;
         1064  +  int i;
         1065  +  i64 iOff;
         1066  +
         1067  +  rc = zipfileReadEOCD(pTab, aBlob, nBlob, pTab->pWriteFd, &eocd);
         1068  +  iOff = eocd.iOffset;
         1069  +  for(i=0; rc==SQLITE_OK && i<eocd.nEntry; i++){
         1070  +    ZipfileEntry *pNew = 0;
         1071  +    rc = zipfileGetEntry(pTab, aBlob, nBlob, pTab->pWriteFd, iOff, &pNew);
         1072  +
         1073  +    if( rc==SQLITE_OK ){
         1074  +      zipfileAddEntry(pTab, 0, pNew);
         1075  +      iOff += ZIPFILE_CDS_FIXED_SZ;
         1076  +      iOff += (int)pNew->cds.nExtra + pNew->cds.nFile + pNew->cds.nComment;
         1077  +    }
         1078  +  }
         1079  +  return rc;
         1080  +}
  1001   1081   
  1002   1082   /*
  1003   1083   ** xFilter callback.
  1004   1084   */
  1005   1085   static int zipfileFilter(
  1006   1086     sqlite3_vtab_cursor *cur, 
  1007   1087     int idxNum, const char *idxStr,
................................................................................
  1019   1099       zFile = pTab->zFile;
  1020   1100     }else if( idxNum==0 ){
  1021   1101       /* Error. This is an eponymous virtual table and the user has not 
  1022   1102       ** supplied a file name. */
  1023   1103       zipfileSetErrmsg(pCsr, "table function zipfile() requires an argument");
  1024   1104       return SQLITE_ERROR;
  1025   1105     }else if( sqlite3_value_type(argv[0])==SQLITE_BLOB ){
         1106  +    const u8 *aBlob = (const u8*)sqlite3_value_blob(argv[0]);
         1107  +    int nBlob = sqlite3_value_bytes(argv[0]);
         1108  +    assert( pTab->pFirstEntry==0 );
         1109  +    rc = zipfileLoadDirectory(pTab, aBlob, nBlob);
         1110  +    pCsr->pFreeEntry = pTab->pFirstEntry;
         1111  +    pTab->pFirstEntry = pTab->pLastEntry = 0;
         1112  +    if( rc!=SQLITE_OK ) return rc;
         1113  +    bInMemory = 1;
  1026   1114     }else{
  1027   1115       zFile = (const char*)sqlite3_value_text(argv[0]);
  1028   1116     }
  1029   1117   
  1030   1118     if( 0==pTab->pWriteFd && 0==bInMemory ){
  1031   1119       pCsr->pFile = fopen(zFile, "rb");
  1032   1120       if( pCsr->pFile==0 ){
  1033   1121         zipfileSetErrmsg(pCsr, "cannot open file: %s", zFile);
  1034   1122         rc = SQLITE_ERROR;
  1035   1123       }else{
  1036         -      rc = zipfileReadEOCD(pTab, pCsr->pFile, &pCsr->eocd);
         1124  +      rc = zipfileReadEOCD(pTab, 0, 0, pCsr->pFile, &pCsr->eocd);
  1037   1125         if( rc==SQLITE_OK ){
  1038   1126           if( pCsr->eocd.nEntry==0 ){
  1039   1127             pCsr->bEof = 1;
  1040   1128           }else{
  1041   1129             pCsr->iNextOff = pCsr->eocd.iOffset;
  1042   1130             rc = zipfileNext(cur);
  1043   1131           }
  1044   1132         }
  1045   1133       }
  1046   1134     }else{
  1047   1135       pCsr->bNoop = 1;
  1048         -    pCsr->pCurrent = pTab->pFirstEntry;
         1136  +    pCsr->pCurrent = pCsr->pFreeEntry ? pCsr->pFreeEntry : pTab->pFirstEntry;
  1049   1137       rc = zipfileNext(cur);
  1050   1138     }
  1051   1139   
  1052   1140     return rc;
  1053   1141   }
  1054   1142   
  1055   1143   /*
................................................................................
  1078   1166       pIdxInfo->estimatedCost = (double)(((sqlite3_int64)1) << 50);
  1079   1167       pIdxInfo->idxNum = 0;
  1080   1168     }
  1081   1169   
  1082   1170     return SQLITE_OK;
  1083   1171   }
  1084   1172   
  1085         -/*
  1086         -** Add object pNew to the end of the linked list that begins at
  1087         -** ZipfileTab.pFirstEntry and ends with pLastEntry.
  1088         -*/
  1089         -static void zipfileAddEntry(
  1090         -  ZipfileTab *pTab, 
  1091         -  ZipfileEntry *pBefore, 
  1092         -  ZipfileEntry *pNew
  1093         -){
  1094         -  assert( (pTab->pFirstEntry==0)==(pTab->pLastEntry==0) );
  1095         -  assert( pNew->pNext==0 );
  1096         -  if( pBefore==0 ){
  1097         -    if( pTab->pFirstEntry==0 ){
  1098         -      pTab->pFirstEntry = pTab->pLastEntry = pNew;
  1099         -    }else{
  1100         -      assert( pTab->pLastEntry->pNext==0 );
  1101         -      pTab->pLastEntry->pNext = pNew;
  1102         -      pTab->pLastEntry = pNew;
  1103         -    }
  1104         -  }else{
  1105         -    ZipfileEntry **pp;
  1106         -    for(pp=&pTab->pFirstEntry; *pp!=pBefore; pp=&((*pp)->pNext));
  1107         -    pNew->pNext = pBefore;
  1108         -    *pp = pNew;
  1109         -  }
  1110         -}
  1111         -
  1112         -static int zipfileLoadDirectory(ZipfileTab *pTab){
  1113         -  ZipfileEOCD eocd;
  1114         -  int rc;
  1115         -  int i;
  1116         -  i64 iOff;
  1117         -
  1118         -  rc = zipfileReadEOCD(pTab, pTab->pWriteFd, &eocd);
  1119         -  iOff = eocd.iOffset;
  1120         -  for(i=0; rc==SQLITE_OK && i<eocd.nEntry; i++){
  1121         -    ZipfileEntry *pNew = 0;
  1122         -    rc = zipfileGetEntry(pTab, pTab->pWriteFd, iOff, &pNew);
  1123         -
  1124         -    if( rc==SQLITE_OK ){
  1125         -      zipfileAddEntry(pTab, 0, pNew);
  1126         -      iOff += ZIPFILE_CDS_FIXED_SZ;
  1127         -      iOff += (int)pNew->cds.nExtra + pNew->cds.nFile + pNew->cds.nComment;
  1128         -    }
  1129         -  }
  1130         -  return rc;
  1131         -}
  1132         -
  1133   1173   static ZipfileEntry *zipfileNewEntry(const char *zPath){
  1134   1174     ZipfileEntry *pNew;
  1135   1175     pNew = sqlite3_malloc(sizeof(ZipfileEntry));
  1136   1176     if( pNew ){
  1137   1177       memset(pNew, 0, sizeof(ZipfileEntry));
  1138   1178       pNew->cds.zFile = sqlite3_mprintf("%s", zPath);
  1139   1179       if( pNew->cds.zFile==0 ){
................................................................................
  1454   1494       pTab->base.zErrMsg = sqlite3_mprintf(
  1455   1495           "zipfile: failed to open file %s for writing", pTab->zFile
  1456   1496       );
  1457   1497       rc = SQLITE_ERROR;
  1458   1498     }else{
  1459   1499       fseek(pTab->pWriteFd, 0, SEEK_END);
  1460   1500       pTab->szCurrent = pTab->szOrig = (i64)ftell(pTab->pWriteFd);
  1461         -    rc = zipfileLoadDirectory(pTab);
         1501  +    rc = zipfileLoadDirectory(pTab, 0, 0);
  1462   1502     }
  1463   1503   
  1464   1504     if( rc!=SQLITE_OK ){
  1465   1505       zipfileCleanupTransaction(pTab);
  1466   1506     }
  1467   1507   
  1468   1508     return rc;

Changes to test/zipfile.test.

    17     17   ifcapable !vtab {
    18     18     finish_test; return
    19     19   }
    20     20   if {[catch {load_static_extension db zipfile} error]} {
    21     21     puts "Skipping zipfile tests, hit load error: $error"
    22     22     finish_test; return
    23     23   }
           24  +
           25  +proc do_zipfile_blob_test {tn file} {
           26  +  set res1 [
           27  +    db eval { SELECT name,mode,mtime,method,quote(data) FROM zipfile($file) }
           28  +  ]
           29  +
           30  +  set fd [open $file]
           31  +  fconfigure $fd -translation binary -encoding binary
           32  +  set data [read $fd]
           33  +  close $fd
           34  +
           35  +  set res2 [db eval { SELECT name,mode,mtime,method,quote(data) FROM zipfile($data) }]
           36  +  uplevel [list do_test $tn [list set {} $res2] $res1]
           37  +}
    24     38   
    25     39   forcedelete test.zip
    26     40   do_execsql_test 1.0 {
    27     41     CREATE VIRTUAL TABLE temp.zz USING zipfile('test.zip');
    28     42     PRAGMA table_info(zz);
    29     43   } {
    30     44     0 name {} 1 {} 1 
................................................................................
    56     70   
    57     71   do_execsql_test 1.2 {
    58     72     SELECT name, mtime, data FROM zipfile('test.zip')
    59     73   } {
    60     74     f.txt 1000000000 abcde 
    61     75     g.txt 1000000002 12345
    62     76   }
           77  +do_zipfile_blob_test 1.2.1 test.zip
    63     78   
    64     79   do_execsql_test 1.3 {
    65     80     INSERT INTO zz(name, mode, mtime, data) VALUES('h.txt', 
    66     81       '-rw-r--r--', 1000000004, 'aaaaaaaaaabbbbbbbbbb'
    67     82     );
    68     83   }
           84  +do_zipfile_blob_test 1.3.1 test.zip
    69     85   
    70     86   do_execsql_test 1.4 {
    71     87     SELECT name, mtime, data, method FROM zipfile('test.zip');
    72     88   } {
    73     89     f.txt 1000000000 abcde 0
    74     90     g.txt 1000000002 12345 0
    75     91     h.txt 1000000004 aaaaaaaaaabbbbbbbbbb 8
................................................................................
   108    124   do_execsql_test 1.6.1 {
   109    125     SELECT name, mode, mtime, data, method FROM zipfile('test.zip');
   110    126   } {
   111    127     f.txt 33188 1000000000 abcde 0
   112    128     h.txt 33188 1000000004 aaaaaaaaaabbbbbbbbbb 8
   113    129     i.txt 33188 1000000006 zxcvb 0
   114    130   }
          131  +do_zipfile_blob_test 1.6.1a test.zip
   115    132   
   116    133   do_execsql_test 1.6.2 {
   117    134     UPDATE zz SET mtime=4 WHERE name='i.txt';
   118    135     SELECT name, mode, mtime, data, method FROM zipfile('test.zip');
   119    136   } {
   120    137     f.txt 33188 1000000000 abcde 0
   121    138     h.txt 33188 1000000004 aaaaaaaaaabbbbbbbbbb 8
................................................................................
   126    143     UPDATE zz SET mode='-rw-r--r-x' WHERE name='h.txt';
   127    144     SELECT name, mode, mtime, data, method FROM zipfile('test.zip');
   128    145   } {
   129    146     f.txt 33188 1000000000 abcde 0
   130    147     h.txt 33189 1000000004 aaaaaaaaaabbbbbbbbbb 8
   131    148     i.txt 33188 4 zxcvb 0
   132    149   }
          150  +do_zipfile_blob_test 1.6.3a test.zip
   133    151   
   134    152   do_execsql_test 1.6.4 {
   135    153     UPDATE zz SET name = 'blue.txt' WHERE name='f.txt';
   136    154     SELECT name, mode, mtime, data, method FROM zipfile('test.zip');
   137    155   } {
   138    156     blue.txt 33188 1000000000 abcde 0
   139    157     h.txt 33189 1000000004 aaaaaaaaaabbbbbbbbbb 8
   140    158     i.txt 33188 4 zxcvb 0
   141    159   }
          160  +do_zipfile_blob_test 1.6.4a test.zip
   142    161   
   143    162   do_execsql_test 1.6.5 {
   144    163     UPDATE zz SET data = 'edcba' WHERE name='blue.txt';
   145    164     SELECT name, mode, mtime, data, method FROM zipfile('test.zip');
   146    165   } {
   147    166     blue.txt 33188 1000000000 edcba 0
   148    167     h.txt 33189 1000000004 aaaaaaaaaabbbbbbbbbb 8
................................................................................
   195    214   do_execsql_test 2.4 {
   196    215     SELECT name, mode, data FROM zzz;
   197    216   } {
   198    217     dirname3/ 16877 {}
   199    218     dirname2/ 16877 {}
   200    219     dirname2/file1.txt 33188 abcdefghijklmnop
   201    220   }
          221  +do_zipfile_blob_test 2.4.1 test.zip
   202    222   
   203    223   # If on unix, check that the [unzip] utility can unpack our archive.
   204    224   #
   205    225   if {$::tcl_platform(platform)=="unix"} {
   206    226     do_test 2.5.1 {
   207    227       forcedelete dirname
   208    228       forcedelete dirname2