Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions zlibWrapper/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,11 @@ release : STDFLAGS =
release : DEBUGFLAGS =
release : all

all: fitblk example zwrapbench minigzip
all: fitblk example zwrapbench minigzip gzfinishtest

test: example fitblk example_zstd fitblk_zstd zwrapbench minigzip minigzip_zstd
test: example fitblk example_zstd fitblk_zstd zwrapbench minigzip minigzip_zstd gzfinishtest gzfinishtest_zstd
./gzfinishtest
./gzfinishtest_zstd
./example
./example_zstd
./fitblk 10240 <$(TEST_FILE)
Expand Down Expand Up @@ -83,6 +85,12 @@ test-valgrind: clean example fitblk example_zstd fitblk_zstd zwrapbench
#.c.o:
# $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@

gzfinishtest: gzfinishtest.o zstd_zlibwrapper.o $(GZFILES) $(ZSTDLIBRARY)
$(LINK.o) $^ $(LDLIBS) $(OUTPUT_OPTION)

gzfinishtest_zstd: gzfinishtest.o zstdTurnedOn_zlibwrapper.o $(GZFILES) $(ZSTDLIBRARY)
$(LINK.o) $^ $(LDLIBS) $(OUTPUT_OPTION)

minigzip: minigzip.o zstd_zlibwrapper.o $(GZFILES) $(ZSTDLIBRARY)

minigzip_zstd: minigzip.o zstdTurnedOn_zlibwrapper.o $(GZFILES) $(ZSTDLIBRARY)
Expand Down
91 changes: 91 additions & 0 deletions zlibWrapper/examples/gzfinishtest.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
* in the COPYING file in the root directory of this source tree).
* You may select, at your option, one of the above-listed licenses.
*/

/* gzfinishtest : check that gzflush(Z_FINISH) does not start an empty member.
*
* Writes one small buffer, finishes the member with gzflush(), flushes again
* with no data in between, then closes the file. The result must contain
* exactly one gzip member : the file size must equal the size obtained when
* writing the same data without the intermediate flushes.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ZLIB_CONST
#define Z_PREFIX
#include "zlib.h"

static int writeMode(const char* path, int mode)
{
gzFile file = gzopen(path, "wb");
if (file == NULL) {
fprintf(stderr, "gzfinishtest: gzopen failed\n");
return 1;
}
if (gzwrite(file, "hello", 5) != 5) {
fprintf(stderr, "gzfinishtest: gzwrite failed\n");
return 1;
}
if (mode >= 1) {
if (gzflush(file, Z_FINISH) != Z_OK) {
fprintf(stderr, "gzfinishtest: gzflush failed\n");
return 1;
}
}
if (mode >= 2) {
/* second finish with no data in between : must not emit a member */
if (gzflush(file, Z_FINISH) != Z_OK) {
fprintf(stderr, "gzfinishtest: second gzflush failed\n");
return 1;
}
}
if (gzclose(file) != Z_OK) {
fprintf(stderr, "gzfinishtest: gzclose failed\n");
return 1;
}
return 0;
}

static long fileSize(const char* path)
{
FILE* const f = fopen(path, "rb");
long size;
if (f == NULL) return -1;
if (fseek(f, 0, SEEK_END) != 0) { fclose(f); return -1; }
size = ftell(f);
fclose(f);
return size;
}

int main(int argc, char** argv)
{
const char* name = (argc > 1) ? argv[1] : "gzfinishtest.tmp";
long plain, flushed, twice;

if (writeMode(name, 0)) return 1;
plain = fileSize(name);
if (writeMode(name, 1)) return 1;
flushed = fileSize(name);
if (writeMode(name, 2)) return 1;
twice = fileSize(name);

if (plain < 0 || flushed != plain || twice != plain) {
fprintf(stderr, "gzfinishtest: file sizes differ : plain=%ld flushed=%ld twice=%ld "
"(spurious empty gzip member after Z_FINISH)\n",
plain, flushed, twice);
remove(name);
return 1;
}

printf("gzfinishtest OK : %ld bytes in all cases\n", plain);
remove(name);
return 0;
}
1 change: 1 addition & 0 deletions zlibWrapper/gzguts.h
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ typedef struct {
/* just for writing */
int level; /* compression level */
int strategy; /* compression strategy */
int reset; /* true if a reset is pending after a Z_FINISH */
/* seek request */
z_off64_t skip; /* amount to skip (already rewound if backwards) */
int seek; /* true if seek request pending */
Expand Down
1 change: 1 addition & 0 deletions zlibWrapper/gzlib.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ local void gz_reset(gz_statep state) {
state.state->how = LOOK; /* look for gzip header */
}
state.state->seek = 0; /* no seek request pending */
state.state->reset = 0; /* no deflateReset pending */
gz_error(state, Z_OK, NULL); /* clear error */
state.state->x.pos = 0; /* no uncompressed data yet */
state.state->strm.avail_in = 0; /* no input data yet */
Expand Down
11 changes: 10 additions & 1 deletion zlibWrapper/gzwrite.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,15 @@ local int gz_comp(gz_statep state, int flush) {
return 0;
}

/* check for a pending reset */
if (state.state->reset) {
/* don't start a new gzip member unless there is data to write */
if (strm->avail_in == 0)
return 0;
deflateReset(strm);
state.state->reset = 0;
}

/* run deflate() on provided input until it produces no more output */
ret = Z_OK;
do {
Expand Down Expand Up @@ -135,7 +144,7 @@ local int gz_comp(gz_statep state, int flush) {

/* if that completed a deflate stream, allow another to start */
if (flush == Z_FINISH)
deflateReset(strm);
state.state->reset = 1;

/* all done, no errors */
return 0;
Expand Down