diff options
| author | cashmere <cashmere@autistici.org> | 2026-09-04 09:05:24 +0200 |
|---|---|---|
| committer | cashmere <cashmere@autistici.org> | 2026-09-04 09:05:24 +0200 |
| commit | 4f49b16079b27d7ce633619e4cddfdf2bffbc952 (patch) | |
| tree | c296c1e7f3c3e2f6859c6d3a1b1b208779b89679 /src/gzip.c | |
| download | relic-master.tar.gz | |
Diffstat (limited to 'src/gzip.c')
| -rw-r--r-- | src/gzip.c | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/src/gzip.c b/src/gzip.c new file mode 100644 index 0000000..dfb1563 --- /dev/null +++ b/src/gzip.c @@ -0,0 +1,140 @@ +/* +** Copyright (c) 2011 D. Richard Hipp +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the Simplified BSD License (also +** known as the "2-Clause License" or "FreeBSD License".) + +** This program is distributed in the hope that it will be useful, +** but without any warranty; without even the implied warranty of +** merchantability or fitness for a particular purpose. +** +** Author contact information: +** drh@hwaci.com +** http://www.hwaci.com/drh/ +** +******************************************************************************* +** +** This file contains code used to incrementally generate a GZIP compressed +** file. The GZIP format is described in RFC-1952. +** +** State information is stored in static variables, so this implementation +** can only be building up a single GZIP file at a time. +*/ +#include "config.h" +#include <assert.h> +#include <zlib.h> +#include "gzip.h" + +/* +** State information for the GZIP file under construction. +*/ +struct gzip_state { + int eState; /* 0: idle 1: header 2: compressing */ + unsigned long iCRC; /* The checksum */ + z_stream stream; /* The working compressor */ + Blob out; /* Results stored here */ +} gzip; + +/* +** Write a 32-bit integer as little-endian into the given buffer. +*/ +static void put32(char *z, int v){ + z[0] = v & 0xff; + z[1] = (v>>8) & 0xff; + z[2] = (v>>16) & 0xff; + z[3] = (v>>24) & 0xff; +} + +/* +** Begin constructing a gzip file. +*/ +void gzip_begin(sqlite3_int64 now){ + char aHdr[10]; + assert( gzip.eState==0 ); + blob_zero(&gzip.out); + aHdr[0] = 0x1f; + aHdr[1] = 0x8b; + aHdr[2] = 8; + aHdr[3] = 0; + if( now==-1 ){ + now = db_int64(0, "SELECT (julianday('now') - 2440587.5)*86400.0"); + } + put32(&aHdr[4], now&0xffffffff); + aHdr[8] = 2; + aHdr[9] = -1; + blob_append(&gzip.out, aHdr, 10); + gzip.iCRC = 0; + gzip.eState = 1; +} + +/* +** Add nIn bytes of content from pIn to the gzip file. +*/ +#define GZIP_BUFSZ 100000 +void gzip_step(const char *pIn, int nIn){ + char *zOutBuf; + int nOut; + + nOut = nIn + nIn/10 + 100; + if( nOut<100000 ) nOut = 100000; + zOutBuf = fossil_malloc(nOut); + gzip.stream.avail_in = nIn; + gzip.stream.next_in = (unsigned char*)pIn; + gzip.stream.avail_out = nOut; + gzip.stream.next_out = (unsigned char*)zOutBuf; + if( gzip.eState==1 ){ + gzip.stream.zalloc = (alloc_func)0; + gzip.stream.zfree = (free_func)0; + gzip.stream.opaque = 0; + deflateInit2(&gzip.stream, 9, Z_DEFLATED, -MAX_WBITS,8,Z_DEFAULT_STRATEGY); + gzip.eState = 2; + } + gzip.iCRC = crc32(gzip.iCRC, gzip.stream.next_in, gzip.stream.avail_in); + do{ + deflate(&gzip.stream, nIn==0 ? Z_FINISH : 0); + blob_append(&gzip.out, zOutBuf, nOut - gzip.stream.avail_out); + gzip.stream.avail_out = nOut; + gzip.stream.next_out = (unsigned char*)zOutBuf; + }while( gzip.stream.avail_in>0 ); + fossil_free(zOutBuf); +} + +/* +** Finish the gzip file and put the content in *pOut +*/ +void gzip_finish(Blob *pOut){ + char aTrailer[8]; + assert( gzip.eState>0 ); + gzip_step("", 0); + deflateEnd(&gzip.stream); + put32(aTrailer, gzip.iCRC); + put32(&aTrailer[4], gzip.stream.total_in); + blob_append(&gzip.out, aTrailer, 8); + *pOut = gzip.out; + blob_zero(&gzip.out); + gzip.eState = 0; +} + +/* +** COMMAND: test-gzip +** +** Usage: %fossil test-gzip FILENAME +** +** Compress a file using gzip. +*/ +void test_gzip_cmd(void){ + Blob b; + char *zOut; + if( g.argc!=3 ) usage("FILENAME"); + sqlite3_open(":memory:", &g.db); + gzip_begin(-1); + blob_read_from_file(&b, g.argv[2], ExtFILE); + zOut = mprintf("%s.gz", g.argv[2]); + gzip_step(blob_buffer(&b), blob_size(&b)); + blob_reset(&b); + gzip_finish(&b); + blob_write_to_file(&b, zOut); + blob_reset(&b); + fossil_free(zOut); +} |
