Annotation of embedaddon/sqlite3/src/test_hexio.c, revision 1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>