summaryrefslogtreecommitdiffstats
path: root/lib/libz/gzio.c
diff options
context:
space:
mode:
authorsteve <steve@FreeBSD.org>1998-02-28 06:08:17 +0000
committersteve <steve@FreeBSD.org>1998-02-28 06:08:17 +0000
commit237ff31c6d598cfde1da4334ec1a86b35f19571c (patch)
tree6427e9261e25aa42e2def462b2cc2b1a1b674e9a /lib/libz/gzio.c
parent8514318799bade2eb145aee36f8731edc4053a78 (diff)
downloadFreeBSD-src-237ff31c6d598cfde1da4334ec1a86b35f19571c.zip
FreeBSD-src-237ff31c6d598cfde1da4334ec1a86b35f19571c.tar.gz
Merge conflicts.
Diffstat (limited to 'lib/libz/gzio.c')
-rw-r--r--lib/libz/gzio.c397
1 files changed, 365 insertions, 32 deletions
diff --git a/lib/libz/gzio.c b/lib/libz/gzio.c
index f62b125..e3782d5 100644
--- a/lib/libz/gzio.c
+++ b/lib/libz/gzio.c
@@ -1,6 +1,8 @@
/* gzio.c -- IO on .gz files
- * Copyright (C) 1995-1996 Jean-loup Gailly.
+ * Copyright (C) 1995-1998 Jean-loup Gailly.
* For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Compile this file with -DNO_DEFLATE to avoid the compression code.
*/
/* $FreeBSD$ */
@@ -11,7 +13,8 @@
struct internal_state {int dummy;}; /* for buggy compilers */
-#define Z_BUFSIZE 4096
+#define Z_BUFSIZE 16384
+#define Z_PRINTF_BUFSIZE 4096
#define ALLOC(size) malloc(size)
#define TRYFREE(p) {if (p) free(p);}
@@ -38,10 +41,12 @@ typedef struct gz_stream {
char *path; /* path name for debugging only */
int transparent; /* 1 if input file is not a .gz file */
char mode; /* 'w' or 'r' */
+ long startpos; /* start of compressed data in file (header skipped) */
} gz_stream;
local gzFile gz_open OF((const char *path, const char *mode, int fd));
+local int do_flush OF((gzFile file, int flush));
local int get_byte OF((gz_stream *s));
local void check_header OF((gz_stream *s));
local int destroy OF((gz_stream *s));
@@ -64,6 +69,7 @@ local gzFile gz_open (path, mode, fd)
{
int err;
int level = Z_DEFAULT_COMPRESSION; /* compression level */
+ int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
char *p = (char*)mode;
gz_stream *s;
char fmode[80]; /* copy of mode, without the compression level */
@@ -99,6 +105,10 @@ local gzFile gz_open (path, mode, fd)
if (*p == 'w' || *p == 'a') s->mode = 'w';
if (*p >= '0' && *p <= '9') {
level = *p - '0';
+ } else if (*p == 'f') {
+ strategy = Z_FILTERED;
+ } else if (*p == 'h') {
+ strategy = Z_HUFFMAN_ONLY;
} else {
*m++ = *p; /* copy the mode */
}
@@ -106,19 +116,24 @@ local gzFile gz_open (path, mode, fd)
if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL;
if (s->mode == 'w') {
+#ifdef NO_DEFLATE
+ err = Z_STREAM_ERROR;
+#else
err = deflateInit2(&(s->stream), level,
- Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, 0);
+ Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy);
/* windowBits is passed < 0 to suppress zlib header */
s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
-
+#endif
if (err != Z_OK || s->outbuf == Z_NULL) {
return destroy(s), (gzFile)Z_NULL;
}
} else {
- err = inflateInit2(&(s->stream), -MAX_WBITS);
s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE);
+ err = inflateInit2(&(s->stream), -MAX_WBITS);
+ /* windowBits is passed < 0 to tell that there is no zlib header */
+
if (err != Z_OK || s->inbuf == Z_NULL) {
return destroy(s), (gzFile)Z_NULL;
}
@@ -126,7 +141,7 @@ local gzFile gz_open (path, mode, fd)
s->stream.avail_out = Z_BUFSIZE;
errno = 0;
- s->file = fd < 0 ? FOPEN(path, fmode) : (FILE*)fdopen(fd, fmode);
+ s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode);
if (s->file == NULL) {
return destroy(s), (gzFile)Z_NULL;
@@ -136,16 +151,24 @@ local gzFile gz_open (path, mode, fd)
*/
fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE);
+ s->startpos = 10L;
+ /* We use 10L instead of ftell(s->file) to because ftell causes an
+ * fflush on some systems. This version of the library doesn't use
+ * startpos anyway in write mode, so this initialization is not
+ * necessary.
+ */
} else {
check_header(s); /* skip the .gz header */
+ s->startpos = (ftell(s->file) - s->stream.avail_in);
}
+
return (gzFile)s;
}
/* ===========================================================================
Opens a gzip (.gz) file for reading or writing.
*/
-gzFile gzopen (path, mode)
+gzFile ZEXPORT gzopen (path, mode)
const char *path;
const char *mode;
{
@@ -156,7 +179,7 @@ gzFile gzopen (path, mode)
Associate a gzFile with the file descriptor fd. fd is not dup'ed here
to mimic the behavio(u)r of fdopen.
*/
-gzFile gzdopen (fd, mode)
+gzFile ZEXPORT gzdopen (fd, mode)
int fd;
const char *mode;
{
@@ -169,6 +192,31 @@ gzFile gzdopen (fd, mode)
}
/* ===========================================================================
+ * Update the compression level and strategy
+ */
+int ZEXPORT gzsetparams (file, level, strategy)
+ gzFile file;
+ int level;
+ int strategy;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
+
+ /* Make room to allow flushing */
+ if (s->stream.avail_out == 0) {
+
+ s->stream.next_out = s->outbuf;
+ if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
+ s->z_err = Z_ERRNO;
+ }
+ s->stream.avail_out = Z_BUFSIZE;
+ }
+
+ return deflateParams (&(s->stream), level, strategy);
+}
+
+/* ===========================================================================
Read a byte from a gz_stream; update next_in and avail_in. Return EOF
for end of file.
IN assertion: the stream s has been sucessfully opened for reading.
@@ -212,8 +260,11 @@ local void check_header(s)
for (len = 0; len < 2; len++) {
c = get_byte(s);
if (c != gz_magic[len]) {
- s->transparent = 1;
- if (c != EOF) s->stream.avail_in++, s->stream.next_in--;
+ if (len != 0) s->stream.avail_in++, s->stream.next_in--;
+ if (c != EOF) {
+ s->stream.avail_in++, s->stream.next_in--;
+ s->transparent = 1;
+ }
s->z_err = s->stream.avail_in != 0 ? Z_OK : Z_STREAM_END;
return;
}
@@ -260,14 +311,21 @@ local int destroy (s)
TRYFREE(s->msg);
if (s->stream.state != NULL) {
- if (s->mode == 'w') {
- err = deflateEnd(&(s->stream));
- } else if (s->mode == 'r') {
- err = inflateEnd(&(s->stream));
- }
+ if (s->mode == 'w') {
+#ifdef NO_DEFLATE
+ err = Z_STREAM_ERROR;
+#else
+ err = deflateEnd(&(s->stream));
+#endif
+ } else if (s->mode == 'r') {
+ err = inflateEnd(&(s->stream));
+ }
}
if (s->file != NULL && fclose(s->file)) {
- err = Z_ERRNO;
+#ifdef ESPIPE
+ if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */
+#endif
+ err = Z_ERRNO;
}
if (s->z_err < 0) err = s->z_err;
@@ -282,13 +340,13 @@ local int destroy (s)
Reads the given number of uncompressed bytes from the compressed file.
gzread returns the number of bytes actually read (0 for end of file).
*/
-int gzread (file, buf, len)
+int ZEXPORT gzread (file, buf, len)
gzFile file;
voidp buf;
unsigned len;
{
gz_stream *s = (gz_stream*)file;
- Bytef *start = buf; /* starting point for crc computation */
+ Bytef *start = (Bytef*)buf; /* starting point for crc computation */
Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */
if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR;
@@ -296,7 +354,8 @@ int gzread (file, buf, len)
if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1;
if (s->z_err == Z_STREAM_END) return 0; /* EOF */
- s->stream.next_out = next_out = buf;
+ next_out = (Byte*)buf;
+ s->stream.next_out = (Bytef*)buf;
s->stream.avail_out = len;
while (s->stream.avail_out != 0) {
@@ -317,7 +376,10 @@ int gzread (file, buf, len)
s->stream.avail_out -= fread(next_out, 1, s->stream.avail_out,
s->file);
}
- return (int)(len - s->stream.avail_out);
+ len -= s->stream.avail_out;
+ s->stream.total_in += (uLong)len;
+ s->stream.total_out += (uLong)len;
+ return (int)len;
}
if (s->stream.avail_in == 0 && !s->z_eof) {
@@ -345,7 +407,12 @@ int gzread (file, buf, len)
/* Check for concatenated .gz files: */
check_header(s);
if (s->z_err == Z_OK) {
+ uLong total_in = s->stream.total_in;
+ uLong total_out = s->stream.total_out;
+
inflateReset(&(s->stream));
+ s->stream.total_in = total_in;
+ s->stream.total_out = total_out;
s->crc = crc32(0L, Z_NULL, 0);
}
}
@@ -357,11 +424,49 @@ int gzread (file, buf, len)
return (int)(len - s->stream.avail_out);
}
+
+/* ===========================================================================
+ Reads one byte from the compressed file. gzgetc returns this byte
+ or -1 in case of end of file or error.
+*/
+int ZEXPORT gzgetc(file)
+ gzFile file;
+{
+ unsigned char c;
+
+ return gzread(file, &c, 1) == 1 ? c : -1;
+}
+
+
+/* ===========================================================================
+ Reads bytes from the compressed file until len-1 characters are
+ read, or a newline character is read and transferred to buf, or an
+ end-of-file condition is encountered. The string is then terminated
+ with a null character.
+ gzgets returns buf, or Z_NULL in case of error.
+
+ The current implementation is not optimized at all.
+*/
+char * ZEXPORT gzgets(file, buf, len)
+ gzFile file;
+ char *buf;
+ int len;
+{
+ char *b = buf;
+ if (buf == Z_NULL || len <= 0) return Z_NULL;
+
+ while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ;
+ *buf = '\0';
+ return b == buf && len > 0 ? Z_NULL : b;
+}
+
+
+#ifndef NO_DEFLATE
/* ===========================================================================
Writes the given number of uncompressed bytes into the compressed file.
gzwrite returns the number of bytes actually written (0 in case of error).
*/
-int gzwrite (file, buf, len)
+int ZEXPORT gzwrite (file, buf, len)
gzFile file;
const voidp buf;
unsigned len;
@@ -370,7 +475,7 @@ int gzwrite (file, buf, len)
if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
- s->stream.next_in = buf;
+ s->stream.next_in = (Bytef*)buf;
s->stream.avail_in = len;
while (s->stream.avail_in != 0) {
@@ -387,18 +492,95 @@ int gzwrite (file, buf, len)
s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
if (s->z_err != Z_OK) break;
}
- s->crc = crc32(s->crc, buf, len);
+ s->crc = crc32(s->crc, (const Bytef *)buf, len);
return (int)(len - s->stream.avail_in);
}
/* ===========================================================================
+ Converts, formats, and writes the args to the compressed file under
+ control of the format string, as in fprintf. gzprintf returns the number of
+ uncompressed bytes actually written (0 in case of error).
+*/
+#ifdef STDC
+#include <stdarg.h>
+
+int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...)
+{
+ char buf[Z_PRINTF_BUFSIZE];
+ va_list va;
+ int len;
+
+ va_start(va, format);
+#ifdef HAS_vsnprintf
+ (void)vsnprintf(buf, sizeof(buf), format, va);
+#else
+ (void)vsprintf(buf, format, va);
+#endif
+ va_end(va);
+ len = strlen(buf); /* some *sprintf don't return the nb of bytes written */
+ if (len <= 0) return 0;
+
+ return gzwrite(file, buf, (unsigned)len);
+}
+#else /* not ANSI C */
+
+int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+ a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
+ gzFile file;
+ const char *format;
+ int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+ a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
+{
+ char buf[Z_PRINTF_BUFSIZE];
+ int len;
+
+#ifdef HAS_snprintf
+ snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
+ a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+#else
+ sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
+ a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+#endif
+ len = strlen(buf); /* old sprintf doesn't return the nb of bytes written */
+ if (len <= 0) return 0;
+
+ return gzwrite(file, buf, len);
+}
+#endif
+
+/* ===========================================================================
+ Writes c, converted to an unsigned char, into the compressed file.
+ gzputc returns the value that was written, or -1 in case of error.
+*/
+int ZEXPORT gzputc(file, c)
+ gzFile file;
+ int c;
+{
+ unsigned char cc = (unsigned char) c; /* required for big endian systems */
+
+ return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1;
+}
+
+
+/* ===========================================================================
+ Writes the given null-terminated string to the compressed file, excluding
+ the terminating null character.
+ gzputs returns the number of characters written, or -1 in case of error.
+*/
+int ZEXPORT gzputs(file, s)
+ gzFile file;
+ const char *s;
+{
+ return gzwrite(file, (const voidp)s, (unsigned)strlen(s));
+}
+
+
+/* ===========================================================================
Flushes all pending output into the compressed file. The parameter
flush is as in the deflate() function.
- gzflush should be called only when strictly necessary because it can
- degrade compression.
*/
-int gzflush (file, flush)
+local int do_flush (file, flush)
gzFile file;
int flush;
{
@@ -424,6 +606,9 @@ int gzflush (file, flush)
if (done) break;
s->z_err = deflate(&(s->stream), flush);
+ /* Ignore the second of two consecutive flushes: */
+ if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK;
+
/* deflate has finished flushing only when it hasn't used up
* all the available space in the output buffer:
*/
@@ -431,9 +616,154 @@ int gzflush (file, flush)
if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break;
}
+ return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
+}
+
+int ZEXPORT gzflush (file, flush)
+ gzFile file;
+ int flush;
+{
+ gz_stream *s = (gz_stream*)file;
+ int err = do_flush (file, flush);
+
+ if (err) return err;
fflush(s->file);
return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
}
+#endif /* NO_DEFLATE */
+
+/* ===========================================================================
+ Sets the starting position for the next gzread or gzwrite on the given
+ compressed file. The offset represents a number of bytes in the
+ gzseek returns the resulting offset location as measured in bytes from
+ the beginning of the uncompressed stream, or -1 in case of error.
+ SEEK_END is not implemented, returns error.
+ In this version of the library, gzseek can be extremely slow.
+*/
+z_off_t ZEXPORT gzseek (file, offset, whence)
+ gzFile file;
+ z_off_t offset;
+ int whence;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || whence == SEEK_END ||
+ s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) {
+ return -1L;
+ }
+
+ if (s->mode == 'w') {
+#ifdef NO_DEFLATE
+ return -1L;
+#else
+ if (whence == SEEK_SET) {
+ offset -= s->stream.total_out;
+ }
+ if (offset < 0) return -1L;
+
+ /* At this point, offset is the number of zero bytes to write. */
+ if (s->inbuf == Z_NULL) {
+ s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */
+ zmemzero(s->inbuf, Z_BUFSIZE);
+ }
+ while (offset > 0) {
+ uInt size = Z_BUFSIZE;
+ if (offset < Z_BUFSIZE) size = (uInt)offset;
+
+ size = gzwrite(file, s->inbuf, size);
+ if (size == 0) return -1L;
+
+ offset -= size;
+ }
+ return (z_off_t)s->stream.total_in;
+#endif
+ }
+ /* Rest of function is for reading only */
+
+ /* compute absolute position */
+ if (whence == SEEK_CUR) {
+ offset += s->stream.total_out;
+ }
+ if (offset < 0) return -1L;
+
+ if (s->transparent) {
+ /* map to fseek */
+ s->stream.avail_in = 0;
+ s->stream.next_in = s->inbuf;
+ if (fseek(s->file, offset, SEEK_SET) < 0) return -1L;
+
+ s->stream.total_in = s->stream.total_out = (uLong)offset;
+ return offset;
+ }
+
+ /* For a negative seek, rewind and use positive seek */
+ if ((uLong)offset >= s->stream.total_out) {
+ offset -= s->stream.total_out;
+ } else if (gzrewind(file) < 0) {
+ return -1L;
+ }
+ /* offset is now the number of bytes to skip. */
+
+ if (offset != 0 && s->outbuf == Z_NULL) {
+ s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
+ }
+ while (offset > 0) {
+ int size = Z_BUFSIZE;
+ if (offset < Z_BUFSIZE) size = (int)offset;
+
+ size = gzread(file, s->outbuf, (uInt)size);
+ if (size <= 0) return -1L;
+ offset -= size;
+ }
+ return (z_off_t)s->stream.total_out;
+}
+
+/* ===========================================================================
+ Rewinds input file.
+*/
+int ZEXPORT gzrewind (file)
+ gzFile file;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'r') return -1;
+
+ s->z_err = Z_OK;
+ s->z_eof = 0;
+ s->stream.avail_in = 0;
+ s->stream.next_in = s->inbuf;
+
+ if (s->startpos == 0) { /* not a compressed file */
+ rewind(s->file);
+ return 0;
+ }
+
+ (void) inflateReset(&s->stream);
+ return fseek(s->file, s->startpos, SEEK_SET);
+}
+
+/* ===========================================================================
+ Returns the starting position for the next gzread or gzwrite on the
+ given compressed file. This position represents a number of bytes in the
+ uncompressed data stream.
+*/
+z_off_t ZEXPORT gztell (file)
+ gzFile file;
+{
+ return gzseek(file, 0L, SEEK_CUR);
+}
+
+/* ===========================================================================
+ Returns 1 when EOF has previously been detected reading the given
+ input stream, otherwise zero.
+*/
+int ZEXPORT gzeof (file)
+ gzFile file;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ return (s == NULL || s->mode != 'r') ? 0 : s->z_eof;
+}
/* ===========================================================================
Outputs a long in LSB order to the given file
@@ -470,7 +800,7 @@ local uLong getLong (s)
Flushes all pending output if necessary, closes the compressed file
and deallocates all the (de)compression state.
*/
-int gzclose (file)
+int ZEXPORT gzclose (file)
gzFile file;
{
int err;
@@ -479,14 +809,17 @@ int gzclose (file)
if (s == NULL) return Z_STREAM_ERROR;
if (s->mode == 'w') {
- err = gzflush (file, Z_FINISH);
- if (err != Z_OK) return destroy(file);
+#ifdef NO_DEFLATE
+ return Z_STREAM_ERROR;
+#else
+ err = do_flush (file, Z_FINISH);
+ if (err != Z_OK) return destroy((gz_stream*)file);
putLong (s->file, s->crc);
putLong (s->file, s->stream.total_in);
-
+#endif
}
- return destroy(file);
+ return destroy((gz_stream*)file);
}
/* ===========================================================================
@@ -496,7 +829,7 @@ int gzclose (file)
errnum is set to Z_ERRNO and the application may consult errno
to get the exact error code.
*/
-const char* gzerror (file, errnum)
+const char* ZEXPORT gzerror (file, errnum)
gzFile file;
int *errnum;
{
OpenPOWER on IntegriCloud