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"
28 ** Convert binary to hex. The input zBuf[] contains N bytes of
29 ** binary data. zBuf[] is 2*n+1 bytes long. Overwrite zBuf[]
30 ** with a hexadecimal representation of its original binary input.
32 void sqlite3TestBinToHex(unsigned char *zBuf
, int N
){
33 const unsigned char zHex
[] = "0123456789ABCDEF";
38 for(j
=N
-1; j
>=0; j
--){
40 zBuf
[i
--] = zHex
[c
&0xf];
41 zBuf
[i
--] = zHex
[c
>>4];
47 ** Convert hex to binary. The input zIn[] contains N bytes of
48 ** hexadecimal. Convert this into binary and write aOut[] with
49 ** the binary data. Spaces in the original input are ignored.
50 ** Return the number of bytes of binary rendered.
52 int sqlite3TestHexToBin(const unsigned char *zIn
, int N
, unsigned char *aOut
){
53 const unsigned char aMap
[] = {
54 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
55 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
56 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
57 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 0, 0, 0, 0, 0, 0,
58 0,11,12,13,14,15,16, 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,11,12,13,14,15,16, 0, 0, 0, 0, 0, 0, 0, 0, 0,
61 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
62 0, 0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 0, 0, 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,
91 ** Usage: hexio_read FILENAME OFFSET AMT
93 ** Read AMT bytes from file FILENAME beginning at OFFSET from the
94 ** beginning of the file. Convert that information to hexadecimal
95 ** and return the resulting HEX string.
97 static int hexio_read(
101 Tcl_Obj
*CONST objv
[]
110 Tcl_WrongNumArgs(interp
, 1, objv
, "FILENAME OFFSET AMT");
113 if( Tcl_GetIntFromObj(interp
, objv
[2], &offset
) ) return TCL_ERROR
;
114 if( Tcl_GetIntFromObj(interp
, objv
[3], &amt
) ) return TCL_ERROR
;
115 zFile
= Tcl_GetString(objv
[1]);
116 zBuf
= sqlite3_malloc( amt
*2+1 );
120 in
= fopen(zFile
, "rb");
122 in
= fopen(zFile
, "r");
125 Tcl_AppendResult(interp
, "cannot open input file ", zFile
, 0);
128 fseek(in
, offset
, SEEK_SET
);
129 got
= (int)fread(zBuf
, 1, amt
, in
);
134 sqlite3TestBinToHex(zBuf
, got
);
135 Tcl_AppendResult(interp
, zBuf
, 0);
142 ** Usage: hexio_write FILENAME OFFSET DATA
144 ** Write DATA into file FILENAME beginning at OFFSET from the
145 ** beginning of the file. DATA is expressed in hexadecimal.
147 static int hexio_write(
151 Tcl_Obj
*CONST objv
[]
154 int nIn
, nOut
, written
;
156 const unsigned char *zIn
;
161 Tcl_WrongNumArgs(interp
, 1, objv
, "FILENAME OFFSET HEXDATA");
164 if( Tcl_GetIntFromObj(interp
, objv
[2], &offset
) ) return TCL_ERROR
;
165 zFile
= Tcl_GetString(objv
[1]);
166 zIn
= (const unsigned char *)Tcl_GetStringFromObj(objv
[3], &nIn
);
167 aOut
= sqlite3_malloc( nIn
/2 );
171 nOut
= sqlite3TestHexToBin(zIn
, nIn
, aOut
);
172 out
= fopen(zFile
, "r+b");
174 out
= fopen(zFile
, "r+");
177 Tcl_AppendResult(interp
, "cannot open output file ", zFile
, 0);
180 fseek(out
, offset
, SEEK_SET
);
181 written
= (int)fwrite(aOut
, 1, nOut
, out
);
184 Tcl_SetObjResult(interp
, Tcl_NewIntObj(written
));
189 ** USAGE: hexio_get_int HEXDATA
191 ** Interpret the HEXDATA argument as a big-endian integer. Return
192 ** the value of that integer. HEXDATA can contain between 2 and 8
193 ** hexadecimal digits.
195 static int hexio_get_int(
199 Tcl_Obj
*CONST objv
[]
203 const unsigned char *zIn
;
205 unsigned char aNum
[4];
208 Tcl_WrongNumArgs(interp
, 1, objv
, "HEXDATA");
211 zIn
= (const unsigned char *)Tcl_GetStringFromObj(objv
[1], &nIn
);
212 aOut
= sqlite3_malloc( nIn
/2 );
216 nOut
= sqlite3TestHexToBin(zIn
, nIn
, aOut
);
218 memcpy(aNum
, aOut
, 4);
220 memset(aNum
, 0, sizeof(aNum
));
221 memcpy(&aNum
[4-nOut
], aOut
, nOut
);
224 val
= (aNum
[0]<<24) | (aNum
[1]<<16) | (aNum
[2]<<8) | aNum
[3];
225 Tcl_SetObjResult(interp
, Tcl_NewIntObj(val
));
231 ** USAGE: hexio_render_int16 INTEGER
233 ** Render INTEGER has a 16-bit big-endian integer in hexadecimal.
235 static int hexio_render_int16(
239 Tcl_Obj
*CONST objv
[]
242 unsigned char aNum
[10];
245 Tcl_WrongNumArgs(interp
, 1, objv
, "INTEGER");
248 if( Tcl_GetIntFromObj(interp
, objv
[1], &val
) ) return TCL_ERROR
;
251 sqlite3TestBinToHex(aNum
, 2);
252 Tcl_SetObjResult(interp
, Tcl_NewStringObj((char*)aNum
, 4));
258 ** USAGE: hexio_render_int32 INTEGER
260 ** Render INTEGER has a 32-bit big-endian integer in hexadecimal.
262 static int hexio_render_int32(
266 Tcl_Obj
*CONST objv
[]
269 unsigned char aNum
[10];
272 Tcl_WrongNumArgs(interp
, 1, objv
, "INTEGER");
275 if( Tcl_GetIntFromObj(interp
, objv
[1], &val
) ) return TCL_ERROR
;
280 sqlite3TestBinToHex(aNum
, 4);
281 Tcl_SetObjResult(interp
, Tcl_NewStringObj((char*)aNum
, 8));
286 ** USAGE: utf8_to_utf8 HEX
288 ** The argument is a UTF8 string represented in hexadecimal.
289 ** The UTF8 might not be well-formed. Run this string through
290 ** sqlite3Utf8to8() convert it back to hex and return the result.
292 static int utf8_to_utf8(
296 Tcl_Obj
*CONST objv
[]
301 const unsigned char *zOrig
;
304 Tcl_WrongNumArgs(interp
, 1, objv
, "HEX");
307 zOrig
= (unsigned char *)Tcl_GetStringFromObj(objv
[1], &n
);
308 z
= sqlite3_malloc( n
+3 );
309 n
= sqlite3TestHexToBin(zOrig
, n
, z
);
311 nOut
= sqlite3Utf8To8(z
);
312 sqlite3TestBinToHex(z
,nOut
);
313 Tcl_AppendResult(interp
, (char*)z
, 0);
317 Tcl_AppendResult(interp
,
318 "[utf8_to_utf8] unavailable - SQLITE_DEBUG not defined", 0
324 static int getFts3Varint(const char *p
, sqlite_int64
*v
){
325 const unsigned char *q
= (const unsigned char *) p
;
326 sqlite_uint64 x
= 0, y
= 1;
327 while( (*q
& 0x80) == 0x80 ){
328 x
+= y
* (*q
++ & 0x7f);
332 *v
= (sqlite_int64
) x
;
333 return (int) (q
- (unsigned char *)p
);
338 ** USAGE: read_fts3varint BLOB VARNAME
340 ** Read a varint from the start of BLOB. Set variable VARNAME to contain
341 ** the interpreted value. Return the number of bytes of BLOB consumed.
343 static int read_fts3varint(
347 Tcl_Obj
*CONST objv
[]
350 unsigned char *zBlob
;
355 Tcl_WrongNumArgs(interp
, 1, objv
, "BLOB VARNAME");
358 zBlob
= Tcl_GetByteArrayFromObj(objv
[1], &nBlob
);
360 nVal
= getFts3Varint((char*)zBlob
, (sqlite3_int64
*)(&iVal
));
361 Tcl_ObjSetVar2(interp
, objv
[2], 0, Tcl_NewWideIntObj(iVal
), 0);
362 Tcl_SetObjResult(interp
, Tcl_NewIntObj(nVal
));
368 ** Register commands with the TCL interpreter.
370 int Sqlitetest_hexio_Init(Tcl_Interp
*interp
){
373 Tcl_ObjCmdProc
*xProc
;
375 { "hexio_read", hexio_read
},
376 { "hexio_write", hexio_write
},
377 { "hexio_get_int", hexio_get_int
},
378 { "hexio_render_int16", hexio_render_int16
},
379 { "hexio_render_int32", hexio_render_int32
},
380 { "utf8_to_utf8", utf8_to_utf8
},
381 { "read_fts3varint", read_fts3varint
},
384 for(i
=0; i
<sizeof(aObjCmd
)/sizeof(aObjCmd
[0]); i
++){
385 Tcl_CreateObjCommand(interp
, aObjCmd
[i
].zName
, aObjCmd
[i
].xProc
, 0, 0);