xref: /sqlite-3.40.0/src/test_hexio.c (revision 7b14b990)
115926590Sdrh /*
215926590Sdrh ** 2007 April 6
315926590Sdrh **
415926590Sdrh ** The author disclaims copyright to this source code.  In place of
515926590Sdrh ** a legal notice, here is a blessing:
615926590Sdrh **
715926590Sdrh **    May you do good and not evil.
815926590Sdrh **    May you find forgiveness for yourself and forgive others.
915926590Sdrh **    May you share freely, never taking more than you give.
1015926590Sdrh **
1115926590Sdrh *************************************************************************
1215926590Sdrh ** Code for testing all sorts of SQLite interfaces.  This code
1315926590Sdrh ** implements TCL commands for reading and writing the binary
1415926590Sdrh ** database files and displaying the content of those files as
1515926590Sdrh ** hexadecimal.  We could, in theory, use the built-in "binary"
1615926590Sdrh ** command of TCL to do a lot of this, but there are some issues
1715926590Sdrh ** with historical versions of the "binary" command.  So it seems
1815926590Sdrh ** easier and safer to build our own mechanism.
1915926590Sdrh */
2053c14021Sdrh #include "sqliteInt.h"
2152b1dbb5Smistachkin #if defined(INCLUDE_SQLITE_TCL_H)
2252b1dbb5Smistachkin #  include "sqlite_tcl.h"
2352b1dbb5Smistachkin #else
2415926590Sdrh #  include "tcl.h"
2552b1dbb5Smistachkin #endif
2615926590Sdrh #include <stdlib.h>
2715926590Sdrh #include <string.h>
2815926590Sdrh #include <assert.h>
2915926590Sdrh 
3015926590Sdrh 
3115926590Sdrh /*
3215926590Sdrh ** Convert binary to hex.  The input zBuf[] contains N bytes of
3315926590Sdrh ** binary data.  zBuf[] is 2*n+1 bytes long.  Overwrite zBuf[]
3415926590Sdrh ** with a hexadecimal representation of its original binary input.
3515926590Sdrh */
sqlite3TestBinToHex(unsigned char * zBuf,int N)369c7a60dfSdrh void sqlite3TestBinToHex(unsigned char *zBuf, int N){
3715926590Sdrh   const unsigned char zHex[] = "0123456789ABCDEF";
3815926590Sdrh   int i, j;
3915926590Sdrh   unsigned char c;
4015926590Sdrh   i = N*2;
4115926590Sdrh   zBuf[i--] = 0;
4215926590Sdrh   for(j=N-1; j>=0; j--){
4315926590Sdrh     c = zBuf[j];
4415926590Sdrh     zBuf[i--] = zHex[c&0xf];
4515926590Sdrh     zBuf[i--] = zHex[c>>4];
4615926590Sdrh   }
4715926590Sdrh   assert( i==-1 );
4815926590Sdrh }
4915926590Sdrh 
5015926590Sdrh /*
5115926590Sdrh ** Convert hex to binary.  The input zIn[] contains N bytes of
5215926590Sdrh ** hexadecimal.  Convert this into binary and write aOut[] with
5315926590Sdrh ** the binary data.  Spaces in the original input are ignored.
5415926590Sdrh ** Return the number of bytes of binary rendered.
5515926590Sdrh */
sqlite3TestHexToBin(const unsigned char * zIn,int N,unsigned char * aOut)569c7a60dfSdrh int sqlite3TestHexToBin(const unsigned char *zIn, int N, unsigned char *aOut){
5715926590Sdrh   const unsigned char aMap[] = {
5815926590Sdrh      0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
5915926590Sdrh      0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
6015926590Sdrh      0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
6115926590Sdrh      1, 2, 3, 4, 5, 6, 7, 8,  9,10, 0, 0, 0, 0, 0, 0,
6215926590Sdrh      0,11,12,13,14,15,16, 0,  0, 0, 0, 0, 0, 0, 0, 0,
6315926590Sdrh      0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
6415926590Sdrh      0,11,12,13,14,15,16, 0,  0, 0, 0, 0, 0, 0, 0, 0,
6515926590Sdrh      0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
6615926590Sdrh      0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
6715926590Sdrh      0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
6815926590Sdrh      0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
6915926590Sdrh      0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
7015926590Sdrh      0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
7115926590Sdrh      0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
7215926590Sdrh      0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
7315926590Sdrh      0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
7415926590Sdrh   };
7515926590Sdrh   int i, j;
7615926590Sdrh   int hi=1;
7715926590Sdrh   unsigned char c;
7815926590Sdrh 
7915926590Sdrh   for(i=j=0; i<N; i++){
8015926590Sdrh     c = aMap[zIn[i]];
8115926590Sdrh     if( c==0 ) continue;
8215926590Sdrh     if( hi ){
8315926590Sdrh       aOut[j] = (c-1)<<4;
8415926590Sdrh       hi = 0;
8515926590Sdrh     }else{
8615926590Sdrh       aOut[j++] |= c-1;
8715926590Sdrh       hi = 1;
8815926590Sdrh     }
8915926590Sdrh   }
9015926590Sdrh   return j;
9115926590Sdrh }
9215926590Sdrh 
9315926590Sdrh 
9415926590Sdrh /*
9515926590Sdrh ** Usage:   hexio_read  FILENAME  OFFSET  AMT
9615926590Sdrh **
9715926590Sdrh ** Read AMT bytes from file FILENAME beginning at OFFSET from the
9815926590Sdrh ** beginning of the file.  Convert that information to hexadecimal
9915926590Sdrh ** and return the resulting HEX string.
10015926590Sdrh */
hexio_read(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])1017617e4a8Smistachkin static int SQLITE_TCLAPI hexio_read(
10215926590Sdrh   void * clientData,
10315926590Sdrh   Tcl_Interp *interp,
10415926590Sdrh   int objc,
10515926590Sdrh   Tcl_Obj *CONST objv[]
10615926590Sdrh ){
10715926590Sdrh   int offset;
10815926590Sdrh   int amt, got;
10915926590Sdrh   const char *zFile;
11015926590Sdrh   unsigned char *zBuf;
11115926590Sdrh   FILE *in;
11215926590Sdrh 
11315926590Sdrh   if( objc!=4 ){
11415926590Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "FILENAME OFFSET AMT");
11515926590Sdrh     return TCL_ERROR;
11615926590Sdrh   }
11715926590Sdrh   if( Tcl_GetIntFromObj(interp, objv[2], &offset) ) return TCL_ERROR;
11815926590Sdrh   if( Tcl_GetIntFromObj(interp, objv[3], &amt) ) return TCL_ERROR;
11915926590Sdrh   zFile = Tcl_GetString(objv[1]);
12017435752Sdrh   zBuf = sqlite3_malloc( amt*2+1 );
12115926590Sdrh   if( zBuf==0 ){
12215926590Sdrh     return TCL_ERROR;
12315926590Sdrh   }
124498b8767Sdrh   in = fopen(zFile, "rb");
125498b8767Sdrh   if( in==0 ){
12615926590Sdrh     in = fopen(zFile, "r");
127498b8767Sdrh   }
12815926590Sdrh   if( in==0 ){
12915926590Sdrh     Tcl_AppendResult(interp, "cannot open input file ", zFile, 0);
13015926590Sdrh     return TCL_ERROR;
13115926590Sdrh   }
13215926590Sdrh   fseek(in, offset, SEEK_SET);
13383cc1392Sdrh   got = (int)fread(zBuf, 1, amt, in);
13415926590Sdrh   fclose(in);
13515926590Sdrh   if( got<0 ){
13615926590Sdrh     got = 0;
13715926590Sdrh   }
1389c7a60dfSdrh   sqlite3TestBinToHex(zBuf, got);
13915926590Sdrh   Tcl_AppendResult(interp, zBuf, 0);
14017435752Sdrh   sqlite3_free(zBuf);
14115926590Sdrh   return TCL_OK;
14215926590Sdrh }
14315926590Sdrh 
14415926590Sdrh 
14515926590Sdrh /*
14615926590Sdrh ** Usage:   hexio_write  FILENAME  OFFSET  DATA
14715926590Sdrh **
14815926590Sdrh ** Write DATA into file FILENAME beginning at OFFSET from the
14915926590Sdrh ** beginning of the file.  DATA is expressed in hexadecimal.
15015926590Sdrh */
hexio_write(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])1517617e4a8Smistachkin static int SQLITE_TCLAPI hexio_write(
15215926590Sdrh   void * clientData,
15315926590Sdrh   Tcl_Interp *interp,
15415926590Sdrh   int objc,
15515926590Sdrh   Tcl_Obj *CONST objv[]
15615926590Sdrh ){
15715926590Sdrh   int offset;
15815926590Sdrh   int nIn, nOut, written;
15915926590Sdrh   const char *zFile;
16015926590Sdrh   const unsigned char *zIn;
16115926590Sdrh   unsigned char *aOut;
16215926590Sdrh   FILE *out;
16315926590Sdrh 
16415926590Sdrh   if( objc!=4 ){
16515926590Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "FILENAME OFFSET HEXDATA");
16615926590Sdrh     return TCL_ERROR;
16715926590Sdrh   }
16815926590Sdrh   if( Tcl_GetIntFromObj(interp, objv[2], &offset) ) return TCL_ERROR;
16915926590Sdrh   zFile = Tcl_GetString(objv[1]);
17015926590Sdrh   zIn = (const unsigned char *)Tcl_GetStringFromObj(objv[3], &nIn);
171*7b14b990Sdan   aOut = sqlite3_malloc( 1 + nIn/2 );
17215926590Sdrh   if( aOut==0 ){
17315926590Sdrh     return TCL_ERROR;
17415926590Sdrh   }
1759c7a60dfSdrh   nOut = sqlite3TestHexToBin(zIn, nIn, aOut);
176498b8767Sdrh   out = fopen(zFile, "r+b");
177498b8767Sdrh   if( out==0 ){
17815926590Sdrh     out = fopen(zFile, "r+");
179498b8767Sdrh   }
18015926590Sdrh   if( out==0 ){
18115926590Sdrh     Tcl_AppendResult(interp, "cannot open output file ", zFile, 0);
18215926590Sdrh     return TCL_ERROR;
18315926590Sdrh   }
18415926590Sdrh   fseek(out, offset, SEEK_SET);
18583cc1392Sdrh   written = (int)fwrite(aOut, 1, nOut, out);
18617435752Sdrh   sqlite3_free(aOut);
18715926590Sdrh   fclose(out);
18815926590Sdrh   Tcl_SetObjResult(interp, Tcl_NewIntObj(written));
18915926590Sdrh   return TCL_OK;
19015926590Sdrh }
19115926590Sdrh 
19215926590Sdrh /*
19315926590Sdrh ** USAGE:   hexio_get_int   HEXDATA
19415926590Sdrh **
19515926590Sdrh ** Interpret the HEXDATA argument as a big-endian integer.  Return
19615926590Sdrh ** the value of that integer.  HEXDATA can contain between 2 and 8
19715926590Sdrh ** hexadecimal digits.
19815926590Sdrh */
hexio_get_int(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])1997617e4a8Smistachkin static int SQLITE_TCLAPI hexio_get_int(
20015926590Sdrh   void * clientData,
20115926590Sdrh   Tcl_Interp *interp,
20215926590Sdrh   int objc,
20315926590Sdrh   Tcl_Obj *CONST objv[]
20415926590Sdrh ){
20515926590Sdrh   int val;
20615926590Sdrh   int nIn, nOut;
20715926590Sdrh   const unsigned char *zIn;
20815926590Sdrh   unsigned char *aOut;
20915926590Sdrh   unsigned char aNum[4];
21015926590Sdrh 
21115926590Sdrh   if( objc!=2 ){
21215926590Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "HEXDATA");
21315926590Sdrh     return TCL_ERROR;
21415926590Sdrh   }
21515926590Sdrh   zIn = (const unsigned char *)Tcl_GetStringFromObj(objv[1], &nIn);
216*7b14b990Sdan   aOut = sqlite3_malloc( 1 + nIn/2 );
21715926590Sdrh   if( aOut==0 ){
21815926590Sdrh     return TCL_ERROR;
21915926590Sdrh   }
2209c7a60dfSdrh   nOut = sqlite3TestHexToBin(zIn, nIn, aOut);
22115926590Sdrh   if( nOut>=4 ){
22215926590Sdrh     memcpy(aNum, aOut, 4);
22315926590Sdrh   }else{
22415926590Sdrh     memset(aNum, 0, sizeof(aNum));
225431e8537Sdrh     memcpy(&aNum[4-nOut], aOut, nOut);
22615926590Sdrh   }
22717435752Sdrh   sqlite3_free(aOut);
22815926590Sdrh   val = (aNum[0]<<24) | (aNum[1]<<16) | (aNum[2]<<8) | aNum[3];
22915926590Sdrh   Tcl_SetObjResult(interp, Tcl_NewIntObj(val));
23015926590Sdrh   return TCL_OK;
23115926590Sdrh }
23215926590Sdrh 
23315926590Sdrh 
23415926590Sdrh /*
23515926590Sdrh ** USAGE:   hexio_render_int16   INTEGER
23615926590Sdrh **
23715926590Sdrh ** Render INTEGER has a 16-bit big-endian integer in hexadecimal.
23815926590Sdrh */
hexio_render_int16(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])2397617e4a8Smistachkin static int SQLITE_TCLAPI hexio_render_int16(
24015926590Sdrh   void * clientData,
24115926590Sdrh   Tcl_Interp *interp,
24215926590Sdrh   int objc,
24315926590Sdrh   Tcl_Obj *CONST objv[]
24415926590Sdrh ){
24515926590Sdrh   int val;
24615926590Sdrh   unsigned char aNum[10];
24715926590Sdrh 
24815926590Sdrh   if( objc!=2 ){
24915926590Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "INTEGER");
25015926590Sdrh     return TCL_ERROR;
25115926590Sdrh   }
25215926590Sdrh   if( Tcl_GetIntFromObj(interp, objv[1], &val) ) return TCL_ERROR;
25315926590Sdrh   aNum[0] = val>>8;
25415926590Sdrh   aNum[1] = val;
2559c7a60dfSdrh   sqlite3TestBinToHex(aNum, 2);
25615926590Sdrh   Tcl_SetObjResult(interp, Tcl_NewStringObj((char*)aNum, 4));
25715926590Sdrh   return TCL_OK;
25815926590Sdrh }
25915926590Sdrh 
26015926590Sdrh 
26115926590Sdrh /*
26215926590Sdrh ** USAGE:   hexio_render_int32   INTEGER
26315926590Sdrh **
26415926590Sdrh ** Render INTEGER has a 32-bit big-endian integer in hexadecimal.
26515926590Sdrh */
hexio_render_int32(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])2667617e4a8Smistachkin static int SQLITE_TCLAPI hexio_render_int32(
26715926590Sdrh   void * clientData,
26815926590Sdrh   Tcl_Interp *interp,
26915926590Sdrh   int objc,
27015926590Sdrh   Tcl_Obj *CONST objv[]
27115926590Sdrh ){
27215926590Sdrh   int val;
27315926590Sdrh   unsigned char aNum[10];
27415926590Sdrh 
27515926590Sdrh   if( objc!=2 ){
27615926590Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "INTEGER");
27715926590Sdrh     return TCL_ERROR;
27815926590Sdrh   }
27915926590Sdrh   if( Tcl_GetIntFromObj(interp, objv[1], &val) ) return TCL_ERROR;
28015926590Sdrh   aNum[0] = val>>24;
28115926590Sdrh   aNum[1] = val>>16;
28215926590Sdrh   aNum[2] = val>>8;
28315926590Sdrh   aNum[3] = val;
2849c7a60dfSdrh   sqlite3TestBinToHex(aNum, 4);
28515926590Sdrh   Tcl_SetObjResult(interp, Tcl_NewStringObj((char*)aNum, 8));
28615926590Sdrh   return TCL_OK;
28715926590Sdrh }
28815926590Sdrh 
28953c14021Sdrh /*
29053c14021Sdrh ** USAGE:  utf8_to_utf8  HEX
29153c14021Sdrh **
29253c14021Sdrh ** The argument is a UTF8 string represented in hexadecimal.
29353c14021Sdrh ** The UTF8 might not be well-formed.  Run this string through
29453c14021Sdrh ** sqlite3Utf8to8() convert it back to hex and return the result.
29553c14021Sdrh */
utf8_to_utf8(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])2967617e4a8Smistachkin static int SQLITE_TCLAPI utf8_to_utf8(
29753c14021Sdrh   void * clientData,
29853c14021Sdrh   Tcl_Interp *interp,
29953c14021Sdrh   int objc,
30053c14021Sdrh   Tcl_Obj *CONST objv[]
30153c14021Sdrh ){
30228c66307Sdanielk1977 #ifdef SQLITE_DEBUG
30353c14021Sdrh   int n;
30453c14021Sdrh   int nOut;
30553c14021Sdrh   const unsigned char *zOrig;
30653c14021Sdrh   unsigned char *z;
30753c14021Sdrh   if( objc!=2 ){
30853c14021Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "HEX");
30953c14021Sdrh     return TCL_ERROR;
31053c14021Sdrh   }
31153c14021Sdrh   zOrig = (unsigned char *)Tcl_GetStringFromObj(objv[1], &n);
312*7b14b990Sdan   z = sqlite3_malloc( n+4 );
3139c7a60dfSdrh   n = sqlite3TestHexToBin(zOrig, n, z);
31453c14021Sdrh   z[n] = 0;
31553c14021Sdrh   nOut = sqlite3Utf8To8(z);
3169c7a60dfSdrh   sqlite3TestBinToHex(z,nOut);
31753c14021Sdrh   Tcl_AppendResult(interp, (char*)z, 0);
31853c14021Sdrh   sqlite3_free(z);
31953c14021Sdrh   return TCL_OK;
320211fb084Sdan #else
321211fb084Sdan   Tcl_AppendResult(interp,
322211fb084Sdan       "[utf8_to_utf8] unavailable - SQLITE_DEBUG not defined", 0
323211fb084Sdan   );
324211fb084Sdan   return TCL_ERROR;
325211fb084Sdan #endif
32653c14021Sdrh }
32715926590Sdrh 
getFts3Varint(const char * p,sqlite_int64 * v)3284b4d4469Sdan static int getFts3Varint(const char *p, sqlite_int64 *v){
3294b4d4469Sdan   const unsigned char *q = (const unsigned char *) p;
3304b4d4469Sdan   sqlite_uint64 x = 0, y = 1;
3314b4d4469Sdan   while( (*q & 0x80) == 0x80 ){
3324b4d4469Sdan     x += y * (*q++ & 0x7f);
3334b4d4469Sdan     y <<= 7;
3344b4d4469Sdan   }
3354b4d4469Sdan   x += y * (*q++);
3364b4d4469Sdan   *v = (sqlite_int64) x;
3374b4d4469Sdan   return (int) (q - (unsigned char *)p);
3384b4d4469Sdan }
3394b4d4469Sdan 
putFts3Varint(char * p,sqlite_int64 v)340572b0dddSdan static int putFts3Varint(char *p, sqlite_int64 v){
341572b0dddSdan   unsigned char *q = (unsigned char *) p;
342572b0dddSdan   sqlite_uint64 vu = v;
343572b0dddSdan   do{
344572b0dddSdan     *q++ = (unsigned char) ((vu & 0x7f) | 0x80);
345572b0dddSdan     vu >>= 7;
346572b0dddSdan   }while( vu!=0 );
347572b0dddSdan   q[-1] &= 0x7f;  /* turn off high bit in final byte */
348572b0dddSdan   assert( q - (unsigned char *)p <= 10 );
349572b0dddSdan   return (int) (q - (unsigned char *)p);
350572b0dddSdan }
3514b4d4469Sdan 
35209977bb9Sdan /*
353f5fff2a7Sdan ** USAGE:  read_fts3varint BLOB VARNAME
35409977bb9Sdan **
35509977bb9Sdan ** Read a varint from the start of BLOB. Set variable VARNAME to contain
35609977bb9Sdan ** the interpreted value. Return the number of bytes of BLOB consumed.
35709977bb9Sdan */
read_fts3varint(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])3587617e4a8Smistachkin static int SQLITE_TCLAPI read_fts3varint(
35909977bb9Sdan   void * clientData,
36009977bb9Sdan   Tcl_Interp *interp,
36109977bb9Sdan   int objc,
36209977bb9Sdan   Tcl_Obj *CONST objv[]
36309977bb9Sdan ){
36409977bb9Sdan   int nBlob;
36509977bb9Sdan   unsigned char *zBlob;
36609977bb9Sdan   sqlite3_int64 iVal;
36709977bb9Sdan   int nVal;
36809977bb9Sdan 
36909977bb9Sdan   if( objc!=3 ){
37009977bb9Sdan     Tcl_WrongNumArgs(interp, 1, objv, "BLOB VARNAME");
37109977bb9Sdan     return TCL_ERROR;
37209977bb9Sdan   }
37309977bb9Sdan   zBlob = Tcl_GetByteArrayFromObj(objv[1], &nBlob);
37409977bb9Sdan 
375614d2650Sdrh   nVal = getFts3Varint((char*)zBlob, (sqlite3_int64 *)(&iVal));
37609977bb9Sdan   Tcl_ObjSetVar2(interp, objv[2], 0, Tcl_NewWideIntObj(iVal), 0);
37709977bb9Sdan   Tcl_SetObjResult(interp, Tcl_NewIntObj(nVal));
37809977bb9Sdan   return TCL_OK;
37909977bb9Sdan }
38009977bb9Sdan 
381572b0dddSdan /*
382572b0dddSdan ** USAGE:  make_fts3record ARGLIST
383572b0dddSdan */
make_fts3record(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])384572b0dddSdan static int SQLITE_TCLAPI make_fts3record(
385572b0dddSdan   void * clientData,
386572b0dddSdan   Tcl_Interp *interp,
387572b0dddSdan   int objc,
388572b0dddSdan   Tcl_Obj *CONST objv[]
389572b0dddSdan ){
390572b0dddSdan   Tcl_Obj **aArg = 0;
391572b0dddSdan   int nArg = 0;
392572b0dddSdan   unsigned char *aOut = 0;
393572b0dddSdan   int nOut = 0;
394572b0dddSdan   int nAlloc = 0;
395572b0dddSdan   int i;
396572b0dddSdan 
397572b0dddSdan   if( objc!=2 ){
398572b0dddSdan     Tcl_WrongNumArgs(interp, 1, objv, "LIST");
399572b0dddSdan     return TCL_ERROR;
400572b0dddSdan   }
401572b0dddSdan   if( Tcl_ListObjGetElements(interp, objv[1], &nArg, &aArg) ){
402572b0dddSdan     return TCL_ERROR;
403572b0dddSdan   }
404572b0dddSdan 
405572b0dddSdan   for(i=0; i<nArg; i++){
406572b0dddSdan     sqlite3_int64 iVal;
407572b0dddSdan     if( TCL_OK==Tcl_GetWideIntFromObj(0, aArg[i], &iVal) ){
408572b0dddSdan       if( nOut+10>nAlloc ){
409572b0dddSdan         int nNew = nAlloc?nAlloc*2:128;
410572b0dddSdan         unsigned char *aNew = sqlite3_realloc(aOut, nNew);
411572b0dddSdan         if( aNew==0 ){
412572b0dddSdan           sqlite3_free(aOut);
413572b0dddSdan           return TCL_ERROR;
414572b0dddSdan         }
415572b0dddSdan         aOut = aNew;
416572b0dddSdan         nAlloc = nNew;
417572b0dddSdan       }
418572b0dddSdan       nOut += putFts3Varint((char*)&aOut[nOut], iVal);
419572b0dddSdan     }else{
420572b0dddSdan       int nVal = 0;
421572b0dddSdan       char *zVal = Tcl_GetStringFromObj(aArg[i], &nVal);
422572b0dddSdan       while( (nOut + nVal)>nAlloc ){
423572b0dddSdan         int nNew = nAlloc?nAlloc*2:128;
424572b0dddSdan         unsigned char *aNew = sqlite3_realloc(aOut, nNew);
425572b0dddSdan         if( aNew==0 ){
426572b0dddSdan           sqlite3_free(aOut);
427572b0dddSdan           return TCL_ERROR;
428572b0dddSdan         }
429572b0dddSdan         aOut = aNew;
430572b0dddSdan         nAlloc = nNew;
431572b0dddSdan       }
432572b0dddSdan       memcpy(&aOut[nOut], zVal, nVal);
433572b0dddSdan       nOut += nVal;
434572b0dddSdan     }
435572b0dddSdan   }
436572b0dddSdan 
437572b0dddSdan   Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(aOut, nOut));
438572b0dddSdan   sqlite3_free(aOut);
439572b0dddSdan   return TCL_OK;
440572b0dddSdan }
441572b0dddSdan 
44215926590Sdrh 
44315926590Sdrh /*
44415926590Sdrh ** Register commands with the TCL interpreter.
44515926590Sdrh */
Sqlitetest_hexio_Init(Tcl_Interp * interp)44615926590Sdrh int Sqlitetest_hexio_Init(Tcl_Interp *interp){
44715926590Sdrh   static struct {
44815926590Sdrh      char *zName;
44915926590Sdrh      Tcl_ObjCmdProc *xProc;
45015926590Sdrh   } aObjCmd[] = {
45115926590Sdrh      { "hexio_read",                   hexio_read            },
45215926590Sdrh      { "hexio_write",                  hexio_write           },
45315926590Sdrh      { "hexio_get_int",                hexio_get_int         },
45415926590Sdrh      { "hexio_render_int16",           hexio_render_int16    },
45515926590Sdrh      { "hexio_render_int32",           hexio_render_int32    },
45653c14021Sdrh      { "utf8_to_utf8",                 utf8_to_utf8          },
457f5fff2a7Sdan      { "read_fts3varint",              read_fts3varint       },
458572b0dddSdan      { "make_fts3record",              make_fts3record       },
45915926590Sdrh   };
46015926590Sdrh   int i;
46115926590Sdrh   for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
46215926590Sdrh     Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0);
46315926590Sdrh   }
46415926590Sdrh   return TCL_OK;
46515926590Sdrh }
466