ecaa021759
FossilOrigin-Name: 93ac8573eead9b785a24715239e71cd3ef730bf16332cf3b5e264a6491374cac
132 lines
3.8 KiB
C
132 lines
3.8 KiB
C
/*
|
|
** 2014-06-13
|
|
**
|
|
** The author disclaims copyright to this source code. In place of
|
|
** a legal notice, here is a blessing:
|
|
**
|
|
** May you do good and not evil.
|
|
** May you find forgiveness for yourself and forgive others.
|
|
** May you share freely, never taking more than you give.
|
|
**
|
|
******************************************************************************
|
|
**
|
|
** This SQLite extension implements SQL compression functions
|
|
** compress() and uncompress() using ZLIB.
|
|
*/
|
|
#include "sqlite3ext.h"
|
|
SQLITE_EXTENSION_INIT1
|
|
#include <zlib.h>
|
|
|
|
/*
|
|
** Implementation of the "compress(X)" SQL function. The input X is
|
|
** compressed using zLib and the output is returned.
|
|
**
|
|
** The output is a BLOB that begins with a variable-length integer that
|
|
** is the input size in bytes (the size of X before compression). The
|
|
** variable-length integer is implemented as 1 to 5 bytes. There are
|
|
** seven bits per integer stored in the lower seven bits of each byte.
|
|
** More significant bits occur first. The most significant bit (0x80)
|
|
** is a flag to indicate the end of the integer.
|
|
**
|
|
** This function, SQLAR, and ZIP all use the same "deflate" compression
|
|
** algorithm, but each is subtly different:
|
|
**
|
|
** * ZIP uses raw deflate.
|
|
**
|
|
** * SQLAR uses the "zlib format" which is raw deflate with a two-byte
|
|
** algorithm-identification header and a four-byte checksum at the end.
|
|
**
|
|
** * This utility uses the "zlib format" like SQLAR, but adds the variable-
|
|
** length integer uncompressed size value at the beginning.
|
|
**
|
|
** This function might be extended in the future to support compression
|
|
** formats other than deflate, by providing a different algorithm-id
|
|
** mark following the variable-length integer size parameter.
|
|
*/
|
|
static void compressFunc(
|
|
sqlite3_context *context,
|
|
int argc,
|
|
sqlite3_value **argv
|
|
){
|
|
const unsigned char *pIn;
|
|
unsigned char *pOut;
|
|
unsigned int nIn;
|
|
unsigned long int nOut;
|
|
unsigned char x[8];
|
|
int rc;
|
|
int i, j;
|
|
|
|
pIn = sqlite3_value_blob(argv[0]);
|
|
nIn = sqlite3_value_bytes(argv[0]);
|
|
nOut = 13 + nIn + (nIn+999)/1000;
|
|
pOut = sqlite3_malloc( nOut+5 );
|
|
for(i=4; i>=0; i--){
|
|
x[i] = (nIn >> (7*(4-i)))&0x7f;
|
|
}
|
|
for(i=0; i<4 && x[i]==0; i++){}
|
|
for(j=0; i<=4; i++, j++) pOut[j] = x[i];
|
|
pOut[j-1] |= 0x80;
|
|
rc = compress(&pOut[j], &nOut, pIn, nIn);
|
|
if( rc==Z_OK ){
|
|
sqlite3_result_blob(context, pOut, nOut+j, sqlite3_free);
|
|
}else{
|
|
sqlite3_free(pOut);
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Implementation of the "uncompress(X)" SQL function. The argument X
|
|
** is a blob which was obtained from compress(Y). The output will be
|
|
** the value Y.
|
|
*/
|
|
static void uncompressFunc(
|
|
sqlite3_context *context,
|
|
int argc,
|
|
sqlite3_value **argv
|
|
){
|
|
const unsigned char *pIn;
|
|
unsigned char *pOut;
|
|
unsigned int nIn;
|
|
unsigned long int nOut;
|
|
int rc;
|
|
unsigned int i;
|
|
|
|
pIn = sqlite3_value_blob(argv[0]);
|
|
nIn = sqlite3_value_bytes(argv[0]);
|
|
nOut = 0;
|
|
for(i=0; i<nIn && i<5; i++){
|
|
nOut = (nOut<<7) | (pIn[i]&0x7f);
|
|
if( (pIn[i]&0x80)!=0 ){ i++; break; }
|
|
}
|
|
pOut = sqlite3_malloc( nOut+1 );
|
|
rc = uncompress(pOut, &nOut, &pIn[i], nIn-i);
|
|
if( rc==Z_OK ){
|
|
sqlite3_result_blob(context, pOut, nOut, sqlite3_free);
|
|
}else{
|
|
sqlite3_free(pOut);
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef _WIN32
|
|
__declspec(dllexport)
|
|
#endif
|
|
int sqlite3_compress_init(
|
|
sqlite3 *db,
|
|
char **pzErrMsg,
|
|
const sqlite3_api_routines *pApi
|
|
){
|
|
int rc = SQLITE_OK;
|
|
SQLITE_EXTENSION_INIT2(pApi);
|
|
(void)pzErrMsg; /* Unused parameter */
|
|
rc = sqlite3_create_function(db, "compress", 1,
|
|
SQLITE_UTF8 | SQLITE_INNOCUOUS,
|
|
0, compressFunc, 0, 0);
|
|
if( rc==SQLITE_OK ){
|
|
rc = sqlite3_create_function(db, "uncompress", 1,
|
|
SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC,
|
|
0, uncompressFunc, 0, 0);
|
|
}
|
|
return rc;
|
|
}
|