using System.Diagnostics; using System.IO; using System.Text; namespace Community.CsharpSqlite { #if TCLSH using tcl.lang; using Tcl_Interp = tcl.lang.Interp; using Tcl_Obj = tcl.lang.TclObject; public partial class Sqlite3 { /* ** 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. ************************************************************************* ** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart ** C#-SQLite is an independent reimplementation of the SQLite software library ** ** SQLITE_SOURCE_ID: 2011-05-19 13:26:54 ed1da510a239ea767a01dc332b667119fa3c908e ** ************************************************************************* */ //#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. */ static void sqlite3TestBinToHex( byte[] zBuf, int N ) { StringBuilder zHex = new StringBuilder( "0123456789ABCDEF" ); int i, j; byte c; i = N * 2; zBuf[i--] = 0; for ( j = N - 1; j >= 0; j-- ) { c = zBuf[j]; zBuf[i--] = (byte)zHex[c & 0xf]; zBuf[i--] = (byte)zHex[c >> 4]; } Debug.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. */ static int sqlite3TestHexToBin( string zIn, int N, byte[] aOut ) { int[] aMap = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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; int c; for ( i = j = 0; i < N; i++ ) { c = aMap[zIn[i]]; if ( c == 0 ) continue; if ( hi != 0 ) { aOut[j] = (byte)( ( c - 1 ) << 4 ); hi = 0; } else { aOut[j++] |= (byte)( 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( object clientdata, Tcl_Interp interp, int objc, Tcl_Obj[] objv ) { int offset = 0; int amt = 0, got; string zFile; byte[] zBuf; FileStream _in; if ( objc != 4 ) { TCL.Tcl_WrongNumArgs( interp, 1, objv, "FILENAME OFFSET AMT" ); return TCL.TCL_ERROR; } if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[2], out offset ) ) return TCL.TCL_ERROR; if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[3], out amt ) ) return TCL.TCL_ERROR; zFile = TCL.Tcl_GetString( objv[1] ); zBuf = new byte[amt * 2 + 1];// sqlite3Malloc( amt * 2 + 1 ); if ( zBuf == null ) { return TCL.TCL_ERROR; } _in = new FileStream( zFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite ); //if( _in==null){ // _in = fopen(zFile, "r"); //} if ( _in == null ) { TCL.Tcl_AppendResult( interp, "cannot open input file ", zFile ); return TCL.TCL_ERROR; } _in.Seek( offset, SeekOrigin.Begin ); //fseek(_in, offset, SEEK_SET); got = _in.Read( zBuf, 0, amt ); // got = fread( zBuf, 1, amt, _in ); _in.Flush(); _in.Close();// fclose( _in ); if ( got < 0 ) { got = 0; } sqlite3TestBinToHex( zBuf, got ); TCL.Tcl_AppendResult( interp, System.Text.Encoding.UTF8.GetString( zBuf, 0, zBuf.Length ).Substring( 0, got * 2 ) ); zBuf = null;// sqlite3DbFree( db, ref zBuf ); return TCL.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( object clientdata, Tcl_Interp interp, int objc, Tcl_Obj[] objv ) { int offset = 0; int nIn = 0, nOut, written; string zFile; string zIn; byte[] aOut; FileStream _out; if ( objc != 4 ) { TCL.Tcl_WrongNumArgs( interp, 1, objv, "FILENAME OFFSET HEXDATA" ); return TCL.TCL_ERROR; } if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[2], out offset ) ) return TCL.TCL_ERROR; zFile = TCL.Tcl_GetString( objv[1] ); zIn = TCL.Tcl_GetStringFromObj( objv[3], out nIn ); aOut = new byte[nIn / 2 + 1];//sqlite3Malloc( nIn/2 ); if ( aOut == null ) { return TCL.TCL_ERROR; } nOut = sqlite3TestHexToBin( zIn, nIn, aOut ); _out = new FileStream( zFile, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite );// fopen( zFile, "r+b" ); //if( _out==0 ){ // _out = fopen(zFile, "r+"); //} if ( _out == null ) { TCL.Tcl_AppendResult( interp, "cannot open output file ", zFile ); return TCL.TCL_ERROR; } _out.Seek( offset, SeekOrigin.Begin );// fseek( _out, offset, SEEK_SET ); written = (int)_out.Position; _out.Write( aOut, 0, nOut );// written = fwrite( aOut, 1, nOut, _out ); written = (int)_out.Position - written; aOut = null;// sqlite3DbFree( db, ref aOut ); _out.Flush(); _out.Close();// fclose( _out ); TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewIntObj( written ) ); return TCL.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( object clientdata, Tcl_Interp interp, int objc, Tcl_Obj[] objv ) { int val; int nIn = 0, nOut; string zIn; byte[] aOut; byte[] aNum = new byte[4]; if ( objc != 2 ) { TCL.Tcl_WrongNumArgs( interp, 1, objv, "HEXDATA" ); return TCL.TCL_ERROR; } zIn = TCL.Tcl_GetStringFromObj( objv[1], out nIn ); aOut = new byte[nIn / 2];// sqlite3Malloc( nIn / 2 ); if ( aOut == null ) { return TCL.TCL_ERROR; } nOut = sqlite3TestHexToBin( zIn, nIn, aOut ); if ( nOut >= 4 ) { aNum[0] = aOut[0]; // memcpy( aNum, aOut, 4 ); aNum[1] = aOut[1]; aNum[2] = aOut[2]; aNum[3] = aOut[3]; } else { //memset(aNum, 0, sizeof(aNum)); //memcpy(&aNum[4-nOut], aOut, nOut); aNum[4 - nOut] = aOut[0]; if ( nOut > 1 ) aNum[4 - nOut + 1] = aOut[1]; if ( nOut > 2 ) aNum[4 - nOut + 2] = aOut[2]; if ( nOut > 3 ) aNum[4 - nOut + 3] = aOut[3]; } aOut = null;// sqlite3DbFree( db, ref aOut ); val = ( aNum[0] << 24 ) | ( aNum[1] << 16 ) | ( aNum[2] << 8 ) | aNum[3]; TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewIntObj( val ) ); return TCL.TCL_OK; } /* ** USAGE: hexio_render_int16 INTEGER ** ** Render INTEGER has a 16-bit big-endian integer _in hexadecimal. */ static int hexio_render_int16( object clientdata, Tcl_Interp interp, int objc, Tcl_Obj[] objv ) { int val = 0; byte[] aNum = new byte[10]; if ( objc != 2 ) { TCL.Tcl_WrongNumArgs( interp, 1, objv, "INTEGER" ); return TCL.TCL_ERROR; } if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[1], out val ) ) return TCL.TCL_ERROR; aNum[0] = (byte)( val >> 8 ); aNum[1] = (byte)val; sqlite3TestBinToHex( aNum, 2 ); TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewStringObj( aNum, 4 ) ); return TCL.TCL_OK; } /* ** USAGE: hexio_render_int32 INTEGER ** ** Render INTEGER has a 32-bit big-endian integer _in hexadecimal. */ static int hexio_render_int32( object clientdata, Tcl_Interp interp, int objc, Tcl_Obj[] objv ) { int val = 0; byte[] aNum = new byte[10]; if ( objc != 2 ) { TCL.Tcl_WrongNumArgs( interp, 1, objv, "INTEGER" ); return TCL.TCL_ERROR; } if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[1], out val ) ) return TCL.TCL_ERROR; aNum[0] = (byte)( val >> 24 ); aNum[1] = (byte)( val >> 16 ); aNum[2] = (byte)( val >> 8 ); aNum[3] = (byte)val; sqlite3TestBinToHex( aNum, 4 ); TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewStringObj( aNum, 8 ) ); return TCL.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( object clientdata, Tcl_Interp interp, int objc, Tcl_Obj[] objv ){ #if SQLITE_DEBUG int n = 0; int nOut; string zOrig; byte[] z; if( objc!=2 ){ TCL.Tcl_WrongNumArgs(interp, 1, objv, "HEX"); return TCL.TCL_ERROR; } zOrig = TCL.Tcl_GetStringFromObj(objv[1], out n); z = new byte[2 * n + 1];//sqlite3Malloc( n + 3 ); nOut = sqlite3TestHexToBin( zOrig, n, z ); //z[n] = 0; nOut = sqlite3Utf8To8(z); sqlite3TestBinToHex( z, zOrig.Length ); TCL.Tcl_AppendResult(interp, Encoding.ASCII.GetString(z,0,n)); //sqlite3_free( z ); return TCL.TCL_OK; #else Tcl_AppendResult(interp, "[utf8_to_utf8] unavailable - SQLITE_DEBUG not defined", 0 ); return TCL.TCL_ERROR; #endif } //static int getFts3Varint(string 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[] objv //){ // int nBlob; // unsigned string zBlob; // sqlite3_int64 iVal; // int nVal; // if( objc!=3 ){ // Tcl_WrongNumArgs(interp, 1, objv, "BLOB VARNAME"); // return TCL.TCL_ERROR; // } // zBlob = TCL.Tcl_GetByteArrayFromObj(objv[1], &nBlob); // nVal = getFts3Varint((char)zBlob, (sqlite3_int64 )(&iVal)); // Tcl_ObjSetVar2(interp, objv[2], 0, TCL.TCL_NewWideIntObj(iVal), 0); // Tcl_SetObjResult(interp, TCL.TCL_NewIntObj(nVal)); // return TCL.TCL_OK; //} /* ** Register commands with the TCL interpreter. */ static public int Sqlitetest_hexio_Init( Tcl_Interp interp ) { //static struct { // string zName; // Tcl_ObjCmdProc *xProc; //} _aObjCmd[] aObjCmd = new _aObjCmd[] { new _aObjCmd( "hexio_read", hexio_read ), new _aObjCmd( "hexio_write", hexio_write ), new _aObjCmd( "hexio_get_int", hexio_get_int ), new _aObjCmd( "hexio_render_int16", hexio_render_int16 ), new _aObjCmd( "hexio_render_int32", hexio_render_int32 ), new _aObjCmd( "utf8_to_utf8", utf8_to_utf8 ), // { "read_fts3varint", read_fts3varint }, }; int i; for ( i = 0; i < aObjCmd.Length; i++ ) { TCL.Tcl_CreateObjCommand( interp, aObjCmd[i].zName, aObjCmd[i].xProc, null, null ); } return TCL.TCL_OK; } } #endif }