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