/ Check-in [954231d2]
Login

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

Overview
Comment:Merge changes to get FTS5 working with MSVC.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | fts5
Files: files | file ages | folders
SHA1: 954231d29d60460d423ecb132bbfb725b0ea375a
User & Date: mistachkin 2015-06-26 17:10:12
Context
2015-06-26
18:50
Fix some cases in the fts5 code where a corrupt database could cause a buffer overread. check-in: 360c57bb user: dan tags: fts5
17:10
Merge changes to get FTS5 working with MSVC. check-in: 954231d2 user: mistachkin tags: fts5
16:55
Merge upstream changes. Get the test fixture working with FTS5. Fix compiler warnings. Closed-Leaf check-in: bfcd1608 user: mistachkin tags: fts5Msvc
16:42
Remove fts5 initialization code from core file main.c. check-in: c91a93b3 user: dan tags: fts5
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to Makefile.msc.

   823    823   LIBOBJS0 = vdbe.lo parse.lo alter.lo analyze.lo attach.lo auth.lo \
   824    824            backup.lo bitvec.lo btmutex.lo btree.lo build.lo \
   825    825            callback.lo complete.lo ctime.lo date.lo dbstat.lo delete.lo \
   826    826            expr.lo fault.lo fkey.lo \
   827    827            fts3.lo fts3_aux.lo fts3_expr.lo fts3_hash.lo fts3_icu.lo \
   828    828            fts3_porter.lo fts3_snippet.lo fts3_tokenizer.lo fts3_tokenizer1.lo \
   829    829            fts3_tokenize_vtab.lo fts3_unicode.lo fts3_unicode2.lo fts3_write.lo \
          830  +         fts5.lo \
   830    831            func.lo global.lo hash.lo \
   831    832            icu.lo insert.lo journal.lo legacy.lo loadext.lo \
   832    833            main.lo malloc.lo mem0.lo mem1.lo mem2.lo mem3.lo mem5.lo \
   833    834            memjournal.lo \
   834    835            mutex.lo mutex_noop.lo mutex_unix.lo mutex_w32.lo \
   835    836            notify.lo opcodes.lo os.lo os_unix.lo os_win.lo \
   836    837            pager.lo pcache.lo pcache1.lo pragma.lo prepare.lo printf.lo \
................................................................................
  1074   1075   #
  1075   1076   TESTEXT = \
  1076   1077     $(TOP)\ext\misc\amatch.c \
  1077   1078     $(TOP)\ext\misc\closure.c \
  1078   1079     $(TOP)\ext\misc\eval.c \
  1079   1080     $(TOP)\ext\misc\fileio.c \
  1080   1081     $(TOP)\ext\misc\fuzzer.c \
         1082  +  fts5.c \
         1083  +  $(TOP)\ext\fts5\fts5_tcl.c \
  1081   1084     $(TOP)\ext\misc\ieee754.c \
  1082   1085     $(TOP)\ext\misc\nextchar.c \
  1083   1086     $(TOP)\ext\misc\percentile.c \
  1084   1087     $(TOP)\ext\misc\regexp.c \
  1085   1088     $(TOP)\ext\misc\spellfix.c \
  1086   1089     $(TOP)\ext\misc\totype.c \
  1087   1090     $(TOP)\ext\misc\wholenumber.c
................................................................................
  1649   1652   
  1650   1653   fts3_write.lo:	$(TOP)\ext\fts3\fts3_write.c $(HDR) $(EXTHDR)
  1651   1654   	$(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_write.c
  1652   1655   
  1653   1656   rtree.lo:	$(TOP)\ext\rtree\rtree.c $(HDR) $(EXTHDR)
  1654   1657   	$(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\rtree\rtree.c
  1655   1658   
         1659  +# FTS5 things
         1660  +#
         1661  +FTS5_SRC = \
         1662  +   $(TOP)\ext\fts5\fts5.h \
         1663  +   $(TOP)\ext\fts5\fts5Int.h \
         1664  +   $(TOP)\ext\fts5\fts5_aux.c \
         1665  +   $(TOP)\ext\fts5\fts5_buffer.c \
         1666  +   $(TOP)\ext\fts5\fts5_main.c \
         1667  +   $(TOP)\ext\fts5\fts5_config.c \
         1668  +   $(TOP)\ext\fts5\fts5_expr.c \
         1669  +   $(TOP)\ext\fts5\fts5_hash.c \
         1670  +   $(TOP)\ext\fts5\fts5_index.c \
         1671  +   fts5parse.c fts5parse.h \
         1672  +   $(TOP)\ext\fts5\fts5_storage.c \
         1673  +   $(TOP)\ext\fts5\fts5_tokenize.c \
         1674  +   $(TOP)\ext\fts5\fts5_unicode2.c \
         1675  +   $(TOP)\ext\fts5\fts5_varint.c \
         1676  +   $(TOP)\ext\fts5\fts5_vocab.c
         1677  +
         1678  +fts5parse.c:	$(TOP)\ext\fts5\fts5parse.y lemon.exe
         1679  +	copy $(TOP)\ext\fts5\fts5parse.y .
         1680  +	del /Q fts5parse.h 2>NUL
         1681  +	.\lemon.exe $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(OPTS) fts5parse.y
         1682  +	move fts5parse.c fts5parse.c.orig
         1683  +	echo #ifdef SQLITE_ENABLE_FTS5 > $@
         1684  +	type fts5parse.c.orig \
         1685  +		| $(NAWK) "/.*/ { gsub(/yy/,\"fts5yy\");print }" \
         1686  +		| $(NAWK) "/.*/ { gsub(/YY/,\"fts5YY\");print }" \
         1687  +		| $(NAWK) "/.*/ { gsub(/TOKEN/,\"FTS5TOKEN\");print }" >> $@
         1688  +	echo #endif /* SQLITE_ENABLE_FTS5 */ >> $@
         1689  +
         1690  +fts5parse.h: fts5parse.c
         1691  +
         1692  +fts5.c: $(FTS5_SRC)
         1693  +	$(TCLSH_CMD) $(TOP)\ext\fts5\tool\mkfts5c.tcl
         1694  +
         1695  +fts5.lo:	fts5.c $(HDR) $(EXTHDR)
         1696  +	$(LTCOMPILE) $(NO_WARN) -DSQLITE_ENABLE_FTS5 -c fts5.c
         1697  +
         1698  +fts5.dll:	fts5.lo
         1699  +	$(LD) $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) /DLL /OUT:$@ fts5.lo
  1656   1700   
  1657   1701   # Rules to build the 'testfixture' application.
  1658   1702   #
  1659   1703   # If using the amalgamation, use sqlite3.c directly to build the test
  1660   1704   # fixture.  Otherwise link against libsqlite3.lib.  (This distinction is
  1661   1705   # necessary because the test fixture requires non-API symbols which are
  1662   1706   # hidden when the library is built via the amalgamation).
................................................................................
  1788   1832   	del /Q sqlite3.exe sqlite3.dll sqlite3.def 2>NUL
  1789   1833   	del /Q sqlite3.c sqlite3-*.c 2>NUL
  1790   1834   	del /Q sqlite3rc.h 2>NUL
  1791   1835   	del /Q shell.c sqlite3ext.h 2>NUL
  1792   1836   	del /Q sqlite3_analyzer.exe sqlite3_analyzer.c 2>NUL
  1793   1837   	del /Q sqlite-*-output.vsix 2>NUL
  1794   1838   	del /Q fuzzershell.exe fuzzcheck.exe sqldiff.exe 2>NUL
         1839  +	del /Q fts5.c fts5parse.* 2>NUL
  1795   1840   
  1796   1841   # Dynamic link library section.
  1797   1842   #
  1798   1843   dll: sqlite3.dll
  1799   1844   
  1800   1845   sqlite3.def: libsqlite3.lib
  1801   1846   	echo EXPORTS > sqlite3.def
  1802   1847   	dumpbin /all libsqlite3.lib \
  1803   1848   		| $(NAWK) "/ 1 _?sqlite3_/ { sub(/^.* _?/,\"\");print }" \
  1804   1849   		| sort >> sqlite3.def
  1805   1850   
  1806   1851   sqlite3.dll: $(LIBOBJ) $(LIBRESOBJS) $(CORE_LINK_DEP)
  1807   1852   	$(LD) $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) /DLL $(CORE_LINK_OPTS) /OUT:$@ $(LIBOBJ) $(LIBRESOBJS) $(LTLIBS) $(TLIBS)

Changes to ext/fts5/fts5Int.h.

   200    200   void sqlite3Fts5BufferAppendString(int *, Fts5Buffer*, const char*);
   201    201   void sqlite3Fts5BufferFree(Fts5Buffer*);
   202    202   void sqlite3Fts5BufferZero(Fts5Buffer*);
   203    203   void sqlite3Fts5BufferSet(int*, Fts5Buffer*, int, const u8*);
   204    204   void sqlite3Fts5BufferAppendPrintf(int *, Fts5Buffer*, char *zFmt, ...);
   205    205   void sqlite3Fts5BufferAppend32(int*, Fts5Buffer*, int);
   206    206   
   207         -char *sqlite3Fts5Mprintf(int *pRc, char *zFmt, ...);
          207  +char *sqlite3Fts5Mprintf(int *pRc, const char *zFmt, ...);
   208    208   
   209    209   #define fts5BufferZero(x)             sqlite3Fts5BufferZero(x)
   210    210   #define fts5BufferGrow(a,b,c)         sqlite3Fts5BufferGrow(a,b,c)
   211    211   #define fts5BufferAppendVarint(a,b,c) sqlite3Fts5BufferAppendVarint(a,b,c)
   212    212   #define fts5BufferFree(a)             sqlite3Fts5BufferFree(a)
   213    213   #define fts5BufferAppendBlob(a,b,c,d) sqlite3Fts5BufferAppendBlob(a,b,c,d)
   214    214   #define fts5BufferSet(a,b,c,d)        sqlite3Fts5BufferSet(a,b,c,d)

Changes to ext/fts5/fts5_buffer.c.

   121    121       }else{
   122    122         sqlite3Fts5BufferAppendString(pRc, pBuf, zTmp);
   123    123         sqlite3_free(zTmp);
   124    124       }
   125    125     }
   126    126   }
   127    127   
   128         -char *sqlite3Fts5Mprintf(int *pRc, char *zFmt, ...){
          128  +char *sqlite3Fts5Mprintf(int *pRc, const char *zFmt, ...){
   129    129     char *zRet = 0;
   130    130     if( *pRc==SQLITE_OK ){
   131    131       va_list ap;
   132    132       va_start(ap, zFmt);
   133    133       zRet = sqlite3_vmprintf(zFmt, ap);
   134    134       va_end(ap);
   135    135       if( zRet==0 ){

Changes to ext/fts5/fts5_config.c.

   598    598   ** object passed as the only argument. Return SQLITE_OK if successful, or
   599    599   ** an SQLite error code if an error occurs.
   600    600   */
   601    601   int sqlite3Fts5ConfigDeclareVtab(Fts5Config *pConfig){
   602    602     int i;
   603    603     int rc = SQLITE_OK;
   604    604     char *zSql;
   605         -  char *zOld;
   606    605   
   607    606     zSql = sqlite3Fts5Mprintf(&rc, "CREATE TABLE x(");
   608    607     for(i=0; zSql && i<pConfig->nCol; i++){
   609    608       const char *zSep = (i==0?"":", ");
   610    609       zSql = sqlite3Fts5Mprintf(&rc, "%z%s%Q", zSql, zSep, pConfig->azCol[i]);
   611    610     }
   612    611     zSql = sqlite3Fts5Mprintf(&rc, "%z, %Q HIDDEN, %s HIDDEN)", 

Changes to ext/fts5/fts5_expr.c.

  1042   1042           Fts5ExprNode *pLeft = pNode->apChild[0];
  1043   1043           rc = fts5ExprNodeNext(pExpr, pLeft, bFromValid, iFrom);
  1044   1044           break;
  1045   1045         }
  1046   1046   
  1047   1047         case FTS5_OR: {
  1048   1048           int i;
  1049         -        int iLast = pNode->iRowid;
         1049  +        i64 iLast = pNode->iRowid;
  1050   1050   
  1051   1051           for(i=0; rc==SQLITE_OK && i<pNode->nChild; i++){
  1052   1052             Fts5ExprNode *p1 = pNode->apChild[i];
  1053   1053             assert( p1->bEof || fts5RowidCmp(pExpr, p1->iRowid, iLast)>=0 );
  1054   1054             if( p1->bEof==0 ){
  1055   1055               if( (p1->iRowid==iLast) 
  1056   1056                || (bFromValid && fts5RowidCmp(pExpr, p1->iRowid, iFrom)<0)
................................................................................
  1911   1911       if( zErr ){
  1912   1912         sqlite3_result_error(pCtx, zErr, -1);
  1913   1913         sqlite3_free(zErr);
  1914   1914       }else{
  1915   1915         sqlite3_result_error_code(pCtx, rc);
  1916   1916       }
  1917   1917     }
  1918         -  sqlite3_free(azConfig);
         1918  +  sqlite3_free((void *)azConfig);
  1919   1919     sqlite3Fts5ConfigFree(pConfig);
  1920   1920     sqlite3Fts5ExprFree(pExpr);
  1921   1921   }
  1922   1922   
  1923   1923   static void fts5ExprFunctionHr(
  1924   1924     sqlite3_context *pCtx,          /* Function call context */
  1925   1925     int nArg,                       /* Number of args */

Changes to ext/fts5/fts5_index.c.

  3545   3545   static void fts5IndexAutomerge(
  3546   3546     Fts5Index *p,                   /* FTS5 backend object */
  3547   3547     Fts5Structure **ppStruct,       /* IN/OUT: Current structure of index */
  3548   3548     int nLeaf                       /* Number of output leaves just written */
  3549   3549   ){
  3550   3550     if( p->rc==SQLITE_OK && p->pConfig->nAutomerge>0 ){
  3551   3551       Fts5Structure *pStruct = *ppStruct;
  3552         -    i64 nWrite;                   /* Initial value of write-counter */
         3552  +    u64 nWrite;                   /* Initial value of write-counter */
  3553   3553       int nWork;                    /* Number of work-quanta to perform */
  3554   3554       int nRem;                     /* Number of leaf pages left to write */
  3555   3555   
  3556   3556       /* Update the write-counter. While doing so, set nWork. */
  3557   3557       nWrite = pStruct->nWriteCounter;
  3558         -    nWork = ((nWrite + nLeaf) / p->nWorkUnit) - (nWrite / p->nWorkUnit);
         3558  +    nWork = (int)(((nWrite + nLeaf) / p->nWorkUnit) - (nWrite / p->nWorkUnit));
  3559   3559       pStruct->nWriteCounter += nLeaf;
  3560         -    nRem = p->nWorkUnit * nWork * pStruct->nLevel;
         3560  +    nRem = (int)(p->nWorkUnit * nWork * pStruct->nLevel);
  3561   3561   
  3562   3562       fts5IndexMerge(p, ppStruct, nRem);
  3563   3563     }
  3564   3564   }
  3565   3565   
  3566   3566   static void fts5IndexCrisismerge(
  3567   3567     Fts5Index *p,                   /* FTS5 backend object */
................................................................................
  4548   4548   ** Return SQLITE_OK if successful, or an SQLite error code if an error
  4549   4549   ** occurs.
  4550   4550   */
  4551   4551   int sqlite3Fts5IndexSetCookie(Fts5Index *p, int iNew){
  4552   4552     int rc;                              /* Return code */
  4553   4553     Fts5Config *pConfig = p->pConfig;    /* Configuration object */
  4554   4554     u8 aCookie[4];                       /* Binary representation of iNew */
         4555  +  sqlite3_blob *pBlob = 0;
  4555   4556   
  4556   4557     assert( p->rc==SQLITE_OK );
  4557         -
  4558   4558     sqlite3Fts5Put32(aCookie, iNew);
  4559         -  sqlite3_blob *pBlob = 0;
         4559  +
  4560   4560     rc = sqlite3_blob_open(pConfig->db, pConfig->zDb, p->zDataTbl, 
  4561   4561         "block", FTS5_STRUCTURE_ROWID, 1, &pBlob
  4562   4562     );
  4563   4563     if( rc==SQLITE_OK ){
  4564   4564       sqlite3_blob_write(pBlob, aCookie, 4, 0);
  4565   4565       rc = sqlite3_blob_close(pBlob);
  4566   4566     }
................................................................................
  4783   4783     u64 *pCksum
  4784   4784   ){
  4785   4785     int rc = p->rc;
  4786   4786     if( pPrev->n==0 ){
  4787   4787       fts5BufferSet(&rc, pPrev, n, (const u8*)z);
  4788   4788     }else
  4789   4789     if( rc==SQLITE_OK && (pPrev->n!=n || memcmp(pPrev->p, z, n)) ){
  4790         -    u32 cksum3 = *pCksum;
         4790  +    u64 cksum3 = *pCksum;
  4791   4791       const char *zTerm = (const char*)&pPrev->p[1];  /* term sans prefix-byte */
  4792   4792       int nTerm = pPrev->n-1;            /* Size of zTerm in bytes */
  4793   4793       int iIdx = (pPrev->p[0] - FTS5_MAIN_PREFIX);
  4794   4794       int flags = (iIdx==0 ? 0 : FTS5INDEX_QUERY_PREFIX);
  4795   4795       int rc;
  4796   4796       u64 ck1 = 0;
  4797   4797       u64 ck2 = 0;

Changes to ext/fts5/fts5_main.c.

  1383   1383         );
  1384   1384         rc = SQLITE_ERROR;
  1385   1385       }else{
  1386   1386         i64 iDel = sqlite3_value_int64(apVal[0]);  /* Rowid to delete */
  1387   1387         rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel);
  1388   1388       }
  1389   1389     }else{
  1390         -    assert( nArg>1 );
  1391   1390       sqlite3_value *pCmd = apVal[2 + pConfig->nCol];
         1391  +    assert( nArg>1 );
  1392   1392       if( SQLITE_NULL!=sqlite3_value_type(pCmd) ){
  1393   1393         const char *z = (const char*)sqlite3_value_text(pCmd);
  1394   1394         if( pConfig->eContent!=FTS5_CONTENT_NORMAL 
  1395   1395          && 0==sqlite3_stricmp("delete", z) 
  1396   1396         ){
  1397   1397           rc = fts5SpecialDelete(pTab, apVal, pRowid);
  1398   1398         }else{
................................................................................
  2220   2220     char buf[8];
  2221   2221     assert( nArg==0 );
  2222   2222     assert( sizeof(buf)>=sizeof(pGlobal) );
  2223   2223     memcpy(buf, (void*)&pGlobal, sizeof(pGlobal));
  2224   2224     sqlite3_result_blob(pCtx, buf, sizeof(pGlobal), SQLITE_TRANSIENT);
  2225   2225   }
  2226   2226   
  2227         -#ifdef _WIN32_
         2227  +#ifdef _WIN32
  2228   2228   __declspec(dllexport)
  2229   2229   #endif
  2230   2230   int sqlite3_fts5_init(
  2231   2231     sqlite3 *db,
  2232   2232     char **pzErrMsg,
  2233   2233     const sqlite3_api_routines *pApi
  2234   2234   ){

Changes to ext/fts5/fts5_storage.c.

   154    154     sqlite3 *db,
   155    155     char **pzErr,
   156    156     const char *zFormat,
   157    157     ...
   158    158   ){
   159    159     int rc;
   160    160     va_list ap;                     /* ... printf arguments */
          161  +  char *zSql;
          162  +
   161    163     va_start(ap, zFormat);
   162         -  char *zSql = sqlite3_vmprintf(zFormat, ap);
          164  +  zSql = sqlite3_vmprintf(zFormat, ap);
   163    165   
   164    166     if( zSql==0 ){
   165    167       rc = SQLITE_NOMEM;
   166    168     }else{
   167    169       rc = sqlite3_exec(db, zSql, 0, 0, pzErr);
   168    170       sqlite3_free(zSql);
   169    171     }

Changes to ext/fts5/fts5_tcl.c.

   525    525       }
   526    526     }
   527    527   }
   528    528   
   529    529   static void xF5tDestroy(void *pCtx){
   530    530     F5tFunction *p = (F5tFunction*)pCtx;
   531    531     Tcl_DecrRefCount(p->pScript);
   532         -  ckfree(p);
          532  +  ckfree((char *)p);
   533    533   }
   534    534   
   535    535   /*
   536    536   **      sqlite3_fts5_create_function DB NAME SCRIPT
   537    537   **
   538    538   ** Description...
   539    539   */
................................................................................
   720    720   
   721    721     if( rc==TCL_OK ){
   722    722       rc = Tcl_EvalObjEx(pMod->interp, pEval, TCL_GLOBAL_ONLY);
   723    723     }
   724    724     Tcl_DecrRefCount(pEval);
   725    725   
   726    726     if( rc==TCL_OK ){
   727         -    F5tTokenizerInstance *pInst = ckalloc(sizeof(F5tTokenizerInstance));
          727  +    F5tTokenizerInstance *pInst;
          728  +    pInst = (F5tTokenizerInstance*)ckalloc(sizeof(F5tTokenizerInstance));
   728    729       memset(pInst, 0, sizeof(F5tTokenizerInstance));
   729    730       pInst->interp = pMod->interp;
   730    731       pInst->pScript = Tcl_GetObjResult(pMod->interp);
   731    732       pInst->pContext = pMod->pContext;
   732    733       Tcl_IncrRefCount(pInst->pScript);
   733    734       *ppOut = (Fts5Tokenizer*)pInst;
   734    735     }
................................................................................
   736    737     return rc;
   737    738   }
   738    739   
   739    740   
   740    741   static void f5tTokenizerDelete(Fts5Tokenizer *p){
   741    742     F5tTokenizerInstance *pInst = (F5tTokenizerInstance*)p;
   742    743     Tcl_DecrRefCount(pInst->pScript);
   743         -  ckfree(pInst);
          744  +  ckfree((char *)pInst);
   744    745   }
   745    746   
   746    747   static int f5tTokenizerTokenize(
   747    748     Fts5Tokenizer *p, 
   748    749     void *pCtx,
   749    750     const char *pText, int nText, 
   750    751     int (*xToken)(void*, const char*, int, int, int)
................................................................................
   812    813     Tcl_SetResult(interp, (char*)sqlite3ErrName(rc), TCL_VOLATILE);
   813    814     return TCL_OK;
   814    815   }
   815    816   
   816    817   static void f5tDelTokenizer(void *pCtx){
   817    818     F5tTokenizerModule *pMod = (F5tTokenizerModule*)pCtx;
   818    819     Tcl_DecrRefCount(pMod->pScript);
   819         -  ckfree(pMod);
          820  +  ckfree((char *)pMod);
   820    821   }
   821    822   
   822    823   /*
   823    824   **      sqlite3_fts5_create_tokenizer DB NAME SCRIPT
   824    825   **
   825    826   ** Register a tokenizer named NAME implemented by script SCRIPT. When
   826    827   ** a tokenizer instance is created (fts5_tokenizer.xCreate), any tokenizer
................................................................................
   960    961       { "sqlite3_fts5_create_function",  f5tCreateFunction, 0 },
   961    962       { "sqlite3_fts5_may_be_corrupt",   f5tMayBeCorrupt, 0 },
   962    963       { "sqlite3_fts5_token_hash",       f5tTokenHash, 0 }
   963    964     };
   964    965     int i;
   965    966     F5tTokenizerContext *pContext;
   966    967   
   967         -  pContext = ckalloc(sizeof(F5tTokenizerContext));
          968  +  pContext = (F5tTokenizerContext*)ckalloc(sizeof(F5tTokenizerContext));
   968    969     memset(pContext, 0, sizeof(*pContext));
   969    970   
   970    971     for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
   971    972       struct Cmd *p = &aCmd[i];
   972    973       void *pCtx = 0;
   973    974       if( p->bTokenizeCtx ) pCtx = (void*)pContext;
   974    975       Tcl_CreateObjCommand(interp, p->zName, p->xProc, pCtx, (i ? 0 : xF5tFree));