Skip to content

Instantly share code, notes, and snippets.

@nmoinvaz
Last active May 25, 2020 13:45
Show Gist options
  • Save nmoinvaz/fb9f806955b9dec77c09d3ec986c9442 to your computer and use it in GitHub Desktop.
Save nmoinvaz/fb9f806955b9dec77c09d3ec986c9442 to your computer and use it in GitHub Desktop.
Zlib-ng deflate parameter testing tool
/* deflateparams.c -- test deflate under specific conditions
* Copyright (C) 2020 Nathan Moinvaziri
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/*
add_executable(deflateparams test/deflateparams.c)
configure_test_executable(deflateparams)
target_link_libraries(deflateparams zlib)
*/
#include <stdio.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <inttypes.h>
#include "zbuild.h"
#ifdef ZLIB_COMPAT
# include "zlib.h"
#else
# include "zlib-ng.h"
#endif
#if defined(WIN32) || defined(__CYGWIN__)
# include <fcntl.h>
# include <io.h>
# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
#else
# define SET_BINARY_MODE(file)
#endif
#if MAX_MEM_LEVEL >= 8
# define DEF_MEM_LEVEL 8
#else
# define DEF_MEM_LEVEL MAX_MEM_LEVEL
#endif
#define CHECK_ERR(err, msg) { \
if (err != Z_OK) { \
fprintf(stderr, "%s error: %d\n", msg, err); \
exit(1); \
} \
}
static alloc_func zalloc = NULL;
static free_func zfree = NULL;
/* ===========================================================================
* deflate() using small buffers
*/
void deflate_params_small(unsigned char *buf, uint32_t len, int level, int window_bits, int mem_level, int strategy)
{
PREFIX3(stream) c_stream; /* compression stream */
unsigned char compr[4096];
int err;
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(deflateInit2)(&c_stream, level, Z_DEFLATED, window_bits, mem_level, strategy);
CHECK_ERR(err, "deflateInit2");
c_stream.next_in = (const unsigned char *)buf;
c_stream.next_out = (unsigned char *)compr;
while (c_stream.total_in < len) {
c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */
err = PREFIX(deflate)(&c_stream, Z_NO_FLUSH);
CHECK_ERR(err, "deflate");
if (c_stream.next_out == compr + sizeof(compr)) {
fwrite(compr, 1, (size_t)sizeof(compr), stdout);
c_stream.next_out = (unsigned char *)compr;
}
}
/* Finish the stream, still forcing small buffers: */
c_stream.avail_in = 0;
do {
if (c_stream.next_out == compr + sizeof(compr)) {
fwrite(compr, 1, (size_t)sizeof(compr), stdout);
c_stream.next_out = (unsigned char *)compr;
}
c_stream.avail_out = 1; /* force small buffers */
err = PREFIX(deflate)(&c_stream, Z_FINISH);
if (err == Z_STREAM_END) break;
CHECK_ERR(err, "deflate");
} while (err == Z_OK);
if (c_stream.next_out != compr) {
fwrite(compr, 1, c_stream.next_out - compr, stdout);
}
err = PREFIX(deflateEnd)(&c_stream);
CHECK_ERR(err, "deflateEnd");
}
/* ===========================================================================
* deflate() with large buffers
*/
void deflate_params_large(unsigned char *buf, uint32_t len, int level, int window_bits, int mem_level, int strategy)
{
PREFIX3(stream) c_stream; /* compression stream */
unsigned char compr[4096];
int err;
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(deflateInit2)(&c_stream, level, Z_DEFLATED, window_bits, mem_level, strategy);
CHECK_ERR(err, "deflateInit2");
c_stream.next_in = (const unsigned char *)buf;
c_stream.next_out = (unsigned char *)compr;
while (c_stream.total_in < len) {
c_stream.avail_in = c_stream.avail_out = sizeof(compr); /* Force large buffers */
if (c_stream.avail_in > (len - c_stream.total_in))
c_stream.avail_in = (len - c_stream.total_in);
err = PREFIX(deflate)(&c_stream, Z_NO_FLUSH);
CHECK_ERR(err, "deflate");
fwrite(compr, 1, c_stream.next_out - compr, stdout);
}
/* Finish the stream using large buffers */
c_stream.avail_in = 0;
do {
c_stream.avail_out = sizeof(compr);
err = PREFIX(deflate)(&c_stream, Z_FINISH);
fwrite(compr, 1, c_stream.next_out - compr, stdout);
if (err == Z_STREAM_END) break;
CHECK_ERR(err, "deflate");
} while (err == Z_OK);
err = PREFIX(deflateEnd)(&c_stream);
CHECK_ERR(err, "deflateEnd");
}
/* ===========================================================================
* deflate() with params
*/
void deflate_params(unsigned char *buf, uint32_t len, int level, int window_bits, int mem_level, int strategy)
{
PREFIX3(stream) c_stream; /* compression stream */
size_t compr_bound;
unsigned char *compr;
int err;
c_stream.zalloc = zalloc;
c_stream.zfree = zfree;
c_stream.opaque = (void *)0;
c_stream.total_in = 0;
c_stream.total_out = 0;
compr_bound = PREFIX(compressBound)(len);
compr = malloc(compr_bound);
assert(compr != NULL);
err = PREFIX(deflateInit2)(&c_stream, level, Z_DEFLATED, window_bits, mem_level, strategy);
CHECK_ERR(err, "deflateInit2");
c_stream.next_in = (const unsigned char *)buf;
c_stream.avail_in = len;
c_stream.next_out = compr;
c_stream.avail_out = (uint32_t)compr_bound;
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");
fwrite(compr, 1, c_stream.total_out, stdout);
free(compr);
}
/* ===========================================================================
* Usage: deflateparams [-f] [-h] [-R] [-F] [-m 1 to 8] [-s] [-l] [-w #] [-0 to -9] [input file]
* -f : compress with Z_FILTERED
* -h : compress with Z_HUFFMAN_ONLY
* -R : compress with Z_RLE
* -F : compress with Z_FIXED
* -m : memory level 1-8
* -s : small buffer
* -l : large buffer
* -w : window bits
* -0 to -9 : compression level
*/
int main(int argc, char **argv) {
int32_t i;
int32_t mem_level = DEF_MEM_LEVEL;
int32_t window_bits = MAX_WBITS;
int32_t strategy = Z_DEFAULT_STRATEGY;
int32_t level = 6;
uint8_t small_buf = 0;
uint8_t large_buf = 0;
size_t len, read;
unsigned char *buf;
FILE *f;
for (i = 1; i < argc; i++) {
if ((strcmp(argv[i], "-m") == 0) && (i + 1 < argc))
mem_level = atoi(argv[++i]);
else if ((strcmp(argv[i], "-w") == 0) && (i + 1 < argc))
window_bits = atoi(argv[++i]);
else if (strcmp(argv[i], "-s") == 0)
small_buf = 1;
else if (strcmp(argv[i], "-l") == 0)
large_buf = 1;
else if (strcmp(argv[i], "-f") == 0)
strategy = Z_FILTERED;
else if (strcmp(argv[i], "-h") == 0)
strategy = Z_HUFFMAN_ONLY;
else if (strcmp(argv[i], "-R") == 0)
strategy = Z_RLE;
else if (argv[i][0] == '-' && argv[i][1] >= '0' && argv[i][1] <= '9' && argv[i][2] == 0)
level = argv[i][1] - '0';
else
break;
}
printf("deflateParams: level %d memLevel %d windowBits %d strategy %d\n", level, mem_level,
window_bits, strategy);
if (i == argc) {
fprintf(stderr, "No input file specified\n");
exit(1);
}
SET_BINARY_MODE(stdout);
f = fopen(argv[i], "rb+");
if (f == NULL) {
/* Failed to open this file: it may be a directory. */
fprintf(stderr, "Failed to open file: %s\n", argv[i]);
exit(1);
}
fseek(f, 0, SEEK_END);
len = ftell(f);
fseek(f, 0, SEEK_SET);
buf = (unsigned char *)malloc(len);
read = fread(buf, 1, len, f);
assert(read == len);
if (small_buf) {
deflate_params_small(buf, len, level, window_bits, mem_level, strategy);
} else if (large_buf) {
deflate_params_large(buf, len, level, window_bits, mem_level, strategy);
} else {
deflate_params(buf, len, level, window_bits, mem_level, strategy);
}
free(buf);
fclose(f);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment