diff options
author | Hans-Christoph Steiner <hans@eds.org> | 2012-03-30 20:42:12 -0400 |
---|---|---|
committer | Hans-Christoph Steiner <hans@eds.org> | 2012-03-30 20:42:12 -0400 |
commit | 7bb481fda9ecb134804b49c2ce77ca28f7eea583 (patch) | |
tree | 31b520b9914d3e2453968abe375f2c102772c3dc /src/test_hexio.c |
Imported Upstream version 2.0.3
Diffstat (limited to 'src/test_hexio.c')
-rw-r--r-- | src/test_hexio.c | 388 |
1 files changed, 388 insertions, 0 deletions
diff --git a/src/test_hexio.c b/src/test_hexio.c new file mode 100644 index 0000000..e3258e8 --- /dev/null +++ b/src/test_hexio.c @@ -0,0 +1,388 @@ +/* +** 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 <stdlib.h> +#include <string.h> +#include <assert.h> + + +/* +** 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<N; i++){ + c = aMap[zIn[i]]; + if( c==0 ) continue; + if( hi ){ + aOut[j] = (c-1)<<4; + hi = 0; + }else{ + aOut[j++] |= c-1; + hi = 1; + } + } + return j; +} + + +/* +** Usage: hexio_read FILENAME OFFSET AMT +** +** Read AMT bytes from file FILENAME beginning at OFFSET from the +** beginning of the file. Convert that information to hexadecimal +** and return the resulting HEX string. +*/ +static int hexio_read( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + int offset; + int amt, got; + const char *zFile; + unsigned char *zBuf; + FILE *in; + + if( objc!=4 ){ + Tcl_WrongNumArgs(interp, 1, objv, "FILENAME OFFSET AMT"); + return TCL_ERROR; + } + if( Tcl_GetIntFromObj(interp, objv[2], &offset) ) return TCL_ERROR; + if( Tcl_GetIntFromObj(interp, objv[3], &amt) ) return TCL_ERROR; + zFile = Tcl_GetString(objv[1]); + zBuf = sqlite3_malloc( amt*2+1 ); + if( zBuf==0 ){ + return TCL_ERROR; + } + in = fopen(zFile, "rb"); + if( in==0 ){ + in = fopen(zFile, "r"); + } + if( in==0 ){ + Tcl_AppendResult(interp, "cannot open input file ", zFile, 0); + return TCL_ERROR; + } + fseek(in, offset, SEEK_SET); + got = fread(zBuf, 1, amt, in); + fclose(in); + if( got<0 ){ + got = 0; + } + sqlite3TestBinToHex(zBuf, got); + Tcl_AppendResult(interp, zBuf, 0); + sqlite3_free(zBuf); + return TCL_OK; +} + + +/* +** Usage: hexio_write FILENAME OFFSET DATA +** +** Write DATA into file FILENAME beginning at OFFSET from the +** beginning of the file. DATA is expressed in hexadecimal. +*/ +static int hexio_write( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + int offset; + int nIn, nOut, written; + const char *zFile; + const unsigned char *zIn; + unsigned char *aOut; + FILE *out; + + if( objc!=4 ){ + Tcl_WrongNumArgs(interp, 1, objv, "FILENAME OFFSET HEXDATA"); + return TCL_ERROR; + } + if( Tcl_GetIntFromObj(interp, objv[2], &offset) ) return TCL_ERROR; + zFile = Tcl_GetString(objv[1]); + zIn = (const unsigned char *)Tcl_GetStringFromObj(objv[3], &nIn); + aOut = sqlite3_malloc( nIn/2 ); + if( aOut==0 ){ + return TCL_ERROR; + } + nOut = sqlite3TestHexToBin(zIn, nIn, aOut); + out = fopen(zFile, "r+b"); + if( out==0 ){ + out = fopen(zFile, "r+"); + } + if( out==0 ){ + Tcl_AppendResult(interp, "cannot open output file ", zFile, 0); + return TCL_ERROR; + } + fseek(out, offset, SEEK_SET); + written = fwrite(aOut, 1, nOut, out); + sqlite3_free(aOut); + fclose(out); + Tcl_SetObjResult(interp, Tcl_NewIntObj(written)); + return TCL_OK; +} + +/* +** USAGE: hexio_get_int HEXDATA +** +** Interpret the HEXDATA argument as a big-endian integer. Return +** the value of that integer. HEXDATA can contain between 2 and 8 +** hexadecimal digits. +*/ +static int hexio_get_int( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + int val; + int nIn, nOut; + const unsigned char *zIn; + unsigned char *aOut; + unsigned char aNum[4]; + + if( objc!=2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "HEXDATA"); + return TCL_ERROR; + } + zIn = (const unsigned char *)Tcl_GetStringFromObj(objv[1], &nIn); + aOut = sqlite3_malloc( nIn/2 ); + if( aOut==0 ){ + return TCL_ERROR; + } + nOut = sqlite3TestHexToBin(zIn, nIn, aOut); + if( nOut>=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); + return TCL_OK; +#else + Tcl_AppendResult(interp, + "[utf8_to_utf8] unavailable - SQLITE_DEBUG not defined", 0 + ); + return TCL_ERROR; +#endif +} + +static int getFts3Varint(const char *p, sqlite_int64 *v){ + const unsigned char *q = (const unsigned char *) p; + sqlite_uint64 x = 0, y = 1; + while( (*q & 0x80) == 0x80 ){ + x += y * (*q++ & 0x7f); + y <<= 7; + } + x += y * (*q++); + *v = (sqlite_int64) x; + return (int) (q - (unsigned char *)p); +} + + +/* +** USAGE: read_fts3varint 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_fts3varint( + 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 = getFts3Varint((char*)zBlob, (sqlite3_int64 *)(&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_fts3varint", read_fts3varint }, + }; + int i; + for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ + Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0); + } + return TCL_OK; +} |