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( 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( 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
+3 );
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
);
342 ** USAGE: read_fts3varint BLOB VARNAME
344 ** Read a varint from the start of BLOB. Set variable VARNAME to contain
345 ** the interpreted value. Return the number of bytes of BLOB consumed.
347 static int SQLITE_TCLAPI
read_fts3varint(
351 Tcl_Obj
*CONST objv
[]
354 unsigned char *zBlob
;
359 Tcl_WrongNumArgs(interp
, 1, objv
, "BLOB VARNAME");
362 zBlob
= Tcl_GetByteArrayFromObj(objv
[1], &nBlob
);
364 nVal
= getFts3Varint((char*)zBlob
, (sqlite3_int64
*)(&iVal
));
365 Tcl_ObjSetVar2(interp
, objv
[2], 0, Tcl_NewWideIntObj(iVal
), 0);
366 Tcl_SetObjResult(interp
, Tcl_NewIntObj(nVal
));
372 ** Register commands with the TCL interpreter.
374 int Sqlitetest_hexio_Init(Tcl_Interp
*interp
){
377 Tcl_ObjCmdProc
*xProc
;
379 { "hexio_read", hexio_read
},
380 { "hexio_write", hexio_write
},
381 { "hexio_get_int", hexio_get_int
},
382 { "hexio_render_int16", hexio_render_int16
},
383 { "hexio_render_int32", hexio_render_int32
},
384 { "utf8_to_utf8", utf8_to_utf8
},
385 { "read_fts3varint", read_fts3varint
},
388 for(i
=0; i
<sizeof(aObjCmd
)/sizeof(aObjCmd
[0]); i
++){
389 Tcl_CreateObjCommand(interp
, aObjCmd
[i
].zName
, aObjCmd
[i
].xProc
, 0, 0);