diff options
Diffstat (limited to 'ext/sqlite/libsqlite/src/encode.c')
-rw-r--r-- | ext/sqlite/libsqlite/src/encode.c | 67 |
1 files changed, 38 insertions, 29 deletions
diff --git a/ext/sqlite/libsqlite/src/encode.c b/ext/sqlite/libsqlite/src/encode.c index 5614999ab9..7d959b00ca 100644 --- a/ext/sqlite/libsqlite/src/encode.c +++ b/ext/sqlite/libsqlite/src/encode.c @@ -18,6 +18,7 @@ ** $Id$ */ #include <string.h> +#include <assert.h> /* ** How This Encoder Works @@ -26,7 +27,7 @@ ** 0x00. This is accomplished by using an escape character to encode ** 0x27 and 0x00 as a two-byte sequence. The escape character is always ** 0x01. An 0x00 is encoded as the two byte sequence 0x01 0x01. The -** 0x27 character is encoded as the two byte sequence 0x01 0x03. Finally, +** 0x27 character is encoded as the two byte sequence 0x01 0x28. Finally, ** the escape character itself is encoded as the two-character sequence ** 0x01 0x02. ** @@ -34,7 +35,7 @@ ** ** 0x00 -> 0x01 0x01 ** 0x01 -> 0x01 0x02 -** 0x27 -> 0x01 0x03 +** 0x27 -> 0x01 0x28 ** ** If that were all the encoder did, it would work, but in certain cases ** it could double the size of the encoded string. For example, to @@ -80,7 +81,7 @@ ** the offset in step 7 below. ** ** (6) Convert each 0x01 0x01 sequence into a single character 0x00. -** Convert 0x01 0x02 into 0x01. Convert 0x01 0x03 into 0x27. +** Convert 0x01 0x02 into 0x01. Convert 0x01 0x28 into 0x27. ** ** (7) Subtract the offset value that was the first character of ** the encoded buffer from all characters in the output buffer. @@ -114,13 +115,20 @@ ** ** The return value is the number of characters in the encoded ** string, excluding the "\000" terminator. +** +** If out==NULL then no output is generated but the routine still returns +** the number of characters that would have been generated if out had +** not been NULL. */ int sqlite_encode_binary(const unsigned char *in, int n, unsigned char *out){ int i, j, e, m; + unsigned char x; int cnt[256]; if( n<=0 ){ - out[0] = 'x'; - out[1] = 0; + if( out ){ + out[0] = 'x'; + out[1] = 0; + } return 1; } memset(cnt, 0, sizeof(cnt)); @@ -136,24 +144,21 @@ int sqlite_encode_binary(const unsigned char *in, int n, unsigned char *out){ if( m==0 ) break; } } + if( out==0 ){ + return n+m+1; + } out[0] = e; j = 1; for(i=0; i<n; i++){ - int c = (in[i] - e)&0xff; - if( c==0 ){ - out[j++] = 1; - out[j++] = 1; - }else if( c==1 ){ + x = in[i] - e; + if( x==0 || x==1 || x=='\''){ out[j++] = 1; - out[j++] = 2; - }else if( c=='\'' ){ - out[j++] = 1; - out[j++] = 3; - }else{ - out[j++] = c; + x++; } + out[j++] = x; } out[j] = 0; + assert( j==n+m+1 ); return j; } @@ -168,38 +173,32 @@ int sqlite_encode_binary(const unsigned char *in, int n, unsigned char *out){ ** to decode a string in place. */ int sqlite_decode_binary(const unsigned char *in, unsigned char *out){ - int i, c, e; + int i, e; + unsigned char c; e = *(in++); i = 0; while( (c = *(in++))!=0 ){ if( c==1 ){ - c = *(in++); - if( c==1 ){ - c = 0; - }else if( c==2 ){ - c = 1; - }else if( c==3 ){ - c = '\''; - }else{ - return -1; - } + c = *(in++) - 1; } - out[i++] = (c + e)&0xff; + out[i++] = c + e; } return i; } #ifdef ENCODER_TEST +#include <stdio.h> /* ** The subroutines above are not tested by the usual test suite. To test ** these routines, compile just this one file with a -DENCODER_TEST=1 option ** and run the result. */ int main(int argc, char **argv){ - int i, j, n, m, nOut; + int i, j, n, m, nOut, nByteIn, nByteOut; unsigned char in[30000]; unsigned char out[33000]; + nByteIn = nByteOut = 0; for(i=0; i<sizeof(in); i++){ printf("Test %d: ", i+1); n = rand() % (i+1); @@ -213,11 +212,17 @@ int main(int argc, char **argv){ }else{ for(j=0; j<n; j++) in[j] = rand() & 0xff; } + nByteIn += n; nOut = sqlite_encode_binary(in, n, out); + nByteOut += nOut; if( nOut!=strlen(out) ){ printf(" ERROR return value is %d instead of %d\n", nOut, strlen(out)); exit(1); } + if( nOut!=sqlite_encode_binary(in, n, 0) ){ + printf(" ERROR actual output size disagrees with predicted size\n"); + exit(1); + } m = (256*n + 1262)/253; printf("size %d->%d (max %d)", n, strlen(out)+1, m); if( strlen(out)+1>m ){ @@ -241,5 +246,9 @@ int main(int argc, char **argv){ } printf(" OK\n"); } + fprintf(stderr,"Finished. Total encoding: %d->%d bytes\n", + nByteIn, nByteOut); + fprintf(stderr,"Avg size increase: %.3f%%\n", + (nByteOut-nByteIn)*100.0/(double)nByteIn); } #endif /* ENCODER_TEST */ |