xref: /sqlite-3.40.0/ext/misc/compress.c (revision 929a9406)
1 /*
2 ** 2014-06-13
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 **
13 ** This SQLite extension implements SQL compression functions
14 ** compress() and uncompress() using ZLIB.
15 */
16 #include "sqlite3ext.h"
17 SQLITE_EXTENSION_INIT1
18 #include <zlib.h>
19 
20 /*
21 ** Implementation of the "compress(X)" SQL function.  The input X is
22 ** compressed using zLib and the output is returned.
23 **
24 ** The output is a BLOB that begins with a variable-length integer that
25 ** is the input size in bytes (the size of X before compression).  The
26 ** variable-length integer is implemented as 1 to 5 bytes.  There are
27 ** seven bits per integer stored in the lower seven bits of each byte.
28 ** More significant bits occur first.  The most significant bit (0x80)
29 ** is a flag to indicate the end of the integer.
30 **
31 ** This function, SQLAR, and ZIP all use the same "deflate" compression
32 ** algorithm, but each is subtly different:
33 **
34 **   *  ZIP uses raw deflate.
35 **
36 **   *  SQLAR uses the "zlib format" which is raw deflate with a two-byte
37 **      algorithm-identification header and a four-byte checksum at the end.
38 **
39 **   *  This utility uses the "zlib format" like SQLAR, but adds the variable-
40 **      length integer uncompressed size value at the beginning.
41 **
42 ** This function might be extended in the future to support compression
43 ** formats other than deflate, by providing a different algorithm-id
44 ** mark following the variable-length integer size parameter.
45 */
compressFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)46 static void compressFunc(
47   sqlite3_context *context,
48   int argc,
49   sqlite3_value **argv
50 ){
51   const unsigned char *pIn;
52   unsigned char *pOut;
53   unsigned int nIn;
54   unsigned long int nOut;
55   unsigned char x[8];
56   int rc;
57   int i, j;
58 
59   pIn = sqlite3_value_blob(argv[0]);
60   nIn = sqlite3_value_bytes(argv[0]);
61   nOut = 13 + nIn + (nIn+999)/1000;
62   pOut = sqlite3_malloc( nOut+5 );
63   for(i=4; i>=0; i--){
64     x[i] = (nIn >> (7*(4-i)))&0x7f;
65   }
66   for(i=0; i<4 && x[i]==0; i++){}
67   for(j=0; i<=4; i++, j++) pOut[j] = x[i];
68   pOut[j-1] |= 0x80;
69   rc = compress(&pOut[j], &nOut, pIn, nIn);
70   if( rc==Z_OK ){
71     sqlite3_result_blob(context, pOut, nOut+j, sqlite3_free);
72   }else{
73     sqlite3_free(pOut);
74   }
75 }
76 
77 /*
78 ** Implementation of the "uncompress(X)" SQL function.  The argument X
79 ** is a blob which was obtained from compress(Y).  The output will be
80 ** the value Y.
81 */
uncompressFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)82 static void uncompressFunc(
83   sqlite3_context *context,
84   int argc,
85   sqlite3_value **argv
86 ){
87   const unsigned char *pIn;
88   unsigned char *pOut;
89   unsigned int nIn;
90   unsigned long int nOut;
91   int rc;
92   int i;
93 
94   pIn = sqlite3_value_blob(argv[0]);
95   nIn = sqlite3_value_bytes(argv[0]);
96   nOut = 0;
97   for(i=0; i<nIn && i<5; i++){
98     nOut = (nOut<<7) | (pIn[i]&0x7f);
99     if( (pIn[i]&0x80)!=0 ){ i++; break; }
100   }
101   pOut = sqlite3_malloc( nOut+1 );
102   rc = uncompress(pOut, &nOut, &pIn[i], nIn-i);
103   if( rc==Z_OK ){
104     sqlite3_result_blob(context, pOut, nOut, sqlite3_free);
105   }else{
106     sqlite3_free(pOut);
107   }
108 }
109 
110 
111 #ifdef _WIN32
112 __declspec(dllexport)
113 #endif
sqlite3_compress_init(sqlite3 * db,char ** pzErrMsg,const sqlite3_api_routines * pApi)114 int sqlite3_compress_init(
115   sqlite3 *db,
116   char **pzErrMsg,
117   const sqlite3_api_routines *pApi
118 ){
119   int rc = SQLITE_OK;
120   SQLITE_EXTENSION_INIT2(pApi);
121   (void)pzErrMsg;  /* Unused parameter */
122   rc = sqlite3_create_function(db, "compress", 1,
123                     SQLITE_UTF8 | SQLITE_INNOCUOUS,
124                     0, compressFunc, 0, 0);
125   if( rc==SQLITE_OK ){
126     rc = sqlite3_create_function(db, "uncompress", 1,
127                     SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC,
128                     0, uncompressFunc, 0, 0);
129   }
130   return rc;
131 }
132