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 */
94 char *err_info; /* additional error information string for some errors */
96 unsigned int avail_in; /* number of bytes available at next_in */
97 unsigned char *next_in; /* next input byte */
99 /* zlib inflate stream */
100 z_stream strm; /* stream structure in-place (not a pointer) */
101 int dont_check_crc; /* 1 if we aren't supposed to check the CRC */
104 GPtrArray *fast_seek;
108 /* values for gz_state compression */
109 #define UNKNOWN 0 /* look for a gzip header */
110 #define UNCOMPRESSED 1 /* copy input directly */
112 #define ZLIB 2 /* decompress a zlib stream */
113 #define GZIP_AFTER_HEADER 3
116 static int /* gz_load */
117 raw_read(FILE_T state, unsigned char *buf, unsigned int count, unsigned *have)
123 ret = read(state->fd, buf + *have, count - *have);
127 state->raw_pos += ret;
128 } while (*have < count);
131 state->err_info = NULL;
139 static int /* gz_avail */
140 fill_in_buffer(FILE_T state)
144 if (state->eof == 0) {
145 if (raw_read(state, state->in, state->size, (unsigned *)&(state->avail_in)) == -1)
147 state->next_in = state->in;
152 #define ZLIB_WINSIZE 32768
154 struct fast_seek_point {
155 gint64 out; /* corresponding offset in uncompressed data */
156 gint64 in; /* offset in input file of first full byte */
161 #ifdef HAVE_INFLATEPRIME
162 int bits; /* number of bits (1-7) from byte at in - 1, or 0 */
164 unsigned char window[ZLIB_WINSIZE]; /* preceding 32K of uncompressed data */
166 /* be gentle with Z_STREAM_END, 8 bytes more... Another solution would be to comment checks out */
173 struct zlib_cur_seek_point {
174 unsigned char window[ZLIB_WINSIZE]; /* preceding 32K of uncompressed data */
179 #define SPAN G_GINT64_CONSTANT(1048576)
180 static struct fast_seek_point *
181 fast_seek_find(FILE_T file, gint64 pos)
183 struct fast_seek_point *smallest = NULL;
184 struct fast_seek_point *item;
187 if (!file->fast_seek)
190 for (low = 0, max = file->fast_seek->len; low < max; ) {
192 item = file->fast_seek->pdata[i];
196 else if (pos > item->out) {
207 fast_seek_header(FILE_T file, gint64 in_pos, gint64 out_pos, int compression)
209 struct fast_seek_point *item = NULL;
211 if (file->fast_seek->len != 0)
212 item = file->fast_seek->pdata[file->fast_seek->len - 1];
214 if (!item || item->out < out_pos) {
215 struct fast_seek_point *val = g_malloc(sizeof(struct fast_seek_point));
218 val->compression = compression;
220 g_ptr_array_add(file->fast_seek, val);
225 fast_seek_reset(FILE_T state _U_)
228 if (state->compression == ZLIB && state->fast_seek_cur) {
229 struct zlib_cur_seek_point *cur = (struct zlib_cur_seek_point *) state->fast_seek_cur;
238 /* Get next byte from input, or -1 if end or error.
242 * 1) errors from raw_read(), and thus from fill_in_buffer(), are
243 * "sticky", and fill_in_buffer() won't do any reading if there's
246 * 2) GZ_GETC() returns -1 on an EOF;
248 * so it's safe to make multiple GZ_GETC() calls and only check the
249 * last one for an error. */
250 #define GZ_GETC() ((state->avail_in == 0 && fill_in_buffer(state) == -1) ? -1 : \
251 (state->avail_in == 0 ? -1 : \
252 (state->avail_in--, *(state->next_in)++)))
254 /* Get a one-byte integer and return 0 on success and the value in *ret.
255 Otherwise -1 is returned, state->err is set, and *ret is not modified. */
257 gz_next1(FILE_T state, guint8 *ret)
263 if (state->err == 0) {
265 state->err = WTAP_ERR_SHORT_READ;
266 state->err_info = NULL;
274 /* Get a two-byte little-endian integer and return 0 on success and the value
275 in *ret. Otherwise -1 is returned, state->err is set, and *ret is not
278 gz_next2(FILE_T state, guint16 *ret)
286 if (state->err == 0) {
288 state->err = WTAP_ERR_SHORT_READ;
289 state->err_info = NULL;
293 val += (guint16)ch << 8;
298 /* Get a four-byte little-endian integer and return 0 on success and the value
299 in *ret. Otherwise -1 is returned, state->err is set, and *ret is not
302 gz_next4(FILE_T state, guint32 *ret)
308 val += (unsigned)GZ_GETC() << 8;
309 val += (guint32)GZ_GETC() << 16;
312 if (state->err == 0) {
314 state->err = WTAP_ERR_SHORT_READ;
315 state->err_info = NULL;
319 val += (guint32)ch << 24;
324 /* Skip the specified number of bytes and return 0 on success. Otherwise -1
327 gz_skipn(FILE_T state, size_t n)
330 if (GZ_GETC() == -1) {
331 if (state->err == 0) {
333 state->err = WTAP_ERR_SHORT_READ;
334 state->err_info = NULL;
343 /* Skip a null-terminated string and return 0 on success. Otherwise -1
346 gz_skipzstr(FILE_T state)
350 /* It's null-terminated, so scan until we read a byte with
351 the value 0 or get an error. */
352 while ((ch = GZ_GETC()) > 0)
355 if (state->err == 0) {
357 state->err = WTAP_ERR_SHORT_READ;
358 state->err_info = NULL;
366 zlib_fast_seek_add(FILE_T file, struct zlib_cur_seek_point *point, int bits, gint64 in_pos, gint64 out_pos)
368 /* it's for sure after gzip header, so file->fast_seek->len != 0 */
369 struct fast_seek_point *item = file->fast_seek->pdata[file->fast_seek->len - 1];;
371 #ifndef HAVE_INFLATEPRIME
376 /* 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)
377 * Inserting value in middle of sorted array is expensive, so we want to add only in the end.
378 * It's not big deal, cause first-read don't usually invoke seeking
380 if (item->out + SPAN < out_pos) {
381 struct fast_seek_point *val = g_malloc(sizeof(struct fast_seek_point));
384 val->compression = ZLIB;
385 #ifdef HAVE_INFLATEPRIME
386 val->data.zlib.bits = bits;
388 if (point->pos != 0) {
389 unsigned int left = ZLIB_WINSIZE - point->pos;
391 memcpy(val->data.zlib.window, point->window + point->pos, left);
392 memcpy(val->data.zlib.window + left, point->window, point->pos);
394 memcpy(val->data.zlib.window, point->window, ZLIB_WINSIZE);
396 val->data.zlib.adler = file->strm.adler;
397 val->data.zlib.total_out = file->strm.total_out;
398 g_ptr_array_add(file->fast_seek, val);
402 static void /* gz_decomp */
403 zlib_read(FILE_T state, unsigned char *buf, unsigned int count)
405 int ret = 0; /* XXX */
407 z_streamp strm = &(state->strm);
409 unsigned char *buf2 = buf;
410 unsigned int count2 = count;
412 strm->avail_out = count;
413 strm->next_out = buf;
415 /* fill output buffer up to end of deflate stream or error */
417 /* get more input for inflate() */
418 if (state->avail_in == 0 && fill_in_buffer(state) == -1)
420 if (state->avail_in == 0) {
422 state->err = WTAP_ERR_SHORT_READ;
423 state->err_info = NULL;
427 strm->avail_in = state->avail_in;
428 strm->next_in = state->next_in;
429 /* decompress and handle errors */
430 /* ret = inflate(strm, Z_NO_FLUSH); */
431 ret = inflate(strm, Z_BLOCK);
432 state->avail_in = strm->avail_in;
433 state->next_in = strm->next_in;
434 if (ret == Z_STREAM_ERROR) {
435 state->err = WTAP_ERR_DECOMPRESS;
436 state->err_info = strm->msg;
439 if (ret == Z_NEED_DICT) {
440 state->err = WTAP_ERR_DECOMPRESS;
441 state->err_info = "preset dictionary needed";
444 if (ret == Z_MEM_ERROR) {
445 /* This means "not enough memory". */
447 state->err_info = NULL;
450 if (ret == Z_DATA_ERROR) { /* deflate stream invalid */
451 state->err = WTAP_ERR_DECOMPRESS;
452 state->err_info = strm->msg;
459 strm->adler = crc32(strm->adler, buf2, count2 - strm->avail_out);
460 if (state->fast_seek_cur) {
461 struct zlib_cur_seek_point *cur = (struct zlib_cur_seek_point *) state->fast_seek_cur;
462 unsigned int ready = count2 - strm->avail_out;
464 if (ready < ZLIB_WINSIZE) {
465 unsigned left = ZLIB_WINSIZE - cur->pos;
468 memcpy(cur->window + cur->pos, buf2, left);
470 memcpy(cur->window, buf2 + left, ready - left);
472 cur->pos = ready - left;
475 memcpy(cur->window + cur->pos, buf2, ready);
480 if (cur->have >= ZLIB_WINSIZE)
481 cur->have = ZLIB_WINSIZE;
484 memcpy(cur->window, buf2 + (ready - ZLIB_WINSIZE), ZLIB_WINSIZE);
486 cur->have = ZLIB_WINSIZE;
489 if (cur->have >= ZLIB_WINSIZE && ret != Z_STREAM_END && (strm->data_type & 128) && !(strm->data_type & 64))
490 zlib_fast_seek_add(state, cur, (strm->data_type & 7), state->raw_pos - strm->avail_in, state->pos + (count - strm->avail_out));
492 buf2 = (buf2 + count2 - strm->avail_out);
493 count2 = strm->avail_out;
495 } while (strm->avail_out && ret != Z_STREAM_END);
497 /* update available output and crc check value */
499 state->have = count - strm->avail_out;
501 /* Check gzip trailer if at end of deflate stream.
502 We don't fail immediately here, we just set an error
503 indication, so that we try to process what data we
504 got before the error. The next attempt to read
505 something past that data will get the error. */
506 if (ret == Z_STREAM_END) {
507 if (gz_next4(state, &crc) != -1 &&
508 gz_next4(state, &len) != -1) {
509 if (crc != strm->adler && !state->dont_check_crc) {
510 state->err = WTAP_ERR_DECOMPRESS;
511 state->err_info = "bad CRC";
512 } else if (len != (strm->total_out & 0xffffffffL)) {
513 state->err = WTAP_ERR_DECOMPRESS;
514 state->err_info = "length field wrong";
517 state->compression = UNKNOWN; /* ready for next stream, once have is 0 */
518 g_free(state->fast_seek_cur);
519 state->fast_seek_cur = NULL;
525 gz_head(FILE_T state)
527 /* get some data in the input buffer */
528 if (state->avail_in == 0) {
529 if (fill_in_buffer(state) == -1)
531 if (state->avail_in == 0)
535 /* look for the gzip magic header bytes 31 and 139 */
537 if (state->next_in[0] == 31) {
540 if (state->avail_in == 0 && fill_in_buffer(state) == -1)
542 if (state->avail_in && state->next_in[0] == 139) {
548 /* we have a gzip header, woo hoo! */
552 /* read rest of header */
554 /* compression method (CM) */
555 if (gz_next1(state, &cm) == -1)
558 state->err = WTAP_ERR_DECOMPRESS;
559 state->err_info = "unknown compression method";
564 if (gz_next1(state, &flags) == -1)
566 if (flags & 0xe0) { /* reserved flag bits */
567 state->err = WTAP_ERR_DECOMPRESS;
568 state->err_info = "reserved flag bits set";
572 /* modification time (MTIME) */
573 if (gz_skipn(state, 4) == -1)
576 /* extra flags (XFL) */
577 if (gz_skipn(state, 1) == -1)
580 /* operating system (OS) */
581 if (gz_skipn(state, 1) == -1)
585 /* extra field - get XLEN */
586 if (gz_next2(state, &len) == -1)
589 /* skip the extra field */
590 if (gz_skipn(state, len) == -1)
595 if (gz_skipzstr(state) == -1)
600 if (gz_skipzstr(state) == -1)
605 if (gz_next2(state, &hcrc) == -1)
607 /* XXX - check the CRC? */
610 /* set up for decompression */
611 inflateReset(&(state->strm));
612 state->strm.adler = crc32(0L, Z_NULL, 0);
613 state->compression = ZLIB;
615 if (state->fast_seek) {
616 struct zlib_cur_seek_point *cur = g_malloc(sizeof(struct zlib_cur_seek_point));
618 cur->pos = cur->have = 0;
619 g_free(state->fast_seek_cur);
620 state->fast_seek_cur = cur;
621 fast_seek_header(state, state->raw_pos - state->avail_in, state->pos, GZIP_AFTER_HEADER);
626 /* not a gzip file -- save first byte (31) and fall to raw i/o */
633 /* { 0xFD, '7', 'z', 'X', 'Z', 0x00 } */
634 /* FD 37 7A 58 5A 00 */
636 if (state->fast_seek)
637 fast_seek_header(state, state->raw_pos - state->avail_in - state->have, state->pos, UNCOMPRESSED);
639 /* doing raw i/o, save start of raw data for seeking, copy any leftover
640 input to output -- this assumes that the output buffer is larger than
641 the input buffer, which also assures space for gzungetc() */
642 state->raw = state->pos;
643 state->next = state->out;
644 if (state->avail_in) {
645 memcpy(state->next + state->have, state->next_in, state->avail_in);
646 state->have += state->avail_in;
649 state->compression = UNCOMPRESSED;
653 static int /* gz_make */
654 fill_out_buffer(FILE_T state)
656 if (state->compression == UNKNOWN) { /* look for gzip header */
657 if (gz_head(state) == -1)
659 if (state->have) /* got some data from gz_head() */
662 if (state->compression == UNCOMPRESSED) { /* straight copy */
663 if (raw_read(state, state->out, state->size /* << 1 */, &(state->have)) == -1)
665 state->next = state->out;
668 else if (state->compression == ZLIB) { /* decompress */
669 zlib_read(state, state->out, state->size << 1);
676 gz_skip(FILE_T state, gint64 len)
680 /* skip over len bytes or reach end-of-file, whichever comes first */
683 /* We have stuff in the output buffer; skip over
685 n = (gint64)state->have > len ? (unsigned)len : state->have;
690 } else if (state->err) {
691 /* We have nothing in the output buffer, and
692 we have an error that may not have been
693 reported yet; that means we can't generate
694 any more data into the output buffer, so
695 return an error indication. */
697 } else if (state->eof && state->avail_in == 0) {
698 /* We have nothing in the output buffer, and
699 we're at the end of the input; just return. */
702 /* We have nothing in the output buffer, and
703 we can generate more data; get more output,
704 looking for header if required. */
705 if (fill_out_buffer(state) == -1)
712 gz_reset(FILE_T state)
714 state->have = 0; /* no output data available */
715 state->eof = 0; /* not at end of file */
716 state->compression = UNKNOWN; /* look for gzip header */
718 state->seek = 0; /* no seek request pending */
719 state->err = 0; /* clear error */
720 state->err_info = NULL;
721 state->pos = 0; /* no uncompressed data yet */
722 state->avail_in = 0; /* no input data yet */
728 #ifdef _STATBUF_ST_BLKSIZE /* XXX, _STATBUF_ST_BLKSIZE portable? */
731 int want = GZBUFSIZE;
737 /* allocate FILE_T structure to return */
738 state = g_try_malloc(sizeof *state);
742 state->fast_seek_cur = NULL;
743 state->fast_seek = NULL;
745 /* open the file with the appropriate mode (or just use fd) */
748 /* save the current position for rewinding (only if reading) */
749 state->start = ws_lseek64(state->fd, 0, SEEK_CUR);
750 if (state->start == -1) state->start = 0;
751 state->raw_pos = state->start;
753 /* initialize stream */
756 #ifdef _STATBUF_ST_BLKSIZE
757 if (fstat(fd, &st) >= 0) {
758 want = st.st_blksize;
759 /* XXX, verify result? */
763 /* allocate buffers */
764 state->in = g_try_malloc(want);
765 state->out = g_try_malloc(want << 1);
767 if (state->in == NULL || state->out == NULL) {
776 /* allocate inflate memory */
777 state->strm.zalloc = Z_NULL;
778 state->strm.zfree = Z_NULL;
779 state->strm.opaque = Z_NULL;
780 state->strm.avail_in = 0;
781 state->strm.next_in = Z_NULL;
782 if (inflateInit2(&(state->strm), -15) != Z_OK) { /* raw inflate */
790 /* for now, assume we should check the crc */
791 state->dont_check_crc = 0;
798 file_open(const char *path)
806 /* open file and do correct filename conversions.
808 XXX - do we need O_LARGEFILE? On UN*X, if we need to do
809 something special to get large file support, the configure
810 script should have set us up with the appropriate #defines,
811 so we should be getting a large-file-enabled file descriptor
812 here. Pre-Large File Summit UN*Xes, and possibly even some
813 post-LFS UN*Xes, might require O_LARGEFILE here, though.
814 If so, we should probably handle that in ws_open(). */
815 if ((fd = ws_open(path, O_RDONLY|O_BINARY, 0000)) == -1)
818 /* open file handle */
827 * If this file's name ends in ".caz", it's probably a compressed
828 * Windows Sniffer file. The compression is gzip, but they don't
829 * bother filling in the CRC; we set a flag to ignore CRC errors.
831 suffixp = strrchr(path, '.');
832 if (suffixp != NULL) {
833 if (g_ascii_strcasecmp(suffixp, ".caz") == 0)
834 ft->dont_check_crc = 1;
842 file_set_random_access(FILE_T stream, gboolean random _U_, GPtrArray *seek)
844 stream->fast_seek = seek;
848 file_seek(FILE_T file, gint64 offset, int whence, int *err)
850 struct fast_seek_point *here;
853 /* can only seek from start or relative to current position */
854 if (whence != SEEK_SET && whence != SEEK_CUR) {
855 g_assert_not_reached();
862 /* normalize offset to a SEEK_CUR specification */
863 if (whence == SEEK_SET)
866 offset += file->skip;
870 if ((here = fast_seek_find(file, file->pos + offset)) && (offset < 0 || offset > SPAN || here->compression == UNCOMPRESSED)) {
874 if (here->compression == ZLIB) {
875 #ifdef HAVE_INFLATEPRIME
876 off = here->in - (here->data.zlib.bits ? 1 : 0);
881 } else if (here->compression == GZIP_AFTER_HEADER) {
887 off2 = (file->pos + offset);
888 off = here->in + (off2 - here->out);
891 if (ws_lseek64(file->fd, off, SEEK_SET) == -1) {
895 fast_seek_reset(file);
902 file->err_info = NULL;
906 if (here->compression == ZLIB) {
907 z_stream *strm = &file->strm;
910 strm->adler = here->data.zlib.adler;
911 strm->total_out = here->data.zlib.total_out;
912 #ifdef HAVE_INFLATEPRIME
913 if (here->data.zlib.bits) {
918 if (state->err == 0) {
920 *err = WTAP_ERR_SHORT_READ;
925 (void)inflatePrime(strm, here->data.zlib.bits, ret >> (8 - here->data.zlib.bits));
928 (void)inflateSetDictionary(strm, here->data.zlib.window, ZLIB_WINSIZE);
929 file->compression = ZLIB;
930 } else if (here->compression == GZIP_AFTER_HEADER) {
931 z_stream *strm = &file->strm;
934 strm->adler = crc32(0L, Z_NULL, 0);
935 file->compression = ZLIB;
938 file->compression = here->compression;
940 offset = (file->pos + offset) - off2;
942 /* g_print("OK! %ld\n", offset); */
948 return file->pos + offset;
951 /* if within raw area while reading, just go there */
952 if (file->compression == UNCOMPRESSED && file->pos + offset >= file->raw) {
953 if (ws_lseek64(file->fd, offset - file->have, SEEK_CUR) == -1) {
957 file->raw_pos += (offset - file->have);
962 file->err_info = NULL;
968 /* calculate skip amount, rewinding if needed for back seek when reading */
971 if (offset < 0) { /* before start of file! */
975 /* rewind, then skip to offset */
977 /* back up and start over */
978 if (ws_lseek64(file->fd, file->start, SEEK_SET) == -1) {
982 fast_seek_reset(file);
983 file->raw_pos = file->start;
987 /* skip what's in output buffer (one less gzgetc() check) */
988 n = (gint64)file->have > offset ? (unsigned)offset : file->have;
994 /* request skip (if not zero) */
999 return file->pos + offset;
1003 file_tell(FILE_T stream)
1005 /* return position */
1006 return stream->pos + (stream->seek ? stream->skip : 0);
1009 gint64 file_tell_raw(FILE_T stream)
1011 return stream->raw_pos;
1015 file_read(void *buf, unsigned int len, FILE_T file)
1019 /* if len is zero, avoid unnecessary operations */
1023 /* process a skip request */
1026 if (gz_skip(file, file->skip) == -1)
1030 /* get len bytes to buf, or less than len if at the end */
1034 /* We have stuff in the output buffer; copy
1036 n = file->have > len ? len : file->have;
1037 memcpy(buf, file->next, n);
1040 } else if (file->err) {
1041 /* We have nothing in the output buffer, and
1042 we have an error that may not have been
1043 reported yet; that means we can't generate
1044 any more data into the output buffer, so
1045 return an error indication. */
1047 } else if (file->eof && file->avail_in == 0) {
1048 /* We have nothing in the output buffer, and
1049 we're at the end of the input; just return
1050 with what we've gotten so far. */
1053 /* We have nothing in the output buffer, and
1054 we can generate more data; get more output,
1055 looking for header if required, and
1056 keep looping to process the new stuff
1057 in the output buffer. */
1058 if (fill_out_buffer(file) == -1)
1060 continue; /* no progress yet -- go back to memcpy() above */
1062 /* update progress */
1064 buf = (char *)buf + n;
1073 file_getc(FILE_T file)
1075 unsigned char buf[1];
1078 /* check that we're reading and that there's no error */
1082 /* try output buffer (no need to check for skip request) */
1086 return *(file->next)++;
1089 ret = file_read(buf, 1, file);
1090 return ret < 1 ? -1 : buf[0];
1094 file_gets(char *buf, int len, FILE_T file)
1100 /* check parameters */
1101 if (buf == NULL || len < 1)
1104 /* check that there's no error */
1108 /* process a skip request */
1111 if (gz_skip(file, file->skip) == -1)
1115 /* copy output bytes up to new line or len - 1, whichever comes first --
1116 append a terminating zero to the string (we don't check for a zero in
1117 the contents, let the user worry about that) */
1119 left = (unsigned)len - 1;
1121 /* assure that something is in the output buffer */
1122 if (file->have == 0) {
1123 /* We have nothing in the output buffer. */
1125 /* We have an error that may not have
1126 been reported yet; that means we
1127 can't generate any more data into
1128 the output buffer, so return an
1129 error indication. */
1132 if (fill_out_buffer(file) == -1)
1133 return NULL; /* error */
1134 if (file->have == 0) { /* end of file */
1135 if (buf == str) /* got bupkus */
1137 break; /* got something -- return it */
1141 /* look for end-of-line in current output buffer */
1142 n = file->have > left ? left : file->have;
1143 eol = memchr(file->next, '\n', n);
1145 n = (unsigned)(eol - file->next) + 1;
1147 /* copy through end-of-line, or remainder if not found */
1148 memcpy(buf, file->next, n);
1154 } while (left && eol == NULL);
1156 /* found end-of-line or out of space -- terminate string and return it */
1162 file_eof(FILE_T file)
1164 /* return end-of-file state */
1165 return (file->eof && file->avail_in == 0 && file->have == 0);
1169 * Routine to return a Wiretap error code (0 for no error, an errno
1170 * for a file error, or a WTAP_ERR_ code for other errors) for an
1171 * I/O stream. Also returns an error string for some errors.
1174 file_error(FILE_T fh, gchar **err_info)
1177 *err_info = (fh->err_info == NULL) ? NULL : g_strdup(fh->err_info);
1184 file_clearerr(FILE_T stream)
1186 /* clear error and end-of-file */
1188 stream->err_info = NULL;
1193 file_close(FILE_T file)
1197 /* free memory and close file */
1200 inflateEnd(&(file->strm));
1205 g_free(file->fast_seek_cur);
1207 file->err_info = NULL;
1213 /* internal gzip file state data structure for writing */
1214 struct wtap_writer {
1215 int fd; /* file descriptor */
1216 gint64 pos; /* current position in uncompressed data */
1217 unsigned size; /* buffer size, zero if not allocated yet */
1218 unsigned want; /* requested buffer size, default is GZBUFSIZE */
1219 unsigned char *in; /* input buffer */
1220 unsigned char *out; /* output buffer (double-sized when reading) */
1221 unsigned char *next; /* next output data to deliver or write */
1222 int level; /* compression level */
1223 int strategy; /* compression strategy */
1224 int err; /* error code */
1225 /* zlib deflate stream */
1226 z_stream strm; /* stream structure in-place (not a pointer) */
1230 gzwfile_open(const char *path)
1236 fd = ws_open(path, O_BINARY|O_WRONLY|O_CREAT|O_TRUNC, 0666);
1239 state = gzwfile_fdopen(fd);
1240 if (state == NULL) {
1249 gzwfile_fdopen(int fd)
1253 /* allocate wtap_writer structure to return */
1254 state = g_try_malloc(sizeof *state);
1258 state->size = 0; /* no buffers allocated yet */
1259 state->want = GZBUFSIZE; /* requested buffer size */
1261 state->level = Z_DEFAULT_COMPRESSION;
1262 state->strategy = Z_DEFAULT_STRATEGY;
1264 /* initialize stream */
1265 state->err = Z_OK; /* clear error */
1266 state->pos = 0; /* no uncompressed data yet */
1267 state->strm.avail_in = 0; /* no input data yet */
1273 /* Initialize state for writing a gzip file. Mark initialization by setting
1274 state->size to non-zero. Return -1, and set state->err, on failure;
1275 return 0 on success. */
1277 gz_init(GZWFILE_T state)
1280 z_streamp strm = &(state->strm);
1282 /* allocate input and output buffers */
1283 state->in = g_try_malloc(state->want);
1284 state->out = g_try_malloc(state->want);
1285 if (state->in == NULL || state->out == NULL) {
1288 state->err = ENOMEM;
1292 /* allocate deflate memory, set up for gzip compression */
1293 strm->zalloc = Z_NULL;
1294 strm->zfree = Z_NULL;
1295 strm->opaque = Z_NULL;
1296 ret = deflateInit2(strm, state->level, Z_DEFLATED,
1297 15 + 16, 8, state->strategy);
1301 if (ret == Z_MEM_ERROR) {
1302 /* This means "not enough memory". */
1303 state->err = ENOMEM;
1305 /* This "shouldn't happen". */
1306 state->err = WTAP_ERR_INTERNAL;
1311 /* mark state as initialized */
1312 state->size = state->want;
1314 /* initialize write buffer */
1315 strm->avail_out = state->size;
1316 strm->next_out = state->out;
1317 state->next = strm->next_out;
1321 /* Compress whatever is at avail_in and next_in and write to the output file.
1322 Return -1, and set state->err, if there is an error writing to the output
1323 file; return 0 on success.
1324 flush is assumed to be a valid deflate() flush value. If flush is Z_FINISH,
1325 then the deflate() state is reset to start a new gzip stream. */
1327 gz_comp(GZWFILE_T state, int flush)
1331 z_streamp strm = &(state->strm);
1333 /* allocate memory if this is the first time through */
1334 if (state->size == 0 && gz_init(state) == -1)
1337 /* run deflate() on provided input until it produces no more output */
1340 /* write out current buffer contents if full, or if flushing, but if
1341 doing Z_FINISH then don't write until we get to Z_STREAM_END */
1342 if (strm->avail_out == 0 || (flush != Z_NO_FLUSH &&
1343 (flush != Z_FINISH || ret == Z_STREAM_END))) {
1344 have = (unsigned)(strm->next_out - state->next);
1346 got = write(state->fd, state->next, have);
1351 if ((unsigned)got != have) {
1352 state->err = WTAP_ERR_SHORT_WRITE;
1356 if (strm->avail_out == 0) {
1357 strm->avail_out = state->size;
1358 strm->next_out = state->out;
1360 state->next = strm->next_out;
1364 have = strm->avail_out;
1365 ret = deflate(strm, flush);
1366 if (ret == Z_STREAM_ERROR) {
1367 /* This "shouldn't happen". */
1368 state->err = WTAP_ERR_INTERNAL;
1371 have -= strm->avail_out;
1374 /* if that completed a deflate stream, allow another to start */
1375 if (flush == Z_FINISH)
1378 /* all done, no errors */
1382 /* Write out len bytes from buf. Return 0, and set state->err, on
1383 failure or on an attempt to write 0 bytes (in which case state->err
1384 is Z_OK); return the number of bytes written on success. */
1386 gzwfile_write(GZWFILE_T state, const void *buf, unsigned len)
1392 strm = &(state->strm);
1394 /* check that there's no error */
1395 if (state->err != Z_OK)
1398 /* if len is zero, avoid unnecessary operations */
1402 /* allocate memory if this is the first time through */
1403 if (state->size == 0 && gz_init(state) == -1)
1406 /* for small len, copy to input buffer, otherwise compress directly */
1407 if (len < state->size) {
1408 /* copy to input buffer, compress when full */
1410 if (strm->avail_in == 0)
1411 strm->next_in = state->in;
1412 n = state->size - strm->avail_in;
1415 memcpy(strm->next_in + strm->avail_in, buf, n);
1416 strm->avail_in += n;
1418 buf = (char *)buf + n;
1420 if (len && gz_comp(state, Z_NO_FLUSH) == -1)
1425 /* consume whatever's left in the input buffer */
1426 if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
1429 /* directly compress user buffer to file */
1430 strm->avail_in = len;
1431 strm->next_in = (voidp)buf;
1433 if (gz_comp(state, Z_NO_FLUSH) == -1)
1437 /* input was all buffered or compressed (put will fit in int) */
1441 /* Flush out what we've written so far. Returns -1, and sets state->err,
1442 on failure; returns 0 on success. */
1444 gzwfile_flush(GZWFILE_T state)
1446 /* check that there's no error */
1447 if (state->err != Z_OK)
1450 /* compress remaining data with Z_SYNC_FLUSH */
1451 gz_comp(state, Z_SYNC_FLUSH);
1452 if (state->err != Z_OK)
1457 /* Flush out all data written, and close the file. Returns a Wiretap
1458 error on failure; returns 0 on success. */
1460 gzwfile_close(GZWFILE_T state)
1464 /* flush, free memory, and close file */
1465 if (gz_comp(state, Z_FINISH) == -1 && ret == 0)
1467 (void)deflateEnd(&(state->strm));
1471 if (close(state->fd) == -1 && ret == 0)
1478 gzwfile_geterr(GZWFILE_T state)