| 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 |