| OLD | NEW | 
 | (Empty) | 
|    1 /* |  | 
|    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. |  | 
|   19 ** |  | 
|   20 ** $Id: test_hexio.c,v 1.7 2008/05/12 16:17:42 drh Exp $ |  | 
|   21 */ |  | 
|   22 #include "sqliteInt.h" |  | 
|   23 #include "tcl.h" |  | 
|   24 #include <stdlib.h> |  | 
|   25 #include <string.h> |  | 
|   26 #include <assert.h> |  | 
|   27  |  | 
|   28  |  | 
|   29 /* |  | 
|   30 ** Convert binary to hex.  The input zBuf[] contains N bytes of |  | 
|   31 ** binary data.  zBuf[] is 2*n+1 bytes long.  Overwrite zBuf[] |  | 
|   32 ** with a hexadecimal representation of its original binary input. |  | 
|   33 */ |  | 
|   34 void sqlite3TestBinToHex(unsigned char *zBuf, int N){ |  | 
|   35   const unsigned char zHex[] = "0123456789ABCDEF"; |  | 
|   36   int i, j; |  | 
|   37   unsigned char c; |  | 
|   38   i = N*2; |  | 
|   39   zBuf[i--] = 0; |  | 
|   40   for(j=N-1; j>=0; j--){ |  | 
|   41     c = zBuf[j]; |  | 
|   42     zBuf[i--] = zHex[c&0xf]; |  | 
|   43     zBuf[i--] = zHex[c>>4]; |  | 
|   44   } |  | 
|   45   assert( i==-1 ); |  | 
|   46 } |  | 
|   47  |  | 
|   48 /* |  | 
|   49 ** Convert hex to binary.  The input zIn[] contains N bytes of |  | 
|   50 ** hexadecimal.  Convert this into binary and write aOut[] with |  | 
|   51 ** the binary data.  Spaces in the original input are ignored. |  | 
|   52 ** Return the number of bytes of binary rendered. |  | 
|   53 */ |  | 
|   54 int sqlite3TestHexToBin(const unsigned char *zIn, int N, unsigned char *aOut){ |  | 
|   55   const unsigned char aMap[] = { |  | 
|   56      0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, |  | 
|   57      0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, |  | 
|   58      0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, |  | 
|   59      1, 2, 3, 4, 5, 6, 7, 8,  9,10, 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,11,12,13,14,15,16, 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      0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, |  | 
|   71      0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, |  | 
|   72   }; |  | 
|   73   int i, j; |  | 
|   74   int hi=1; |  | 
|   75   unsigned char c; |  | 
|   76  |  | 
|   77   for(i=j=0; i<N; i++){ |  | 
|   78     c = aMap[zIn[i]]; |  | 
|   79     if( c==0 ) continue; |  | 
|   80     if( hi ){ |  | 
|   81       aOut[j] = (c-1)<<4; |  | 
|   82       hi = 0; |  | 
|   83     }else{ |  | 
|   84       aOut[j++] |= c-1; |  | 
|   85       hi = 1; |  | 
|   86     } |  | 
|   87   } |  | 
|   88   return j; |  | 
|   89 } |  | 
|   90  |  | 
|   91  |  | 
|   92 /* |  | 
|   93 ** Usage:   hexio_read  FILENAME  OFFSET  AMT |  | 
|   94 ** |  | 
|   95 ** Read AMT bytes from file FILENAME beginning at OFFSET from the |  | 
|   96 ** beginning of the file.  Convert that information to hexadecimal |  | 
|   97 ** and return the resulting HEX string. |  | 
|   98 */ |  | 
|   99 static int hexio_read( |  | 
|  100   void * clientData, |  | 
|  101   Tcl_Interp *interp, |  | 
|  102   int objc, |  | 
|  103   Tcl_Obj *CONST objv[] |  | 
|  104 ){ |  | 
|  105   int offset; |  | 
|  106   int amt, got; |  | 
|  107   const char *zFile; |  | 
|  108   unsigned char *zBuf; |  | 
|  109   FILE *in; |  | 
|  110  |  | 
|  111   if( objc!=4 ){ |  | 
|  112     Tcl_WrongNumArgs(interp, 1, objv, "FILENAME OFFSET AMT"); |  | 
|  113     return TCL_ERROR; |  | 
|  114   } |  | 
|  115   if( Tcl_GetIntFromObj(interp, objv[2], &offset) ) return TCL_ERROR; |  | 
|  116   if( Tcl_GetIntFromObj(interp, objv[3], &amt) ) return TCL_ERROR; |  | 
|  117   zFile = Tcl_GetString(objv[1]); |  | 
|  118   zBuf = sqlite3_malloc( amt*2+1 ); |  | 
|  119   if( zBuf==0 ){ |  | 
|  120     return TCL_ERROR; |  | 
|  121   } |  | 
|  122   in = fopen(zFile, "rb"); |  | 
|  123   if( in==0 ){ |  | 
|  124     in = fopen(zFile, "r"); |  | 
|  125   } |  | 
|  126   if( in==0 ){ |  | 
|  127     Tcl_AppendResult(interp, "cannot open input file ", zFile, 0); |  | 
|  128     return TCL_ERROR; |  | 
|  129   } |  | 
|  130   fseek(in, offset, SEEK_SET); |  | 
|  131   got = fread(zBuf, 1, amt, in); |  | 
|  132   fclose(in); |  | 
|  133   if( got<0 ){ |  | 
|  134     got = 0; |  | 
|  135   } |  | 
|  136   sqlite3TestBinToHex(zBuf, got); |  | 
|  137   Tcl_AppendResult(interp, zBuf, 0); |  | 
|  138   sqlite3_free(zBuf); |  | 
|  139   return TCL_OK; |  | 
|  140 } |  | 
|  141  |  | 
|  142  |  | 
|  143 /* |  | 
|  144 ** Usage:   hexio_write  FILENAME  OFFSET  DATA |  | 
|  145 ** |  | 
|  146 ** Write DATA into file FILENAME beginning at OFFSET from the |  | 
|  147 ** beginning of the file.  DATA is expressed in hexadecimal. |  | 
|  148 */ |  | 
|  149 static int hexio_write( |  | 
|  150   void * clientData, |  | 
|  151   Tcl_Interp *interp, |  | 
|  152   int objc, |  | 
|  153   Tcl_Obj *CONST objv[] |  | 
|  154 ){ |  | 
|  155   int offset; |  | 
|  156   int nIn, nOut, written; |  | 
|  157   const char *zFile; |  | 
|  158   const unsigned char *zIn; |  | 
|  159   unsigned char *aOut; |  | 
|  160   FILE *out; |  | 
|  161  |  | 
|  162   if( objc!=4 ){ |  | 
|  163     Tcl_WrongNumArgs(interp, 1, objv, "FILENAME OFFSET HEXDATA"); |  | 
|  164     return TCL_ERROR; |  | 
|  165   } |  | 
|  166   if( Tcl_GetIntFromObj(interp, objv[2], &offset) ) return TCL_ERROR; |  | 
|  167   zFile = Tcl_GetString(objv[1]); |  | 
|  168   zIn = (const unsigned char *)Tcl_GetStringFromObj(objv[3], &nIn); |  | 
|  169   aOut = sqlite3_malloc( nIn/2 ); |  | 
|  170   if( aOut==0 ){ |  | 
|  171     return TCL_ERROR; |  | 
|  172   } |  | 
|  173   nOut = sqlite3TestHexToBin(zIn, nIn, aOut); |  | 
|  174   out = fopen(zFile, "r+b"); |  | 
|  175   if( out==0 ){ |  | 
|  176     out = fopen(zFile, "r+"); |  | 
|  177   } |  | 
|  178   if( out==0 ){ |  | 
|  179     Tcl_AppendResult(interp, "cannot open output file ", zFile, 0); |  | 
|  180     return TCL_ERROR; |  | 
|  181   } |  | 
|  182   fseek(out, offset, SEEK_SET); |  | 
|  183   written = fwrite(aOut, 1, nOut, out); |  | 
|  184   sqlite3_free(aOut); |  | 
|  185   fclose(out); |  | 
|  186   Tcl_SetObjResult(interp, Tcl_NewIntObj(written)); |  | 
|  187   return TCL_OK; |  | 
|  188 } |  | 
|  189  |  | 
|  190 /* |  | 
|  191 ** USAGE:   hexio_get_int   HEXDATA |  | 
|  192 ** |  | 
|  193 ** Interpret the HEXDATA argument as a big-endian integer.  Return |  | 
|  194 ** the value of that integer.  HEXDATA can contain between 2 and 8 |  | 
|  195 ** hexadecimal digits. |  | 
|  196 */ |  | 
|  197 static int hexio_get_int( |  | 
|  198   void * clientData, |  | 
|  199   Tcl_Interp *interp, |  | 
|  200   int objc, |  | 
|  201   Tcl_Obj *CONST objv[] |  | 
|  202 ){ |  | 
|  203   int val; |  | 
|  204   int nIn, nOut; |  | 
|  205   const unsigned char *zIn; |  | 
|  206   unsigned char *aOut; |  | 
|  207   unsigned char aNum[4]; |  | 
|  208  |  | 
|  209   if( objc!=2 ){ |  | 
|  210     Tcl_WrongNumArgs(interp, 1, objv, "HEXDATA"); |  | 
|  211     return TCL_ERROR; |  | 
|  212   } |  | 
|  213   zIn = (const unsigned char *)Tcl_GetStringFromObj(objv[1], &nIn); |  | 
|  214   aOut = sqlite3_malloc( nIn/2 ); |  | 
|  215   if( aOut==0 ){ |  | 
|  216     return TCL_ERROR; |  | 
|  217   } |  | 
|  218   nOut = sqlite3TestHexToBin(zIn, nIn, aOut); |  | 
|  219   if( nOut>=4 ){ |  | 
|  220     memcpy(aNum, aOut, 4); |  | 
|  221   }else{ |  | 
|  222     memset(aNum, 0, sizeof(aNum)); |  | 
|  223     memcpy(&aNum[4-nOut], aOut, nOut); |  | 
|  224   } |  | 
|  225   sqlite3_free(aOut); |  | 
|  226   val = (aNum[0]<<24) | (aNum[1]<<16) | (aNum[2]<<8) | aNum[3]; |  | 
|  227   Tcl_SetObjResult(interp, Tcl_NewIntObj(val)); |  | 
|  228   return TCL_OK; |  | 
|  229 } |  | 
|  230  |  | 
|  231  |  | 
|  232 /* |  | 
|  233 ** USAGE:   hexio_render_int16   INTEGER |  | 
|  234 ** |  | 
|  235 ** Render INTEGER has a 16-bit big-endian integer in hexadecimal. |  | 
|  236 */ |  | 
|  237 static int hexio_render_int16( |  | 
|  238   void * clientData, |  | 
|  239   Tcl_Interp *interp, |  | 
|  240   int objc, |  | 
|  241   Tcl_Obj *CONST objv[] |  | 
|  242 ){ |  | 
|  243   int val; |  | 
|  244   unsigned char aNum[10]; |  | 
|  245  |  | 
|  246   if( objc!=2 ){ |  | 
|  247     Tcl_WrongNumArgs(interp, 1, objv, "INTEGER"); |  | 
|  248     return TCL_ERROR; |  | 
|  249   } |  | 
|  250   if( Tcl_GetIntFromObj(interp, objv[1], &val) ) return TCL_ERROR; |  | 
|  251   aNum[0] = val>>8; |  | 
|  252   aNum[1] = val; |  | 
|  253   sqlite3TestBinToHex(aNum, 2); |  | 
|  254   Tcl_SetObjResult(interp, Tcl_NewStringObj((char*)aNum, 4)); |  | 
|  255   return TCL_OK; |  | 
|  256 } |  | 
|  257  |  | 
|  258  |  | 
|  259 /* |  | 
|  260 ** USAGE:   hexio_render_int32   INTEGER |  | 
|  261 ** |  | 
|  262 ** Render INTEGER has a 32-bit big-endian integer in hexadecimal. |  | 
|  263 */ |  | 
|  264 static int hexio_render_int32( |  | 
|  265   void * clientData, |  | 
|  266   Tcl_Interp *interp, |  | 
|  267   int objc, |  | 
|  268   Tcl_Obj *CONST objv[] |  | 
|  269 ){ |  | 
|  270   int val; |  | 
|  271   unsigned char aNum[10]; |  | 
|  272  |  | 
|  273   if( objc!=2 ){ |  | 
|  274     Tcl_WrongNumArgs(interp, 1, objv, "INTEGER"); |  | 
|  275     return TCL_ERROR; |  | 
|  276   } |  | 
|  277   if( Tcl_GetIntFromObj(interp, objv[1], &val) ) return TCL_ERROR; |  | 
|  278   aNum[0] = val>>24; |  | 
|  279   aNum[1] = val>>16; |  | 
|  280   aNum[2] = val>>8; |  | 
|  281   aNum[3] = val; |  | 
|  282   sqlite3TestBinToHex(aNum, 4); |  | 
|  283   Tcl_SetObjResult(interp, Tcl_NewStringObj((char*)aNum, 8)); |  | 
|  284   return TCL_OK; |  | 
|  285 } |  | 
|  286  |  | 
|  287 /* |  | 
|  288 ** USAGE:  utf8_to_utf8  HEX |  | 
|  289 ** |  | 
|  290 ** The argument is a UTF8 string represented in hexadecimal. |  | 
|  291 ** The UTF8 might not be well-formed.  Run this string through |  | 
|  292 ** sqlite3Utf8to8() convert it back to hex and return the result. |  | 
|  293 */ |  | 
|  294 static int utf8_to_utf8( |  | 
|  295   void * clientData, |  | 
|  296   Tcl_Interp *interp, |  | 
|  297   int objc, |  | 
|  298   Tcl_Obj *CONST objv[] |  | 
|  299 ){ |  | 
|  300 #ifdef SQLITE_DEBUG |  | 
|  301   int n; |  | 
|  302   int nOut; |  | 
|  303   const unsigned char *zOrig; |  | 
|  304   unsigned char *z; |  | 
|  305   if( objc!=2 ){ |  | 
|  306     Tcl_WrongNumArgs(interp, 1, objv, "HEX"); |  | 
|  307     return TCL_ERROR; |  | 
|  308   } |  | 
|  309   zOrig = (unsigned char *)Tcl_GetStringFromObj(objv[1], &n); |  | 
|  310   z = sqlite3_malloc( n+3 ); |  | 
|  311   n = sqlite3TestHexToBin(zOrig, n, z); |  | 
|  312   z[n] = 0; |  | 
|  313   nOut = sqlite3Utf8To8(z); |  | 
|  314   sqlite3TestBinToHex(z,nOut); |  | 
|  315   Tcl_AppendResult(interp, (char*)z, 0); |  | 
|  316   sqlite3_free(z); |  | 
|  317 #endif |  | 
|  318   return TCL_OK; |  | 
|  319 } |  | 
|  320  |  | 
|  321  |  | 
|  322 /* |  | 
|  323 ** Register commands with the TCL interpreter. |  | 
|  324 */ |  | 
|  325 int Sqlitetest_hexio_Init(Tcl_Interp *interp){ |  | 
|  326   static struct { |  | 
|  327      char *zName; |  | 
|  328      Tcl_ObjCmdProc *xProc; |  | 
|  329   } aObjCmd[] = { |  | 
|  330      { "hexio_read",                   hexio_read            }, |  | 
|  331      { "hexio_write",                  hexio_write           }, |  | 
|  332      { "hexio_get_int",                hexio_get_int         }, |  | 
|  333      { "hexio_render_int16",           hexio_render_int16    }, |  | 
|  334      { "hexio_render_int32",           hexio_render_int32    }, |  | 
|  335      { "utf8_to_utf8",                 utf8_to_utf8          }, |  | 
|  336   }; |  | 
|  337   int i; |  | 
|  338   for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ |  | 
|  339     Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0); |  | 
|  340   } |  | 
|  341   return TCL_OK; |  | 
|  342 } |  | 
| OLD | NEW |