4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
7 ** May you do good and not evil.
8 ** May you find forgiveness for yourself and forgive others.
9 ** May you share freely, never taking more than you give.
11 *************************************************************************
12 ** Code for testing all sorts of SQLite interfaces. This code
13 ** implements TCL commands for reading and writing the binary
14 ** database files and displaying the content of those files as
15 ** hexadecimal. We could, in theory, use the built-in "binary"
16 ** command of TCL to do a lot of this, but there are some issues
17 ** with historical versions of the "binary" command. So it seems
18 ** easier and safer to build our own mechanism.
20 #include "sqliteInt.h"
21 #if defined(INCLUDE_SQLITE_TCL_H)
22 # include "sqlite_tcl.h"
32 ** Convert binary to hex. The input zBuf[] contains N bytes of
33 ** binary data. zBuf[] is 2*n+1 bytes long. Overwrite zBuf[]
34 ** with a hexadecimal representation of its original binary input.
36 void sqlite3TestBinToHex(unsigned char *zBuf
, int N
){
37 const unsigned char zHex
[] = "0123456789ABCDEF";
42 for(j
=N
-1; j
>=0; j
--){
44 zBuf
[i
--] = zHex
[c
&0xf];
45 zBuf
[i
--] = zHex
[c
>>4];
51 ** Convert hex to binary. The input zIn[] contains N bytes of
52 ** hexadecimal. Convert this into binary and write aOut[] with
53 ** the binary data. Spaces in the original input are ignored.
54 ** Return the number of bytes of binary rendered.
56 int sqlite3TestHexToBin(const unsigned char *zIn
, int N
, unsigned char *aOut
){
57 const unsigned char aMap
[] = {
58 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
59 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
60 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
61 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 0, 0, 0, 0, 0, 0,
62 0,11,12,13,14,15,16, 0, 0, 0, 0, 0, 0, 0, 0, 0,
63 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
64 0,11,12,13,14,15,16, 0, 0, 0, 0, 0, 0, 0, 0, 0,
65 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
66 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
67 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
68 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
69 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
70 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
71 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
72 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
73 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
95 ** Usage: hexio_read FILENAME OFFSET AMT
97 ** Read AMT bytes from file FILENAME beginning at OFFSET from the
98 ** beginning of the file. Convert that information to hexadecimal
99 ** and return the resulting HEX string.
101 static int SQLITE_TCLAPI
hexio_read(
105 Tcl_Obj
*CONST objv
[]
114 Tcl_WrongNumArgs(interp
, 1, objv
, "FILENAME OFFSET AMT");
117 if( Tcl_GetIntFromObj(interp
, objv
[2], &offset
) ) return TCL_ERROR
;
118 if( Tcl_GetIntFromObj(interp
, objv
[3], &amt
) ) return TCL_ERROR
;
119 zFile
= Tcl_GetString(objv
[1]);
120 zBuf
= sqlite3_malloc( amt
*2+1 );
124 in
= fopen(zFile
, "rb");
126 in
= fopen(zFile
, "r");
129 Tcl_AppendResult(interp
, "cannot open input file ", zFile
, 0);
132 fseek(in
, offset
, SEEK_SET
);
133 got
= (int)fread(zBuf
, 1, amt
, in
);
138 sqlite3TestBinToHex(zBuf
, got
);
139 Tcl_AppendResult(interp
, zBuf
, 0);
146 ** Usage: hexio_write FILENAME OFFSET DATA
148 ** Write DATA into file FILENAME beginning at OFFSET from the
149 ** beginning of the file. DATA is expressed in hexadecimal.
151 static int SQLITE_TCLAPI
hexio_write(
155 Tcl_Obj
*CONST objv
[]
158 int nIn
, nOut
, written
;
160 const unsigned char *zIn
;
165 Tcl_WrongNumArgs(interp
, 1, objv
, "FILENAME OFFSET HEXDATA");
168 if( Tcl_GetIntFromObj(interp
, objv
[2], &offset
) ) return TCL_ERROR
;
169 zFile
= Tcl_GetString(objv
[1]);
170 zIn
= (const unsigned char *)Tcl_GetStringFromObj(objv
[3], &nIn
);
171 aOut
= sqlite3_malloc( 1 + nIn
/2 );
175 nOut
= sqlite3TestHexToBin(zIn
, nIn
, aOut
);
176 out
= fopen(zFile
, "r+b");
178 out
= fopen(zFile
, "r+");
181 Tcl_AppendResult(interp
, "cannot open output file ", zFile
, 0);
184 fseek(out
, offset
, SEEK_SET
);
185 written
= (int)fwrite(aOut
, 1, nOut
, out
);
188 Tcl_SetObjResult(interp
, Tcl_NewIntObj(written
));
193 ** USAGE: hexio_get_int HEXDATA
195 ** Interpret the HEXDATA argument as a big-endian integer. Return
196 ** the value of that integer. HEXDATA can contain between 2 and 8
197 ** hexadecimal digits.
199 static int SQLITE_TCLAPI
hexio_get_int(
203 Tcl_Obj
*CONST objv
[]
207 const unsigned char *zIn
;
209 unsigned char aNum
[4];
212 Tcl_WrongNumArgs(interp
, 1, objv
, "HEXDATA");
215 zIn
= (const unsigned char *)Tcl_GetStringFromObj(objv
[1], &nIn
);
216 aOut
= sqlite3_malloc( 1 + nIn
/2 );
220 nOut
= sqlite3TestHexToBin(zIn
, nIn
, aOut
);
222 memcpy(aNum
, aOut
, 4);
224 memset(aNum
, 0, sizeof(aNum
));
225 memcpy(&aNum
[4-nOut
], aOut
, nOut
);
228 val
= (aNum
[0]<<24) | (aNum
[1]<<16) | (aNum
[2]<<8) | aNum
[3];
229 Tcl_SetObjResult(interp
, Tcl_NewIntObj(val
));
235 ** USAGE: hexio_render_int16 INTEGER
237 ** Render INTEGER has a 16-bit big-endian integer in hexadecimal.
239 static int SQLITE_TCLAPI
hexio_render_int16(
243 Tcl_Obj
*CONST objv
[]
246 unsigned char aNum
[10];
249 Tcl_WrongNumArgs(interp
, 1, objv
, "INTEGER");
252 if( Tcl_GetIntFromObj(interp
, objv
[1], &val
) ) return TCL_ERROR
;
255 sqlite3TestBinToHex(aNum
, 2);
256 Tcl_SetObjResult(interp
, Tcl_NewStringObj((char*)aNum
, 4));
262 ** USAGE: hexio_render_int32 INTEGER
264 ** Render INTEGER has a 32-bit big-endian integer in hexadecimal.
266 static int SQLITE_TCLAPI
hexio_render_int32(
270 Tcl_Obj
*CONST objv
[]
273 unsigned char aNum
[10];
276 Tcl_WrongNumArgs(interp
, 1, objv
, "INTEGER");
279 if( Tcl_GetIntFromObj(interp
, objv
[1], &val
) ) return TCL_ERROR
;
284 sqlite3TestBinToHex(aNum
, 4);
285 Tcl_SetObjResult(interp
, Tcl_NewStringObj((char*)aNum
, 8));
290 ** USAGE: utf8_to_utf8 HEX
292 ** The argument is a UTF8 string represented in hexadecimal.
293 ** The UTF8 might not be well-formed. Run this string through
294 ** sqlite3Utf8to8() convert it back to hex and return the result.
296 static int SQLITE_TCLAPI
utf8_to_utf8(
300 Tcl_Obj
*CONST objv
[]
305 const unsigned char *zOrig
;
308 Tcl_WrongNumArgs(interp
, 1, objv
, "HEX");
311 zOrig
= (unsigned char *)Tcl_GetStringFromObj(objv
[1], &n
);
312 z
= sqlite3_malloc( n
+4 );
313 n
= sqlite3TestHexToBin(zOrig
, n
, z
);
315 nOut
= sqlite3Utf8To8(z
);
316 sqlite3TestBinToHex(z
,nOut
);
317 Tcl_AppendResult(interp
, (char*)z
, 0);
321 Tcl_AppendResult(interp
,
322 "[utf8_to_utf8] unavailable - SQLITE_DEBUG not defined", 0
328 static int getFts3Varint(const char *p
, sqlite_int64
*v
){
329 const unsigned char *q
= (const unsigned char *) p
;
330 sqlite_uint64 x
= 0, y
= 1;
331 while( (*q
& 0x80) == 0x80 ){
332 x
+= y
* (*q
++ & 0x7f);
336 *v
= (sqlite_int64
) x
;
337 return (int) (q
- (unsigned char *)p
);
340 static int putFts3Varint(char *p
, sqlite_int64 v
){
341 unsigned char *q
= (unsigned char *) p
;
342 sqlite_uint64 vu
= v
;
344 *q
++ = (unsigned char) ((vu
& 0x7f) | 0x80);
347 q
[-1] &= 0x7f; /* turn off high bit in final byte */
348 assert( q
- (unsigned char *)p
<= 10 );
349 return (int) (q
- (unsigned char *)p
);
353 ** USAGE: read_fts3varint BLOB VARNAME
355 ** Read a varint from the start of BLOB. Set variable VARNAME to contain
356 ** the interpreted value. Return the number of bytes of BLOB consumed.
358 static int SQLITE_TCLAPI
read_fts3varint(
362 Tcl_Obj
*CONST objv
[]
365 unsigned char *zBlob
;
370 Tcl_WrongNumArgs(interp
, 1, objv
, "BLOB VARNAME");
373 zBlob
= Tcl_GetByteArrayFromObj(objv
[1], &nBlob
);
375 nVal
= getFts3Varint((char*)zBlob
, (sqlite3_int64
*)(&iVal
));
376 Tcl_ObjSetVar2(interp
, objv
[2], 0, Tcl_NewWideIntObj(iVal
), 0);
377 Tcl_SetObjResult(interp
, Tcl_NewIntObj(nVal
));
382 ** USAGE: make_fts3record ARGLIST
384 static int SQLITE_TCLAPI
make_fts3record(
388 Tcl_Obj
*CONST objv
[]
392 unsigned char *aOut
= 0;
398 Tcl_WrongNumArgs(interp
, 1, objv
, "LIST");
401 if( Tcl_ListObjGetElements(interp
, objv
[1], &nArg
, &aArg
) ){
405 for(i
=0; i
<nArg
; i
++){
407 if( TCL_OK
==Tcl_GetWideIntFromObj(0, aArg
[i
], &iVal
) ){
408 if( nOut
+10>nAlloc
){
409 int nNew
= nAlloc
?nAlloc
*2:128;
410 unsigned char *aNew
= sqlite3_realloc(aOut
, nNew
);
418 nOut
+= putFts3Varint((char*)&aOut
[nOut
], iVal
);
421 char *zVal
= Tcl_GetStringFromObj(aArg
[i
], &nVal
);
422 while( (nOut
+ nVal
)>nAlloc
){
423 int nNew
= nAlloc
?nAlloc
*2:128;
424 unsigned char *aNew
= sqlite3_realloc(aOut
, nNew
);
432 memcpy(&aOut
[nOut
], zVal
, nVal
);
437 Tcl_SetObjResult(interp
, Tcl_NewByteArrayObj(aOut
, nOut
));
444 ** Register commands with the TCL interpreter.
446 int Sqlitetest_hexio_Init(Tcl_Interp
*interp
){
449 Tcl_ObjCmdProc
*xProc
;
451 { "hexio_read", hexio_read
},
452 { "hexio_write", hexio_write
},
453 { "hexio_get_int", hexio_get_int
},
454 { "hexio_render_int16", hexio_render_int16
},
455 { "hexio_render_int32", hexio_render_int32
},
456 { "utf8_to_utf8", utf8_to_utf8
},
457 { "read_fts3varint", read_fts3varint
},
458 { "make_fts3record", make_fts3record
},
461 for(i
=0; i
<sizeof(aObjCmd
)/sizeof(aObjCmd
[0]); i
++){
462 Tcl_CreateObjCommand(interp
, aObjCmd
[i
].zName
, aObjCmd
[i
].xProc
, 0, 0);