Bump bundled libarchive version to 3.5.2

- Update bunlded libarchive version used on Windows/Mac
- Enable requested zstd support while we are at it. Closes #211
This commit is contained in:
Floris Bos 2021-12-09 12:22:14 +01:00
parent 03e083b4f3
commit 67618a2eac
1869 changed files with 166685 additions and 9489 deletions

View file

@ -0,0 +1,629 @@
/* example.c contains minimal changes required to be compiled with zlibWrapper:
* - #include "zlib.h" was changed to #include "zstd_zlibwrapper.h"
* - test_flush() and test_sync() use functions not supported by zlibWrapper
therefore they are disabled while zstd compression is turned on */
/* example.c -- usage example of the zlib compression library
*/
/*
Copyright (c) 1995-2006, 2011 Jean-loup Gailly
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgement in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/* @(#) $Id$ */
#include "zstd_zlibwrapper.h"
#include <stdio.h>
#ifdef STDC
# include <string.h>
# include <stdlib.h>
#endif
#if defined(VMS) || defined(RISCOS)
# define TESTFILE "foo-gz"
#else
# define TESTFILE "foo.gz"
#endif
#define CHECK_ERR(err, msg) { \
if (err != Z_OK) { \
fprintf(stderr, "%s error: %d\n", msg, err); \
exit(1); \
} \
}
z_const char hello[] = "hello, hello! I said hello, hello!";
/* "hello world" would be more standard, but the repeated "hello"
* stresses the compression code better, sorry...
*/
const char dictionary[] = "hello, hello!";
uLong dictId; /* Adler32 value of the dictionary */
void test_deflate OF((Byte *compr, uLong comprLen));
void test_inflate OF((Byte *compr, uLong comprLen,
Byte *uncompr, uLong uncomprLen));
void test_large_deflate OF((Byte *compr, uLong comprLen,
Byte *uncompr, uLong uncomprLen));
void test_large_inflate OF((Byte *compr, uLong comprLen,
Byte *uncompr, uLong uncomprLen));
void test_flush OF((Byte *compr, uLong *comprLen));
void test_sync OF((Byte *compr, uLong comprLen,
Byte *uncompr, uLong uncomprLen));
void test_dict_deflate OF((Byte *compr, uLong comprLen));
void test_dict_inflate OF((Byte *compr, uLong comprLen,
Byte *uncompr, uLong uncomprLen));
int main OF((int argc, char *argv[]));
#ifdef Z_SOLO
void *myalloc OF((void *, unsigned, unsigned));
void myfree OF((void *, void *));
void *myalloc(q, n, m)
void *q;
unsigned n, m;
{
void *buf = calloc(n, m);
q = Z_NULL;
/* printf("myalloc %p n=%d m=%d\n", buf, n, m); */
return buf;
}
void myfree(void *q, void *p)
{
/* printf("myfree %p\n", p); */
q = Z_NULL;
free(p);
}
static alloc_func zalloc = myalloc;
static free_func zfree = myfree;
#else /* !Z_SOLO */
static alloc_func zalloc = (alloc_func)0;
static free_func zfree = (free_func)0;
void test_compress OF((Byte *compr, uLong comprLen,
Byte *uncompr, uLong uncomprLen));
void test_gzio OF((const char *fname,
Byte *uncompr, uLong uncomprLen));
/* ===========================================================================
* Test compress() and uncompress()
*/
void test_compress(compr, comprLen, uncompr, uncomprLen)
Byte *compr, *uncompr;
uLong comprLen, uncomprLen;
{
int err;
uLong len = (uLong)strlen(hello)+1;
err = compress(compr, &comprLen, (const Bytef*)hello, len);
CHECK_ERR(err, "compress");
strcpy((char*)uncompr, "garbage");
err = uncompress(uncompr, &uncomprLen, compr, comprLen);
CHECK_ERR(err, "uncompress");
if (strcmp((char*)uncompr, hello)) {
fprintf(stderr, "bad uncompress\n");
exit(1);
} else {
printf("uncompress(): %s\n", (char *)uncompr);
}
}
/* ===========================================================================
* Test read/write of .gz files
*/
void test_gzio(fname, uncompr, uncomprLen)
const char *fname; /* compressed file name */
Byte *uncompr;
uLong uncomprLen;
{
#ifdef NO_GZCOMPRESS
fprintf(stderr, "NO_GZCOMPRESS -- gz* functions cannot compress\n");
#else
int err;
int len = (int)strlen(hello)+1;
gzFile file;
z_off_t pos;
file = gzopen(fname, "wb");
if (file == NULL) {
fprintf(stderr, "gzopen error\n");
exit(1);
}
gzputc(file, 'h');
if (gzputs(file, "ello") != 4) {
fprintf(stderr, "gzputs err: %s\n", gzerror(file, &err));
exit(1);
}
if (gzprintf(file, ", %s! I said hello, hello!", "hello") != 8+21) {
fprintf(stderr, "gzprintf err: %s\n", gzerror(file, &err));
exit(1);
}
gzseek(file, 1L, SEEK_CUR); /* add one zero byte */
gzclose(file);
file = gzopen(fname, "rb");
if (file == NULL) {
fprintf(stderr, "gzopen error\n");
exit(1);
}
strcpy((char*)uncompr, "garbage");
if (gzread(file, uncompr, (unsigned)uncomprLen) != len) {
fprintf(stderr, "gzread err: %s\n", gzerror(file, &err));
exit(1);
}
if (strcmp((char*)uncompr, hello)) {
fprintf(stderr, "bad gzread: %s\n", (char*)uncompr);
exit(1);
} else {
printf("gzread(): %s\n", (char*)uncompr);
}
pos = gzseek(file, -8L, SEEK_CUR);
if (pos != 6+21 || gztell(file) != pos) {
fprintf(stderr, "gzseek error, pos=%ld, gztell=%ld\n",
(long)pos, (long)gztell(file));
exit(1);
}
if (gzgetc(file) != ' ') {
fprintf(stderr, "gzgetc error\n");
exit(1);
}
if (gzungetc(' ', file) != ' ') {
fprintf(stderr, "gzungetc error\n");
exit(1);
}
gzgets(file, (char*)uncompr, (int)uncomprLen);
if (strlen((char*)uncompr) != 7) { /* " hello!" */
fprintf(stderr, "gzgets err after gzseek: %s\n", gzerror(file, &err));
exit(1);
}
if (strcmp((char*)uncompr, hello + 6+21)) {
fprintf(stderr, "bad gzgets after gzseek\n");
exit(1);
} else {
printf("gzgets() after gzseek: %s\n", (char*)uncompr);
}
gzclose(file);
#endif
}
#endif /* Z_SOLO */
/* ===========================================================================
* Test deflate() with small buffers
*/
void test_deflate(compr, comprLen)
Byte *compr;
uLong comprLen;
{
z_stream c_stream; /* compression stream */
int err;
uLong len = (uLong)strlen(hello)+1;
c_stream.zalloc = zalloc;
c_stream.zfree = zfree;
c_stream.opaque = (voidpf)0;
err = 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 = deflate(&c_stream, Z_NO_FLUSH);
CHECK_ERR(err, "deflate");
}
/* Finish the stream, still forcing small buffers: */
for (;;) {
c_stream.avail_out = 1;
err = deflate(&c_stream, Z_FINISH);
if (err == Z_STREAM_END) break;
CHECK_ERR(err, "deflate");
}
err = deflateEnd(&c_stream);
CHECK_ERR(err, "deflateEnd");
}
/* ===========================================================================
* Test inflate() with small buffers
*/
void test_inflate(compr, comprLen, uncompr, uncomprLen)
Byte *compr, *uncompr;
uLong comprLen, uncomprLen;
{
int err;
z_stream d_stream; /* decompression stream */
strcpy((char*)uncompr, "garbage");
d_stream.zalloc = zalloc;
d_stream.zfree = zfree;
d_stream.opaque = (voidpf)0;
d_stream.next_in = compr;
d_stream.avail_in = 0;
d_stream.next_out = uncompr;
err = 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 = inflate(&d_stream, Z_NO_FLUSH);
if (err == Z_STREAM_END) break;
CHECK_ERR(err, "inflate");
}
err = inflateEnd(&d_stream);
CHECK_ERR(err, "inflateEnd");
if (strcmp((char*)uncompr, hello)) {
fprintf(stderr, "bad inflate\n");
exit(1);
} else {
printf("inflate(): %s\n", (char *)uncompr);
}
}
/* ===========================================================================
* Test deflate() with large buffers and dynamic change of compression level
*/
void test_large_deflate(compr, comprLen, uncompr, uncomprLen)
Byte *compr, *uncompr;
uLong comprLen, uncomprLen;
{
z_stream c_stream; /* compression stream */
int err;
c_stream.zalloc = zalloc;
c_stream.zfree = zfree;
c_stream.opaque = (voidpf)0;
err = deflateInit(&c_stream, Z_BEST_SPEED);
CHECK_ERR(err, "deflateInit");
c_stream.next_out = compr;
c_stream.avail_out = (uInt)comprLen;
/* At this point, uncompr is still mostly zeroes, so it should compress
* very well:
*/
c_stream.next_in = uncompr;
c_stream.avail_in = (uInt)uncomprLen;
err = deflate(&c_stream, Z_NO_FLUSH);
CHECK_ERR(err, "deflate");
if (c_stream.avail_in != 0) {
fprintf(stderr, "deflate not greedy\n");
exit(1);
}
/* Feed in already compressed data and switch to no compression: */
deflateParams(&c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY);
c_stream.next_in = compr;
c_stream.avail_in = (uInt)comprLen/2;
err = deflate(&c_stream, Z_NO_FLUSH);
CHECK_ERR(err, "deflate");
/* Switch back to compressing mode: */
deflateParams(&c_stream, Z_BEST_COMPRESSION, Z_FILTERED);
c_stream.next_in = uncompr;
c_stream.avail_in = (uInt)uncomprLen;
err = deflate(&c_stream, Z_NO_FLUSH);
CHECK_ERR(err, "deflate");
err = deflate(&c_stream, Z_FINISH);
if (err != Z_STREAM_END) {
fprintf(stderr, "deflate should report Z_STREAM_END\n");
exit(1);
}
err = deflateEnd(&c_stream);
CHECK_ERR(err, "deflateEnd");
}
/* ===========================================================================
* Test inflate() with large buffers
*/
void test_large_inflate(compr, comprLen, uncompr, uncomprLen)
Byte *compr, *uncompr;
uLong comprLen, uncomprLen;
{
int err;
z_stream d_stream; /* decompression stream */
strcpy((char*)uncompr, "garbage");
d_stream.zalloc = zalloc;
d_stream.zfree = zfree;
d_stream.opaque = (voidpf)0;
d_stream.next_in = compr;
d_stream.avail_in = (uInt)comprLen;
err = inflateInit(&d_stream);
CHECK_ERR(err, "inflateInit");
for (;;) {
d_stream.next_out = uncompr; /* discard the output */
d_stream.avail_out = (uInt)uncomprLen;
err = inflate(&d_stream, Z_NO_FLUSH);
if (err == Z_STREAM_END) break;
CHECK_ERR(err, "large inflate");
}
err = inflateEnd(&d_stream);
CHECK_ERR(err, "inflateEnd");
if (d_stream.total_out != 2*uncomprLen + comprLen/2) {
fprintf(stderr, "bad large inflate: %ld\n", d_stream.total_out);
exit(1);
} else {
printf("large_inflate(): OK\n");
}
}
/* ===========================================================================
* Test deflate() with full flush
*/
void test_flush(compr, comprLen)
Byte *compr;
uLong *comprLen;
{
z_stream c_stream; /* compression stream */
int err;
uInt len = (uInt)strlen(hello)+1;
c_stream.zalloc = zalloc;
c_stream.zfree = zfree;
c_stream.opaque = (voidpf)0;
err = 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 = (uInt)*comprLen;
err = 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 = deflate(&c_stream, Z_FINISH);
if (err != Z_STREAM_END) {
CHECK_ERR(err, "deflate");
}
err = deflateEnd(&c_stream);
CHECK_ERR(err, "deflateEnd");
*comprLen = c_stream.total_out;
}
/* ===========================================================================
* Test inflateSync()
*/
void test_sync(compr, comprLen, uncompr, uncomprLen)
Byte *compr, *uncompr;
uLong comprLen, uncomprLen;
{
int err;
z_stream d_stream; /* decompression stream */
strcpy((char*)uncompr, "garbage");
d_stream.zalloc = zalloc;
d_stream.zfree = zfree;
d_stream.opaque = (voidpf)0;
d_stream.next_in = compr;
d_stream.avail_in = 2; /* just read the zlib header */
err = inflateInit(&d_stream);
CHECK_ERR(err, "inflateInit");
d_stream.next_out = uncompr;
d_stream.avail_out = (uInt)uncomprLen;
inflate(&d_stream, Z_NO_FLUSH);
CHECK_ERR(err, "inflate");
d_stream.avail_in = (uInt)comprLen-2; /* read all compressed data */
err = inflateSync(&d_stream); /* but skip the damaged part */
CHECK_ERR(err, "inflateSync");
err = inflate(&d_stream, Z_FINISH);
if (err != Z_DATA_ERROR) {
fprintf(stderr, "inflate should report DATA_ERROR\n");
/* Because of incorrect adler32 */
exit(1);
}
err = inflateEnd(&d_stream);
CHECK_ERR(err, "inflateEnd");
printf("after inflateSync(): hel%s\n", (char *)uncompr);
}
/* ===========================================================================
* Test deflate() with preset dictionary
*/
void test_dict_deflate(compr, comprLen)
Byte *compr;
uLong comprLen;
{
z_stream c_stream; /* compression stream */
int err;
c_stream.zalloc = zalloc;
c_stream.zfree = zfree;
c_stream.opaque = (voidpf)0;
err = deflateInit(&c_stream, Z_BEST_COMPRESSION);
CHECK_ERR(err, "deflateInit");
err = deflateSetDictionary(&c_stream,
(const Bytef*)dictionary, (int)sizeof(dictionary));
CHECK_ERR(err, "deflateSetDictionary");
dictId = c_stream.adler;
c_stream.next_out = compr;
c_stream.avail_out = (uInt)comprLen;
c_stream.next_in = (z_const unsigned char *)hello;
c_stream.avail_in = (uInt)strlen(hello)+1;
err = deflate(&c_stream, Z_FINISH);
if (err != Z_STREAM_END) {
fprintf(stderr, "deflate should report Z_STREAM_END\n");
exit(1);
}
err = deflateEnd(&c_stream);
CHECK_ERR(err, "deflateEnd");
}
/* ===========================================================================
* Test inflate() with a preset dictionary
*/
void test_dict_inflate(compr, comprLen, uncompr, uncomprLen)
Byte *compr, *uncompr;
uLong comprLen, uncomprLen;
{
int err;
z_stream d_stream; /* decompression stream */
strcpy((char*)uncompr, "garbage");
d_stream.zalloc = zalloc;
d_stream.zfree = zfree;
d_stream.opaque = (voidpf)0;
d_stream.next_in = compr;
d_stream.avail_in = (uInt)comprLen;
err = inflateInit(&d_stream);
CHECK_ERR(err, "inflateInit");
d_stream.next_out = uncompr;
d_stream.avail_out = (uInt)uncomprLen;
for (;;) {
err = inflate(&d_stream, Z_NO_FLUSH);
if (err == Z_STREAM_END) break;
if (err == Z_NEED_DICT) {
if (d_stream.adler != dictId) {
fprintf(stderr, "unexpected dictionary");
exit(1);
}
err = inflateSetDictionary(&d_stream, (const Bytef*)dictionary,
(int)sizeof(dictionary));
}
CHECK_ERR(err, "inflate with dict");
}
err = inflateEnd(&d_stream);
CHECK_ERR(err, "inflateEnd");
if (strcmp((char*)uncompr, hello)) {
fprintf(stderr, "bad inflate with dict\n");
exit(1);
} else {
printf("inflate with dictionary: %s\n", (char *)uncompr);
}
}
/* ===========================================================================
* Usage: example [output.gz [input.gz]]
*/
int main(argc, argv)
int argc;
char *argv[];
{
Byte *compr, *uncompr;
uLong comprLen = 10000*sizeof(int); /* don't overflow on MSDOS */
uLong uncomprLen = comprLen;
static const char* myVersion = ZLIB_VERSION;
if (zlibVersion()[0] != myVersion[0]) {
fprintf(stderr, "incompatible zlib version\n");
exit(1);
} else if (strcmp(zlibVersion(), ZLIB_VERSION) != 0) {
fprintf(stderr, "warning: different zlib version\n");
}
printf("zlib version %s = 0x%04x, compile flags = 0x%lx\n",
ZLIB_VERSION, ZLIB_VERNUM, zlibCompileFlags());
if (ZWRAP_isUsingZSTDcompression()) printf("zstd version %s\n", zstdVersion());
compr = (Byte*)calloc((uInt)comprLen, 1);
uncompr = (Byte*)calloc((uInt)uncomprLen, 1);
/* compr and uncompr are cleared to avoid reading uninitialized
* data and to ensure that uncompr compresses well.
*/
if (compr == Z_NULL || uncompr == Z_NULL) {
printf("out of memory\n");
exit(1);
}
#ifdef Z_SOLO
argc = strlen(argv[0]);
#else
test_compress(compr, comprLen, uncompr, uncomprLen);
test_gzio((argc > 1 ? argv[1] : TESTFILE),
uncompr, uncomprLen);
#endif
test_deflate(compr, comprLen);
test_inflate(compr, comprLen, uncompr, uncomprLen);
test_large_deflate(compr, comprLen, uncompr, uncomprLen);
test_large_inflate(compr, comprLen, uncompr, uncomprLen);
if (!ZWRAP_isUsingZSTDcompression()) {
test_flush(compr, &comprLen);
test_sync(compr, comprLen, uncompr, uncomprLen);
}
comprLen = uncomprLen;
test_dict_deflate(compr, comprLen);
test_dict_inflate(compr, comprLen, uncompr, uncomprLen);
free(compr);
free(uncompr);
return 0;
}

View file

@ -0,0 +1,618 @@
/* example.c -- usage example of the zlib compression library
*/
/*
Copyright (c) 1995-2006, 2011 Jean-loup Gailly
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgement in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/* @(#) $Id$ */
#include "zlib.h"
#include <stdio.h>
#ifdef STDC
# include <string.h>
# include <stdlib.h>
#endif
#if defined(VMS) || defined(RISCOS)
# define TESTFILE "foo-gz"
#else
# define TESTFILE "foo.gz"
#endif
#define CHECK_ERR(err, msg) { \
if (err != Z_OK) { \
fprintf(stderr, "%s error: %d\n", msg, err); \
exit(1); \
} \
}
z_const char hello[] = "hello, hello!";
/* "hello world" would be more standard, but the repeated "hello"
* stresses the compression code better, sorry...
*/
const char dictionary[] = "hello";
uLong dictId; /* Adler32 value of the dictionary */
void test_deflate OF((Byte *compr, uLong comprLen));
void test_inflate OF((Byte *compr, uLong comprLen,
Byte *uncompr, uLong uncomprLen));
void test_large_deflate OF((Byte *compr, uLong comprLen,
Byte *uncompr, uLong uncomprLen));
void test_large_inflate OF((Byte *compr, uLong comprLen,
Byte *uncompr, uLong uncomprLen));
void test_flush OF((Byte *compr, uLong *comprLen));
void test_sync OF((Byte *compr, uLong comprLen,
Byte *uncompr, uLong uncomprLen));
void test_dict_deflate OF((Byte *compr, uLong comprLen));
void test_dict_inflate OF((Byte *compr, uLong comprLen,
Byte *uncompr, uLong uncomprLen));
int main OF((int argc, char *argv[]));
#ifdef Z_SOLO
void *myalloc OF((void *, unsigned, unsigned));
void myfree OF((void *, void *));
void *myalloc(q, n, m)
void *q;
unsigned n, m;
{
q = Z_NULL;
return calloc(n, m);
}
void myfree(void *q, void *p)
{
q = Z_NULL;
free(p);
}
static alloc_func zalloc = myalloc;
static free_func zfree = myfree;
#else /* !Z_SOLO */
static alloc_func zalloc = (alloc_func)0;
static free_func zfree = (free_func)0;
void test_compress OF((Byte *compr, uLong comprLen,
Byte *uncompr, uLong uncomprLen));
void test_gzio OF((const char *fname,
Byte *uncompr, uLong uncomprLen));
/* ===========================================================================
* Test compress() and uncompress()
*/
void test_compress(compr, comprLen, uncompr, uncomprLen)
Byte *compr, *uncompr;
uLong comprLen, uncomprLen;
{
int err;
uLong len = (uLong)strlen(hello)+1;
err = compress(compr, &comprLen, (const Bytef*)hello, len);
CHECK_ERR(err, "compress");
strcpy((char*)uncompr, "garbage");
err = uncompress(uncompr, &uncomprLen, compr, comprLen);
CHECK_ERR(err, "uncompress");
if (strcmp((char*)uncompr, hello)) {
fprintf(stderr, "bad uncompress\n");
exit(1);
} else {
printf("uncompress(): %s\n", (char *)uncompr);
}
}
/* ===========================================================================
* Test read/write of .gz files
*/
void test_gzio(fname, uncompr, uncomprLen)
const char *fname; /* compressed file name */
Byte *uncompr;
uLong uncomprLen;
{
#ifdef NO_GZCOMPRESS
fprintf(stderr, "NO_GZCOMPRESS -- gz* functions cannot compress\n");
#else
int err;
int len = (int)strlen(hello)+1;
gzFile file;
z_off_t pos;
file = gzopen(fname, "wb");
if (file == NULL) {
fprintf(stderr, "gzopen error\n");
exit(1);
}
gzputc(file, 'h');
if (gzputs(file, "ello") != 4) {
fprintf(stderr, "gzputs err: %s\n", gzerror(file, &err));
exit(1);
}
if (gzprintf(file, ", %s!", "hello") != 8) {
fprintf(stderr, "gzprintf err: %s\n", gzerror(file, &err));
exit(1);
}
gzseek(file, 1L, SEEK_CUR); /* add one zero byte */
gzclose(file);
file = gzopen(fname, "rb");
if (file == NULL) {
fprintf(stderr, "gzopen error\n");
exit(1);
}
strcpy((char*)uncompr, "garbage");
if (gzread(file, uncompr, (unsigned)uncomprLen) != len) {
fprintf(stderr, "gzread err: %s\n", gzerror(file, &err));
exit(1);
}
if (strcmp((char*)uncompr, hello)) {
fprintf(stderr, "bad gzread: %s\n", (char*)uncompr);
exit(1);
} else {
printf("gzread(): %s\n", (char*)uncompr);
}
pos = gzseek(file, -8L, SEEK_CUR);
if (pos != 6 || gztell(file) != pos) {
fprintf(stderr, "gzseek error, pos=%ld, gztell=%ld\n",
(long)pos, (long)gztell(file));
exit(1);
}
if (gzgetc(file) != ' ') {
fprintf(stderr, "gzgetc error\n");
exit(1);
}
if (gzungetc(' ', file) != ' ') {
fprintf(stderr, "gzungetc error\n");
exit(1);
}
gzgets(file, (char*)uncompr, (int)uncomprLen);
if (strlen((char*)uncompr) != 7) { /* " hello!" */
fprintf(stderr, "gzgets err after gzseek: %s\n", gzerror(file, &err));
exit(1);
}
if (strcmp((char*)uncompr, hello + 6)) {
fprintf(stderr, "bad gzgets after gzseek\n");
exit(1);
} else {
printf("gzgets() after gzseek: %s\n", (char*)uncompr);
}
gzclose(file);
#endif
}
#endif /* Z_SOLO */
/* ===========================================================================
* Test deflate() with small buffers
*/
void test_deflate(compr, comprLen)
Byte *compr;
uLong comprLen;
{
z_stream c_stream; /* compression stream */
int err;
uLong len = (uLong)strlen(hello)+1;
c_stream.zalloc = zalloc;
c_stream.zfree = zfree;
c_stream.opaque = (voidpf)0;
err = 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 = deflate(&c_stream, Z_NO_FLUSH);
CHECK_ERR(err, "deflate");
}
/* Finish the stream, still forcing small buffers: */
for (;;) {
c_stream.avail_out = 1;
err = deflate(&c_stream, Z_FINISH);
if (err == Z_STREAM_END) break;
CHECK_ERR(err, "deflate");
}
err = deflateEnd(&c_stream);
CHECK_ERR(err, "deflateEnd");
}
/* ===========================================================================
* Test inflate() with small buffers
*/
void test_inflate(compr, comprLen, uncompr, uncomprLen)
Byte *compr, *uncompr;
uLong comprLen, uncomprLen;
{
int err;
z_stream d_stream; /* decompression stream */
strcpy((char*)uncompr, "garbage");
d_stream.zalloc = zalloc;
d_stream.zfree = zfree;
d_stream.opaque = (voidpf)0;
d_stream.next_in = compr;
d_stream.avail_in = 0;
d_stream.next_out = uncompr;
err = 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 = inflate(&d_stream, Z_NO_FLUSH);
if (err == Z_STREAM_END) break;
CHECK_ERR(err, "inflate");
}
err = inflateEnd(&d_stream);
CHECK_ERR(err, "inflateEnd");
if (strcmp((char*)uncompr, hello)) {
fprintf(stderr, "bad inflate\n");
exit(1);
} else {
printf("inflate(): %s\n", (char *)uncompr);
}
}
/* ===========================================================================
* Test deflate() with large buffers and dynamic change of compression level
*/
void test_large_deflate(compr, comprLen, uncompr, uncomprLen)
Byte *compr, *uncompr;
uLong comprLen, uncomprLen;
{
z_stream c_stream; /* compression stream */
int err;
c_stream.zalloc = zalloc;
c_stream.zfree = zfree;
c_stream.opaque = (voidpf)0;
err = deflateInit(&c_stream, Z_BEST_SPEED);
CHECK_ERR(err, "deflateInit");
c_stream.next_out = compr;
c_stream.avail_out = (uInt)comprLen;
/* At this point, uncompr is still mostly zeroes, so it should compress
* very well:
*/
c_stream.next_in = uncompr;
c_stream.avail_in = (uInt)uncomprLen;
err = deflate(&c_stream, Z_NO_FLUSH);
CHECK_ERR(err, "deflate");
if (c_stream.avail_in != 0) {
fprintf(stderr, "deflate not greedy\n");
exit(1);
}
/* Feed in already compressed data and switch to no compression: */
deflateParams(&c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY);
c_stream.next_in = compr;
c_stream.avail_in = (uInt)comprLen/2;
err = deflate(&c_stream, Z_NO_FLUSH);
CHECK_ERR(err, "deflate");
/* Switch back to compressing mode: */
deflateParams(&c_stream, Z_BEST_COMPRESSION, Z_FILTERED);
c_stream.next_in = uncompr;
c_stream.avail_in = (uInt)uncomprLen;
err = deflate(&c_stream, Z_NO_FLUSH);
CHECK_ERR(err, "deflate");
err = deflate(&c_stream, Z_FINISH);
if (err != Z_STREAM_END) {
fprintf(stderr, "deflate should report Z_STREAM_END\n");
exit(1);
}
err = deflateEnd(&c_stream);
CHECK_ERR(err, "deflateEnd");
}
/* ===========================================================================
* Test inflate() with large buffers
*/
void test_large_inflate(compr, comprLen, uncompr, uncomprLen)
Byte *compr, *uncompr;
uLong comprLen, uncomprLen;
{
int err;
z_stream d_stream; /* decompression stream */
strcpy((char*)uncompr, "garbage");
d_stream.zalloc = zalloc;
d_stream.zfree = zfree;
d_stream.opaque = (voidpf)0;
d_stream.next_in = compr;
d_stream.avail_in = (uInt)comprLen;
err = inflateInit(&d_stream);
CHECK_ERR(err, "inflateInit");
for (;;) {
d_stream.next_out = uncompr; /* discard the output */
d_stream.avail_out = (uInt)uncomprLen;
err = inflate(&d_stream, Z_NO_FLUSH);
if (err == Z_STREAM_END) break;
CHECK_ERR(err, "large inflate");
}
err = inflateEnd(&d_stream);
CHECK_ERR(err, "inflateEnd");
if (d_stream.total_out != 2*uncomprLen + comprLen/2) {
fprintf(stderr, "bad large inflate: %ld\n", d_stream.total_out);
exit(1);
} else {
printf("large_inflate(): OK\n");
}
}
/* ===========================================================================
* Test deflate() with full flush
*/
void test_flush(compr, comprLen)
Byte *compr;
uLong *comprLen;
{
z_stream c_stream; /* compression stream */
int err;
uInt len = (uInt)strlen(hello)+1;
c_stream.zalloc = zalloc;
c_stream.zfree = zfree;
c_stream.opaque = (voidpf)0;
err = 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 = (uInt)*comprLen;
err = 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 = deflate(&c_stream, Z_FINISH);
if (err != Z_STREAM_END) {
CHECK_ERR(err, "deflate");
}
err = deflateEnd(&c_stream);
CHECK_ERR(err, "deflateEnd");
*comprLen = c_stream.total_out;
}
/* ===========================================================================
* Test inflateSync()
*/
void test_sync(compr, comprLen, uncompr, uncomprLen)
Byte *compr, *uncompr;
uLong comprLen, uncomprLen;
{
int err;
z_stream d_stream; /* decompression stream */
strcpy((char*)uncompr, "garbage");
d_stream.zalloc = zalloc;
d_stream.zfree = zfree;
d_stream.opaque = (voidpf)0;
d_stream.next_in = compr;
d_stream.avail_in = 2; /* just read the zlib header */
err = inflateInit(&d_stream);
CHECK_ERR(err, "inflateInit");
d_stream.next_out = uncompr;
d_stream.avail_out = (uInt)uncomprLen;
inflate(&d_stream, Z_NO_FLUSH);
CHECK_ERR(err, "inflate");
d_stream.avail_in = (uInt)comprLen-2; /* read all compressed data */
err = inflateSync(&d_stream); /* but skip the damaged part */
CHECK_ERR(err, "inflateSync");
err = inflate(&d_stream, Z_FINISH);
if (err != Z_DATA_ERROR) {
fprintf(stderr, "inflate should report DATA_ERROR\n");
/* Because of incorrect adler32 */
exit(1);
}
err = inflateEnd(&d_stream);
CHECK_ERR(err, "inflateEnd");
printf("after inflateSync(): hel%s\n", (char *)uncompr);
}
/* ===========================================================================
* Test deflate() with preset dictionary
*/
void test_dict_deflate(compr, comprLen)
Byte *compr;
uLong comprLen;
{
z_stream c_stream; /* compression stream */
int err;
c_stream.zalloc = zalloc;
c_stream.zfree = zfree;
c_stream.opaque = (voidpf)0;
err = deflateInit(&c_stream, Z_BEST_COMPRESSION);
CHECK_ERR(err, "deflateInit");
err = deflateSetDictionary(&c_stream,
(const Bytef*)dictionary, (int)sizeof(dictionary));
CHECK_ERR(err, "deflateSetDictionary");
dictId = c_stream.adler;
c_stream.next_out = compr;
c_stream.avail_out = (uInt)comprLen;
c_stream.next_in = (z_const unsigned char *)hello;
c_stream.avail_in = (uInt)strlen(hello)+1;
err = deflate(&c_stream, Z_FINISH);
if (err != Z_STREAM_END) {
fprintf(stderr, "deflate should report Z_STREAM_END\n");
exit(1);
}
err = deflateEnd(&c_stream);
CHECK_ERR(err, "deflateEnd");
}
/* ===========================================================================
* Test inflate() with a preset dictionary
*/
void test_dict_inflate(compr, comprLen, uncompr, uncomprLen)
Byte *compr, *uncompr;
uLong comprLen, uncomprLen;
{
int err;
z_stream d_stream; /* decompression stream */
strcpy((char*)uncompr, "garbage");
d_stream.zalloc = zalloc;
d_stream.zfree = zfree;
d_stream.opaque = (voidpf)0;
d_stream.next_in = compr;
d_stream.avail_in = (uInt)comprLen;
err = inflateInit(&d_stream);
CHECK_ERR(err, "inflateInit");
d_stream.next_out = uncompr;
d_stream.avail_out = (uInt)uncomprLen;
for (;;) {
err = inflate(&d_stream, Z_NO_FLUSH);
if (err == Z_STREAM_END) break;
if (err == Z_NEED_DICT) {
if (d_stream.adler != dictId) {
fprintf(stderr, "unexpected dictionary");
exit(1);
}
err = inflateSetDictionary(&d_stream, (const Bytef*)dictionary,
(int)sizeof(dictionary));
}
CHECK_ERR(err, "inflate with dict");
}
err = inflateEnd(&d_stream);
CHECK_ERR(err, "inflateEnd");
if (strcmp((char*)uncompr, hello)) {
fprintf(stderr, "bad inflate with dict\n");
exit(1);
} else {
printf("inflate with dictionary: %s\n", (char *)uncompr);
}
}
/* ===========================================================================
* Usage: example [output.gz [input.gz]]
*/
int main(argc, argv)
int argc;
char *argv[];
{
Byte *compr, *uncompr;
uLong comprLen = 10000*sizeof(int); /* don't overflow on MSDOS */
uLong uncomprLen = comprLen;
static const char* myVersion = ZLIB_VERSION;
if (zlibVersion()[0] != myVersion[0]) {
fprintf(stderr, "incompatible zlib version\n");
exit(1);
} else if (strcmp(zlibVersion(), ZLIB_VERSION) != 0) {
fprintf(stderr, "warning: different zlib version\n");
}
printf("zlib version %s = 0x%04x, compile flags = 0x%lx\n",
ZLIB_VERSION, ZLIB_VERNUM, zlibCompileFlags());
compr = (Byte*)calloc((uInt)comprLen, 1);
uncompr = (Byte*)calloc((uInt)uncomprLen, 1);
/* compr and uncompr are cleared to avoid reading uninitialized
* data and to ensure that uncompr compresses well.
*/
if (compr == Z_NULL || uncompr == Z_NULL) {
printf("out of memory\n");
exit(1);
}
#ifdef Z_SOLO
argc = strlen(argv[0]);
#else
test_compress(compr, comprLen, uncompr, uncomprLen);
test_gzio((argc > 1 ? argv[1] : TESTFILE),
uncompr, uncomprLen);
#endif
test_deflate(compr, comprLen);
test_inflate(compr, comprLen, uncompr, uncomprLen);
test_large_deflate(compr, comprLen, uncompr, uncomprLen);
test_large_inflate(compr, comprLen, uncompr, uncomprLen);
test_flush(compr, &comprLen);
test_sync(compr, comprLen, uncompr, uncomprLen);
comprLen = uncomprLen;
test_dict_deflate(compr, comprLen);
test_dict_inflate(compr, comprLen, uncompr, uncomprLen);
free(compr);
free(uncompr);
return 0;
}

View file

@ -0,0 +1,254 @@
/* fitblk.c contains minimal changes required to be compiled with zlibWrapper:
* - #include "zlib.h" was changed to #include "zstd_zlibwrapper.h"
* - writing block to stdout was disabled */
/* fitblk.c: example of fitting compressed output to a specified size
Not copyrighted -- provided to the public domain
Version 1.1 25 November 2004 Mark Adler */
/* Version history:
1.0 24 Nov 2004 First version
1.1 25 Nov 2004 Change deflateInit2() to deflateInit()
Use fixed-size, stack-allocated raw buffers
Simplify code moving compression to subroutines
Use assert() for internal errors
Add detailed description of approach
*/
/* Approach to just fitting a requested compressed size:
fitblk performs three compression passes on a portion of the input
data in order to determine how much of that input will compress to
nearly the requested output block size. The first pass generates
enough deflate blocks to produce output to fill the requested
output size plus a specified excess amount (see the EXCESS define
below). The last deflate block may go quite a bit past that, but
is discarded. The second pass decompresses and recompresses just
the compressed data that fit in the requested plus excess sized
buffer. The deflate process is terminated after that amount of
input, which is less than the amount consumed on the first pass.
The last deflate block of the result will be of a comparable size
to the final product, so that the header for that deflate block and
the compression ratio for that block will be about the same as in
the final product. The third compression pass decompresses the
result of the second step, but only the compressed data up to the
requested size minus an amount to allow the compressed stream to
complete (see the MARGIN define below). That will result in a
final compressed stream whose length is less than or equal to the
requested size. Assuming sufficient input and a requested size
greater than a few hundred bytes, the shortfall will typically be
less than ten bytes.
If the input is short enough that the first compression completes
before filling the requested output size, then that compressed
stream is return with no recompression.
EXCESS is chosen to be just greater than the shortfall seen in a
two pass approach similar to the above. That shortfall is due to
the last deflate block compressing more efficiently with a smaller
header on the second pass. EXCESS is set to be large enough so
that there is enough uncompressed data for the second pass to fill
out the requested size, and small enough so that the final deflate
block of the second pass will be close in size to the final deflate
block of the third and final pass. MARGIN is chosen to be just
large enough to assure that the final compression has enough room
to complete in all cases.
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "zstd_zlibwrapper.h"
#define LOG_FITBLK(...) /*printf(__VA_ARGS__)*/
#define local static
/* print nastygram and leave */
local void quit(char *why)
{
fprintf(stderr, "fitblk abort: %s\n", why);
exit(1);
}
#define RAWLEN 4096 /* intermediate uncompressed buffer size */
/* compress from file to def until provided buffer is full or end of
input reached; return last deflate() return value, or Z_ERRNO if
there was read error on the file */
local int partcompress(FILE *in, z_streamp def)
{
int ret, flush;
unsigned char raw[RAWLEN];
flush = Z_SYNC_FLUSH;
do {
def->avail_in = (uInt)fread(raw, 1, RAWLEN, in);
if (ferror(in))
return Z_ERRNO;
def->next_in = raw;
if (feof(in))
flush = Z_FINISH;
LOG_FITBLK("partcompress1 avail_in=%d total_in=%d avail_out=%d total_out=%d\n", (int)def->avail_in, (int)def->total_in, (int)def->avail_out, (int)def->total_out);
ret = deflate(def, flush);
LOG_FITBLK("partcompress2 ret=%d avail_in=%d total_in=%d avail_out=%d total_out=%d\n", ret, (int)def->avail_in, (int)def->total_in, (int)def->avail_out, (int)def->total_out);
assert(ret != Z_STREAM_ERROR);
} while (def->avail_out != 0 && flush == Z_SYNC_FLUSH);
return ret;
}
/* recompress from inf's input to def's output; the input for inf and
the output for def are set in those structures before calling;
return last deflate() return value, or Z_MEM_ERROR if inflate()
was not able to allocate enough memory when it needed to */
local int recompress(z_streamp inf, z_streamp def)
{
int ret, flush;
unsigned char raw[RAWLEN];
flush = Z_NO_FLUSH;
LOG_FITBLK("recompress start\n");
do {
/* decompress */
inf->avail_out = RAWLEN;
inf->next_out = raw;
LOG_FITBLK("recompress1inflate avail_in=%d total_in=%d avail_out=%d total_out=%d\n", (int)inf->avail_in, (int)inf->total_in, (int)inf->avail_out, (int)inf->total_out);
ret = inflate(inf, Z_NO_FLUSH);
LOG_FITBLK("recompress2inflate avail_in=%d total_in=%d avail_out=%d total_out=%d\n", (int)inf->avail_in, (int)inf->total_in, (int)inf->avail_out, (int)inf->total_out);
assert(ret != Z_STREAM_ERROR && ret != Z_DATA_ERROR &&
ret != Z_NEED_DICT);
if (ret == Z_MEM_ERROR)
return ret;
/* compress what was decompresed until done or no room */
def->avail_in = RAWLEN - inf->avail_out;
def->next_in = raw;
if (inf->avail_out != 0)
flush = Z_FINISH;
LOG_FITBLK("recompress1deflate avail_in=%d total_in=%d avail_out=%d total_out=%d\n", (int)def->avail_in, (int)def->total_in, (int)def->avail_out, (int)def->total_out);
ret = deflate(def, flush);
LOG_FITBLK("recompress2deflate ret=%d avail_in=%d total_in=%d avail_out=%d total_out=%d\n", ret, (int)def->avail_in, (int)def->total_in, (int)def->avail_out, (int)def->total_out);
assert(ret != Z_STREAM_ERROR);
} while (ret != Z_STREAM_END && def->avail_out != 0);
return ret;
}
#define EXCESS 256 /* empirically determined stream overage */
#define MARGIN 8 /* amount to back off for completion */
/* compress from stdin to fixed-size block on stdout */
int main(int argc, char **argv)
{
int ret; /* return code */
unsigned size; /* requested fixed output block size */
unsigned have; /* bytes written by deflate() call */
unsigned char *blk; /* intermediate and final stream */
unsigned char *tmp; /* close to desired size stream */
z_stream def, inf; /* zlib deflate and inflate states */
/* get requested output size */
if (argc != 2)
quit("need one argument: size of output block");
ret = (int)strtol(argv[1], argv + 1, 10);
if (argv[1][0] != 0)
quit("argument must be a number");
if (ret < 8) /* 8 is minimum zlib stream size */
quit("need positive size of 8 or greater");
size = (unsigned)ret;
printf("zlib version %s\n", ZLIB_VERSION);
if (ZWRAP_isUsingZSTDcompression()) printf("zstd version %s\n", zstdVersion());
/* allocate memory for buffers and compression engine */
blk = (unsigned char*)malloc(size + EXCESS);
def.zalloc = Z_NULL;
def.zfree = Z_NULL;
def.opaque = Z_NULL;
ret = deflateInit(&def, Z_DEFAULT_COMPRESSION);
if (ret != Z_OK || blk == NULL)
quit("out of memory");
/* compress from stdin until output full, or no more input */
def.avail_out = size + EXCESS;
def.next_out = blk;
LOG_FITBLK("partcompress1 total_in=%d total_out=%d\n", (int)def.total_in, (int)def.total_out);
ret = partcompress(stdin, &def);
printf("partcompress total_in=%d total_out=%d\n", (int)def.total_in, (int)def.total_out);
if (ret == Z_ERRNO)
quit("error reading input");
/* if it all fit, then size was undersubscribed -- done! */
if (ret == Z_STREAM_END && def.avail_out >= EXCESS) {
/* write block to stdout */
have = size + EXCESS - def.avail_out;
/* if (fwrite(blk, 1, have, stdout) != have || ferror(stdout))
* quit("error writing output"); */
/* clean up and print results to stderr */
ret = deflateEnd(&def);
assert(ret != Z_STREAM_ERROR);
free(blk);
fprintf(stderr,
"%u bytes unused out of %u requested (all input)\n",
size - have, size);
return 0;
}
/* it didn't all fit -- set up for recompression */
inf.zalloc = Z_NULL;
inf.zfree = Z_NULL;
inf.opaque = Z_NULL;
inf.avail_in = 0;
inf.next_in = Z_NULL;
ret = inflateInit(&inf);
tmp = (unsigned char*)malloc(size + EXCESS);
if (ret != Z_OK || tmp == NULL)
quit("out of memory");
ret = deflateReset(&def);
assert(ret != Z_STREAM_ERROR);
/* do first recompression close to the right amount */
inf.avail_in = size + EXCESS;
inf.next_in = blk;
def.avail_out = size + EXCESS;
def.next_out = tmp;
LOG_FITBLK("recompress1 inf.total_in=%d def.total_out=%d\n", (int)inf.total_in, (int)def.total_out);
ret = recompress(&inf, &def);
LOG_FITBLK("recompress1 inf.total_in=%d def.total_out=%d\n", (int)inf.total_in, (int)def.total_out);
if (ret == Z_MEM_ERROR)
quit("out of memory");
/* set up for next recompression */
ret = inflateReset(&inf);
assert(ret != Z_STREAM_ERROR);
ret = deflateReset(&def);
assert(ret != Z_STREAM_ERROR);
/* do second and final recompression (third compression) */
inf.avail_in = size - MARGIN; /* assure stream will complete */
inf.next_in = tmp;
def.avail_out = size;
def.next_out = blk;
LOG_FITBLK("recompress2 inf.total_in=%d def.total_out=%d\n", (int)inf.total_in, (int)def.total_out);
ret = recompress(&inf, &def);
LOG_FITBLK("recompress2 inf.total_in=%d def.total_out=%d\n", (int)inf.total_in, (int)def.total_out);
if (ret == Z_MEM_ERROR)
quit("out of memory");
assert(ret == Z_STREAM_END); /* otherwise MARGIN too small */
/* done -- write block to stdout */
have = size - def.avail_out;
/* if (fwrite(blk, 1, have, stdout) != have || ferror(stdout))
* quit("error writing output"); */
/* clean up and print results to stderr */
free(tmp);
ret = inflateEnd(&inf);
assert(ret != Z_STREAM_ERROR);
ret = deflateEnd(&def);
assert(ret != Z_STREAM_ERROR);
free(blk);
fprintf(stderr,
"%u bytes unused out of %u requested (%lu input)\n",
size - have, size, def.total_in);
return 0;
}

View file

@ -0,0 +1,233 @@
/* fitblk.c: example of fitting compressed output to a specified size
Not copyrighted -- provided to the public domain
Version 1.1 25 November 2004 Mark Adler */
/* Version history:
1.0 24 Nov 2004 First version
1.1 25 Nov 2004 Change deflateInit2() to deflateInit()
Use fixed-size, stack-allocated raw buffers
Simplify code moving compression to subroutines
Use assert() for internal errors
Add detailed description of approach
*/
/* Approach to just fitting a requested compressed size:
fitblk performs three compression passes on a portion of the input
data in order to determine how much of that input will compress to
nearly the requested output block size. The first pass generates
enough deflate blocks to produce output to fill the requested
output size plus a specified excess amount (see the EXCESS define
below). The last deflate block may go quite a bit past that, but
is discarded. The second pass decompresses and recompresses just
the compressed data that fit in the requested plus excess sized
buffer. The deflate process is terminated after that amount of
input, which is less than the amount consumed on the first pass.
The last deflate block of the result will be of a comparable size
to the final product, so that the header for that deflate block and
the compression ratio for that block will be about the same as in
the final product. The third compression pass decompresses the
result of the second step, but only the compressed data up to the
requested size minus an amount to allow the compressed stream to
complete (see the MARGIN define below). That will result in a
final compressed stream whose length is less than or equal to the
requested size. Assuming sufficient input and a requested size
greater than a few hundred bytes, the shortfall will typically be
less than ten bytes.
If the input is short enough that the first compression completes
before filling the requested output size, then that compressed
stream is return with no recompression.
EXCESS is chosen to be just greater than the shortfall seen in a
two pass approach similar to the above. That shortfall is due to
the last deflate block compressing more efficiently with a smaller
header on the second pass. EXCESS is set to be large enough so
that there is enough uncompressed data for the second pass to fill
out the requested size, and small enough so that the final deflate
block of the second pass will be close in size to the final deflate
block of the third and final pass. MARGIN is chosen to be just
large enough to assure that the final compression has enough room
to complete in all cases.
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "zlib.h"
#define local static
/* print nastygram and leave */
local void quit(char *why)
{
fprintf(stderr, "fitblk abort: %s\n", why);
exit(1);
}
#define RAWLEN 4096 /* intermediate uncompressed buffer size */
/* compress from file to def until provided buffer is full or end of
input reached; return last deflate() return value, or Z_ERRNO if
there was read error on the file */
local int partcompress(FILE *in, z_streamp def)
{
int ret, flush;
unsigned char raw[RAWLEN];
flush = Z_NO_FLUSH;
do {
def->avail_in = fread(raw, 1, RAWLEN, in);
if (ferror(in))
return Z_ERRNO;
def->next_in = raw;
if (feof(in))
flush = Z_FINISH;
ret = deflate(def, flush);
assert(ret != Z_STREAM_ERROR);
} while (def->avail_out != 0 && flush == Z_NO_FLUSH);
return ret;
}
/* recompress from inf's input to def's output; the input for inf and
the output for def are set in those structures before calling;
return last deflate() return value, or Z_MEM_ERROR if inflate()
was not able to allocate enough memory when it needed to */
local int recompress(z_streamp inf, z_streamp def)
{
int ret, flush;
unsigned char raw[RAWLEN];
flush = Z_NO_FLUSH;
do {
/* decompress */
inf->avail_out = RAWLEN;
inf->next_out = raw;
ret = inflate(inf, Z_NO_FLUSH);
assert(ret != Z_STREAM_ERROR && ret != Z_DATA_ERROR &&
ret != Z_NEED_DICT);
if (ret == Z_MEM_ERROR)
return ret;
/* compress what was decompresed until done or no room */
def->avail_in = RAWLEN - inf->avail_out;
def->next_in = raw;
if (inf->avail_out != 0)
flush = Z_FINISH;
ret = deflate(def, flush);
assert(ret != Z_STREAM_ERROR);
} while (ret != Z_STREAM_END && def->avail_out != 0);
return ret;
}
#define EXCESS 256 /* empirically determined stream overage */
#define MARGIN 8 /* amount to back off for completion */
/* compress from stdin to fixed-size block on stdout */
int main(int argc, char **argv)
{
int ret; /* return code */
unsigned size; /* requested fixed output block size */
unsigned have; /* bytes written by deflate() call */
unsigned char *blk; /* intermediate and final stream */
unsigned char *tmp; /* close to desired size stream */
z_stream def, inf; /* zlib deflate and inflate states */
/* get requested output size */
if (argc != 2)
quit("need one argument: size of output block");
ret = strtol(argv[1], argv + 1, 10);
if (argv[1][0] != 0)
quit("argument must be a number");
if (ret < 8) /* 8 is minimum zlib stream size */
quit("need positive size of 8 or greater");
size = (unsigned)ret;
/* allocate memory for buffers and compression engine */
blk = malloc(size + EXCESS);
def.zalloc = Z_NULL;
def.zfree = Z_NULL;
def.opaque = Z_NULL;
ret = deflateInit(&def, Z_DEFAULT_COMPRESSION);
if (ret != Z_OK || blk == NULL)
quit("out of memory");
/* compress from stdin until output full, or no more input */
def.avail_out = size + EXCESS;
def.next_out = blk;
ret = partcompress(stdin, &def);
if (ret == Z_ERRNO)
quit("error reading input");
/* if it all fit, then size was undersubscribed -- done! */
if (ret == Z_STREAM_END && def.avail_out >= EXCESS) {
/* write block to stdout */
have = size + EXCESS - def.avail_out;
if (fwrite(blk, 1, have, stdout) != have || ferror(stdout))
quit("error writing output");
/* clean up and print results to stderr */
ret = deflateEnd(&def);
assert(ret != Z_STREAM_ERROR);
free(blk);
fprintf(stderr,
"%u bytes unused out of %u requested (all input)\n",
size - have, size);
return 0;
}
/* it didn't all fit -- set up for recompression */
inf.zalloc = Z_NULL;
inf.zfree = Z_NULL;
inf.opaque = Z_NULL;
inf.avail_in = 0;
inf.next_in = Z_NULL;
ret = inflateInit(&inf);
tmp = malloc(size + EXCESS);
if (ret != Z_OK || tmp == NULL)
quit("out of memory");
ret = deflateReset(&def);
assert(ret != Z_STREAM_ERROR);
/* do first recompression close to the right amount */
inf.avail_in = size + EXCESS;
inf.next_in = blk;
def.avail_out = size + EXCESS;
def.next_out = tmp;
ret = recompress(&inf, &def);
if (ret == Z_MEM_ERROR)
quit("out of memory");
/* set up for next recompression */
ret = inflateReset(&inf);
assert(ret != Z_STREAM_ERROR);
ret = deflateReset(&def);
assert(ret != Z_STREAM_ERROR);
/* do second and final recompression (third compression) */
inf.avail_in = size - MARGIN; /* assure stream will complete */
inf.next_in = tmp;
def.avail_out = size;
def.next_out = blk;
ret = recompress(&inf, &def);
if (ret == Z_MEM_ERROR)
quit("out of memory");
assert(ret == Z_STREAM_END); /* otherwise MARGIN too small */
/* done -- write block to stdout */
have = size - def.avail_out;
if (fwrite(blk, 1, have, stdout) != have || ferror(stdout))
quit("error writing output");
/* clean up and print results to stderr */
free(tmp);
ret = inflateEnd(&inf);
assert(ret != Z_STREAM_ERROR);
ret = deflateEnd(&def);
assert(ret != Z_STREAM_ERROR);
free(blk);
fprintf(stderr,
"%u bytes unused out of %u requested (%lu input)\n",
size - have, size, def.total_in);
return 0;
}

View file

@ -0,0 +1,640 @@
/* minigzip.c contains minimal changes required to be compiled with zlibWrapper:
* - #include "zlib.h" was changed to #include "zstd_zlibwrapper.h" */
/* minigzip.c -- simulate gzip using the zlib compression library
* Copyright (C) 1995-2006, 2010, 2011 Jean-loup Gailly.
* For conditions of distribution and use, see http://www.zlib.net/zlib_license.html
*/
/*
* minigzip is a minimal implementation of the gzip utility. This is
* only an example of using zlib and isn't meant to replace the
* full-featured gzip. No attempt is made to deal with file systems
* limiting names to 14 or 8+3 characters, etc... Error checking is
* very limited. So use minigzip only for testing; use gzip for the
* real thing. On MSDOS, use only on file names without extension
* or in pipe mode.
*/
/* @(#) $Id$ */
#define _POSIX_SOURCE /* fileno */
#include "zstd_zlibwrapper.h"
#include <stdio.h>
#ifdef STDC
# include <string.h>
# include <stdlib.h>
#endif
#ifdef USE_MMAP
# include <sys/types.h>
# include <sys/mman.h>
# include <sys/stat.h>
#endif
#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__)
# include <fcntl.h>
# include <io.h>
# ifdef UNDER_CE
# include <stdlib.h>
# endif
# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
#else
# define SET_BINARY_MODE(file)
#endif
#ifdef _MSC_VER
# define snprintf _snprintf
#endif
#ifdef VMS
# define unlink delete
# define GZ_SUFFIX "-gz"
#endif
#ifdef RISCOS
# define unlink remove
# define GZ_SUFFIX "-gz"
# define fileno(file) file->__file
#endif
#if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
# include <unix.h> /* for fileno */
#endif
#if !defined(Z_HAVE_UNISTD_H) && !defined(_LARGEFILE64_SOURCE)
#ifndef WIN32 /* unlink already in stdio.h for WIN32 */
extern int unlink OF((const char *));
#endif
#endif
#if defined(UNDER_CE)
# include <windows.h>
# define perror(s) pwinerror(s)
/* Map the Windows error number in ERROR to a locale-dependent error
message string and return a pointer to it. Typically, the values
for ERROR come from GetLastError.
The string pointed to shall not be modified by the application,
but may be overwritten by a subsequent call to strwinerror
The strwinerror function does not change the current setting
of GetLastError. */
static char *strwinerror (error)
DWORD error;
{
static char buf[1024];
wchar_t *msgbuf;
DWORD lasterr = GetLastError();
DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_ALLOCATE_BUFFER,
NULL,
error,
0, /* Default language */
(LPVOID)&msgbuf,
0,
NULL);
if (chars != 0) {
/* If there is an \r\n appended, zap it. */
if (chars >= 2
&& msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') {
chars -= 2;
msgbuf[chars] = 0;
}
if (chars > sizeof (buf) - 1) {
chars = sizeof (buf) - 1;
msgbuf[chars] = 0;
}
wcstombs(buf, msgbuf, chars + 1);
LocalFree(msgbuf);
}
else {
sprintf(buf, "unknown win32 error (%ld)", error);
}
SetLastError(lasterr);
return buf;
}
static void pwinerror (s)
const char *s;
{
if (s && *s)
fprintf(stderr, "%s: %s\n", s, strwinerror(GetLastError ()));
else
fprintf(stderr, "%s\n", strwinerror(GetLastError ()));
}
#endif /* UNDER_CE */
#ifndef GZ_SUFFIX
# define GZ_SUFFIX ".gz"
#endif
#define SUFFIX_LEN (sizeof(GZ_SUFFIX)-1)
#define BUFLEN 16384
#define MAX_NAME_LEN 1024
#ifdef MAXSEG_64K
# define local static
/* Needed for systems with limitation on stack size. */
#else
# define local
#endif
#ifdef Z_SOLO
/* for Z_SOLO, create simplified gz* functions using deflate and inflate */
#if defined(Z_HAVE_UNISTD_H) || defined(Z_LARGE)
# include <unistd.h> /* for unlink() */
#endif
void *myalloc OF((void *, unsigned, unsigned));
void myfree OF((void *, void *));
void *myalloc(q, n, m)
void *q;
unsigned n, m;
{
q = Z_NULL;
return calloc(n, m);
}
void myfree(q, p)
void *q, *p;
{
q = Z_NULL;
free(p);
}
typedef struct gzFile_s {
FILE *file;
int write;
int err;
char *msg;
z_stream strm;
} *gzFile;
gzFile gzopen OF((const char *, const char *));
gzFile gzdopen OF((int, const char *));
gzFile gz_open OF((const char *, int, const char *));
gzFile gzopen(path, mode)
const char *path;
const char *mode;
{
return gz_open(path, -1, mode);
}
gzFile gzdopen(fd, mode)
int fd;
const char *mode;
{
return gz_open(NULL, fd, mode);
}
gzFile gz_open(path, fd, mode)
const char *path;
int fd;
const char *mode;
{
gzFile gz;
int ret;
gz = malloc(sizeof(struct gzFile_s));
if (gz == NULL)
return NULL;
gz->write = strchr(mode, 'w') != NULL;
gz->strm.zalloc = myalloc;
gz->strm.zfree = myfree;
gz->strm.opaque = Z_NULL;
if (gz->write)
ret = deflateInit2(&(gz->strm), -1, 8, 15 + 16, 8, 0);
else {
gz->strm.next_in = 0;
gz->strm.avail_in = Z_NULL;
ret = inflateInit2(&(gz->strm), 15 + 16);
}
if (ret != Z_OK) {
free(gz);
return NULL;
}
gz->file = path == NULL ? fdopen(fd, gz->write ? "wb" : "rb") :
fopen(path, gz->write ? "wb" : "rb");
if (gz->file == NULL) {
gz->write ? deflateEnd(&(gz->strm)) : inflateEnd(&(gz->strm));
free(gz);
return NULL;
}
gz->err = 0;
gz->msg = "";
return gz;
}
int gzwrite OF((gzFile, const void *, unsigned));
int gzwrite(gz, buf, len)
gzFile gz;
const void *buf;
unsigned len;
{
z_stream *strm;
unsigned char out[BUFLEN];
if (gz == NULL || !gz->write)
return 0;
strm = &(gz->strm);
strm->next_in = (void *)buf;
strm->avail_in = len;
do {
strm->next_out = out;
strm->avail_out = BUFLEN;
(void)deflate(strm, Z_NO_FLUSH);
fwrite(out, 1, BUFLEN - strm->avail_out, gz->file);
} while (strm->avail_out == 0);
return len;
}
int gzread OF((gzFile, void *, unsigned));
int gzread(gz, buf, len)
gzFile gz;
void *buf;
unsigned len;
{
int ret;
unsigned got;
unsigned char in[1];
z_stream *strm;
if (gz == NULL || gz->write)
return 0;
if (gz->err)
return 0;
strm = &(gz->strm);
strm->next_out = (void *)buf;
strm->avail_out = len;
do {
got = fread(in, 1, 1, gz->file);
if (got == 0)
break;
strm->next_in = in;
strm->avail_in = 1;
ret = inflate(strm, Z_NO_FLUSH);
if (ret == Z_DATA_ERROR) {
gz->err = Z_DATA_ERROR;
gz->msg = strm->msg;
return 0;
}
if (ret == Z_STREAM_END)
inflateReset(strm);
} while (strm->avail_out);
return len - strm->avail_out;
}
int gzclose OF((gzFile));
int gzclose(gz)
gzFile gz;
{
z_stream *strm;
unsigned char out[BUFLEN];
if (gz == NULL)
return Z_STREAM_ERROR;
strm = &(gz->strm);
if (gz->write) {
strm->next_in = Z_NULL;
strm->avail_in = 0;
do {
strm->next_out = out;
strm->avail_out = BUFLEN;
(void)deflate(strm, Z_FINISH);
fwrite(out, 1, BUFLEN - strm->avail_out, gz->file);
} while (strm->avail_out == 0);
deflateEnd(strm);
}
else
inflateEnd(strm);
fclose(gz->file);
free(gz);
return Z_OK;
}
const char *gzerror OF((gzFile, int *));
const char *gzerror(gz, err)
gzFile gz;
int *err;
{
*err = gz->err;
return gz->msg;
}
#endif
char *prog;
void error OF((const char *msg));
void gz_compress OF((FILE *in, gzFile out));
#ifdef USE_MMAP
int gz_compress_mmap OF((FILE *in, gzFile out));
#endif
void gz_uncompress OF((gzFile in, FILE *out));
void file_compress OF((char *file, char *mode));
void file_uncompress OF((char *file));
int main OF((int argc, char *argv[]));
/* ===========================================================================
* Display error message and exit
*/
void error(msg)
const char *msg;
{
fprintf(stderr, "%s: %s\n", prog, msg);
exit(1);
}
/* ===========================================================================
* Compress input to output then close both files.
*/
void gz_compress(in, out)
FILE *in;
gzFile out;
{
local char buf[BUFLEN];
int len;
int err;
#ifdef USE_MMAP
/* Try first compressing with mmap. If mmap fails (minigzip used in a
* pipe), use the normal fread loop.
*/
if (gz_compress_mmap(in, out) == Z_OK) return;
#endif
for (;;) {
len = (int)fread(buf, 1, sizeof(buf), in);
if (ferror(in)) {
perror("fread");
exit(1);
}
if (len == 0) break;
if (gzwrite(out, buf, (unsigned)len) != len) error(gzerror(out, &err));
}
fclose(in);
if (gzclose(out) != Z_OK) error("failed gzclose");
}
#ifdef USE_MMAP /* MMAP version, Miguel Albrecht <malbrech@eso.org> */
/* Try compressing the input file at once using mmap. Return Z_OK if
* if success, Z_ERRNO otherwise.
*/
int gz_compress_mmap(in, out)
FILE *in;
gzFile out;
{
int len;
int err;
int ifd = fileno(in);
caddr_t buf; /* mmap'ed buffer for the entire input file */
off_t buf_len; /* length of the input file */
struct stat sb;
/* Determine the size of the file, needed for mmap: */
if (fstat(ifd, &sb) < 0) return Z_ERRNO;
buf_len = sb.st_size;
if (buf_len <= 0) return Z_ERRNO;
/* Now do the actual mmap: */
buf = mmap((caddr_t) 0, buf_len, PROT_READ, MAP_SHARED, ifd, (off_t)0);
if (buf == (caddr_t)(-1)) return Z_ERRNO;
/* Compress the whole file at once: */
len = gzwrite(out, (char *)buf, (unsigned)buf_len);
if (len != (int)buf_len) error(gzerror(out, &err));
munmap(buf, buf_len);
fclose(in);
if (gzclose(out) != Z_OK) error("failed gzclose");
return Z_OK;
}
#endif /* USE_MMAP */
/* ===========================================================================
* Uncompress input to output then close both files.
*/
void gz_uncompress(in, out)
gzFile in;
FILE *out;
{
local char buf[BUFLEN];
int len;
int err;
for (;;) {
len = gzread(in, buf, sizeof(buf));
if (len < 0) error (gzerror(in, &err));
if (len == 0) break;
if ((int)fwrite(buf, 1, (unsigned)len, out) != len) {
error("failed fwrite");
}
}
if (fclose(out)) error("failed fclose");
if (gzclose(in) != Z_OK) error("failed gzclose");
}
/* ===========================================================================
* Compress the given file: create a corresponding .gz file and remove the
* original.
*/
void file_compress(file, mode)
char *file;
char *mode;
{
local char outfile[MAX_NAME_LEN];
FILE *in;
gzFile out;
if (strlen(file) + strlen(GZ_SUFFIX) >= sizeof(outfile)) {
fprintf(stderr, "%s: filename too long\n", prog);
exit(1);
}
strcpy(outfile, file);
strcat(outfile, GZ_SUFFIX);
in = fopen(file, "rb");
if (in == NULL) {
perror(file);
exit(1);
}
out = gzopen(outfile, mode);
if (out == NULL) {
fprintf(stderr, "%s: can't gzopen %s\n", prog, outfile);
exit(1);
}
gz_compress(in, out);
unlink(file);
}
/* ===========================================================================
* Uncompress the given file and remove the original.
*/
void file_uncompress(file)
char *file;
{
local char buf[MAX_NAME_LEN];
char *infile, *outfile;
FILE *out;
gzFile in;
size_t len = strlen(file);
if (len + strlen(GZ_SUFFIX) >= sizeof(buf)) {
fprintf(stderr, "%s: filename too long\n", prog);
exit(1);
}
strcpy(buf, file);
if (len > SUFFIX_LEN && strcmp(file+len-SUFFIX_LEN, GZ_SUFFIX) == 0) {
infile = file;
outfile = buf;
outfile[len-3] = '\0';
} else {
outfile = file;
infile = buf;
strcat(infile, GZ_SUFFIX);
}
in = gzopen(infile, "rb");
if (in == NULL) {
fprintf(stderr, "%s: can't gzopen %s\n", prog, infile);
exit(1);
}
out = fopen(outfile, "wb");
if (out == NULL) {
perror(file);
exit(1);
}
gz_uncompress(in, out);
unlink(infile);
}
/* ===========================================================================
* Usage: minigzip [-c] [-d] [-f] [-h] [-r] [-1 to -9] [files...]
* -c : write to standard output
* -d : decompress
* -f : compress with Z_FILTERED
* -h : compress with Z_HUFFMAN_ONLY
* -r : compress with Z_RLE
* -1 to -9 : compression level
*/
int main(argc, argv)
int argc;
char *argv[];
{
int copyout = 0;
int uncompr = 0;
gzFile file;
char *bname, outmode[20];
strcpy(outmode, "wb6 ");
prog = argv[0];
bname = strrchr(argv[0], '/');
if (bname)
bname++;
else
bname = argv[0];
argc--, argv++;
if (!strcmp(bname, "gunzip"))
uncompr = 1;
else if (!strcmp(bname, "zcat"))
copyout = uncompr = 1;
while (argc > 0) {
if (strcmp(*argv, "-c") == 0)
copyout = 1;
else if (strcmp(*argv, "-d") == 0)
uncompr = 1;
else if (strcmp(*argv, "-f") == 0)
outmode[3] = 'f';
else if (strcmp(*argv, "-h") == 0)
outmode[3] = 'h';
else if (strcmp(*argv, "-r") == 0)
outmode[3] = 'R';
else if ((*argv)[0] == '-' && (*argv)[1] >= '1' && (*argv)[1] <= '9' &&
(*argv)[2] == 0)
outmode[2] = (*argv)[1];
else
break;
argc--, argv++;
}
if (outmode[3] == ' ')
outmode[3] = 0;
if (argc == 0) {
SET_BINARY_MODE(stdin);
SET_BINARY_MODE(stdout);
if (uncompr) {
file = gzdopen(fileno(stdin), "rb");
if (file == NULL) error("can't gzdopen stdin");
gz_uncompress(file, stdout);
} else {
file = gzdopen(fileno(stdout), outmode);
if (file == NULL) error("can't gzdopen stdout");
gz_compress(stdin, file);
}
} else {
if (copyout) {
SET_BINARY_MODE(stdout);
}
do {
if (uncompr) {
if (copyout) {
file = gzopen(*argv, "rb");
if (file == NULL)
fprintf(stderr, "%s: can't gzopen %s\n", prog, *argv);
else
gz_uncompress(file, stdout);
} else {
file_uncompress(*argv);
}
} else {
if (copyout) {
FILE * in = fopen(*argv, "rb");
if (in == NULL) {
perror(*argv);
} else {
file = gzdopen(fileno(stdout), outmode);
if (file == NULL) error("can't gzdopen stdout");
gz_compress(in, file);
}
} else {
file_compress(*argv, outmode);
}
}
} while (argv++, --argc);
}
return 0;
}

File diff suppressed because it is too large Load diff