6 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 /* file_access interface based heavily on zlib gzread.c and gzlib.c from zlib
24 * Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler
27 * This software is provided 'as-is', without any express or implied
28 * warranty. In no event will the authors be held liable for any damages
29 * arising from the use of this software.
31 * Permission is granted to anyone to use this software for any purpose,
32 * including commercial applications, and to alter it and redistribute it
33 * freely, subject to the following restrictions:
35 * 1. The origin of this software must not be misrepresented; you must not
36 * claim that you wrote the original software. If you use this software
37 * in a product, an acknowledgment in the product documentation would be
38 * appreciated but is not required.
39 * 2. Altered source versions must be plainly marked as such, and must not be
40 * misrepresented as being the original software.
41 * 3. This notice may not be removed or altered from any source distribution.
50 #endif /* HAVE_UNISTD_H */
56 #endif /* HAVE_FCNTL_H */
59 #include "file_wrappers.h"
60 #include <wsutil/file_util.h>
63 * See RFC 1952 for a description of the gzip file format.
65 * Some other compressed file formats we might want to support:
67 * XZ format: http://tukaani.org/xz/
69 * Bzip2 format: http://bzip.org/
72 /* #define GZBUFSIZE 8192 */
73 #define GZBUFSIZE 4096
76 int fd; /* file descriptor */
77 gint64 raw_pos; /* current position in file (just to not call lseek()) */
78 gint64 pos; /* current position in uncompressed data */
79 unsigned size; /* buffer size */
80 unsigned char *in; /* input buffer */
81 unsigned char *out; /* output buffer (double-sized when reading) */
82 unsigned char *next; /* next output data to deliver or write */
84 unsigned have; /* amount of output data unused at next */
85 int eof; /* true if end of input file reached */
86 gint64 start; /* where the gzip data started, for rewinding */
87 gint64 raw; /* where the raw data started, for seeking */
88 int compression; /* 0: ?, 1: uncompressed, 2: zlib */
90 gint64 skip; /* amount to skip (already rewound if backwards) */
91 int seek; /* true if seek request pending */
92 /* error information */
93 int err; /* error code */
95 unsigned int avail_in; /* number of bytes available at next_in */
96 unsigned char *next_in; /* next input byte */
98 /* zlib inflate stream */
99 z_stream strm; /* stream structure in-place (not a pointer) */
102 GPtrArray *fast_seek;
106 /* values for gz_state compression */
107 #define UNKNOWN 0 /* look for a gzip header */
108 #define UNCOMPRESSED 1 /* copy input directly */
110 #define ZLIB 2 /* decompress a zlib stream */
111 #define GZIP_AFTER_HEADER 3
114 static int /* gz_load */
115 raw_read(FILE_T state, unsigned char *buf, unsigned int count, unsigned *have)
121 ret = read(state->fd, buf + *have, count - *have);
125 state->raw_pos += ret;
126 } while (*have < count);
136 static int /* gz_avail */
137 fill_in_buffer(FILE_T state)
141 if (state->eof == 0) {
142 if (raw_read(state, state->in, state->size, (unsigned *)&(state->avail_in)) == -1)
144 state->next_in = state->in;
149 #define ZLIB_WINSIZE 32768
151 struct fast_seek_point {
152 gint64 out; /* corresponding offset in uncompressed data */
153 gint64 in; /* offset in input file of first full byte */
158 int bits; /* number of bits (1-7) from byte at in - 1, or 0 */
159 unsigned char window[ZLIB_WINSIZE]; /* preceding 32K of uncompressed data */
161 /* be gentle with Z_STREAM_END, 8 bytes more... Another solution would be to comment checks out */
168 struct zlib_cur_seek_point {
169 unsigned char window[ZLIB_WINSIZE]; /* preceding 32K of uncompressed data */
174 #define SPAN G_GINT64_CONSTANT(1048576)
175 static struct fast_seek_point *
176 fast_seek_find(FILE_T file, gint64 pos)
178 struct fast_seek_point *smallest = NULL;
179 struct fast_seek_point *item;
182 if (!file->fast_seek)
185 for (low = 0, max = file->fast_seek->len; low < max; ) {
187 item = file->fast_seek->pdata[i];
191 else if (pos > item->out) {
202 fast_seek_header(FILE_T file, gint64 in_pos, gint64 out_pos, int compression)
204 struct fast_seek_point *item = NULL;
206 if (file->fast_seek->len != 0)
207 item = file->fast_seek->pdata[file->fast_seek->len - 1];
209 if (!item || item->out < out_pos) {
210 struct fast_seek_point *val = g_malloc(sizeof(struct fast_seek_point));
213 val->compression = compression;
215 g_ptr_array_add(file->fast_seek, val);
220 fast_seek_reset(FILE_T state)
223 if (state->compression == ZLIB && state->fast_seek_cur) {
224 struct zlib_cur_seek_point *cur = (struct zlib_cur_seek_point *) state->fast_seek_cur;
233 /* Get next byte from input, or -1 if end or error. */
234 #define NEXT() ((state->avail_in == 0 && fill_in_buffer(state) == -1) ? -1 : \
235 (state->avail_in == 0 ? -1 : \
236 (state->avail_in--, *(state->next_in)++)))
238 /* Get a four-byte little-endian integer and return 0 on success and the value
239 in *ret. Otherwise -1 is returned and *ret is not modified. */
241 gz_next4(FILE_T state, guint32 *ret)
247 val += (unsigned)NEXT() << 8;
248 val += (guint32)NEXT() << 16;
252 val += (guint32)ch << 24;
258 zlib_fast_seek_add(FILE_T file, struct zlib_cur_seek_point *point, int bits, gint64 in_pos, gint64 out_pos)
260 /* it's for sure after gzip header, so file->fast_seek->len != 0 */
261 struct fast_seek_point *item = file->fast_seek->pdata[file->fast_seek->len - 1];;
263 /* Glib has got Balanced Binary Trees (GTree) but I couldn't find a way to do quick search for nearest (and smaller) value to seek (It's what fast_seek_find() do)
264 * Inserting value in middle of sorted array is expensive, so we want to add only in the end.
265 * It's not big deal, cause first-read don't usually invoke seeking
267 if (item->out + SPAN < out_pos) {
268 struct fast_seek_point *val = g_malloc(sizeof(struct fast_seek_point));
271 val->compression = ZLIB;
273 val->data.zlib.bits = bits;
274 if (point->pos != 0) {
275 unsigned int left = ZLIB_WINSIZE - point->pos;
277 memcpy(val->data.zlib.window, point->window + point->pos, left);
278 memcpy(val->data.zlib.window + left, point->window, point->pos);
280 memcpy(val->data.zlib.window, point->window, ZLIB_WINSIZE);
282 val->data.zlib.adler = file->strm.adler;
283 val->data.zlib.total_out = file->strm.total_out;
284 g_ptr_array_add(file->fast_seek, val);
288 static void /* gz_decomp */
289 zlib_read(FILE_T state, unsigned char *buf, unsigned int count)
291 int ret = 0; /* XXX */
293 z_streamp strm = &(state->strm);
295 unsigned char *buf2 = buf;
296 unsigned int count2 = count;
298 strm->avail_out = count;
299 strm->next_out = buf;
301 /* fill output buffer up to end of deflate stream */
303 /* get more input for inflate() */
304 if (state->avail_in == 0 && fill_in_buffer(state) == -1)
306 if (state->avail_in == 0) {
307 state->err = WTAP_ERR_ZLIB + Z_DATA_ERROR;
311 strm->avail_in = state->avail_in;
312 strm->next_in = state->next_in;
313 /* decompress and handle errors */
314 /* ret = inflate(strm, Z_NO_FLUSH); */
315 ret = inflate(strm, Z_BLOCK);
316 state->avail_in = strm->avail_in;
317 state->next_in = strm->next_in;
318 if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) {
319 state->err = WTAP_ERR_ZLIB + Z_STREAM_ERROR;
322 if (ret == Z_MEM_ERROR) {
323 state->err = WTAP_ERR_ZLIB + Z_MEM_ERROR; /* ENOMEM? */
326 if (ret == Z_DATA_ERROR) { /* deflate stream invalid */
327 state->err = WTAP_ERR_ZLIB + Z_DATA_ERROR;
331 strm->adler = crc32(strm->adler, buf2, count2 - strm->avail_out);
332 if (state->fast_seek_cur) {
333 struct zlib_cur_seek_point *cur = (struct zlib_cur_seek_point *) state->fast_seek_cur;
334 unsigned int ready = count2 - strm->avail_out;
336 if (ready < ZLIB_WINSIZE) {
337 unsigned left = ZLIB_WINSIZE - cur->pos;
340 memcpy(cur->window + cur->pos, buf2, left);
342 memcpy(cur->window, buf2 + left, ready - left);
344 cur->pos = ready - left;
347 memcpy(cur->window + cur->pos, buf2, ready);
352 if (cur->have >= ZLIB_WINSIZE)
353 cur->have = ZLIB_WINSIZE;
356 memcpy(cur->window, buf2 + (ready - ZLIB_WINSIZE), ZLIB_WINSIZE);
358 cur->have = ZLIB_WINSIZE;
361 if (cur->have >= ZLIB_WINSIZE && ret != Z_STREAM_END && (strm->data_type & 128) && !(strm->data_type & 64))
362 zlib_fast_seek_add(state, cur, (strm->data_type & 7), state->raw_pos - strm->avail_in, state->pos + (count - strm->avail_out));
364 buf2 = (buf2 + count2 - strm->avail_out);
365 count2 = strm->avail_out;
367 } while (strm->avail_out && ret != Z_STREAM_END);
369 /* update available output and crc check value */
371 state->have = count - strm->avail_out;
373 /* check gzip trailer if at end of deflate stream */
374 if (ret == Z_STREAM_END) {
375 if (gz_next4(state, &crc) == -1 || gz_next4(state, &len) == -1)
376 state->err = WTAP_ERR_ZLIB + Z_DATA_ERROR;
377 if (crc != strm->adler)
378 state->err = WTAP_ERR_ZLIB + Z_DATA_ERROR;
379 if (len != (strm->total_out & 0xffffffffL))
380 state->err = WTAP_ERR_ZLIB + Z_DATA_ERROR;
381 state->compression = UNKNOWN; /* ready for next stream, once have is 0 */
382 g_free(state->fast_seek_cur);
383 state->fast_seek_cur = NULL;
389 gz_head(FILE_T state)
391 /* get some data in the input buffer */
392 if (state->avail_in == 0) {
393 if (fill_in_buffer(state) == -1)
395 if (state->avail_in == 0)
399 /* look for the gzip magic header bytes 31 and 139 */
401 if (state->next_in[0] == 31) {
404 if (state->avail_in == 0 && fill_in_buffer(state) == -1)
406 if (state->avail_in && state->next_in[0] == 139) {
410 /* we have a gzip header, woo hoo! */
414 /* skip rest of header */
415 if (NEXT() != 8) { /* compression method */
416 state->err = WTAP_ERR_ZLIB + Z_DATA_ERROR;
420 if (flags & 0xe0) { /* reserved flag bits */
421 state->err = WTAP_ERR_ZLIB + Z_DATA_ERROR;
424 NEXT(); /* modification time */
428 NEXT(); /* extra flags */
429 NEXT(); /* operating system */
430 if (flags & 4) { /* extra field */
431 len = (unsigned)NEXT();
432 len += (unsigned)NEXT() << 8;
437 if (flags & 8) /* file name */
440 if (flags & 16) /* comment */
443 if (flags & 2) { /* header crc */
447 /* an unexpected end of file is not checked for here -- it will be
448 noticed on the first request for uncompressed data */
450 /* set up for decompression */
451 inflateReset(&(state->strm));
452 state->strm.adler = crc32(0L, Z_NULL, 0);
453 state->compression = ZLIB;
455 if (state->fast_seek) {
456 struct zlib_cur_seek_point *cur = g_malloc(sizeof(struct zlib_cur_seek_point));
458 cur->pos = cur->have = 0;
459 g_free(state->fast_seek_cur);
460 state->fast_seek_cur = cur;
461 fast_seek_header(state, state->raw_pos - state->avail_in, state->pos, GZIP_AFTER_HEADER);
466 /* not a gzip file -- save first byte (31) and fall to raw i/o */
473 /* { 0xFD, '7', 'z', 'X', 'Z', 0x00 } */
474 /* FD 37 7A 58 5A 00 */
476 if (state->fast_seek)
477 fast_seek_header(state, state->raw_pos - state->avail_in - state->have, state->pos, UNCOMPRESSED);
479 /* doing raw i/o, save start of raw data for seeking, copy any leftover
480 input to output -- this assumes that the output buffer is larger than
481 the input buffer, which also assures space for gzungetc() */
482 state->raw = state->pos;
483 state->next = state->out;
484 if (state->avail_in) {
485 memcpy(state->next + state->have, state->next_in, state->avail_in);
486 state->have += state->avail_in;
489 state->compression = UNCOMPRESSED;
493 static int /* gz_make */
494 fill_out_buffer(FILE_T state)
496 if (state->compression == UNKNOWN) { /* look for gzip header */
497 if (gz_head(state) == -1)
499 if (state->have) /* got some data from gz_head() */
502 if (state->compression == UNCOMPRESSED) { /* straight copy */
503 if (raw_read(state, state->out, state->size /* << 1 */, &(state->have)) == -1)
505 state->next = state->out;
508 else if (state->compression == ZLIB) { /* decompress */
509 zlib_read(state, state->out, state->size << 1);
516 gz_skip(FILE_T state, gint64 len)
520 /* skip over len bytes or reach end-of-file, whichever comes first */
522 /* skip over whatever is in output buffer */
524 n = (gint64)state->have > len ? (unsigned)len : state->have;
531 /* delayed error reporting */
535 /* output buffer empty -- return if we're at the end of the input */
536 else if (state->eof && state->avail_in == 0)
539 /* need more data to skip -- load up output buffer */
541 /* get more output, looking for header if required */
542 if (fill_out_buffer(state) == -1)
549 gz_reset(FILE_T state)
551 state->have = 0; /* no output data available */
552 state->eof = 0; /* not at end of file */
553 state->compression = UNKNOWN; /* look for gzip header */
555 state->seek = 0; /* no seek request pending */
556 state->err = 0; /* clear error */
557 state->pos = 0; /* no uncompressed data yet */
558 state->avail_in = 0; /* no input data yet */
564 #ifdef _STATBUF_ST_BLKSIZE /* XXX, _STATBUF_ST_BLKSIZE portable? */
567 int want = GZBUFSIZE;
573 /* allocate FILE_T structure to return */
574 state = g_try_malloc(sizeof *state);
578 state->fast_seek_cur = NULL;
579 state->fast_seek = NULL;
581 /* open the file with the appropriate mode (or just use fd) */
584 /* save the current position for rewinding (only if reading) */
585 state->start = ws_lseek64(state->fd, 0, SEEK_CUR);
586 if (state->start == -1) state->start = 0;
587 state->raw_pos = state->start;
589 /* initialize stream */
592 #ifdef _STATBUF_ST_BLKSIZE
593 if (fstat(fd, &st) >= 0) {
594 want = st.st_blksize;
595 /* XXX, verify result? */
599 /* allocate buffers */
600 state->in = g_try_malloc(want);
601 state->out = g_try_malloc(want << 1);
603 if (state->in == NULL || state->out == NULL) {
612 /* allocate inflate memory */
613 state->strm.zalloc = Z_NULL;
614 state->strm.zfree = Z_NULL;
615 state->strm.opaque = Z_NULL;
616 state->strm.avail_in = 0;
617 state->strm.next_in = Z_NULL;
618 if (inflateInit2(&(state->strm), -15) != Z_OK) { /* raw inflate */
631 file_open(const char *path)
643 /* open file and do correct filename conversions */
644 if ((fd = ws_open(path, oflag, 0666)) == -1)
647 /* open file handle */
658 file_set_random_access(FILE_T stream, gboolean random _U_, GPtrArray *seek)
660 stream->fast_seek = seek;
664 file_seek(FILE_T file, gint64 offset, int whence, int *err)
666 struct fast_seek_point *here;
669 /* can only seek from start or relative to current position */
670 if (whence != SEEK_SET && whence != SEEK_CUR) {
671 g_assert_not_reached();
678 /* normalize offset to a SEEK_CUR specification */
679 if (whence == SEEK_SET)
682 offset += file->skip;
686 if ((here = fast_seek_find(file, file->pos + offset)) && (offset < 0 || offset > SPAN || here->compression == UNCOMPRESSED)) {
690 if (here->compression == ZLIB) {
691 off = here->in - (here->data.zlib.bits ? 1 : 0);
693 } else if (here->compression == GZIP_AFTER_HEADER) {
699 off2 = (file->pos + offset);
700 off = here->in + (off2 - here->out);
703 if (ws_lseek64(file->fd, off, SEEK_SET) == -1) {
707 fast_seek_reset(file);
717 if (here->compression == ZLIB) {
718 z_stream *strm = &file->strm;
722 strm->adler = here->data.zlib.adler;
723 strm->total_out = here->data.zlib.total_out;
724 if (here->data.zlib.bits) {
732 (void)inflatePrime(strm, here->data.zlib.bits, ret >> (8 - here->data.zlib.bits));
734 (void)inflateSetDictionary(strm, here->data.zlib.window, ZLIB_WINSIZE);
735 file->compression = ZLIB;
736 } else if (here->compression == GZIP_AFTER_HEADER) {
737 z_stream *strm = &file->strm;
740 strm->adler = crc32(0L, Z_NULL, 0);
741 file->compression = ZLIB;
744 file->compression = here->compression;
746 offset = (file->pos + offset) - off2;
748 /* g_print("OK! %ld\n", offset); */
754 return file->pos + offset;
757 /* if within raw area while reading, just go there */
758 if (file->compression == UNCOMPRESSED && file->pos + offset >= file->raw) {
759 if (ws_lseek64(file->fd, offset - file->have, SEEK_CUR) == -1) {
763 file->raw_pos += (offset - file->have);
773 /* calculate skip amount, rewinding if needed for back seek when reading */
776 if (offset < 0) { /* before start of file! */
780 /* rewind, then skip to offset */
782 /* back up and start over */
783 if (ws_lseek64(file->fd, file->start, SEEK_SET) == -1) {
787 fast_seek_reset(file);
788 file->raw_pos = file->start;
792 /* skip what's in output buffer (one less gzgetc() check) */
793 n = (gint64)file->have > offset ? (unsigned)offset : file->have;
799 /* request skip (if not zero) */
804 return file->pos + offset;
808 file_tell(FILE_T stream)
810 /* return position */
811 return stream->pos + (stream->seek ? stream->skip : 0);
815 file_read(void *buf, unsigned int len, FILE_T file)
819 /* if len is zero, avoid unnecessary operations */
823 /* process a skip request */
826 if (gz_skip(file, file->skip) == -1)
830 /* get len bytes to buf, or less than len if at the end */
833 /* first just try copying data from the output buffer */
835 n = file->have > len ? len : file->have;
836 memcpy(buf, file->next, n);
840 /* delayed error reporting (for zlib) */
844 /* output buffer empty -- return if we're at the end of the input */
845 else if (file->eof && file->avail_in == 0)
848 /* need output data */
850 /* get more output, looking for header if required */
851 if (fill_out_buffer(file) == -1)
853 continue; /* no progress yet -- go back to memcpy() above */
855 /* update progress */
857 buf = (char *)buf + n;
866 file_getc(FILE_T file)
868 unsigned char buf[1];
871 /* check that we're reading and that there's no error */
875 /* try output buffer (no need to check for skip request) */
879 return *(file->next)++;
882 ret = file_read(buf, 1, file);
883 return ret < 1 ? -1 : buf[0];
887 file_gets(char *buf, int len, FILE_T file)
893 /* check parameters */
894 if (buf == NULL || len < 1)
897 /* check that there's no error */
901 /* process a skip request */
904 if (gz_skip(file, file->skip) == -1)
908 /* copy output bytes up to new line or len - 1, whichever comes first --
909 append a terminating zero to the string (we don't check for a zero in
910 the contents, let the user worry about that) */
912 left = (unsigned)len - 1;
914 /* assure that something is in the output buffer */
915 if (file->have == 0) {
916 if (fill_out_buffer(file) == -1)
917 return NULL; /* error */
918 if (file->have == 0) { /* end of file */
919 if (buf == str) /* got bupkus */
921 break; /* got something -- return it */
925 /* look for end-of-line in current output buffer */
926 n = file->have > left ? left : file->have;
927 eol = memchr(file->next, '\n', n);
929 n = (unsigned)(eol - file->next) + 1;
931 /* copy through end-of-line, or remainder if not found */
932 memcpy(buf, file->next, n);
938 } while (left && eol == NULL);
940 /* found end-of-line or out of space -- terminate string and return it */
946 file_eof(FILE_T file)
948 /* return end-of-file state */
949 return (file->eof && file->avail_in == 0 && file->have == 0);
953 * Routine to return a Wiretap error code (0 for no error, an errno
954 * for a file error, or a WTAP_ERR_ code for other errors) for an
958 file_error(FILE_T fh)
964 file_clearerr(FILE_T stream)
966 /* clear error and end-of-file */
972 file_close(FILE_T file)
976 /* free memory and close file */
979 inflateEnd(&(file->strm));
984 g_free(file->fast_seek_cur);
991 /* internal gzip file state data structure for writing */
993 int fd; /* file descriptor */
994 gint64 pos; /* current position in uncompressed data */
995 unsigned size; /* buffer size, zero if not allocated yet */
996 unsigned want; /* requested buffer size, default is GZBUFSIZE */
997 unsigned char *in; /* input buffer */
998 unsigned char *out; /* output buffer (double-sized when reading) */
999 unsigned char *next; /* next output data to deliver or write */
1000 int level; /* compression level */
1001 int strategy; /* compression strategy */
1002 int err; /* error code */
1003 /* zlib deflate stream */
1004 z_stream strm; /* stream structure in-place (not a pointer) */
1008 gzwfile_open(const char *path)
1014 fd = ws_open(path, O_BINARY|O_WRONLY|O_CREAT|O_TRUNC, 0666);
1017 state = gzwfile_fdopen(fd);
1018 if (state == NULL) {
1027 gzwfile_fdopen(int fd)
1031 /* allocate wtap_writer structure to return */
1032 state = g_try_malloc(sizeof *state);
1036 state->size = 0; /* no buffers allocated yet */
1037 state->want = GZBUFSIZE; /* requested buffer size */
1039 state->level = Z_DEFAULT_COMPRESSION;
1040 state->strategy = Z_DEFAULT_STRATEGY;
1042 /* initialize stream */
1043 state->err = Z_OK; /* clear error */
1044 state->pos = 0; /* no uncompressed data yet */
1045 state->strm.avail_in = 0; /* no input data yet */
1051 /* Initialize state for writing a gzip file. Mark initialization by setting
1052 state->size to non-zero. Return -1, and set state->err, on failure;
1053 return 0 on success. */
1055 gz_init(GZWFILE_T state)
1058 z_streamp strm = &(state->strm);
1060 /* allocate input and output buffers */
1061 state->in = g_try_malloc(state->want);
1062 state->out = g_try_malloc(state->want);
1063 if (state->in == NULL || state->out == NULL) {
1064 if (state->out != NULL)
1066 if (state->in != NULL)
1068 state->err = WTAP_ERR_ZLIB + Z_MEM_ERROR; /* ENOMEM? */
1072 /* allocate deflate memory, set up for gzip compression */
1073 strm->zalloc = Z_NULL;
1074 strm->zfree = Z_NULL;
1075 strm->opaque = Z_NULL;
1076 ret = deflateInit2(strm, state->level, Z_DEFLATED,
1077 15 + 16, 8, state->strategy);
1080 state->err = WTAP_ERR_ZLIB + Z_MEM_ERROR; /* ENOMEM? */
1084 /* mark state as initialized */
1085 state->size = state->want;
1087 /* initialize write buffer */
1088 strm->avail_out = state->size;
1089 strm->next_out = state->out;
1090 state->next = strm->next_out;
1094 /* Compress whatever is at avail_in and next_in and write to the output file.
1095 Return -1, and set state->err, if there is an error writing to the output
1096 file; return 0 on success.
1097 flush is assumed to be a valid deflate() flush value. If flush is Z_FINISH,
1098 then the deflate() state is reset to start a new gzip stream. */
1100 gz_comp(GZWFILE_T state, int flush)
1104 z_streamp strm = &(state->strm);
1106 /* allocate memory if this is the first time through */
1107 if (state->size == 0 && gz_init(state) == -1)
1110 /* run deflate() on provided input until it produces no more output */
1113 /* write out current buffer contents if full, or if flushing, but if
1114 doing Z_FINISH then don't write until we get to Z_STREAM_END */
1115 if (strm->avail_out == 0 || (flush != Z_NO_FLUSH &&
1116 (flush != Z_FINISH || ret == Z_STREAM_END))) {
1117 have = (unsigned)(strm->next_out - state->next);
1119 got = write(state->fd, state->next, have);
1124 if ((unsigned)got != have) {
1125 state->err = WTAP_ERR_SHORT_WRITE;
1129 if (strm->avail_out == 0) {
1130 strm->avail_out = state->size;
1131 strm->next_out = state->out;
1133 state->next = strm->next_out;
1137 have = strm->avail_out;
1138 ret = deflate(strm, flush);
1139 if (ret == Z_STREAM_ERROR) {
1140 state->err = WTAP_ERR_ZLIB + Z_STREAM_ERROR;
1143 have -= strm->avail_out;
1146 /* if that completed a deflate stream, allow another to start */
1147 if (flush == Z_FINISH)
1150 /* all done, no errors */
1154 /* Write out len bytes from buf. Return 0, and set state->err, on
1155 failure or on an attempt to write 0 bytes (in which case state->err
1156 is Z_OK); return the number of bytes written on success. */
1158 gzwfile_write(GZWFILE_T state, const void *buf, unsigned len)
1164 strm = &(state->strm);
1166 /* check that there's no error */
1167 if (state->err != Z_OK)
1170 /* if len is zero, avoid unnecessary operations */
1174 /* allocate memory if this is the first time through */
1175 if (state->size == 0 && gz_init(state) == -1)
1178 /* for small len, copy to input buffer, otherwise compress directly */
1179 if (len < state->size) {
1180 /* copy to input buffer, compress when full */
1182 if (strm->avail_in == 0)
1183 strm->next_in = state->in;
1184 n = state->size - strm->avail_in;
1187 memcpy(strm->next_in + strm->avail_in, buf, n);
1188 strm->avail_in += n;
1190 buf = (char *)buf + n;
1192 if (len && gz_comp(state, Z_NO_FLUSH) == -1)
1197 /* consume whatever's left in the input buffer */
1198 if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
1201 /* directly compress user buffer to file */
1202 strm->avail_in = len;
1203 strm->next_in = (voidp)buf;
1205 if (gz_comp(state, Z_NO_FLUSH) == -1)
1209 /* input was all buffered or compressed (put will fit in int) */
1213 /* Flush out what we've written so far. Returns -1, and sets state->err,
1214 on failure; returns 0 on success. */
1216 gzwfile_flush(GZWFILE_T state)
1218 /* check that there's no error */
1219 if (state->err != Z_OK)
1222 /* compress remaining data with Z_SYNC_FLUSH */
1223 gz_comp(state, Z_SYNC_FLUSH);
1224 if (state->err != Z_OK)
1229 /* Flush out all data written, and close the file. Returns a Wiretap
1230 error on failure; returns 0 on success. */
1232 gzwfile_close(GZWFILE_T state)
1236 /* flush, free memory, and close file */
1237 if (gz_comp(state, Z_FINISH) == -1 && ret == 0)
1239 (void)deflateEnd(&(state->strm));
1243 if (close(state->fd) == -1 && ret == 0)
1250 gzwfile_geterr(GZWFILE_T state)