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