xref: /sqlite-3.40.0/ext/misc/sqlar.c (revision efc752b1)
1 /*
2 ** 2017-12-17
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 ** Utility functions sqlar_compress() and sqlar_uncompress(). Useful
14 ** for working with sqlar archives and used by the shell tool's built-in
15 ** sqlar support.
16 */
17 #include "sqlite3ext.h"
18 SQLITE_EXTENSION_INIT1
19 #include <zlib.h>
20 #include <assert.h>
21 
22 /*
23 ** Implementation of the "sqlar_compress(X)" SQL function.
24 **
25 ** If the type of X is SQLITE_BLOB, and compressing that blob using
26 ** zlib utility function compress() yields a smaller blob, return the
27 ** compressed blob. Otherwise, return a copy of X.
28 **
29 ** SQLar uses the "zlib format" for compressed content.  The zlib format
30 ** contains a two-byte identification header and a four-byte checksum at
31 ** the end.  This is different from ZIP which uses the raw deflate format.
32 **
33 ** Future enhancements to SQLar might add support for new compression formats.
34 ** If so, those new formats will be identified by alternative headers in the
35 ** compressed data.
36 */
sqlarCompressFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)37 static void sqlarCompressFunc(
38   sqlite3_context *context,
39   int argc,
40   sqlite3_value **argv
41 ){
42   assert( argc==1 );
43   if( sqlite3_value_type(argv[0])==SQLITE_BLOB ){
44     const Bytef *pData = sqlite3_value_blob(argv[0]);
45     uLong nData = sqlite3_value_bytes(argv[0]);
46     uLongf nOut = compressBound(nData);
47     Bytef *pOut;
48 
49     pOut = (Bytef*)sqlite3_malloc(nOut);
50     if( pOut==0 ){
51       sqlite3_result_error_nomem(context);
52       return;
53     }else{
54       if( Z_OK!=compress(pOut, &nOut, pData, nData) ){
55         sqlite3_result_error(context, "error in compress()", -1);
56       }else if( nOut<nData ){
57         sqlite3_result_blob(context, pOut, nOut, SQLITE_TRANSIENT);
58       }else{
59         sqlite3_result_value(context, argv[0]);
60       }
61       sqlite3_free(pOut);
62     }
63   }else{
64     sqlite3_result_value(context, argv[0]);
65   }
66 }
67 
68 /*
69 ** Implementation of the "sqlar_uncompress(X,SZ)" SQL function
70 **
71 ** Parameter SZ is interpreted as an integer. If it is less than or
72 ** equal to zero, then this function returns a copy of X. Or, if
73 ** SZ is equal to the size of X when interpreted as a blob, also
74 ** return a copy of X. Otherwise, decompress blob X using zlib
75 ** utility function uncompress() and return the results (another
76 ** blob).
77 */
sqlarUncompressFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)78 static void sqlarUncompressFunc(
79   sqlite3_context *context,
80   int argc,
81   sqlite3_value **argv
82 ){
83   uLong nData;
84   uLongf sz;
85 
86   assert( argc==2 );
87   sz = sqlite3_value_int(argv[1]);
88 
89   if( sz<=0 || sz==(nData = sqlite3_value_bytes(argv[0])) ){
90     sqlite3_result_value(context, argv[0]);
91   }else{
92     const Bytef *pData= sqlite3_value_blob(argv[0]);
93     Bytef *pOut = sqlite3_malloc(sz);
94     if( Z_OK!=uncompress(pOut, &sz, pData, nData) ){
95       sqlite3_result_error(context, "error in uncompress()", -1);
96     }else{
97       sqlite3_result_blob(context, pOut, sz, SQLITE_TRANSIENT);
98     }
99     sqlite3_free(pOut);
100   }
101 }
102 
103 
104 #ifdef _WIN32
105 __declspec(dllexport)
106 #endif
sqlite3_sqlar_init(sqlite3 * db,char ** pzErrMsg,const sqlite3_api_routines * pApi)107 int sqlite3_sqlar_init(
108   sqlite3 *db,
109   char **pzErrMsg,
110   const sqlite3_api_routines *pApi
111 ){
112   int rc = SQLITE_OK;
113   SQLITE_EXTENSION_INIT2(pApi);
114   (void)pzErrMsg;  /* Unused parameter */
115   rc = sqlite3_create_function(db, "sqlar_compress", 1,
116                                SQLITE_UTF8|SQLITE_INNOCUOUS, 0,
117                                sqlarCompressFunc, 0, 0);
118   if( rc==SQLITE_OK ){
119     rc = sqlite3_create_function(db, "sqlar_uncompress", 2,
120                                  SQLITE_UTF8|SQLITE_INNOCUOUS, 0,
121                                  sqlarUncompressFunc, 0, 0);
122   }
123   return rc;
124 }
125