| /* example.c -- usage example of the zlib compression library |
| * Copyright (C) 1995-2006, 2011, 2016 Jean-loup Gailly |
| * For conditions of distribution and use, see copyright notice in zlib.h |
| */ |
| |
| #include "zbuild.h" |
| #ifdef ZLIB_COMPAT |
| # include "zlib.h" |
| #else |
| # include "zlib-ng.h" |
| #endif |
| #include "deflate.h" |
| |
| #include <stdio.h> |
| #include <stdarg.h> |
| #include <inttypes.h> |
| |
| #define TESTFILE "foo.gz" |
| |
| static const char hello[] = "hello, hello!"; |
| /* "hello world" would be more standard, but the repeated "hello" |
| * stresses the compression code better, sorry... |
| */ |
| |
| static const char dictionary[] = "hello"; |
| static unsigned long dictId = 0; /* Adler32 value of the dictionary */ |
| |
| /* Maximum dictionary size, according to inflateGetDictionary() description. */ |
| #define MAX_DICTIONARY_SIZE 32768 |
| |
| |
| void test_compress (unsigned char *compr, z_size_t comprLen,unsigned char *uncompr, z_size_t uncomprLen); |
| void test_gzio (const char *fname, unsigned char *uncompr, z_size_t uncomprLen); |
| void test_deflate (unsigned char *compr, size_t comprLen); |
| void test_inflate (unsigned char *compr, size_t comprLen, unsigned char *uncompr, size_t uncomprLen); |
| void test_large_deflate (unsigned char *compr, size_t comprLen, unsigned char *uncompr, size_t uncomprLen, int zng_params); |
| void test_large_inflate (unsigned char *compr, size_t comprLen, unsigned char *uncompr, size_t uncomprLen); |
| void test_flush (unsigned char *compr, z_size_t *comprLen); |
| void test_sync (unsigned char *compr, size_t comprLen, unsigned char *uncompr, size_t uncomprLen); |
| void test_dict_deflate (unsigned char *compr, size_t comprLen); |
| void test_dict_inflate (unsigned char *compr, size_t comprLen, unsigned char *uncompr, size_t uncomprLen); |
| int main (int argc, char *argv[]); |
| |
| |
| static alloc_func zalloc = NULL; |
| static free_func zfree = NULL; |
| |
| /* =========================================================================== |
| * Display error message and exit |
| */ |
| void error(const char *format, ...) { |
| va_list va; |
| |
| va_start(va, format); |
| vfprintf(stderr, format, va); |
| va_end(va); |
| |
| exit(1); |
| } |
| |
| #define CHECK_ERR(err, msg) { \ |
| if (err != Z_OK) \ |
| error("%s error: %d\n", msg, err); \ |
| } |
| |
| /* =========================================================================== |
| * Test compress() and uncompress() |
| */ |
| void test_compress(unsigned char *compr, z_size_t comprLen, unsigned char *uncompr, z_size_t uncomprLen) { |
| int err; |
| size_t len = strlen(hello)+1; |
| |
| err = PREFIX(compress)(compr, &comprLen, (const unsigned char*)hello, (z_size_t)len); |
| CHECK_ERR(err, "compress"); |
| |
| strcpy((char*)uncompr, "garbage"); |
| |
| err = PREFIX(uncompress)(uncompr, &uncomprLen, compr, comprLen); |
| CHECK_ERR(err, "uncompress"); |
| |
| if (strcmp((char*)uncompr, hello)) |
| error("bad uncompress\n"); |
| else |
| printf("uncompress(): %s\n", (char *)uncompr); |
| } |
| |
| /* =========================================================================== |
| * Test read/write of .gz files |
| */ |
| void test_gzio(const char *fname, unsigned char *uncompr, z_size_t uncomprLen) { |
| #ifdef NO_GZCOMPRESS |
| fprintf(stderr, "NO_GZCOMPRESS -- gz* functions cannot compress\n"); |
| #else |
| int err; |
| size_t read; |
| size_t len = strlen(hello)+1; |
| gzFile file; |
| z_off64_t pos; |
| z_off64_t comprLen; |
| |
| /* Write gz file with test data */ |
| file = PREFIX(gzopen)(fname, "wb"); |
| if (file == NULL) |
| error("gzopen error\n"); |
| /* Write hello, hello! using gzputs and gzprintf */ |
| PREFIX(gzputc)(file, 'h'); |
| if (PREFIX(gzputs)(file, "ello") != 4) |
| error("gzputs err: %s\n", PREFIX(gzerror)(file, &err)); |
| if (PREFIX(gzprintf)(file, ", %s!", "hello") != 8) |
| error("gzprintf err: %s\n", PREFIX(gzerror)(file, &err)); |
| /* Write string null-teriminator using gzseek */ |
| if (PREFIX(gzseek)(file, 1L, SEEK_CUR) < 0) |
| error("gzseek error, gztell=%ld\n", (long)PREFIX(gztell)(file)); |
| /* Write hello, hello! using gzfwrite using best compression level */ |
| if (PREFIX(gzsetparams)(file, Z_BEST_COMPRESSION, Z_DEFAULT_STRATEGY) != Z_OK) |
| error("gzsetparams err: %s\n", PREFIX(gzerror)(file, &err)); |
| if (PREFIX(gzfwrite)(hello, len, 1, file) == 0) |
| error("gzfwrite err: %s\n", PREFIX(gzerror)(file, &err)); |
| /* Flush compressed bytes to file */ |
| if (PREFIX(gzflush)(file, Z_SYNC_FLUSH) != Z_OK) |
| error("gzflush err: %s\n", PREFIX(gzerror)(file, &err)); |
| comprLen = PREFIX(gzoffset)(file); |
| if (comprLen <= 0) |
| error("gzoffset err: %s\n", PREFIX(gzerror)(file, &err)); |
| PREFIX(gzclose)(file); |
| |
| /* Open gz file we previously wrote */ |
| file = PREFIX(gzopen)(fname, "rb"); |
| if (file == NULL) |
| error("gzopen error\n"); |
| |
| /* Read uncompressed data - hello, hello! string twice */ |
| strcpy((char*)uncompr, "garbages"); |
| if (PREFIX(gzread)(file, uncompr, (unsigned)uncomprLen) != (int)(len + len)) |
| error("gzread err: %s\n", PREFIX(gzerror)(file, &err)); |
| if (strcmp((char*)uncompr, hello)) |
| error("bad gzread: %s\n", (char*)uncompr); |
| else |
| printf("gzread(): %s\n", (char*)uncompr); |
| /* Check position at the end of the gz file */ |
| if (PREFIX(gzeof)(file) != 1) |
| error("gzeof err: not reporting end of stream\n"); |
| |
| /* Seek backwards mid-string and check char reading with gzgetc and gzungetc */ |
| pos = PREFIX(gzseek)(file, -22L, SEEK_CUR); |
| if (pos != 6 || PREFIX(gztell)(file) != pos) |
| error("gzseek error, pos=%ld, gztell=%ld\n", (long)pos, (long)PREFIX(gztell)(file)); |
| if (PREFIX(gzgetc)(file) != ' ') |
| error("gzgetc error\n"); |
| if (PREFIX(gzungetc)(' ', file) != ' ') |
| error("gzungetc error\n"); |
| /* Read first hello, hello! string with gzgets */ |
| strcpy((char*)uncompr, "garbages"); |
| PREFIX(gzgets)(file, (char*)uncompr, (int)uncomprLen); |
| if (strlen((char*)uncompr) != 7) /* " hello!" */ |
| error("gzgets err after gzseek: %s\n", PREFIX(gzerror)(file, &err)); |
| if (strcmp((char*)uncompr, hello + 6)) |
| error("bad gzgets after gzseek\n"); |
| else |
| printf("gzgets() after gzseek: %s\n", (char*)uncompr); |
| /* Seek to second hello, hello! string */ |
| pos = PREFIX(gzseek)(file, 14L, SEEK_SET); |
| if (pos != 14 || PREFIX(gztell)(file) != pos) |
| error("gzseek error, pos=%ld, gztell=%ld\n", (long)pos, (long)PREFIX(gztell)(file)); |
| /* Check position not at end of file */ |
| if (PREFIX(gzeof)(file) != 0) |
| error("gzeof err: reporting end of stream\n"); |
| /* Read first hello, hello! string with gzfread */ |
| strcpy((char*)uncompr, "garbages"); |
| read = PREFIX(gzfread)(uncompr, uncomprLen, 1, file); |
| if (strcmp((const char *)uncompr, hello) != 0) |
| error("bad gzgets\n"); |
| else |
| printf("gzgets(): %s\n", (char*)uncompr); |
| pos = PREFIX(gzoffset)(file); |
| if (pos < 0 || pos != (comprLen + 10)) |
| error("gzoffset err: wrong offset at end\n"); |
| /* Trigger an error and clear it with gzclearerr */ |
| PREFIX(gzfread)(uncompr, (size_t)-1, (size_t)-1, file); |
| PREFIX(gzerror)(file, &err); |
| if (err == 0) |
| error("gzerror err: no error returned\n"); |
| PREFIX(gzclearerr)(file); |
| PREFIX(gzerror)(file, &err); |
| if (err != 0) |
| error("gzclearerr err: not zero %d\n", err); |
| |
| PREFIX(gzclose)(file); |
| |
| if (PREFIX(gzclose)(NULL) != Z_STREAM_ERROR) |
| error("gzclose unexpected return when handle null\n"); |
| Z_UNUSED(read); |
| #endif |
| } |
| |
| /* =========================================================================== |
| * Test deflate() with small buffers |
| */ |
| void test_deflate(unsigned char *compr, size_t comprLen) { |
| PREFIX3(stream) c_stream; /* compression stream */ |
| int err; |
| size_t len = strlen(hello)+1; |
| |
| c_stream.zalloc = zalloc; |
| c_stream.zfree = zfree; |
| c_stream.opaque = (void *)0; |
| c_stream.total_in = 0; |
| c_stream.total_out = 0; |
| |
| err = PREFIX(deflateInit)(&c_stream, Z_DEFAULT_COMPRESSION); |
| CHECK_ERR(err, "deflateInit"); |
| |
| c_stream.next_in = (z_const unsigned char *)hello; |
| c_stream.next_out = compr; |
| |
| while (c_stream.total_in != len && c_stream.total_out < comprLen) { |
| c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */ |
| err = PREFIX(deflate)(&c_stream, Z_NO_FLUSH); |
| CHECK_ERR(err, "deflate"); |
| } |
| /* Finish the stream, still forcing small buffers: */ |
| for (;;) { |
| c_stream.avail_out = 1; |
| err = PREFIX(deflate)(&c_stream, Z_FINISH); |
| if (err == Z_STREAM_END) break; |
| CHECK_ERR(err, "deflate"); |
| } |
| |
| err = PREFIX(deflateEnd)(&c_stream); |
| CHECK_ERR(err, "deflateEnd"); |
| } |
| |
| /* =========================================================================== |
| * Test inflate() with small buffers |
| */ |
| void test_inflate(unsigned char *compr, size_t comprLen, unsigned char *uncompr, size_t uncomprLen) { |
| int err; |
| PREFIX3(stream) d_stream; /* decompression stream */ |
| |
| strcpy((char*)uncompr, "garbage"); |
| |
| d_stream.zalloc = zalloc; |
| d_stream.zfree = zfree; |
| d_stream.opaque = (void *)0; |
| |
| d_stream.next_in = compr; |
| d_stream.avail_in = 0; |
| d_stream.next_out = uncompr; |
| d_stream.total_in = 0; |
| d_stream.total_out = 0; |
| |
| err = PREFIX(inflateInit)(&d_stream); |
| CHECK_ERR(err, "inflateInit"); |
| |
| while (d_stream.total_out < uncomprLen && d_stream.total_in < comprLen) { |
| d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */ |
| err = PREFIX(inflate)(&d_stream, Z_NO_FLUSH); |
| if (err == Z_STREAM_END) break; |
| CHECK_ERR(err, "inflate"); |
| } |
| |
| err = PREFIX(inflateEnd)(&d_stream); |
| CHECK_ERR(err, "inflateEnd"); |
| |
| if (strcmp((char*)uncompr, hello)) |
| error("bad inflate\n"); |
| else |
| printf("inflate(): %s\n", (char *)uncompr); |
| } |
| |
| static unsigned int diff; |
| |
| /* =========================================================================== |
| * Test deflate() with large buffers and dynamic change of compression level |
| */ |
| void test_large_deflate(unsigned char *compr, size_t comprLen, unsigned char *uncompr, size_t uncomprLen, int zng_params) { |
| PREFIX3(stream) c_stream; /* compression stream */ |
| int err; |
| #ifndef ZLIB_COMPAT |
| int level = -1; |
| int strategy = -1; |
| zng_deflate_param_value params[2]; |
| |
| params[0].param = Z_DEFLATE_LEVEL; |
| params[0].buf = &level; |
| params[0].size = sizeof(level); |
| |
| params[1].param = Z_DEFLATE_STRATEGY; |
| params[1].buf = &strategy; |
| params[1].size = sizeof(strategy); |
| #endif |
| |
| c_stream.zalloc = zalloc; |
| c_stream.zfree = zfree; |
| c_stream.opaque = (void *)0; |
| |
| err = PREFIX(deflateInit)(&c_stream, Z_BEST_SPEED); |
| CHECK_ERR(err, "deflateInit"); |
| |
| c_stream.next_out = compr; |
| c_stream.avail_out = (unsigned int)comprLen; |
| |
| /* At this point, uncompr is still mostly zeroes, so it should compress |
| * very well: |
| */ |
| c_stream.next_in = uncompr; |
| c_stream.avail_in = (unsigned int)uncomprLen; |
| err = PREFIX(deflate)(&c_stream, Z_NO_FLUSH); |
| CHECK_ERR(err, "deflate"); |
| if (c_stream.avail_in != 0) |
| error("deflate not greedy\n"); |
| |
| /* Feed in already compressed data and switch to no compression: */ |
| if (zng_params) { |
| #ifndef ZLIB_COMPAT |
| zng_deflateGetParams(&c_stream, params, sizeof(params) / sizeof(params[0])); |
| if (level != Z_BEST_SPEED) |
| error("Expected compression level Z_BEST_SPEED, got %d\n", level); |
| if (strategy != Z_DEFAULT_STRATEGY) |
| error("Expected compression strategy Z_DEFAULT_STRATEGY, got %d\n", strategy); |
| level = Z_NO_COMPRESSION; |
| strategy = Z_DEFAULT_STRATEGY; |
| zng_deflateSetParams(&c_stream, params, sizeof(params) / sizeof(params[0])); |
| #else |
| error("test_large_deflate() called with zng_params=1 in compat mode\n"); |
| #endif |
| } else { |
| PREFIX(deflateParams)(&c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY); |
| } |
| c_stream.next_in = compr; |
| diff = (unsigned int)(c_stream.next_out - compr); |
| c_stream.avail_in = diff; |
| err = PREFIX(deflate)(&c_stream, Z_NO_FLUSH); |
| CHECK_ERR(err, "deflate"); |
| |
| /* Switch back to compressing mode: */ |
| if (zng_params) { |
| #ifndef ZLIB_COMPAT |
| level = -1; |
| strategy = -1; |
| zng_deflateGetParams(&c_stream, params, sizeof(params) / sizeof(params[0])); |
| if (level != Z_NO_COMPRESSION) |
| error("Expected compression level Z_NO_COMPRESSION, got %d\n", level); |
| if (strategy != Z_DEFAULT_STRATEGY) |
| error("Expected compression strategy Z_DEFAULT_STRATEGY, got %d\n", strategy); |
| level = Z_BEST_COMPRESSION; |
| strategy = Z_FILTERED; |
| zng_deflateSetParams(&c_stream, params, sizeof(params) / sizeof(params[0])); |
| #else |
| error("test_large_deflate() called with zng_params=1 in compat mode\n"); |
| #endif |
| } else { |
| PREFIX(deflateParams)(&c_stream, Z_BEST_COMPRESSION, Z_FILTERED); |
| } |
| c_stream.next_in = uncompr; |
| c_stream.avail_in = (unsigned int)uncomprLen; |
| err = PREFIX(deflate)(&c_stream, Z_NO_FLUSH); |
| CHECK_ERR(err, "deflate"); |
| |
| err = PREFIX(deflate)(&c_stream, Z_FINISH); |
| if (err != Z_STREAM_END) |
| error("deflate should report Z_STREAM_END\n"); |
| err = PREFIX(deflateEnd)(&c_stream); |
| CHECK_ERR(err, "deflateEnd"); |
| } |
| |
| /* =========================================================================== |
| * Test inflate() with large buffers |
| */ |
| void test_large_inflate(unsigned char *compr, size_t comprLen, unsigned char *uncompr, size_t uncomprLen) { |
| int err; |
| PREFIX3(stream) d_stream; /* decompression stream */ |
| |
| strcpy((char*)uncompr, "garbage"); |
| |
| d_stream.zalloc = zalloc; |
| d_stream.zfree = zfree; |
| d_stream.opaque = (void *)0; |
| |
| d_stream.next_in = compr; |
| d_stream.avail_in = (unsigned int)comprLen; |
| d_stream.total_in = 0; |
| d_stream.total_out = 0; |
| |
| err = PREFIX(inflateInit)(&d_stream); |
| CHECK_ERR(err, "inflateInit"); |
| |
| for (;;) { |
| d_stream.next_out = uncompr; /* discard the output */ |
| d_stream.avail_out = (unsigned int)uncomprLen; |
| err = PREFIX(inflate)(&d_stream, Z_NO_FLUSH); |
| if (err == Z_STREAM_END) break; |
| CHECK_ERR(err, "large inflate"); |
| } |
| |
| err = PREFIX(inflateEnd)(&d_stream); |
| CHECK_ERR(err, "inflateEnd"); |
| |
| if (d_stream.total_out != 2*uncomprLen + diff) |
| error("bad large inflate: %" PRIu64 "\n", (uint64_t)d_stream.total_out); |
| else |
| printf("large_inflate(): OK\n"); |
| } |
| |
| /* =========================================================================== |
| * Test deflate() with full flush |
| */ |
| void test_flush(unsigned char *compr, z_size_t *comprLen) { |
| PREFIX3(stream) c_stream; /* compression stream */ |
| int err; |
| unsigned int len = (unsigned int)strlen(hello)+1; |
| |
| c_stream.zalloc = zalloc; |
| c_stream.zfree = zfree; |
| c_stream.opaque = (void *)0; |
| |
| err = PREFIX(deflateInit)(&c_stream, Z_DEFAULT_COMPRESSION); |
| CHECK_ERR(err, "deflateInit"); |
| |
| c_stream.next_in = (z_const unsigned char *)hello; |
| c_stream.next_out = compr; |
| c_stream.avail_in = 3; |
| c_stream.avail_out = (unsigned int)*comprLen; |
| err = PREFIX(deflate)(&c_stream, Z_FULL_FLUSH); |
| CHECK_ERR(err, "deflate"); |
| |
| compr[3]++; /* force an error in first compressed block */ |
| c_stream.avail_in = len - 3; |
| |
| err = PREFIX(deflate)(&c_stream, Z_FINISH); |
| if (err != Z_STREAM_END) { |
| CHECK_ERR(err, "deflate"); |
| } |
| err = PREFIX(deflateEnd)(&c_stream); |
| CHECK_ERR(err, "deflateEnd"); |
| |
| *comprLen = (z_size_t)c_stream.total_out; |
| } |
| |
| /* =========================================================================== |
| * Test inflateSync() |
| */ |
| void test_sync(unsigned char *compr, size_t comprLen, unsigned char *uncompr, size_t uncomprLen) { |
| int err; |
| PREFIX3(stream) d_stream; /* decompression stream */ |
| |
| strcpy((char*)uncompr, "garbage"); |
| |
| d_stream.zalloc = zalloc; |
| d_stream.zfree = zfree; |
| d_stream.opaque = (void *)0; |
| |
| d_stream.next_in = compr; |
| d_stream.avail_in = 2; /* just read the zlib header */ |
| |
| err = PREFIX(inflateInit)(&d_stream); |
| CHECK_ERR(err, "inflateInit"); |
| |
| d_stream.next_out = uncompr; |
| d_stream.avail_out = (unsigned int)uncomprLen; |
| |
| err = PREFIX(inflate)(&d_stream, Z_NO_FLUSH); |
| CHECK_ERR(err, "inflate"); |
| |
| d_stream.avail_in = (unsigned int)comprLen-2; /* read all compressed data */ |
| err = PREFIX(inflateSync)(&d_stream); /* but skip the damaged part */ |
| CHECK_ERR(err, "inflateSync"); |
| |
| err = PREFIX(inflate)(&d_stream, Z_FINISH); |
| if (err != Z_STREAM_END) |
| error("inflate should report Z_STREAM_END\n"); |
| err = PREFIX(inflateEnd)(&d_stream); |
| CHECK_ERR(err, "inflateEnd"); |
| |
| printf("after inflateSync(): hel%s\n", (char *)uncompr); |
| } |
| |
| /* =========================================================================== |
| * Test deflate() with preset dictionary |
| */ |
| void test_dict_deflate(unsigned char *compr, size_t comprLen) { |
| PREFIX3(stream) c_stream; /* compression stream */ |
| int err; |
| |
| c_stream.zalloc = zalloc; |
| c_stream.zfree = zfree; |
| c_stream.opaque = (void *)0; |
| c_stream.adler = 0; |
| |
| err = PREFIX(deflateInit)(&c_stream, Z_BEST_COMPRESSION); |
| CHECK_ERR(err, "deflateInit"); |
| |
| err = PREFIX(deflateSetDictionary)(&c_stream, |
| (const unsigned char*)dictionary, (int)sizeof(dictionary)); |
| CHECK_ERR(err, "deflateSetDictionary"); |
| |
| dictId = c_stream.adler; |
| c_stream.next_out = compr; |
| c_stream.avail_out = (unsigned int)comprLen; |
| |
| c_stream.next_in = (z_const unsigned char *)hello; |
| c_stream.avail_in = (unsigned int)strlen(hello)+1; |
| |
| err = PREFIX(deflate)(&c_stream, Z_FINISH); |
| if (err != Z_STREAM_END) |
| error("deflate should report Z_STREAM_END\n"); |
| err = PREFIX(deflateEnd)(&c_stream); |
| CHECK_ERR(err, "deflateEnd"); |
| } |
| |
| /* =========================================================================== |
| * Test inflate() with a preset dictionary |
| */ |
| void test_dict_inflate(unsigned char *compr, size_t comprLen, unsigned char *uncompr, size_t uncomprLen) { |
| int err; |
| uint8_t check_dictionary[MAX_DICTIONARY_SIZE]; |
| uint32_t check_dictionary_len = 0; |
| PREFIX3(stream) d_stream; /* decompression stream */ |
| |
| strcpy((char*)uncompr, "garbage garbage garbage"); |
| |
| d_stream.zalloc = zalloc; |
| d_stream.zfree = zfree; |
| d_stream.opaque = (void *)0; |
| d_stream.adler = 0; |
| d_stream.next_in = compr; |
| d_stream.avail_in = (unsigned int)comprLen; |
| |
| err = PREFIX(inflateInit)(&d_stream); |
| CHECK_ERR(err, "inflateInit"); |
| |
| d_stream.next_out = uncompr; |
| d_stream.avail_out = (unsigned int)uncomprLen; |
| |
| for (;;) { |
| err = PREFIX(inflate)(&d_stream, Z_NO_FLUSH); |
| if (err == Z_STREAM_END) break; |
| if (err == Z_NEED_DICT) { |
| if (d_stream.adler != dictId) |
| error("unexpected dictionary"); |
| err = PREFIX(inflateSetDictionary)(&d_stream, (const unsigned char*)dictionary, |
| (int)sizeof(dictionary)); |
| } |
| CHECK_ERR(err, "inflate with dict"); |
| } |
| |
| err = PREFIX(inflateGetDictionary)(&d_stream, NULL, &check_dictionary_len); |
| CHECK_ERR(err, "inflateGetDictionary"); |
| #ifndef S390_DFLTCC_INFLATE |
| if (check_dictionary_len < sizeof(dictionary)) |
| error("bad dictionary length\n"); |
| #endif |
| |
| err = PREFIX(inflateGetDictionary)(&d_stream, check_dictionary, &check_dictionary_len); |
| CHECK_ERR(err, "inflateGetDictionary"); |
| #ifndef S390_DFLTCC_INFLATE |
| if (memcmp(dictionary, check_dictionary, sizeof(dictionary)) != 0) |
| error("bad dictionary\n"); |
| #endif |
| |
| err = PREFIX(inflateEnd)(&d_stream); |
| CHECK_ERR(err, "inflateEnd"); |
| |
| if (strncmp((char*)uncompr, hello, sizeof(hello))) |
| error("bad inflate with dict\n"); |
| else |
| printf("inflate with dictionary: %s\n", (char *)uncompr); |
| } |
| |
| /* =========================================================================== |
| * Test deflateBound() with small buffers |
| */ |
| void test_deflate_bound(void) { |
| PREFIX3(stream) c_stream; /* compression stream */ |
| int err; |
| unsigned int len = (unsigned int)strlen(hello)+1; |
| int estimateLen = 0; |
| unsigned char *outBuf = NULL; |
| |
| c_stream.zalloc = zalloc; |
| c_stream.zfree = zfree; |
| c_stream.opaque = (voidpf)0; |
| c_stream.avail_in = len; |
| c_stream.next_in = (z_const unsigned char *)hello; |
| c_stream.avail_out = 0; |
| c_stream.next_out = outBuf; |
| |
| err = PREFIX(deflateInit)(&c_stream, Z_DEFAULT_COMPRESSION); |
| CHECK_ERR(err, "deflateInit"); |
| |
| /* calculate actual output length and update structure */ |
| estimateLen = PREFIX(deflateBound)(&c_stream, len); |
| outBuf = malloc(estimateLen); |
| |
| if (outBuf != NULL) { |
| /* update zlib configuration */ |
| c_stream.avail_out = estimateLen; |
| c_stream.next_out = outBuf; |
| |
| /* do the compression */ |
| err = PREFIX(deflate)(&c_stream, Z_FINISH); |
| if (err == Z_STREAM_END) { |
| printf("deflateBound(): OK\n"); |
| } else { |
| CHECK_ERR(err, "deflate"); |
| } |
| } |
| |
| err = PREFIX(deflateEnd)(&c_stream); |
| CHECK_ERR(err, "deflateEnd"); |
| |
| free(outBuf); |
| } |
| |
| /* =========================================================================== |
| * Test deflateCopy() with small buffers |
| */ |
| void test_deflate_copy(unsigned char *compr, size_t comprLen) { |
| PREFIX3(stream) c_stream, c_stream_copy; /* compression stream */ |
| int err; |
| size_t len = strlen(hello)+1; |
| |
| memset(&c_stream, 0, sizeof(c_stream)); |
| |
| c_stream.zalloc = zalloc; |
| c_stream.zfree = zfree; |
| c_stream.opaque = (voidpf)0; |
| |
| err = PREFIX(deflateInit)(&c_stream, Z_DEFAULT_COMPRESSION); |
| CHECK_ERR(err, "deflateInit"); |
| |
| c_stream.next_in = (z_const unsigned char *)hello; |
| c_stream.next_out = compr; |
| |
| while (c_stream.total_in != len && c_stream.total_out < comprLen) { |
| c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */ |
| err = PREFIX(deflate)(&c_stream, Z_NO_FLUSH); |
| CHECK_ERR(err, "deflate"); |
| } |
| |
| /* Finish the stream, still forcing small buffers: */ |
| for (;;) { |
| c_stream.avail_out = 1; |
| err = PREFIX(deflate)(&c_stream, Z_FINISH); |
| if (err == Z_STREAM_END) break; |
| CHECK_ERR(err, "deflate"); |
| } |
| |
| err = PREFIX(deflateCopy)(&c_stream_copy, &c_stream); |
| CHECK_ERR(err, "deflate_copy"); |
| |
| if (c_stream.state->status == c_stream_copy.state->status) { |
| printf("deflate_copy(): OK\n"); |
| } |
| |
| err = PREFIX(deflateEnd)(&c_stream); |
| CHECK_ERR(err, "deflateEnd original"); |
| |
| err = PREFIX(deflateEnd)(&c_stream_copy); |
| CHECK_ERR(err, "deflateEnd copy"); |
| } |
| |
| /* =========================================================================== |
| * Test deflateGetDictionary() with small buffers |
| */ |
| void test_deflate_get_dict(unsigned char *compr, size_t comprLen) { |
| PREFIX3(stream) c_stream; /* compression stream */ |
| int err; |
| unsigned char *dictNew = NULL; |
| unsigned int *dictLen; |
| |
| c_stream.zalloc = zalloc; |
| c_stream.zfree = zfree; |
| c_stream.opaque = (voidpf)0; |
| |
| err = PREFIX(deflateInit)(&c_stream, Z_BEST_COMPRESSION); |
| CHECK_ERR(err, "deflateInit"); |
| |
| c_stream.next_out = compr; |
| c_stream.avail_out = (uInt)comprLen; |
| |
| c_stream.next_in = (z_const unsigned char *)hello; |
| c_stream.avail_in = (unsigned int)strlen(hello)+1; |
| |
| err = PREFIX(deflate)(&c_stream, Z_FINISH); |
| |
| if (err != Z_STREAM_END) |
| error("deflate should report Z_STREAM_END\n"); |
| |
| dictNew = calloc(256, 1); |
| dictLen = (unsigned int *)calloc(4, 1); |
| err = PREFIX(deflateGetDictionary)(&c_stream, dictNew, dictLen); |
| |
| CHECK_ERR(err, "deflateGetDictionary"); |
| if (err == Z_OK) { |
| printf("deflateGetDictionary(): %s\n", dictNew); |
| } |
| |
| err = PREFIX(deflateEnd)(&c_stream); |
| CHECK_ERR(err, "deflateEnd"); |
| |
| free(dictNew); |
| free(dictLen); |
| } |
| |
| /* =========================================================================== |
| * Test deflatePending() with small buffers |
| */ |
| void test_deflate_pending(unsigned char *compr, size_t comprLen) { |
| PREFIX3(stream) c_stream; /* compression stream */ |
| int err; |
| int *bits = calloc(256, 1); |
| unsigned *ped = calloc(256, 1); |
| size_t len = strlen(hello)+1; |
| |
| |
| c_stream.zalloc = zalloc; |
| c_stream.zfree = zfree; |
| c_stream.opaque = (voidpf)0; |
| |
| err = PREFIX(deflateInit)(&c_stream, Z_DEFAULT_COMPRESSION); |
| CHECK_ERR(err, "deflateInit"); |
| |
| c_stream.next_in = (z_const unsigned char *)hello; |
| c_stream.next_out = compr; |
| |
| while (c_stream.total_in != len && c_stream.total_out < comprLen) { |
| c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */ |
| err = PREFIX(deflate)(&c_stream, Z_NO_FLUSH); |
| CHECK_ERR(err, "deflate"); |
| } |
| |
| err = PREFIX(deflatePending)(&c_stream, ped, bits); |
| CHECK_ERR(err, "deflatePending"); |
| |
| if (*bits >= 0 && *bits <= 7) { |
| printf("deflatePending(): OK\n"); |
| } else { |
| printf("deflatePending(): error\n"); |
| } |
| |
| /* Finish the stream, still forcing small buffers: */ |
| for (;;) { |
| c_stream.avail_out = 1; |
| err = PREFIX(deflate)(&c_stream, Z_FINISH); |
| if (err == Z_STREAM_END) break; |
| CHECK_ERR(err, "deflate"); |
| } |
| |
| err = PREFIX(deflateEnd)(&c_stream); |
| CHECK_ERR(err, "deflateEnd"); |
| |
| free(bits); |
| free(ped); |
| } |
| |
| /* =========================================================================== |
| * Test deflatePrime() wrapping gzip around deflate stream |
| */ |
| void test_deflate_prime(unsigned char *compr, size_t comprLen, unsigned char *uncompr, size_t uncomprLen) { |
| PREFIX3(stream) c_stream; /* compression stream */ |
| PREFIX3(stream) d_stream; /* decompression stream */ |
| int err; |
| size_t len = strlen(hello)+1; |
| uint32_t crc = 0; |
| |
| |
| c_stream.zalloc = zalloc; |
| c_stream.zfree = zfree; |
| c_stream.opaque = (voidpf)0; |
| |
| /* Raw deflate windowBits is -15 */ |
| err = PREFIX(deflateInit2)(&c_stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY); |
| CHECK_ERR(err, "deflateInit2"); |
| |
| /* Gzip magic number */ |
| err = PREFIX(deflatePrime)(&c_stream, 16, 0x8b1f); |
| CHECK_ERR(err, "deflatePrime"); |
| /* Gzip compression method (deflate) */ |
| err = PREFIX(deflatePrime)(&c_stream, 8, 0x08); |
| CHECK_ERR(err, "deflatePrime"); |
| /* Gzip flags (one byte, using two odd bit calls) */ |
| err = PREFIX(deflatePrime)(&c_stream, 3, 0x0); |
| CHECK_ERR(err, "deflatePrime"); |
| err = PREFIX(deflatePrime)(&c_stream, 5, 0x0); |
| CHECK_ERR(err, "deflatePrime"); |
| /* Gzip modified time */ |
| err = PREFIX(deflatePrime)(&c_stream, 32, 0x0); |
| CHECK_ERR(err, "deflatePrime"); |
| /* Gzip extra flags */ |
| err = PREFIX(deflatePrime)(&c_stream, 8, 0x0); |
| CHECK_ERR(err, "deflatePrime"); |
| /* Gzip operating system */ |
| err = PREFIX(deflatePrime)(&c_stream, 8, 255); |
| CHECK_ERR(err, "deflatePrime"); |
| |
| c_stream.next_in = (z_const unsigned char *)hello; |
| c_stream.avail_in = (uint32_t)len; |
| c_stream.next_out = compr; |
| c_stream.avail_out = (uint32_t)comprLen; |
| |
| err = PREFIX(deflate)(&c_stream, Z_FINISH); |
| if (err != Z_STREAM_END) |
| CHECK_ERR(err, "deflate"); |
| |
| /* Gzip uncompressed data crc32 */ |
| crc = PREFIX(crc32)(0, (const uint8_t *)hello, (uint32_t)len); |
| err = PREFIX(deflatePrime)(&c_stream, 32, crc); |
| CHECK_ERR(err, "deflatePrime"); |
| /* Gzip uncompressed data length */ |
| err = PREFIX(deflatePrime)(&c_stream, 32, (uint32_t)len); |
| CHECK_ERR(err, "deflatePrime"); |
| |
| err = PREFIX(deflateEnd)(&c_stream); |
| CHECK_ERR(err, "deflateEnd"); |
| |
| d_stream.zalloc = zalloc; |
| d_stream.zfree = zfree; |
| d_stream.opaque = (void *)0; |
| |
| d_stream.next_in = compr; |
| d_stream.avail_in = (uint32_t)c_stream.total_out; |
| d_stream.next_out = uncompr; |
| d_stream.avail_out = (uint32_t)uncomprLen; |
| d_stream.total_in = 0; |
| d_stream.total_out = 0; |
| |
| /* Inflate with gzip header */ |
| err = PREFIX(inflateInit2)(&d_stream, MAX_WBITS + 32); |
| CHECK_ERR(err, "inflateInit"); |
| |
| err = PREFIX(inflate)(&d_stream, Z_FINISH); |
| if (err != Z_BUF_ERROR) { |
| CHECK_ERR(err, "inflate"); |
| } |
| |
| err = PREFIX(inflateEnd)(&d_stream); |
| CHECK_ERR(err, "inflateEnd"); |
| |
| if (strcmp((const char *)uncompr, hello) != 0) |
| error("bad deflatePrime\n"); |
| if (err == Z_OK) |
| printf("deflatePrime(): OK\n"); |
| } |
| |
| /* =========================================================================== |
| * Test deflateSetHeader() with small buffers |
| */ |
| void test_deflate_set_header(unsigned char *compr, size_t comprLen) { |
| PREFIX(gz_header) *head = calloc(1, sizeof(PREFIX(gz_header))); |
| PREFIX3(stream) c_stream; /* compression stream */ |
| int err; |
| size_t len = strlen(hello)+1; |
| |
| |
| if (head == NULL) |
| error("out of memory\n"); |
| |
| c_stream.zalloc = zalloc; |
| c_stream.zfree = zfree; |
| c_stream.opaque = (voidpf)0; |
| |
| /* gzip */ |
| err = PREFIX(deflateInit2)(&c_stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, MAX_WBITS + 16, 8, Z_DEFAULT_STRATEGY); |
| CHECK_ERR(err, "deflateInit2"); |
| |
| head->text = 1; |
| head->comment = (uint8_t *)"comment"; |
| head->name = (uint8_t *)"name"; |
| head->hcrc = 1; |
| head->extra = (uint8_t *)"extra"; |
| head->extra_len = (uint32_t)strlen((const char *)head->extra); |
| |
| err = PREFIX(deflateSetHeader)(&c_stream, head); |
| CHECK_ERR(err, "deflateSetHeader"); |
| if (err == Z_OK) { |
| printf("deflateSetHeader(): OK\n"); |
| } |
| PREFIX(deflateBound)(&c_stream, (unsigned long)comprLen); |
| |
| c_stream.next_in = (unsigned char *)hello; |
| c_stream.next_out = compr; |
| |
| while (c_stream.total_in != len && c_stream.total_out < comprLen) { |
| c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */ |
| err = PREFIX(deflate)(&c_stream, Z_NO_FLUSH); |
| CHECK_ERR(err, "deflate"); |
| } |
| |
| /* Finish the stream, still forcing small buffers: */ |
| for (;;) { |
| c_stream.avail_out = 1; |
| err = PREFIX(deflate)(&c_stream, Z_FINISH); |
| if (err == Z_STREAM_END) break; |
| CHECK_ERR(err, "deflate"); |
| } |
| |
| err = PREFIX(deflateEnd)(&c_stream); |
| CHECK_ERR(err, "deflateEnd"); |
| |
| free(head); |
| } |
| |
| /* =========================================================================== |
| * Test deflateTune() with small buffers |
| */ |
| void test_deflate_tune(unsigned char *compr, size_t comprLen) { |
| PREFIX3(stream) c_stream; /* compression stream */ |
| int err; |
| int good_length = 3; |
| int max_lazy = 5; |
| int nice_length = 18; |
| int max_chain = 6; |
| size_t len = strlen(hello)+1; |
| |
| |
| c_stream.zalloc = zalloc; |
| c_stream.zfree = zfree; |
| c_stream.opaque = (voidpf)0; |
| |
| err = PREFIX(deflateInit)(&c_stream, Z_BEST_COMPRESSION); |
| CHECK_ERR(err, "deflateInit"); |
| |
| err = PREFIX(deflateTune)(&c_stream,(uInt)good_length,(uInt)max_lazy,nice_length,(uInt)max_chain); |
| CHECK_ERR(err, "deflateTune"); |
| if (err == Z_OK) { |
| printf("deflateTune(): OK\n"); |
| } |
| |
| c_stream.next_in = (z_const unsigned char *)hello; |
| c_stream.next_out = compr; |
| |
| while (c_stream.total_in != len && c_stream.total_out < comprLen) { |
| c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */ |
| err = PREFIX(deflate)(&c_stream, Z_NO_FLUSH); |
| CHECK_ERR(err, "deflate"); |
| } |
| |
| /* Finish the stream, still forcing small buffers: */ |
| for (;;) { |
| c_stream.avail_out = 1; |
| err = PREFIX(deflate)(&c_stream, Z_FINISH); |
| if (err == Z_STREAM_END) break; |
| CHECK_ERR(err, "deflate"); |
| } |
| |
| err = PREFIX(deflateEnd)(&c_stream); |
| CHECK_ERR(err, "deflateEnd"); |
| } |
| |
| /* =========================================================================== |
| * Usage: example [output.gz [input.gz]] |
| */ |
| int main(int argc, char *argv[]) { |
| unsigned char *compr, *uncompr; |
| z_size_t comprLen = 10000*sizeof(int); /* don't overflow on MSDOS */ |
| z_size_t uncomprLen = comprLen; |
| static const char* myVersion = PREFIX2(VERSION); |
| |
| if (zVersion()[0] != myVersion[0]) { |
| fprintf(stderr, "incompatible zlib version\n"); |
| exit(1); |
| |
| } else if (strcmp(zVersion(), PREFIX2(VERSION)) != 0) { |
| fprintf(stderr, "warning: different zlib version\n"); |
| } |
| |
| printf("zlib-ng version %s = 0x%08lx, compile flags = 0x%lx\n", |
| ZLIBNG_VERSION, ZLIBNG_VERNUM, PREFIX(zlibCompileFlags)()); |
| |
| compr = (unsigned char*)calloc((unsigned int)comprLen, 1); |
| uncompr = (unsigned char*)calloc((unsigned int)uncomprLen, 1); |
| /* compr and uncompr are cleared to avoid reading uninitialized |
| * data and to ensure that uncompr compresses well. |
| */ |
| if (compr == NULL || uncompr == NULL) |
| error("out of memory\n"); |
| |
| test_compress(compr, comprLen, uncompr, uncomprLen); |
| |
| test_gzio((argc > 1 ? argv[1] : TESTFILE), |
| uncompr, uncomprLen); |
| |
| test_deflate(compr, comprLen); |
| test_inflate(compr, comprLen, uncompr, uncomprLen); |
| |
| test_large_deflate(compr, comprLen, uncompr, uncomprLen, 0); |
| test_large_inflate(compr, comprLen, uncompr, uncomprLen); |
| |
| #ifndef ZLIB_COMPAT |
| test_large_deflate(compr, comprLen, uncompr, uncomprLen, 1); |
| test_large_inflate(compr, comprLen, uncompr, uncomprLen); |
| #endif |
| |
| test_flush(compr, &comprLen); |
| test_sync(compr, comprLen, uncompr, uncomprLen); |
| comprLen = uncomprLen; |
| |
| test_dict_deflate(compr, comprLen); |
| test_dict_inflate(compr, comprLen, uncompr, uncomprLen); |
| |
| test_deflate_bound(); |
| test_deflate_copy(compr, comprLen); |
| test_deflate_get_dict(compr, comprLen); |
| test_deflate_set_header(compr, comprLen); |
| test_deflate_tune(compr, comprLen); |
| test_deflate_pending(compr, comprLen); |
| test_deflate_prime(compr, comprLen, uncompr, uncomprLen); |
| |
| free(compr); |
| free(uncompr); |
| |
| return 0; |
| } |