Thanks to visit codestin.com
Credit goes to chromium.googlesource.com

blob: 048ab13246ac46f988678c9436f6cfd3c01761f2 [file] [log] [blame]
drh15926592007-04-06 15:02:131/*
2** 2007 April 6
3**
4** The author disclaims copyright to this source code. In place of
5** a legal notice, here is a blessing:
6**
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.
10**
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.
drh15926592007-04-06 15:02:1319*/
drh53c14022007-05-10 17:23:1120#include "sqliteInt.h"
drh064b6812024-07-30 15:49:0221#include "tclsqlite.h"
drh15926592007-04-06 15:02:1322#include <stdlib.h>
23#include <string.h>
24#include <assert.h>
25
drh15926592007-04-06 15:02:1326
27/*
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.
31*/
drh9c7a60d2007-10-19 17:47:2432void sqlite3TestBinToHex(unsigned char *zBuf, int N){
drh15926592007-04-06 15:02:1333 const unsigned char zHex[] = "0123456789ABCDEF";
34 int i, j;
35 unsigned char c;
36 i = N*2;
37 zBuf[i--] = 0;
38 for(j=N-1; j>=0; j--){
39 c = zBuf[j];
40 zBuf[i--] = zHex[c&0xf];
41 zBuf[i--] = zHex[c>>4];
42 }
43 assert( i==-1 );
44}
45
46/*
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.
51*/
drh9c7a60d2007-10-19 17:47:2452int sqlite3TestHexToBin(const unsigned char *zIn, int N, unsigned char *aOut){
drh15926592007-04-06 15:02:1353 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,
70 };
71 int i, j;
72 int hi=1;
73 unsigned char c;
74
75 for(i=j=0; i<N; i++){
76 c = aMap[zIn[i]];
77 if( c==0 ) continue;
78 if( hi ){
79 aOut[j] = (c-1)<<4;
80 hi = 0;
81 }else{
82 aOut[j++] |= c-1;
83 hi = 1;
84 }
85 }
86 return j;
87}
88
89
90/*
91** Usage: hexio_read FILENAME OFFSET AMT
92**
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.
96*/
mistachkin7617e4a2016-07-28 17:11:2097static int SQLITE_TCLAPI hexio_read(
drh15926592007-04-06 15:02:1398 void * clientData,
99 Tcl_Interp *interp,
100 int objc,
101 Tcl_Obj *CONST objv[]
102){
103 int offset;
104 int amt, got;
105 const char *zFile;
106 unsigned char *zBuf;
107 FILE *in;
108
109 if( objc!=4 ){
110 Tcl_WrongNumArgs(interp, 1, objv, "FILENAME OFFSET AMT");
111 return TCL_ERROR;
112 }
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]);
drh17435752007-08-16 04:30:38116 zBuf = sqlite3_malloc( amt*2+1 );
drh15926592007-04-06 15:02:13117 if( zBuf==0 ){
118 return TCL_ERROR;
119 }
drh498b8762008-05-12 16:17:42120 in = fopen(zFile, "rb");
121 if( in==0 ){
122 in = fopen(zFile, "r");
123 }
drh15926592007-04-06 15:02:13124 if( in==0 ){
stephanb6503f12025-03-06 13:38:07125 Tcl_AppendResult(interp, "cannot open input file ", zFile, NULL);
drh15926592007-04-06 15:02:13126 return TCL_ERROR;
127 }
128 fseek(in, offset, SEEK_SET);
drh83cc1392012-04-19 18:04:28129 got = (int)fread(zBuf, 1, amt, in);
drh15926592007-04-06 15:02:13130 fclose(in);
131 if( got<0 ){
132 got = 0;
133 }
drh9c7a60d2007-10-19 17:47:24134 sqlite3TestBinToHex(zBuf, got);
stephanb6503f12025-03-06 13:38:07135 Tcl_AppendResult(interp, zBuf, NULL);
drh17435752007-08-16 04:30:38136 sqlite3_free(zBuf);
drh15926592007-04-06 15:02:13137 return TCL_OK;
138}
139
140
141/*
142** Usage: hexio_write FILENAME OFFSET DATA
143**
144** Write DATA into file FILENAME beginning at OFFSET from the
145** beginning of the file. DATA is expressed in hexadecimal.
146*/
mistachkin7617e4a2016-07-28 17:11:20147static int SQLITE_TCLAPI hexio_write(
drh15926592007-04-06 15:02:13148 void * clientData,
149 Tcl_Interp *interp,
150 int objc,
151 Tcl_Obj *CONST objv[]
152){
153 int offset;
drh064b6812024-07-30 15:49:02154 Tcl_Size nIn;
155 int nOut, written;
drh15926592007-04-06 15:02:13156 const char *zFile;
157 const unsigned char *zIn;
158 unsigned char *aOut;
159 FILE *out;
160
161 if( objc!=4 ){
162 Tcl_WrongNumArgs(interp, 1, objv, "FILENAME OFFSET HEXDATA");
163 return TCL_ERROR;
164 }
165 if( Tcl_GetIntFromObj(interp, objv[2], &offset) ) return TCL_ERROR;
166 zFile = Tcl_GetString(objv[1]);
167 zIn = (const unsigned char *)Tcl_GetStringFromObj(objv[3], &nIn);
drh064b6812024-07-30 15:49:02168 aOut = sqlite3_malloc64( 1 + nIn/2 );
drh15926592007-04-06 15:02:13169 if( aOut==0 ){
170 return TCL_ERROR;
171 }
drh064b6812024-07-30 15:49:02172 nOut = sqlite3TestHexToBin(zIn, (int)nIn, aOut);
drh498b8762008-05-12 16:17:42173 out = fopen(zFile, "r+b");
174 if( out==0 ){
175 out = fopen(zFile, "r+");
176 }
drh15926592007-04-06 15:02:13177 if( out==0 ){
stephanb6503f12025-03-06 13:38:07178 Tcl_AppendResult(interp, "cannot open output file ", zFile, NULL);
drh15926592007-04-06 15:02:13179 return TCL_ERROR;
180 }
181 fseek(out, offset, SEEK_SET);
drh83cc1392012-04-19 18:04:28182 written = (int)fwrite(aOut, 1, nOut, out);
drh17435752007-08-16 04:30:38183 sqlite3_free(aOut);
drh15926592007-04-06 15:02:13184 fclose(out);
185 Tcl_SetObjResult(interp, Tcl_NewIntObj(written));
186 return TCL_OK;
187}
188
189/*
drh12599d52024-11-18 17:05:45190** USAGE: hexio_get_int [-littleendian] HEXDATA
drh15926592007-04-06 15:02:13191**
192** Interpret the HEXDATA argument as a big-endian integer. Return
193** the value of that integer. HEXDATA can contain between 2 and 8
194** hexadecimal digits.
195*/
mistachkin7617e4a2016-07-28 17:11:20196static int SQLITE_TCLAPI hexio_get_int(
drh15926592007-04-06 15:02:13197 void * clientData,
198 Tcl_Interp *interp,
199 int objc,
200 Tcl_Obj *CONST objv[]
201){
202 int val;
drh064b6812024-07-30 15:49:02203 Tcl_Size nIn;
204 int nOut;
drh15926592007-04-06 15:02:13205 const unsigned char *zIn;
206 unsigned char *aOut;
207 unsigned char aNum[4];
drh12599d52024-11-18 17:05:45208 int bLittle = 0;
drh15926592007-04-06 15:02:13209
drh12599d52024-11-18 17:05:45210 if( objc==3 ){
211 Tcl_Size n;
212 char *z = Tcl_GetStringFromObj(objv[1], &n);
213 if( n>=2 && n<=13 && memcmp(z, "-littleendian", n)==0 ){
214 bLittle = 1;
215 }
216 }
217 if( (objc-bLittle)!=2 ){
218 Tcl_WrongNumArgs(interp, 1, objv, "[-littleendian] HEXDATA");
drh15926592007-04-06 15:02:13219 return TCL_ERROR;
220 }
drh12599d52024-11-18 17:05:45221 zIn = (const unsigned char *)Tcl_GetStringFromObj(objv[1+bLittle], &nIn);
drh064b6812024-07-30 15:49:02222 aOut = sqlite3_malloc64( 1 + nIn/2 );
drh15926592007-04-06 15:02:13223 if( aOut==0 ){
224 return TCL_ERROR;
225 }
drh064b6812024-07-30 15:49:02226 nOut = sqlite3TestHexToBin(zIn, (int)nIn, aOut);
drh15926592007-04-06 15:02:13227 if( nOut>=4 ){
228 memcpy(aNum, aOut, 4);
229 }else{
230 memset(aNum, 0, sizeof(aNum));
drh431e8532007-04-09 20:30:11231 memcpy(&aNum[4-nOut], aOut, nOut);
drh15926592007-04-06 15:02:13232 }
drh17435752007-08-16 04:30:38233 sqlite3_free(aOut);
drh12599d52024-11-18 17:05:45234 if( bLittle ){
235 val = (int)((u32)aNum[3]<<24) | (aNum[2]<<16) | (aNum[1]<<8) | aNum[0];
236 }else{
237 val = (int)((u32)aNum[0]<<24) | (aNum[1]<<16) | (aNum[2]<<8) | aNum[3];
238 }
drh15926592007-04-06 15:02:13239 Tcl_SetObjResult(interp, Tcl_NewIntObj(val));
240 return TCL_OK;
241}
242
243
244/*
245** USAGE: hexio_render_int16 INTEGER
246**
247** Render INTEGER has a 16-bit big-endian integer in hexadecimal.
248*/
mistachkin7617e4a2016-07-28 17:11:20249static int SQLITE_TCLAPI hexio_render_int16(
drh15926592007-04-06 15:02:13250 void * clientData,
251 Tcl_Interp *interp,
252 int objc,
253 Tcl_Obj *CONST objv[]
254){
255 int val;
256 unsigned char aNum[10];
257
258 if( objc!=2 ){
259 Tcl_WrongNumArgs(interp, 1, objv, "INTEGER");
260 return TCL_ERROR;
261 }
262 if( Tcl_GetIntFromObj(interp, objv[1], &val) ) return TCL_ERROR;
263 aNum[0] = val>>8;
264 aNum[1] = val;
drh9c7a60d2007-10-19 17:47:24265 sqlite3TestBinToHex(aNum, 2);
drh15926592007-04-06 15:02:13266 Tcl_SetObjResult(interp, Tcl_NewStringObj((char*)aNum, 4));
267 return TCL_OK;
268}
269
270
271/*
272** USAGE: hexio_render_int32 INTEGER
273**
274** Render INTEGER has a 32-bit big-endian integer in hexadecimal.
275*/
mistachkin7617e4a2016-07-28 17:11:20276static int SQLITE_TCLAPI hexio_render_int32(
drh15926592007-04-06 15:02:13277 void * clientData,
278 Tcl_Interp *interp,
279 int objc,
280 Tcl_Obj *CONST objv[]
281){
282 int val;
283 unsigned char aNum[10];
284
285 if( objc!=2 ){
286 Tcl_WrongNumArgs(interp, 1, objv, "INTEGER");
287 return TCL_ERROR;
288 }
289 if( Tcl_GetIntFromObj(interp, objv[1], &val) ) return TCL_ERROR;
290 aNum[0] = val>>24;
291 aNum[1] = val>>16;
292 aNum[2] = val>>8;
293 aNum[3] = val;
drh9c7a60d2007-10-19 17:47:24294 sqlite3TestBinToHex(aNum, 4);
drh15926592007-04-06 15:02:13295 Tcl_SetObjResult(interp, Tcl_NewStringObj((char*)aNum, 8));
296 return TCL_OK;
297}
298
drh53c14022007-05-10 17:23:11299/*
300** USAGE: utf8_to_utf8 HEX
301**
302** The argument is a UTF8 string represented in hexadecimal.
303** The UTF8 might not be well-formed. Run this string through
304** sqlite3Utf8to8() convert it back to hex and return the result.
305*/
mistachkin7617e4a2016-07-28 17:11:20306static int SQLITE_TCLAPI utf8_to_utf8(
drh53c14022007-05-10 17:23:11307 void * clientData,
308 Tcl_Interp *interp,
309 int objc,
310 Tcl_Obj *CONST objv[]
311){
danielk197728c66302007-09-01 11:04:26312#ifdef SQLITE_DEBUG
drh064b6812024-07-30 15:49:02313 Tcl_Size n;
drh53c14022007-05-10 17:23:11314 int nOut;
315 const unsigned char *zOrig;
316 unsigned char *z;
317 if( objc!=2 ){
318 Tcl_WrongNumArgs(interp, 1, objv, "HEX");
319 return TCL_ERROR;
320 }
321 zOrig = (unsigned char *)Tcl_GetStringFromObj(objv[1], &n);
drh064b6812024-07-30 15:49:02322 z = sqlite3_malloc64( n+4 );
323 n = sqlite3TestHexToBin(zOrig, (int)n, z);
drh53c14022007-05-10 17:23:11324 z[n] = 0;
325 nOut = sqlite3Utf8To8(z);
drh9c7a60d2007-10-19 17:47:24326 sqlite3TestBinToHex(z,nOut);
stephanb6503f12025-03-06 13:38:07327 Tcl_AppendResult(interp, (char*)z, NULL);
drh53c14022007-05-10 17:23:11328 sqlite3_free(z);
329 return TCL_OK;
dan211fb082011-04-01 09:04:36330#else
331 Tcl_AppendResult(interp,
stephan065c0a62025-03-08 06:53:06332 "[utf8_to_utf8] unavailable - SQLITE_DEBUG not defined", NULL
dan211fb082011-04-01 09:04:36333 );
334 return TCL_ERROR;
335#endif
drh53c14022007-05-10 17:23:11336}
drh15926592007-04-06 15:02:13337
dan4b4d4462009-11-14 23:50:11338static int getFts3Varint(const char *p, sqlite_int64 *v){
339 const unsigned char *q = (const unsigned char *) p;
340 sqlite_uint64 x = 0, y = 1;
341 while( (*q & 0x80) == 0x80 ){
342 x += y * (*q++ & 0x7f);
343 y <<= 7;
344 }
345 x += y * (*q++);
346 *v = (sqlite_int64) x;
347 return (int) (q - (unsigned char *)p);
348}
349
dan572b0dd2019-09-18 17:22:00350static int putFts3Varint(char *p, sqlite_int64 v){
351 unsigned char *q = (unsigned char *) p;
352 sqlite_uint64 vu = v;
353 do{
354 *q++ = (unsigned char) ((vu & 0x7f) | 0x80);
355 vu >>= 7;
356 }while( vu!=0 );
357 q[-1] &= 0x7f; /* turn off high bit in final byte */
358 assert( q - (unsigned char *)p <= 10 );
359 return (int) (q - (unsigned char *)p);
360}
dan4b4d4462009-11-14 23:50:11361
dan09977bb2009-11-13 10:36:20362/*
danf5fff2a2009-12-12 09:51:25363** USAGE: read_fts3varint BLOB VARNAME
dan09977bb2009-11-13 10:36:20364**
365** Read a varint from the start of BLOB. Set variable VARNAME to contain
366** the interpreted value. Return the number of bytes of BLOB consumed.
367*/
mistachkin7617e4a2016-07-28 17:11:20368static int SQLITE_TCLAPI read_fts3varint(
dan09977bb2009-11-13 10:36:20369 void * clientData,
370 Tcl_Interp *interp,
371 int objc,
372 Tcl_Obj *CONST objv[]
373){
drh064b6812024-07-30 15:49:02374 Tcl_Size nBlob;
dan09977bb2009-11-13 10:36:20375 unsigned char *zBlob;
376 sqlite3_int64 iVal;
377 int nVal;
378
379 if( objc!=3 ){
380 Tcl_WrongNumArgs(interp, 1, objv, "BLOB VARNAME");
381 return TCL_ERROR;
382 }
383 zBlob = Tcl_GetByteArrayFromObj(objv[1], &nBlob);
384
drh614d2652009-12-02 18:03:57385 nVal = getFts3Varint((char*)zBlob, (sqlite3_int64 *)(&iVal));
dan09977bb2009-11-13 10:36:20386 Tcl_ObjSetVar2(interp, objv[2], 0, Tcl_NewWideIntObj(iVal), 0);
387 Tcl_SetObjResult(interp, Tcl_NewIntObj(nVal));
388 return TCL_OK;
389}
390
dan572b0dd2019-09-18 17:22:00391/*
392** USAGE: make_fts3record ARGLIST
393*/
394static int SQLITE_TCLAPI make_fts3record(
395 void * clientData,
396 Tcl_Interp *interp,
397 int objc,
398 Tcl_Obj *CONST objv[]
399){
400 Tcl_Obj **aArg = 0;
drh064b6812024-07-30 15:49:02401 Tcl_Size nArg = 0;
dan572b0dd2019-09-18 17:22:00402 unsigned char *aOut = 0;
drh064b6812024-07-30 15:49:02403 sqlite3_int64 nOut = 0;
404 sqlite3_int64 nAlloc = 0;
dan572b0dd2019-09-18 17:22:00405 int i;
dan572b0dd2019-09-18 17:22:00406
407 if( objc!=2 ){
408 Tcl_WrongNumArgs(interp, 1, objv, "LIST");
409 return TCL_ERROR;
410 }
411 if( Tcl_ListObjGetElements(interp, objv[1], &nArg, &aArg) ){
412 return TCL_ERROR;
413 }
414
drh064b6812024-07-30 15:49:02415 for(i=0; i<(int)nArg; i++){
drh4a9a5cb2024-08-10 15:05:22416 Tcl_WideInt iVal;
dan572b0dd2019-09-18 17:22:00417 if( TCL_OK==Tcl_GetWideIntFromObj(0, aArg[i], &iVal) ){
418 if( nOut+10>nAlloc ){
419 int nNew = nAlloc?nAlloc*2:128;
420 unsigned char *aNew = sqlite3_realloc(aOut, nNew);
421 if( aNew==0 ){
422 sqlite3_free(aOut);
423 return TCL_ERROR;
424 }
425 aOut = aNew;
426 nAlloc = nNew;
427 }
428 nOut += putFts3Varint((char*)&aOut[nOut], iVal);
429 }else{
drh064b6812024-07-30 15:49:02430 Tcl_Size nVal = 0;
dan572b0dd2019-09-18 17:22:00431 char *zVal = Tcl_GetStringFromObj(aArg[i], &nVal);
432 while( (nOut + nVal)>nAlloc ){
drh064b6812024-07-30 15:49:02433 sqlite3_int64 nNew = nAlloc?nAlloc*2:128;
434 unsigned char *aNew = sqlite3_realloc64(aOut, nNew);
dan572b0dd2019-09-18 17:22:00435 if( aNew==0 ){
436 sqlite3_free(aOut);
437 return TCL_ERROR;
438 }
439 aOut = aNew;
440 nAlloc = nNew;
441 }
442 memcpy(&aOut[nOut], zVal, nVal);
443 nOut += nVal;
444 }
445 }
446
447 Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(aOut, nOut));
448 sqlite3_free(aOut);
449 return TCL_OK;
450}
451
drh15926592007-04-06 15:02:13452
453/*
454** Register commands with the TCL interpreter.
455*/
456int Sqlitetest_hexio_Init(Tcl_Interp *interp){
457 static struct {
458 char *zName;
459 Tcl_ObjCmdProc *xProc;
460 } aObjCmd[] = {
461 { "hexio_read", hexio_read },
462 { "hexio_write", hexio_write },
463 { "hexio_get_int", hexio_get_int },
464 { "hexio_render_int16", hexio_render_int16 },
465 { "hexio_render_int32", hexio_render_int32 },
drh53c14022007-05-10 17:23:11466 { "utf8_to_utf8", utf8_to_utf8 },
danf5fff2a2009-12-12 09:51:25467 { "read_fts3varint", read_fts3varint },
dan572b0dd2019-09-18 17:22:00468 { "make_fts3record", make_fts3record },
drh15926592007-04-06 15:02:13469 };
470 int i;
471 for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
472 Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0);
473 }
474 return TCL_OK;
475}