/* ** 2007 April 6 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** Code for testing all sorts of SQLite interfaces. This code ** implements TCL commands for reading and writing the binary ** database files and displaying the content of those files as ** hexadecimal. We could, in theory, use the built-in "binary" ** command of TCL to do a lot of this, but there are some issues ** with historical versions of the "binary" command. So it seems ** easier and safer to build our own mechanism. */ #include "sqliteInt.h" #include "tcl.h" #include #include #include /* ** Convert binary to hex. The input zBuf[] contains N bytes of ** binary data. zBuf[] is 2*n+1 bytes long. Overwrite zBuf[] ** with a hexadecimal representation of its original binary input. */ void sqlite3TestBinToHex(unsigned char *zBuf, int N){ const unsigned char zHex[] = "0123456789ABCDEF"; int i, j; unsigned char c; i = N*2; zBuf[i--] = 0; for(j=N-1; j>=0; j--){ c = zBuf[j]; zBuf[i--] = zHex[c&0xf]; zBuf[i--] = zHex[c>>4]; } assert( i==-1 ); } /* ** Convert hex to binary. The input zIn[] contains N bytes of ** hexadecimal. Convert this into binary and write aOut[] with ** the binary data. Spaces in the original input are ignored. ** Return the number of bytes of binary rendered. */ int sqlite3TestHexToBin(const unsigned char *zIn, int N, unsigned char *aOut){ const unsigned char aMap[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 0, 0, 0, 0, 0, 0, 0,11,12,13,14,15,16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,11,12,13,14,15,16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; int i, j; int hi=1; unsigned char c; for(i=j=0; i=4 ){ memcpy(aNum, aOut, 4); }else{ memset(aNum, 0, sizeof(aNum)); memcpy(&aNum[4-nOut], aOut, nOut); } sqlite3_free(aOut); val = (aNum[0]<<24) | (aNum[1]<<16) | (aNum[2]<<8) | aNum[3]; Tcl_SetObjResult(interp, Tcl_NewIntObj(val)); return TCL_OK; } /* ** USAGE: hexio_render_int16 INTEGER ** ** Render INTEGER has a 16-bit big-endian integer in hexadecimal. */ static int hexio_render_int16( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int val; unsigned char aNum[10]; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "INTEGER"); return TCL_ERROR; } if( Tcl_GetIntFromObj(interp, objv[1], &val) ) return TCL_ERROR; aNum[0] = val>>8; aNum[1] = val; sqlite3TestBinToHex(aNum, 2); Tcl_SetObjResult(interp, Tcl_NewStringObj((char*)aNum, 4)); return TCL_OK; } /* ** USAGE: hexio_render_int32 INTEGER ** ** Render INTEGER has a 32-bit big-endian integer in hexadecimal. */ static int hexio_render_int32( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int val; unsigned char aNum[10]; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "INTEGER"); return TCL_ERROR; } if( Tcl_GetIntFromObj(interp, objv[1], &val) ) return TCL_ERROR; aNum[0] = val>>24; aNum[1] = val>>16; aNum[2] = val>>8; aNum[3] = val; sqlite3TestBinToHex(aNum, 4); Tcl_SetObjResult(interp, Tcl_NewStringObj((char*)aNum, 8)); return TCL_OK; } /* ** USAGE: utf8_to_utf8 HEX ** ** The argument is a UTF8 string represented in hexadecimal. ** The UTF8 might not be well-formed. Run this string through ** sqlite3Utf8to8() convert it back to hex and return the result. */ static int utf8_to_utf8( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ #ifdef SQLITE_DEBUG int n; int nOut; const unsigned char *zOrig; unsigned char *z; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "HEX"); return TCL_ERROR; } zOrig = (unsigned char *)Tcl_GetStringFromObj(objv[1], &n); z = sqlite3_malloc( n+3 ); n = sqlite3TestHexToBin(zOrig, n, z); z[n] = 0; nOut = sqlite3Utf8To8(z); sqlite3TestBinToHex(z,nOut); Tcl_AppendResult(interp, (char*)z, 0); sqlite3_free(z); #endif return TCL_OK; } /* ** USAGE: read_varint BLOB VARNAME ** ** Read a varint from the start of BLOB. Set variable VARNAME to contain ** the interpreted value. Return the number of bytes of BLOB consumed. */ static int read_varint( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int nBlob; unsigned char *zBlob; sqlite3_int64 iVal; int nVal; if( objc!=3 ){ Tcl_WrongNumArgs(interp, 1, objv, "BLOB VARNAME"); return TCL_ERROR; } zBlob = Tcl_GetByteArrayFromObj(objv[1], &nBlob); nVal = sqlite3GetVarint(zBlob, (sqlite3_uint64 *)(&iVal)); Tcl_ObjSetVar2(interp, objv[2], 0, Tcl_NewWideIntObj(iVal), 0); Tcl_SetObjResult(interp, Tcl_NewIntObj(nVal)); return TCL_OK; } /* ** Register commands with the TCL interpreter. */ int Sqlitetest_hexio_Init(Tcl_Interp *interp){ static struct { char *zName; Tcl_ObjCmdProc *xProc; } aObjCmd[] = { { "hexio_read", hexio_read }, { "hexio_write", hexio_write }, { "hexio_get_int", hexio_get_int }, { "hexio_render_int16", hexio_render_int16 }, { "hexio_render_int32", hexio_render_int32 }, { "utf8_to_utf8", utf8_to_utf8 }, { "read_varint", read_varint }, }; int i; for(i=0; i