2000-01-13 07:09:20 +00:00
/* file_wrappers.c
*
* Wiretap Library
2001-11-13 23:55:44 +00:00
* Copyright ( c ) 1998 by Gilbert Ramirez < gram @ alumni . rice . edu >
2002-08-28 20:30:45 +00:00
*
2000-01-13 07:09:20 +00:00
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version 2
* of the License , or ( at your option ) any later version .
2002-08-28 20:30:45 +00:00
*
2000-01-13 07:09:20 +00:00
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
2002-08-28 20:30:45 +00:00
*
2000-01-13 07:09:20 +00:00
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
2012-06-28 22:56:06 +00:00
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
2000-01-13 07:09:20 +00:00
*/
2011-04-08 00:28:37 +00:00
/* file_access interface based heavily on zlib gzread.c and gzlib.c from zlib
* Copyright ( C ) 1995 - 2010 Jean - loup Gailly and Mark Adler
* under licence :
*
* 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 acknowledgment 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 .
2014-09-10 16:07:04 +00:00
*/
2011-04-08 00:28:37 +00:00
2000-01-13 07:09:20 +00:00
# include "config.h"
2005-11-10 02:49:54 +00:00
# ifdef HAVE_UNISTD_H
# include <unistd.h>
# endif /* HAVE_UNISTD_H */
2000-01-13 07:09:20 +00:00
# include <errno.h>
# include <stdio.h>
2005-11-07 02:45:19 +00:00
# ifdef HAVE_FCNTL_H
# include <fcntl.h>
# endif /* HAVE_FCNTL_H */
# include <string.h>
2000-05-19 23:07:04 +00:00
# include "wtap-int.h"
2000-01-13 07:09:20 +00:00
# include "file_wrappers.h"
2008-05-22 15:46:27 +00:00
# include <wsutil/file_util.h>
2005-11-06 22:43:25 +00:00
2011-06-09 22:46:00 +00:00
# ifdef HAVE_LIBZ
# include <zlib.h>
# endif /* HAVE_LIBZ */
2011-04-10 17:01:13 +00:00
/*
* See RFC 1952 for a description of the gzip file format .
*
* Some other compressed file formats we might want to support :
*
2014-09-10 16:07:04 +00:00
* XZ format : http : //tukaani.org/xz/
2011-04-10 17:01:13 +00:00
*
2014-09-10 16:07:04 +00:00
* Bzip2 format : http : //bzip.org/
2011-04-10 17:01:13 +00:00
*/
2012-01-21 08:59:21 +00:00
/*
* List of extensions for compressed files .
* If we add support for more compressed file types , this table
* might be expanded to include routines to handle the various
* compression types .
*/
static const char * compressed_file_extensions [ ] = {
# ifdef HAVE_LIBZ
2014-09-10 16:07:04 +00:00
" gz " ,
2012-01-21 08:59:21 +00:00
# endif
2014-09-10 16:07:04 +00:00
NULL
2012-01-21 08:59:21 +00:00
} ;
/*
* Return a GSList of all the compressed file extensions .
* The data pointers all point to items in compressed_file_extensions [ ] ,
* so the GSList can just be freed with g_slist_free ( ) .
*/
GSList *
wtap_get_compressed_file_extensions ( void )
{
2014-09-10 16:07:04 +00:00
const char * * extension ;
GSList * extensions ;
extensions = NULL ;
for ( extension = & compressed_file_extensions [ 0 ] ; * extension ! = NULL ;
extension + + )
extensions = g_slist_append ( extensions , ( gpointer ) ( * extension ) ) ;
return extensions ;
2012-01-21 08:59:21 +00:00
}
2011-04-08 00:28:37 +00:00
/* #define GZBUFSIZE 8192 */
# define GZBUFSIZE 4096
2013-01-06 20:36:33 +00:00
/* values for wtap_reader compression */
typedef enum {
2014-09-10 16:07:04 +00:00
UNKNOWN , /* unknown - look for a gzip header */
UNCOMPRESSED , /* uncompressed - copy input directly */
2013-01-06 20:36:33 +00:00
# ifdef HAVE_LIBZ
2014-09-10 16:07:04 +00:00
ZLIB , /* decompress a zlib stream */
GZIP_AFTER_HEADER
2013-01-06 20:36:33 +00:00
# endif
} compression_t ;
2011-04-10 16:53:32 +00:00
struct wtap_reader {
2014-09-10 16:07:04 +00:00
int fd ; /* file descriptor */
gint64 raw_pos ; /* current position in file (just to not call lseek()) */
gint64 pos ; /* current position in uncompressed data */
guint size ; /* buffer size */
unsigned char * in ; /* input buffer */
unsigned char * out ; /* output buffer (double-sized when reading) */
unsigned char * next ; /* next output data to deliver or write */
guint have ; /* amount of output data unused at next */
gboolean eof ; /* TRUE if end of input file reached */
gint64 start ; /* where the gzip data started, for rewinding */
gint64 raw ; /* where the raw data started, for seeking */
compression_t compression ; /* type of compression, if any */
gboolean is_compressed ; /* FALSE if completely uncompressed, TRUE otherwise */
/* seek request */
gint64 skip ; /* amount to skip (already rewound if backwards) */
gboolean seek_pending ; /* TRUE if seek request pending */
/* error information */
int err ; /* error code */
const char * err_info ; /* additional error information string for some errors */
guint avail_in ; /* number of bytes available at next_in */
unsigned char * next_in ; /* next input byte */
2011-04-10 16:53:32 +00:00
# ifdef HAVE_LIBZ
2014-09-10 16:07:04 +00:00
/* zlib inflate stream */
z_stream strm ; /* stream structure in-place (not a pointer) */
gboolean dont_check_crc ; /* TRUE if we aren't supposed to check the CRC */
2011-04-10 16:53:32 +00:00
# endif
2014-09-10 16:07:04 +00:00
/* fast seeking */
GPtrArray * fast_seek ;
void * fast_seek_cur ;
2011-04-10 16:53:32 +00:00
} ;
2011-04-08 00:28:37 +00:00
2014-09-10 16:07:04 +00:00
static int /* gz_load */
2013-01-04 05:22:43 +00:00
raw_read ( FILE_T state , unsigned char * buf , unsigned int count , guint * have )
2011-04-08 00:28:37 +00:00
{
2014-09-10 16:07:04 +00:00
ssize_t ret ;
* have = 0 ;
do {
ret = read ( state - > fd , buf + * have , count - * have ) ;
if ( ret < = 0 )
break ;
* have + = ( unsigned ) ret ;
state - > raw_pos + = ret ;
} while ( * have < count ) ;
if ( ret < 0 ) {
state - > err = errno ;
state - > err_info = NULL ;
return - 1 ;
}
if ( ret = = 0 )
state - > eof = TRUE ;
return 0 ;
2011-04-08 00:28:37 +00:00
}
static int /* gz_avail */
fill_in_buffer ( FILE_T state )
{
2014-09-10 16:07:04 +00:00
if ( state - > err )
return - 1 ;
if ( state - > eof = = 0 ) {
if ( raw_read ( state , state - > in , state - > size , & ( state - > avail_in ) ) = = - 1 )
return - 1 ;
state - > next_in = state - > in ;
}
return 0 ;
2011-04-08 00:28:37 +00:00
}
2011-04-12 02:40:14 +00:00
# define ZLIB_WINSIZE 32768
struct fast_seek_point {
2014-09-10 16:07:04 +00:00
gint64 out ; /* corresponding offset in uncompressed data */
gint64 in ; /* offset in input file of first full byte */
2011-04-12 02:40:14 +00:00
2014-09-10 16:07:04 +00:00
compression_t compression ;
union {
struct {
2011-04-29 07:49:55 +00:00
# ifdef HAVE_INFLATEPRIME
2014-09-10 16:07:04 +00:00
int bits ; /* number of bits (1-7) from byte at in - 1, or 0 */
2011-04-29 07:49:55 +00:00
# endif
2014-09-10 16:07:04 +00:00
unsigned char window [ ZLIB_WINSIZE ] ; /* preceding 32K of uncompressed data */
2011-04-12 02:40:14 +00:00
2014-09-10 16:07:04 +00:00
/* be gentle with Z_STREAM_END, 8 bytes more... Another solution would be to comment checks out */
guint32 adler ;
guint32 total_out ;
} zlib ;
} data ;
2011-04-12 02:40:14 +00:00
} ;
struct zlib_cur_seek_point {
2014-09-10 16:07:04 +00:00
unsigned char window [ ZLIB_WINSIZE ] ; /* preceding 32K of uncompressed data */
unsigned int pos ;
unsigned int have ;
2011-04-12 02:40:14 +00:00
} ;
# define SPAN G_GINT64_CONSTANT(1048576)
static struct fast_seek_point *
fast_seek_find ( FILE_T file , gint64 pos )
{
2014-09-10 16:07:04 +00:00
struct fast_seek_point * smallest = NULL ;
struct fast_seek_point * item ;
guint low , i , max ;
if ( ! file - > fast_seek )
return NULL ;
for ( low = 0 , max = file - > fast_seek - > len ; low < max ; ) {
i = ( low + max ) / 2 ;
item = ( struct fast_seek_point * ) file - > fast_seek - > pdata [ i ] ;
if ( pos < item - > out )
max = i ;
else if ( pos > item - > out ) {
smallest = item ;
low = i + 1 ;
} else {
return item ;
}
}
return smallest ;
2011-04-12 02:40:14 +00:00
}
static void
2013-01-06 20:36:33 +00:00
fast_seek_header ( FILE_T file , gint64 in_pos , gint64 out_pos ,
2014-09-10 16:07:04 +00:00
compression_t compression )
2011-04-12 02:40:14 +00:00
{
2014-09-10 16:07:04 +00:00
struct fast_seek_point * item = NULL ;
2011-04-12 02:40:14 +00:00
2014-09-10 16:07:04 +00:00
if ( file - > fast_seek - > len ! = 0 )
item = ( struct fast_seek_point * ) file - > fast_seek - > pdata [ file - > fast_seek - > len - 1 ] ;
2011-04-12 02:40:14 +00:00
2014-09-10 16:07:04 +00:00
if ( ! item | | item - > out < out_pos ) {
struct fast_seek_point * val = g_new ( struct fast_seek_point , 1 ) ;
val - > in = in_pos ;
val - > out = out_pos ;
val - > compression = compression ;
2011-04-12 02:40:14 +00:00
2014-09-10 16:07:04 +00:00
g_ptr_array_add ( file - > fast_seek , val ) ;
}
2011-04-12 02:40:14 +00:00
}
static void
2011-04-12 14:33:31 +00:00
fast_seek_reset ( FILE_T state _U_ )
2011-04-12 02:40:14 +00:00
{
# ifdef HAVE_LIBZ
2014-09-10 16:07:04 +00:00
if ( state - > compression = = ZLIB & & state - > fast_seek_cur ) {
struct zlib_cur_seek_point * cur = ( struct zlib_cur_seek_point * ) state - > fast_seek_cur ;
2011-04-12 02:40:14 +00:00
2014-09-10 16:07:04 +00:00
cur - > have = 0 ;
}
2011-04-12 02:40:14 +00:00
# endif
}
2011-04-08 00:28:37 +00:00
# ifdef HAVE_LIBZ
2011-04-20 21:36:23 +00:00
/* Get next byte from input, or -1 if end or error.
*
* Note :
*
2014-09-10 16:07:04 +00:00
* 1 ) errors from raw_read ( ) , and thus from fill_in_buffer ( ) , are
* " sticky " , and fill_in_buffer ( ) won ' t do any reading if there ' s
* an error ;
2011-04-20 21:36:23 +00:00
*
2014-09-10 16:07:04 +00:00
* 2 ) GZ_GETC ( ) returns - 1 on an EOF ;
2011-04-20 21:36:23 +00:00
*
* so it ' s safe to make multiple GZ_GETC ( ) calls and only check the
* last one for an error . */
# define GZ_GETC() ((state->avail_in == 0 && fill_in_buffer(state) == -1) ? -1 : \
2014-09-10 16:07:04 +00:00
( state - > avail_in = = 0 ? - 1 : \
( state - > avail_in - - , * ( state - > next_in ) + + ) ) )
2011-04-08 00:28:37 +00:00
2011-04-20 21:36:23 +00:00
/* Get a one-byte integer and return 0 on success and the value in *ret.
Otherwise - 1 is returned , state - > err is set , and * ret is not modified . */
static int
gz_next1 ( FILE_T state , guint8 * ret )
{
2014-09-10 16:07:04 +00:00
int ch ;
ch = GZ_GETC ( ) ;
if ( ch = = - 1 ) {
if ( state - > err = = 0 ) {
/* EOF */
state - > err = WTAP_ERR_SHORT_READ ;
state - > err_info = NULL ;
}
return - 1 ;
}
* ret = ch ;
return 0 ;
2011-04-20 21:36:23 +00:00
}
/* Get a two-byte little-endian integer and return 0 on success and the value
in * ret . Otherwise - 1 is returned , state - > err is set , and * ret is not
modified . */
static int
gz_next2 ( FILE_T state , guint16 * ret )
{
2014-09-10 16:07:04 +00:00
guint16 val ;
int ch ;
val = GZ_GETC ( ) ;
ch = GZ_GETC ( ) ;
if ( ch = = - 1 ) {
if ( state - > err = = 0 ) {
/* EOF */
state - > err = WTAP_ERR_SHORT_READ ;
state - > err_info = NULL ;
}
return - 1 ;
}
val + = ( guint16 ) ch < < 8 ;
* ret = val ;
return 0 ;
2011-04-20 21:36:23 +00:00
}
2011-04-08 00:28:37 +00:00
/* Get a four-byte little-endian integer and return 0 on success and the value
2011-04-20 21:36:23 +00:00
in * ret . Otherwise - 1 is returned , state - > err is set , and * ret is not
modified . */
2011-04-08 00:28:37 +00:00
static int
gz_next4 ( FILE_T state , guint32 * ret )
{
2014-09-10 16:07:04 +00:00
guint32 val ;
int ch ;
val = GZ_GETC ( ) ;
val + = ( unsigned ) GZ_GETC ( ) < < 8 ;
val + = ( guint32 ) GZ_GETC ( ) < < 16 ;
ch = GZ_GETC ( ) ;
if ( ch = = - 1 ) {
if ( state - > err = = 0 ) {
/* EOF */
state - > err = WTAP_ERR_SHORT_READ ;
state - > err_info = NULL ;
}
return - 1 ;
}
val + = ( guint32 ) ch < < 24 ;
* ret = val ;
return 0 ;
2011-04-08 00:28:37 +00:00
}
2011-04-20 21:36:23 +00:00
/* Skip the specified number of bytes and return 0 on success. Otherwise -1
is returned . */
static int
gz_skipn ( FILE_T state , size_t n )
{
2014-09-10 16:07:04 +00:00
while ( n ! = 0 ) {
if ( GZ_GETC ( ) = = - 1 ) {
if ( state - > err = = 0 ) {
/* EOF */
state - > err = WTAP_ERR_SHORT_READ ;
state - > err_info = NULL ;
}
return - 1 ;
}
n - - ;
}
return 0 ;
2011-04-20 21:36:23 +00:00
}
/* Skip a null-terminated string and return 0 on success. Otherwise -1
is returned . */
static int
gz_skipzstr ( FILE_T state )
{
2014-09-10 16:07:04 +00:00
int ch ;
/* It's null-terminated, so scan until we read a byte with
the value 0 or get an error . */
while ( ( ch = GZ_GETC ( ) ) > 0 )
;
if ( ch = = - 1 ) {
if ( state - > err = = 0 ) {
/* EOF */
state - > err = WTAP_ERR_SHORT_READ ;
state - > err_info = NULL ;
}
return - 1 ;
}
return 0 ;
2011-04-20 21:36:23 +00:00
}
2011-04-12 02:40:14 +00:00
static void
zlib_fast_seek_add ( FILE_T file , struct zlib_cur_seek_point * point , int bits , gint64 in_pos , gint64 out_pos )
{
2014-09-10 16:07:04 +00:00
/* it's for sure after gzip header, so file->fast_seek->len != 0 */
struct fast_seek_point * item = ( struct fast_seek_point * ) file - > fast_seek - > pdata [ file - > fast_seek - > len - 1 ] ;
2011-04-12 02:40:14 +00:00
2011-04-29 07:49:55 +00:00
# ifndef HAVE_INFLATEPRIME
2014-09-10 16:07:04 +00:00
if ( bits )
return ;
2011-04-29 07:49:55 +00:00
# endif
2014-09-10 16:07:04 +00:00
/* 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)
* Inserting value in middle of sorted array is expensive , so we want to add only in the end .
* It ' s not big deal , cause first - read don ' t usually invoke seeking
*/
if ( item - > out + SPAN < out_pos ) {
struct fast_seek_point * val = g_new ( struct fast_seek_point , 1 ) ;
val - > in = in_pos ;
val - > out = out_pos ;
val - > compression = ZLIB ;
2011-04-29 07:49:55 +00:00
# ifdef HAVE_INFLATEPRIME
2014-09-10 16:07:04 +00:00
val - > data . zlib . bits = bits ;
2011-04-29 07:49:55 +00:00
# endif
2014-09-10 16:07:04 +00:00
if ( point - > pos ! = 0 ) {
unsigned int left = ZLIB_WINSIZE - point - > pos ;
memcpy ( val - > data . zlib . window , point - > window + point - > pos , left ) ;
memcpy ( val - > data . zlib . window + left , point - > window , point - > pos ) ;
} else
memcpy ( val - > data . zlib . window , point - > window , ZLIB_WINSIZE ) ;
/*
* XXX - strm . adler is a uLong in at least some versions
* of zlib , and uLong is an unsigned long in at least
* some of those versions , which means it ' s 64 - bit
* on LP64 platforms , even though the checksum is
* 32 - bit . We assume the actual Adler checksum
* is in the lower 32 bits of strm . adler ; as the
* checksum in the file is only 32 bits , we save only
* those lower 32 bits , and cast away any additional
* bits to squelch warnings .
*
* The same applies to strm . total_out .
*/
val - > data . zlib . adler = ( guint32 ) file - > strm . adler ;
val - > data . zlib . total_out = ( guint32 ) file - > strm . total_out ;
g_ptr_array_add ( file - > fast_seek , val ) ;
}
2011-04-12 02:40:14 +00:00
}
static void /* gz_decomp */
2011-04-08 00:28:37 +00:00
zlib_read ( FILE_T state , unsigned char * buf , unsigned int count )
{
2014-09-10 16:07:04 +00:00
int ret = 0 ; /* XXX */
guint32 crc , len ;
z_streamp strm = & ( state - > strm ) ;
unsigned char * buf2 = buf ;
unsigned int count2 = count ;
strm - > avail_out = count ;
strm - > next_out = buf ;
/* fill output buffer up to end of deflate stream or error */
do {
/* get more input for inflate() */
if ( state - > avail_in = = 0 & & fill_in_buffer ( state ) = = - 1 )
break ;
if ( state - > avail_in = = 0 ) {
/* EOF */
state - > err = WTAP_ERR_SHORT_READ ;
state - > err_info = NULL ;
break ;
}
strm - > avail_in = state - > avail_in ;
strm - > next_in = state - > next_in ;
/* decompress and handle errors */
2012-05-19 13:27:43 +00:00
# ifdef Z_BLOCK
2014-09-10 16:07:04 +00:00
ret = inflate ( strm , Z_BLOCK ) ;
2012-05-19 13:27:43 +00:00
# else
2014-09-10 16:07:04 +00:00
ret = inflate ( strm , Z_NO_FLUSH ) ;
2012-05-19 13:27:43 +00:00
# endif
2014-09-10 16:07:04 +00:00
state - > avail_in = strm - > avail_in ;
state - > next_in = strm - > next_in ;
if ( ret = = Z_STREAM_ERROR ) {
state - > err = WTAP_ERR_DECOMPRESS ;
state - > err_info = strm - > msg ;
break ;
}
if ( ret = = Z_NEED_DICT ) {
state - > err = WTAP_ERR_DECOMPRESS ;
state - > err_info = " preset dictionary needed " ;
break ;
}
if ( ret = = Z_MEM_ERROR ) {
/* This means "not enough memory". */
state - > err = ENOMEM ;
state - > err_info = NULL ;
break ;
}
if ( ret = = Z_DATA_ERROR ) { /* deflate stream invalid */
state - > err = WTAP_ERR_DECOMPRESS ;
state - > err_info = strm - > msg ;
break ;
}
/*
* XXX - Z_BUF_ERROR ?
*/
strm - > adler = crc32 ( strm - > adler , buf2 , count2 - strm - > avail_out ) ;
2012-05-19 13:27:43 +00:00
# ifdef Z_BLOCK
2014-09-10 16:07:04 +00:00
if ( state - > fast_seek_cur ) {
struct zlib_cur_seek_point * cur = ( struct zlib_cur_seek_point * ) state - > fast_seek_cur ;
unsigned int ready = count2 - strm - > avail_out ;
if ( ready < ZLIB_WINSIZE ) {
guint left = ZLIB_WINSIZE - cur - > pos ;
if ( ready > = left ) {
memcpy ( cur - > window + cur - > pos , buf2 , left ) ;
if ( ready ! = left )
memcpy ( cur - > window , buf2 + left , ready - left ) ;
cur - > pos = ready - left ;
cur - > have + = ready ;
} else {
memcpy ( cur - > window + cur - > pos , buf2 , ready ) ;
cur - > pos + = ready ;
cur - > have + = ready ;
}
if ( cur - > have > = ZLIB_WINSIZE )
cur - > have = ZLIB_WINSIZE ;
} else {
memcpy ( cur - > window , buf2 + ( ready - ZLIB_WINSIZE ) , ZLIB_WINSIZE ) ;
cur - > pos = 0 ;
cur - > have = ZLIB_WINSIZE ;
}
if ( cur - > have > = ZLIB_WINSIZE & & ret ! = Z_STREAM_END & & ( strm - > data_type & 128 ) & & ! ( strm - > data_type & 64 ) )
zlib_fast_seek_add ( state , cur , ( strm - > data_type & 7 ) , state - > raw_pos - strm - > avail_in , state - > pos + ( count - strm - > avail_out ) ) ;
}
2012-05-19 13:27:43 +00:00
# endif
2014-09-10 16:07:04 +00:00
buf2 = ( buf2 + count2 - strm - > avail_out ) ;
count2 = strm - > avail_out ;
} while ( strm - > avail_out & & ret ! = Z_STREAM_END ) ;
/* update available output and crc check value */
state - > next = buf ;
state - > have = count - strm - > avail_out ;
/* Check gzip trailer if at end of deflate stream.
We don ' t fail immediately here , we just set an error
indication , so that we try to process what data we
got before the error . The next attempt to read
something past that data will get the error . */
if ( ret = = Z_STREAM_END ) {
if ( gz_next4 ( state , & crc ) ! = - 1 & &
gz_next4 ( state , & len ) ! = - 1 ) {
if ( crc ! = strm - > adler & & ! state - > dont_check_crc ) {
state - > err = WTAP_ERR_DECOMPRESS ;
state - > err_info = " bad CRC " ;
} else if ( len ! = ( strm - > total_out & 0xffffffffL ) ) {
state - > err = WTAP_ERR_DECOMPRESS ;
state - > err_info = " length field wrong " ;
}
}
state - > compression = UNKNOWN ; /* ready for next stream, once have is 0 */
g_free ( state - > fast_seek_cur ) ;
state - > fast_seek_cur = NULL ;
}
2011-04-08 00:28:37 +00:00
}
# endif
static int
gz_head ( FILE_T state )
{
2014-09-10 16:07:04 +00:00
/* get some data in the input buffer */
if ( state - > avail_in = = 0 ) {
if ( fill_in_buffer ( state ) = = - 1 )
return - 1 ;
if ( state - > avail_in = = 0 )
return 0 ;
}
/* look for the gzip magic header bytes 31 and 139 */
2011-04-08 00:28:37 +00:00
# ifdef HAVE_LIBZ
2014-09-10 16:07:04 +00:00
if ( state - > next_in [ 0 ] = = 31 ) {
state - > avail_in - - ;
state - > next_in + + ;
if ( state - > avail_in = = 0 & & fill_in_buffer ( state ) = = - 1 )
return - 1 ;
if ( state - > avail_in & & state - > next_in [ 0 ] = = 139 ) {
guint8 cm ;
guint8 flags ;
guint16 len ;
guint16 hcrc ;
/* we have a gzip header, woo hoo! */
state - > avail_in - - ;
state - > next_in + + ;
/* read rest of header */
/* compression method (CM) */
if ( gz_next1 ( state , & cm ) = = - 1 )
return - 1 ;
if ( cm ! = 8 ) {
state - > err = WTAP_ERR_DECOMPRESS ;
state - > err_info = " unknown compression method " ;
return - 1 ;
}
/* flags (FLG) */
if ( gz_next1 ( state , & flags ) = = - 1 )
return - 1 ;
if ( flags & 0xe0 ) { /* reserved flag bits */
state - > err = WTAP_ERR_DECOMPRESS ;
state - > err_info = " reserved flag bits set " ;
return - 1 ;
}
/* modification time (MTIME) */
if ( gz_skipn ( state , 4 ) = = - 1 )
return - 1 ;
/* extra flags (XFL) */
if ( gz_skipn ( state , 1 ) = = - 1 )
return - 1 ;
/* operating system (OS) */
if ( gz_skipn ( state , 1 ) = = - 1 )
return - 1 ;
if ( flags & 4 ) {
/* extra field - get XLEN */
if ( gz_next2 ( state , & len ) = = - 1 )
return - 1 ;
/* skip the extra field */
if ( gz_skipn ( state , len ) = = - 1 )
return - 1 ;
}
if ( flags & 8 ) {
/* file name */
if ( gz_skipzstr ( state ) = = - 1 )
return - 1 ;
}
if ( flags & 16 ) {
/* comment */
if ( gz_skipzstr ( state ) = = - 1 )
return - 1 ;
}
if ( flags & 2 ) {
/* header crc */
if ( gz_next2 ( state , & hcrc ) = = - 1 )
return - 1 ;
/* XXX - check the CRC? */
}
/* set up for decompression */
inflateReset ( & ( state - > strm ) ) ;
state - > strm . adler = crc32 ( 0L , Z_NULL , 0 ) ;
state - > compression = ZLIB ;
state - > is_compressed = TRUE ;
2012-05-19 13:27:43 +00:00
# ifdef Z_BLOCK
2014-09-10 16:07:04 +00:00
if ( state - > fast_seek ) {
struct zlib_cur_seek_point * cur = g_new ( struct zlib_cur_seek_point , 1 ) ;
cur - > pos = cur - > have = 0 ;
g_free ( state - > fast_seek_cur ) ;
state - > fast_seek_cur = cur ;
fast_seek_header ( state , state - > raw_pos - state - > avail_in , state - > pos , GZIP_AFTER_HEADER ) ;
}
2012-05-19 13:27:43 +00:00
# endif
2014-09-10 16:07:04 +00:00
return 0 ;
}
else {
/* not a gzip file -- save first byte (31) and fall to raw i/o */
state - > out [ 0 ] = 31 ;
state - > have = 1 ;
}
}
2011-04-08 00:28:37 +00:00
# endif
# ifdef HAVE_LIBXZ
2014-09-10 16:07:04 +00:00
/* { 0xFD, '7', 'z', 'X', 'Z', 0x00 } */
/* FD 37 7A 58 5A 00 */
2011-04-08 00:28:37 +00:00
# endif
2014-09-10 16:07:04 +00:00
if ( state - > fast_seek )
fast_seek_header ( state , state - > raw_pos - state - > avail_in - state - > have , state - > pos , UNCOMPRESSED ) ;
/* doing raw i/o, save start of raw data for seeking, copy any leftover
input to output - - this assumes that the output buffer is larger than
the input buffer , which also assures space for gzungetc ( ) */
state - > raw = state - > pos ;
state - > next = state - > out ;
if ( state - > avail_in ) {
memcpy ( state - > next + state - > have , state - > next_in , state - > avail_in ) ;
state - > have + = state - > avail_in ;
state - > avail_in = 0 ;
}
state - > compression = UNCOMPRESSED ;
return 0 ;
2011-04-08 00:28:37 +00:00
}
static int /* gz_make */
fill_out_buffer ( FILE_T state )
{
2014-09-10 16:07:04 +00:00
if ( state - > compression = = UNKNOWN ) { /* look for gzip header */
if ( gz_head ( state ) = = - 1 )
return - 1 ;
if ( state - > have ) /* got some data from gz_head() */
return 0 ;
}
if ( state - > compression = = UNCOMPRESSED ) { /* straight copy */
if ( raw_read ( state , state - > out , state - > size /* << 1 */ , & ( state - > have ) ) = = - 1 )
return - 1 ;
state - > next = state - > out ;
}
2011-04-08 00:28:37 +00:00
# ifdef HAVE_LIBZ
2014-09-10 16:07:04 +00:00
else if ( state - > compression = = ZLIB ) { /* decompress */
zlib_read ( state , state - > out , state - > size < < 1 ) ;
}
2011-04-08 00:28:37 +00:00
# endif
2014-09-10 16:07:04 +00:00
return 0 ;
2011-04-08 00:28:37 +00:00
}
static int
gz_skip ( FILE_T state , gint64 len )
{
2014-09-10 16:07:04 +00:00
guint n ;
/* skip over len bytes or reach end-of-file, whichever comes first */
while ( len )
if ( state - > have ) {
/* We have stuff in the output buffer; skip over
it . */
n = ( gint64 ) state - > have > len ? ( unsigned ) len : state - > have ;
state - > have - = n ;
state - > next + = n ;
state - > pos + = n ;
len - = n ;
} else if ( state - > err ) {
/* We have nothing in the output buffer, and
we have an error that may not have been
reported yet ; that means we can ' t generate
any more data into the output buffer , so
return an error indication . */
return - 1 ;
} else if ( state - > eof & & state - > avail_in = = 0 ) {
/* We have nothing in the output buffer, and
we ' re at the end of the input ; just return . */
break ;
} else {
/* We have nothing in the output buffer, and
we can generate more data ; get more output ,
looking for header if required . */
if ( fill_out_buffer ( state ) = = - 1 )
return - 1 ;
}
return 0 ;
2011-04-08 00:28:37 +00:00
}
static void
gz_reset ( FILE_T state )
{
2014-09-10 16:07:04 +00:00
state - > have = 0 ; /* no output data available */
state - > eof = FALSE ; /* not at end of file */
state - > compression = UNKNOWN ; /* look for gzip header */
state - > seek_pending = FALSE ; /* no seek request pending */
state - > err = 0 ; /* clear error */
state - > err_info = NULL ;
state - > pos = 0 ; /* no uncompressed data yet */
state - > avail_in = 0 ; /* no input data yet */
2011-04-08 00:28:37 +00:00
}
FILE_T
2012-06-01 08:05:12 +00:00
file_fdopen ( int fd )
2011-04-08 00:28:37 +00:00
{
2014-09-10 16:07:04 +00:00
# ifdef _STATBUF_ST_BLKSIZE /* XXX, _STATBUF_ST_BLKSIZE portable? */
ws_statb64 st ;
2011-04-08 00:28:37 +00:00
# endif
2014-09-10 16:07:04 +00:00
int want = GZBUFSIZE ;
FILE_T state ;
2011-04-08 00:28:37 +00:00
2014-09-10 16:07:04 +00:00
if ( fd = = - 1 )
return NULL ;
2011-04-08 00:28:37 +00:00
2014-09-10 16:07:04 +00:00
/* allocate FILE_T structure to return */
state = ( FILE_T ) g_try_malloc ( sizeof * state ) ;
if ( state = = NULL )
return NULL ;
2011-04-08 00:28:37 +00:00
2014-09-10 16:07:04 +00:00
state - > fast_seek_cur = NULL ;
state - > fast_seek = NULL ;
2011-04-12 02:40:14 +00:00
2014-09-10 16:07:04 +00:00
/* open the file with the appropriate mode (or just use fd) */
state - > fd = fd ;
2011-04-08 00:28:37 +00:00
2014-09-10 16:07:04 +00:00
/* we don't yet know whether it's compressed */
state - > is_compressed = FALSE ;
2012-05-24 05:05:29 +00:00
2014-09-10 16:07:04 +00:00
/* save the current position for rewinding (only if reading) */
state - > start = ws_lseek64 ( state - > fd , 0 , SEEK_CUR ) ;
if ( state - > start = = - 1 ) state - > start = 0 ;
state - > raw_pos = state - > start ;
2011-04-08 00:28:37 +00:00
2014-09-10 16:07:04 +00:00
/* initialize stream */
gz_reset ( state ) ;
2011-04-08 00:28:37 +00:00
# ifdef _STATBUF_ST_BLKSIZE
2014-09-10 16:07:04 +00:00
if ( ws_fstat64 ( fd , & st ) > = 0 ) {
/*
* Yes , st_blksize can be bigger than an int ; apparently ,
* it ' s a long on LP64 Linux , for example .
*
* If the value is too big to fit into an int , just
* use the default .
*/
if ( st . st_blksize < = G_MAXINT )
want = ( int ) st . st_blksize ;
/* XXX, verify result? */
}
2011-04-08 00:28:37 +00:00
# endif
2014-09-10 16:07:04 +00:00
/* allocate buffers */
state - > in = ( unsigned char * ) g_try_malloc ( want ) ;
state - > out = ( unsigned char * ) g_try_malloc ( want < < 1 ) ;
state - > size = want ;
if ( state - > in = = NULL | | state - > out = = NULL ) {
g_free ( state - > out ) ;
g_free ( state - > in ) ;
g_free ( state ) ;
errno = ENOMEM ;
return NULL ;
}
2006-11-05 22:46:44 +00:00
2005-11-07 02:45:19 +00:00
# ifdef HAVE_LIBZ
2014-09-10 16:07:04 +00:00
/* allocate inflate memory */
state - > strm . zalloc = Z_NULL ;
state - > strm . zfree = Z_NULL ;
state - > strm . opaque = Z_NULL ;
state - > strm . avail_in = 0 ;
state - > strm . next_in = Z_NULL ;
if ( inflateInit2 ( & ( state - > strm ) , - 15 ) ! = Z_OK ) { /* raw inflate */
g_free ( state - > out ) ;
g_free ( state - > in ) ;
g_free ( state ) ;
errno = ENOMEM ;
return NULL ;
}
/* for now, assume we should check the crc */
state - > dont_check_crc = FALSE ;
2011-04-08 00:28:37 +00:00
# endif
2014-09-10 16:07:04 +00:00
/* return stream */
return state ;
2011-04-08 00:28:37 +00:00
}
2006-11-05 22:46:44 +00:00
2005-11-06 22:43:25 +00:00
FILE_T
2011-04-06 07:09:56 +00:00
file_open ( const char * path )
2005-11-06 22:43:25 +00:00
{
2014-09-10 16:07:04 +00:00
int fd ;
FILE_T ft ;
2011-05-09 03:48:41 +00:00
# ifdef HAVE_LIBZ
2014-09-10 16:07:04 +00:00
const char * suffixp ;
2011-05-09 03:48:41 +00:00
# endif
2005-11-06 22:43:25 +00:00
2014-09-10 16:07:04 +00:00
/* open file and do correct filename conversions.
XXX - do we need O_LARGEFILE ? On UN * X , if we need to do
something special to get large file support , the configure
script should have set us up with the appropriate # defines ,
so we should be getting a large - file - enabled file descriptor
here . Pre - Large File Summit UN * Xes , and possibly even some
post - LFS UN * Xes , might require O_LARGEFILE here , though .
If so , we should probably handle that in ws_open ( ) . */
if ( ( fd = ws_open ( path , O_RDONLY | O_BINARY , 0000 ) ) = = - 1 )
return NULL ;
/* open file handle */
ft = file_fdopen ( fd ) ;
if ( ft = = NULL ) {
ws_close ( fd ) ;
return NULL ;
}
2005-11-06 22:43:25 +00:00
2011-05-09 03:48:41 +00:00
# ifdef HAVE_LIBZ
2014-09-10 16:07:04 +00:00
/*
* If this file ' s name ends in " .caz " , it ' s probably a compressed
* Windows Sniffer file . The compression is gzip , but if we
* process the CRC as specified by RFC 1952 , the computed CRC
* doesn ' t match the stored CRC .
*
* Compressed Windows Sniffer files don ' t all have the same CRC
* value ; is it just random crap , or are they running the CRC on
* a different set of data than you ' re supposed to ( e . g . , not
* CRCing some of the data ) , or something such as that ?
*
* For now , we just set a flag to ignore CRC errors .
*/
suffixp = strrchr ( path , ' . ' ) ;
if ( suffixp ! = NULL ) {
if ( g_ascii_strcasecmp ( suffixp , " .caz " ) = = 0 )
ft - > dont_check_crc = TRUE ;
}
2011-05-09 03:48:41 +00:00
# endif
2014-09-10 16:07:04 +00:00
return ft ;
2005-11-06 22:43:25 +00:00
}
2012-12-05 16:19:12 +00:00
void
file_set_random_access ( FILE_T stream , gboolean random_flag _U_ , GPtrArray * seek )
2011-04-12 02:40:14 +00:00
{
2014-09-10 16:07:04 +00:00
stream - > fast_seek = seek ;
2011-04-12 02:40:14 +00:00
}
2006-11-06 00:24:24 +00:00
gint64
2011-04-08 00:28:37 +00:00
file_seek ( FILE_T file , gint64 offset , int whence , int * err )
2000-01-13 07:09:20 +00:00
{
2014-09-10 16:07:04 +00:00
struct fast_seek_point * here ;
guint n ;
2011-04-08 00:28:37 +00:00
2014-09-10 16:07:04 +00:00
/* can only seek from start or relative to current position */
if ( whence ! = SEEK_SET & & whence ! = SEEK_CUR ) {
g_assert_not_reached ( ) ;
2011-04-08 00:28:37 +00:00
/*
2014-09-10 16:07:04 +00:00
* err = EINVAL ;
return - 1 ;
*/
}
/* normalize offset to a SEEK_CUR specification */
if ( whence = = SEEK_SET )
offset - = file - > pos ;
else if ( file - > seek_pending )
offset + = file - > skip ;
file - > seek_pending = FALSE ;
2014-10-25 23:08:02 +00:00
/*
* Are we seeking backwards and , if so , do we have data in the buffer ?
*/
2014-09-10 16:07:04 +00:00
if ( offset < 0 & & file - > next ) {
/*
2014-10-25 23:08:02 +00:00
* Yes .
*
2014-09-10 16:07:04 +00:00
* This is guaranteed to fit in an unsigned int .
* To squelch compiler warnings , we cast the
* result .
*/
guint had = ( unsigned ) ( file - > next - file - > out ) ;
2014-10-25 23:08:02 +00:00
/*
* Do we have enough data before the current position in
* the buffer that we can seek backwards within the buffer ?
*/
2014-09-10 16:07:04 +00:00
if ( - offset < = had ) {
/*
2014-10-25 23:08:02 +00:00
* Yes .
*
2014-09-10 16:07:04 +00:00
* Offset is negative , so - offset is
* non - negative , and - offset is
* < = an unsigned and thus fits in an
* unsigned . Get that value and
* adjust appropriately .
*
* ( Casting offset to unsigned makes
* it positive , which is not what we
* would want , so we cast - offset
* instead . )
*/
guint adjustment = ( unsigned ) ( - offset ) ;
file - > have + = adjustment ;
file - > next - = adjustment ;
file - > pos - = adjustment ;
return file - > pos ;
}
}
2014-10-25 23:08:02 +00:00
/*
* No . Do we have " fast seek " data for the location to which we
* will be seeking ?
*
* XXX , profile
*/
2014-09-10 16:07:04 +00:00
if ( ( here = fast_seek_find ( file , file - > pos + offset ) ) & & ( offset < 0 | | offset > SPAN | | here - > compression = = UNCOMPRESSED ) ) {
gint64 off , off2 ;
2011-04-12 02:40:14 +00:00
2014-10-25 23:08:02 +00:00
/*
* Yes . Use that data to do the seek .
* Note that this will be true only if file_set_random_access ( )
* has been called on this file , which should never be the case
* for a pipe .
*/
2011-04-12 02:40:14 +00:00
# ifdef HAVE_LIBZ
2014-09-10 16:07:04 +00:00
if ( here - > compression = = ZLIB ) {
2011-04-29 07:49:55 +00:00
# ifdef HAVE_INFLATEPRIME
2014-09-10 16:07:04 +00:00
off = here - > in - ( here - > data . zlib . bits ? 1 : 0 ) ;
2011-04-29 07:49:55 +00:00
# else
2014-09-10 16:07:04 +00:00
off = here - > in ;
2011-04-29 07:49:55 +00:00
# endif
2014-09-10 16:07:04 +00:00
off2 = here - > out ;
} else if ( here - > compression = = GZIP_AFTER_HEADER ) {
off = here - > in ;
off2 = here - > out ;
} else
2011-04-12 02:40:14 +00:00
# endif
2014-09-10 16:07:04 +00:00
{
off2 = ( file - > pos + offset ) ;
off = here - > in + ( off2 - here - > out ) ;
}
if ( ws_lseek64 ( file - > fd , off , SEEK_SET ) = = - 1 ) {
* err = errno ;
return - 1 ;
}
fast_seek_reset ( file ) ;
file - > raw_pos = off ;
file - > have = 0 ;
file - > eof = FALSE ;
file - > seek_pending = FALSE ;
file - > err = 0 ;
file - > err_info = NULL ;
file - > avail_in = 0 ;
2011-04-12 02:40:14 +00:00
# ifdef HAVE_LIBZ
2014-09-10 16:07:04 +00:00
if ( here - > compression = = ZLIB ) {
z_stream * strm = & file - > strm ;
2011-04-12 02:40:14 +00:00
2014-09-10 16:07:04 +00:00
inflateReset ( strm ) ;
strm - > adler = here - > data . zlib . adler ;
strm - > total_out = here - > data . zlib . total_out ;
2011-04-29 07:49:55 +00:00
# ifdef HAVE_INFLATEPRIME
2014-09-10 16:07:04 +00:00
if ( here - > data . zlib . bits ) {
FILE_T state = file ;
int ret = GZ_GETC ( ) ;
if ( ret = = - 1 ) {
if ( state - > err = = 0 ) {
/* EOF */
* err = WTAP_ERR_SHORT_READ ;
} else
* err = state - > err ;
return - 1 ;
}
( void ) inflatePrime ( strm , here - > data . zlib . bits , ret > > ( 8 - here - > data . zlib . bits ) ) ;
}
2011-04-29 07:49:55 +00:00
# endif
2014-09-10 16:07:04 +00:00
( void ) inflateSetDictionary ( strm , here - > data . zlib . window , ZLIB_WINSIZE ) ;
file - > compression = ZLIB ;
} else if ( here - > compression = = GZIP_AFTER_HEADER ) {
z_stream * strm = & file - > strm ;
inflateReset ( strm ) ;
strm - > adler = crc32 ( 0L , Z_NULL , 0 ) ;
file - > compression = ZLIB ;
} else
2011-04-12 02:40:14 +00:00
# endif
2014-09-10 16:07:04 +00:00
file - > compression = here - > compression ;
offset = ( file - > pos + offset ) - off2 ;
file - > pos = off2 ;
/* g_print("OK! %ld\n", offset); */
if ( offset ) {
file - > seek_pending = TRUE ;
file - > skip = offset ;
}
return file - > pos + offset ;
}
2014-10-25 23:08:02 +00:00
/*
* Is this an uncompressed file , are we within the raw area ,
* are we either seeking backwards or seeking past the end
* of the buffer , and are we set up for random access with
* file_set_random_access ( ) ?
*
* Again , note that this will never be true on a pipe , as
* file_set_random_access ( ) should never be called if we ' re
* reading from a pipe .
*/
2014-09-10 16:07:04 +00:00
if ( file - > compression = = UNCOMPRESSED & & file - > pos + offset > = file - > raw
2014-10-25 23:08:02 +00:00
& & ( offset < 0 | | offset > = file - > have )
& & ( file - > fast_seek ) )
2014-09-10 16:07:04 +00:00
{
2014-10-25 23:08:02 +00:00
/*
* Yes . Just seek there within the file .
*/
2014-09-10 16:07:04 +00:00
if ( ws_lseek64 ( file - > fd , offset - file - > have , SEEK_CUR ) = = - 1 ) {
* err = errno ;
return - 1 ;
}
file - > raw_pos + = ( offset - file - > have ) ;
file - > have = 0 ;
file - > eof = FALSE ;
file - > seek_pending = FALSE ;
file - > err = 0 ;
file - > err_info = NULL ;
file - > avail_in = 0 ;
file - > pos + = offset ;
return file - > pos ;
}
2014-10-25 23:08:02 +00:00
/*
* Are we seeking backwards ?
*/
2014-09-10 16:07:04 +00:00
if ( offset < 0 ) {
2014-10-25 23:08:02 +00:00
/*
* Yes .
*
* Calculate the amount to skip forward after rewinding .
*/
2014-09-10 16:07:04 +00:00
offset + = file - > pos ;
if ( offset < 0 ) { /* before start of file! */
* err = EINVAL ;
return - 1 ;
}
/* rewind, then skip to offset */
/* back up and start over */
if ( ws_lseek64 ( file - > fd , file - > start , SEEK_SET ) = = - 1 ) {
* err = errno ;
return - 1 ;
}
fast_seek_reset ( file ) ;
file - > raw_pos = file - > start ;
gz_reset ( file ) ;
}
2014-10-25 23:08:02 +00:00
/*
* No , we ' re skipping forwards .
*
* Skip what ' s in output buffer ( one less gzgetc ( ) check ) .
*/
2014-09-10 16:07:04 +00:00
n = ( gint64 ) file - > have > offset ? ( unsigned ) offset : file - > have ;
file - > have - = n ;
file - > next + = n ;
file - > pos + = n ;
offset - = n ;
/* request skip (if not zero) */
if ( offset ) {
file - > seek_pending = TRUE ;
file - > skip = offset ;
}
return file - > pos + offset ;
2000-01-25 04:49:55 +00:00
}
2012-05-02 21:25:48 +00:00
/*
* Skip forward the specified number of bytes in the file .
* Currently implemented as a wrapper around file_seek ( ) ,
* but if , for example , we ever add support for reading
* sequentially from a pipe , this could instead just skip
* forward by reading the bytes in question .
*/
2013-06-03 23:07:42 +00:00
gboolean
2012-05-02 21:25:48 +00:00
file_skip ( FILE_T file , gint64 delta , int * err )
{
2014-09-10 16:07:04 +00:00
if ( file_seek ( file , delta , SEEK_CUR , err ) = = - 1 )
return FALSE ;
return TRUE ;
2012-05-02 21:25:48 +00:00
}
2006-11-05 22:46:44 +00:00
gint64
2011-04-08 00:28:37 +00:00
file_tell ( FILE_T stream )
2000-01-25 04:49:55 +00:00
{
2014-09-10 16:07:04 +00:00
/* return position */
return stream - > pos + ( stream - > seek_pending ? stream - > skip : 0 ) ;
2000-01-13 07:09:20 +00:00
}
2011-05-09 08:12:26 +00:00
gint64
file_tell_raw ( FILE_T stream )
2011-05-09 05:30:59 +00:00
{
2014-09-10 16:07:04 +00:00
return stream - > raw_pos ;
2011-05-09 05:30:59 +00:00
}
2011-05-09 08:12:26 +00:00
int
file_fstat ( FILE_T stream , ws_statb64 * statb , int * err )
{
2014-09-10 16:07:04 +00:00
if ( ws_fstat64 ( stream - > fd , statb ) = = - 1 ) {
if ( err ! = NULL )
* err = errno ;
return - 1 ;
}
return 0 ;
2011-05-09 08:12:26 +00:00
}
2012-05-24 05:05:29 +00:00
gboolean
file_iscompressed ( FILE_T stream )
{
2014-09-10 16:07:04 +00:00
return stream - > is_compressed ;
2012-05-24 05:05:29 +00:00
}
2012-12-05 16:19:12 +00:00
int
2011-04-08 00:28:37 +00:00
file_read ( void * buf , unsigned int len , FILE_T file )
2000-01-13 07:09:20 +00:00
{
2014-09-10 16:07:04 +00:00
guint got , n ;
/* if len is zero, avoid unnecessary operations */
if ( len = = 0 )
return 0 ;
/* process a skip request */
if ( file - > seek_pending ) {
file - > seek_pending = FALSE ;
if ( gz_skip ( file , file - > skip ) = = - 1 )
return - 1 ;
}
/* get len bytes to buf, or less than len if at the end */
got = 0 ;
do {
if ( file - > have ) {
/* We have stuff in the output buffer; copy
what we have . */
n = file - > have > len ? len : file - > have ;
memcpy ( buf , file - > next , n ) ;
file - > next + = n ;
file - > have - = n ;
} else if ( file - > err ) {
/* We have nothing in the output buffer, and
we have an error that may not have been
reported yet ; that means we can ' t generate
any more data into the output buffer , so
return an error indication . */
return - 1 ;
} else if ( file - > eof & & file - > avail_in = = 0 ) {
/* We have nothing in the output buffer, and
we ' re at the end of the input ; just return
with what we ' ve gotten so far . */
break ;
} else {
/* We have nothing in the output buffer, and
we can generate more data ; get more output ,
looking for header if required , and
keep looping to process the new stuff
in the output buffer . */
if ( fill_out_buffer ( file ) = = - 1 )
return - 1 ;
continue ; /* no progress yet -- go back to memcpy() above */
}
/* update progress */
len - = n ;
buf = ( char * ) buf + n ;
got + = n ;
file - > pos + = n ;
} while ( len ) ;
return ( int ) got ;
2000-01-13 07:09:20 +00:00
}
2006-11-05 22:46:44 +00:00
2014-03-18 17:21:51 +00:00
/*
* XXX - this * peeks * at next byte , not a character .
*/
int
file_peekc ( FILE_T file )
{
2014-09-10 16:07:04 +00:00
int ret = 0 ;
/* check that we're reading and that there's no error */
if ( file - > err )
return - 1 ;
/* try output buffer (no need to check for skip request) */
if ( file - > have ) {
return * ( file - > next ) ;
}
/* process a skip request */
if ( file - > seek_pending ) {
file - > seek_pending = FALSE ;
if ( gz_skip ( file , file - > skip ) = = - 1 )
return - 1 ;
}
/* if we processed a skip request, there may be data in the buffer,
* or an error could have occurred ; likewise if we didn ' t do seek but
* now call fill_out_buffer , the errors can occur . So we do this while
* loop to check before and after - this is basically the logic from
* file_read ( ) but only for peeking not consuming a byte
*/
while ( 1 ) {
if ( file - > have ) {
return * ( file - > next ) ;
}
else if ( file - > err ) {
return - 1 ;
}
else if ( file - > eof & & file - > avail_in = = 0 ) {
return - 1 ;
}
else if ( fill_out_buffer ( file ) = = - 1 ) {
return - 1 ;
}
}
/* it's actually impossible to get here */
return ret ;
2014-03-18 17:21:51 +00:00
}
2013-01-06 20:36:33 +00:00
/*
* XXX - this gets a byte , not a character .
*/
2011-04-08 00:28:37 +00:00
int
file_getc ( FILE_T file )
{
2014-09-10 16:07:04 +00:00
unsigned char buf [ 1 ] ;
int ret ;
/* check that we're reading and that there's no error */
if ( file - > err )
return - 1 ;
/* try output buffer (no need to check for skip request) */
if ( file - > have ) {
file - > have - - ;
file - > pos + + ;
return * ( file - > next ) + + ;
}
ret = file_read ( buf , 1 , file ) ;
return ret < 1 ? - 1 : buf [ 0 ] ;
2011-04-08 00:28:37 +00:00
}
char *
file_gets ( char * buf , int len , FILE_T file )
2006-11-05 22:46:44 +00:00
{
2014-09-10 16:07:04 +00:00
guint left , n ;
char * str ;
unsigned char * eol ;
/* check parameters */
if ( buf = = NULL | | len < 1 )
return NULL ;
/* check that there's no error */
if ( file - > err )
return NULL ;
/* process a skip request */
if ( file - > seek_pending ) {
file - > seek_pending = FALSE ;
if ( gz_skip ( file , file - > skip ) = = - 1 )
return NULL ;
}
/* copy output bytes up to new line or len - 1, whichever comes first --
append a terminating zero to the string ( we don ' t check for a zero in
the contents , let the user worry about that ) */
str = buf ;
left = ( unsigned ) len - 1 ;
if ( left ) do {
/* assure that something is in the output buffer */
if ( file - > have = = 0 ) {
/* We have nothing in the output buffer. */
if ( file - > err ) {
/* We have an error that may not have
been reported yet ; that means we
can ' t generate any more data into
the output buffer , so return an
error indication . */
return NULL ;
}
if ( fill_out_buffer ( file ) = = - 1 )
return NULL ; /* error */
if ( file - > have = = 0 ) { /* end of file */
if ( buf = = str ) /* got bupkus */
return NULL ;
break ; /* got something -- return it */
}
}
/* look for end-of-line in current output buffer */
n = file - > have > left ? left : file - > have ;
eol = ( unsigned char * ) memchr ( file - > next , ' \n ' , n ) ;
if ( eol ! = NULL )
n = ( unsigned ) ( eol - file - > next ) + 1 ;
/* copy through end-of-line, or remainder if not found */
memcpy ( buf , file - > next , n ) ;
file - > have - = n ;
file - > next + = n ;
file - > pos + = n ;
left - = n ;
buf + = n ;
} while ( left & & eol = = NULL ) ;
/* found end-of-line or out of space -- terminate string and return it */
buf [ 0 ] = 0 ;
return str ;
2006-11-05 22:46:44 +00:00
}
2012-12-05 16:19:12 +00:00
int
2011-04-08 00:28:37 +00:00
file_eof ( FILE_T file )
2006-11-05 22:46:44 +00:00
{
2014-09-10 16:07:04 +00:00
/* return end-of-file state */
return ( file - > eof & & file - > avail_in = = 0 & & file - > have = = 0 ) ;
2006-11-05 22:46:44 +00:00
}
2011-04-08 00:28:37 +00:00
/*
* Routine to return a Wiretap error code ( 0 for no error , an errno
* for a file error , or a WTAP_ERR_ code for other errors ) for an
2011-04-21 09:41:52 +00:00
* I / O stream . Also returns an error string for some errors .
2011-04-08 00:28:37 +00:00
*/
2000-01-13 07:09:20 +00:00
int
2011-04-21 09:41:52 +00:00
file_error ( FILE_T fh , gchar * * err_info )
2000-01-13 07:09:20 +00:00
{
2014-09-10 16:07:04 +00:00
if ( fh - > err ! = 0 & & err_info ) {
/* g_strdup() returns NULL for NULL argument */
* err_info = g_strdup ( fh - > err_info ) ;
2014-10-08 20:44:46 +00:00
}
2014-09-10 16:07:04 +00:00
return fh - > err ;
2011-04-08 00:28:37 +00:00
}
void
file_clearerr ( FILE_T stream )
{
2014-09-10 16:07:04 +00:00
/* clear error and end-of-file */
stream - > err = 0 ;
stream - > err_info = NULL ;
stream - > eof = FALSE ;
2011-04-08 00:28:37 +00:00
}
2012-06-01 08:05:12 +00:00
void
file_fdclose ( FILE_T file )
{
2014-09-10 16:07:04 +00:00
ws_close ( file - > fd ) ;
file - > fd = - 1 ;
2012-06-01 08:05:12 +00:00
}
gboolean
file_fdreopen ( FILE_T file , const char * path )
{
2014-09-10 16:07:04 +00:00
int fd ;
2012-06-01 08:05:12 +00:00
2014-09-10 16:07:04 +00:00
if ( ( fd = ws_open ( path , O_RDONLY | O_BINARY , 0000 ) ) = = - 1 )
return FALSE ;
file - > fd = fd ;
return TRUE ;
2012-06-01 08:05:12 +00:00
}
void
2011-04-08 00:28:37 +00:00
file_close ( FILE_T file )
{
2014-09-10 16:07:04 +00:00
int fd = file - > fd ;
2011-04-08 00:28:37 +00:00
2014-09-10 16:07:04 +00:00
/* free memory and close file */
if ( file - > size ) {
2011-04-08 00:28:37 +00:00
# ifdef HAVE_LIBZ
2014-09-10 16:07:04 +00:00
inflateEnd ( & ( file - > strm ) ) ;
2011-04-08 00:28:37 +00:00
# endif
2014-09-10 16:07:04 +00:00
g_free ( file - > out ) ;
g_free ( file - > in ) ;
}
g_free ( file - > fast_seek_cur ) ;
file - > err = 0 ;
file - > err_info = NULL ;
g_free ( file ) ;
/*
* If fd is - 1 , somebody ' s done a file_closefd ( ) on us , so
* we don ' t need to close the FD itself , and shouldn ' t do
* so .
*/
if ( fd ! = - 1 )
ws_close ( fd ) ;
2000-01-13 07:09:20 +00:00
}
2006-11-05 22:46:44 +00:00
2011-04-11 21:33:22 +00:00
# ifdef HAVE_LIBZ
/* internal gzip file state data structure for writing */
struct wtap_writer {
int fd ; /* file descriptor */
gint64 pos ; /* current position in uncompressed data */
2013-01-04 05:22:43 +00:00
guint size ; /* buffer size, zero if not allocated yet */
guint want ; /* requested buffer size, default is GZBUFSIZE */
2011-04-11 21:33:22 +00:00
unsigned char * in ; /* input buffer */
unsigned char * out ; /* output buffer (double-sized when reading) */
unsigned char * next ; /* next output data to deliver or write */
int level ; /* compression level */
int strategy ; /* compression strategy */
int err ; /* error code */
2014-09-10 16:07:04 +00:00
/* zlib deflate stream */
2011-04-11 21:33:22 +00:00
z_stream strm ; /* stream structure in-place (not a pointer) */
} ;
GZWFILE_T
gzwfile_open ( const char * path )
{
int fd ;
GZWFILE_T state ;
int save_errno ;
2011-04-11 22:19:01 +00:00
fd = ws_open ( path , O_BINARY | O_WRONLY | O_CREAT | O_TRUNC , 0666 ) ;
2011-04-11 21:33:22 +00:00
if ( fd = = - 1 )
return NULL ;
state = gzwfile_fdopen ( fd ) ;
if ( state = = NULL ) {
save_errno = errno ;
2011-04-12 16:31:16 +00:00
close ( fd ) ;
errno = save_errno ;
2011-04-11 21:33:22 +00:00
}
return state ;
}
GZWFILE_T
gzwfile_fdopen ( int fd )
{
GZWFILE_T state ;
/* allocate wtap_writer structure to return */
2012-06-02 14:13:14 +00:00
state = ( GZWFILE_T ) g_try_malloc ( sizeof * state ) ;
2011-04-11 21:33:22 +00:00
if ( state = = NULL )
return NULL ;
state - > fd = fd ;
state - > size = 0 ; /* no buffers allocated yet */
state - > want = GZBUFSIZE ; /* requested buffer size */
state - > level = Z_DEFAULT_COMPRESSION ;
state - > strategy = Z_DEFAULT_STRATEGY ;
/* initialize stream */
state - > err = Z_OK ; /* clear error */
state - > pos = 0 ; /* no uncompressed data yet */
state - > strm . avail_in = 0 ; /* no input data yet */
/* return stream */
return state ;
}
/* Initialize state for writing a gzip file. Mark initialization by setting
state - > size to non - zero . Return - 1 , and set state - > err , on failure ;
return 0 on success . */
static int
gz_init ( GZWFILE_T state )
{
int ret ;
z_streamp strm = & ( state - > strm ) ;
/* allocate input and output buffers */
2012-06-02 15:32:34 +00:00
state - > in = ( unsigned char * ) g_try_malloc ( state - > want ) ;
state - > out = ( unsigned char * ) g_try_malloc ( state - > want ) ;
2011-04-11 21:33:22 +00:00
if ( state - > in = = NULL | | state - > out = = NULL ) {
2011-04-12 16:31:16 +00:00
g_free ( state - > out ) ;
g_free ( state - > in ) ;
2011-04-15 07:27:03 +00:00
state - > err = ENOMEM ;
2011-04-11 21:33:22 +00:00
return - 1 ;
}
/* allocate deflate memory, set up for gzip compression */
strm - > zalloc = Z_NULL ;
strm - > zfree = Z_NULL ;
strm - > opaque = Z_NULL ;
ret = deflateInit2 ( strm , state - > level , Z_DEFLATED ,
15 + 16 , 8 , state - > strategy ) ;
if ( ret ! = Z_OK ) {
2011-04-12 16:31:16 +00:00
g_free ( state - > out ) ;
2011-04-11 21:33:22 +00:00
g_free ( state - > in ) ;
2011-04-21 17:51:19 +00:00
if ( ret = = Z_MEM_ERROR ) {
2014-09-10 16:07:04 +00:00
/* This means "not enough memory". */
state - > err = ENOMEM ;
2011-04-21 17:51:19 +00:00
} else {
2014-09-10 16:07:04 +00:00
/* This "shouldn't happen". */
state - > err = WTAP_ERR_INTERNAL ;
2011-04-21 17:51:19 +00:00
}
2011-04-11 21:33:22 +00:00
return - 1 ;
}
/* mark state as initialized */
state - > size = state - > want ;
/* initialize write buffer */
strm - > avail_out = state - > size ;
strm - > next_out = state - > out ;
state - > next = strm - > next_out ;
return 0 ;
}
/* Compress whatever is at avail_in and next_in and write to the output file.
Return - 1 , and set state - > err , if there is an error writing to the output
file ; return 0 on success .
flush is assumed to be a valid deflate ( ) flush value . If flush is Z_FINISH ,
then the deflate ( ) state is reset to start a new gzip stream . */
static int
gz_comp ( GZWFILE_T state , int flush )
{
2012-12-21 03:32:16 +00:00
int ret ;
ssize_t got ;
ptrdiff_t have ;
2011-04-11 21:33:22 +00:00
z_streamp strm = & ( state - > strm ) ;
/* allocate memory if this is the first time through */
if ( state - > size = = 0 & & gz_init ( state ) = = - 1 )
return - 1 ;
/* run deflate() on provided input until it produces no more output */
ret = Z_OK ;
do {
/* write out current buffer contents if full, or if flushing, but if
doing Z_FINISH then don ' t write until we get to Z_STREAM_END */
if ( strm - > avail_out = = 0 | | ( flush ! = Z_NO_FLUSH & &
2014-09-10 16:07:04 +00:00
( flush ! = Z_FINISH | | ret = = Z_STREAM_END ) ) ) {
2012-12-21 03:32:16 +00:00
have = strm - > next_out - state - > next ;
2011-04-11 21:33:22 +00:00
if ( have ) {
2014-09-10 16:07:04 +00:00
got = write ( state - > fd , state - > next , ( unsigned int ) have ) ;
if ( got < 0 ) {
2011-04-11 21:33:22 +00:00
state - > err = errno ;
return - 1 ;
}
2012-12-21 03:32:16 +00:00
if ( ( ptrdiff_t ) got ! = have ) {
2011-04-11 21:33:22 +00:00
state - > err = WTAP_ERR_SHORT_WRITE ;
return - 1 ;
}
}
if ( strm - > avail_out = = 0 ) {
strm - > avail_out = state - > size ;
strm - > next_out = state - > out ;
}
state - > next = strm - > next_out ;
}
/* compress */
have = strm - > avail_out ;
ret = deflate ( strm , flush ) ;
if ( ret = = Z_STREAM_ERROR ) {
2011-04-21 17:51:19 +00:00
/* This "shouldn't happen". */
state - > err = WTAP_ERR_INTERNAL ;
2011-04-11 21:33:22 +00:00
return - 1 ;
}
have - = strm - > avail_out ;
} while ( have ) ;
/* if that completed a deflate stream, allow another to start */
if ( flush = = Z_FINISH )
deflateReset ( strm ) ;
/* all done, no errors */
return 0 ;
}
/* Write out len bytes from buf. Return 0, and set state->err, on
failure or on an attempt to write 0 bytes ( in which case state - > err
is Z_OK ) ; return the number of bytes written on success . */
unsigned
2013-01-04 05:22:43 +00:00
gzwfile_write ( GZWFILE_T state , const void * buf , guint len )
2011-04-11 21:33:22 +00:00
{
2013-01-04 05:22:43 +00:00
guint put = len ;
guint n ;
2011-04-11 21:33:22 +00:00
z_streamp strm ;
strm = & ( state - > strm ) ;
/* check that there's no error */
if ( state - > err ! = Z_OK )
return 0 ;
/* if len is zero, avoid unnecessary operations */
if ( len = = 0 )
return 0 ;
/* allocate memory if this is the first time through */
if ( state - > size = = 0 & & gz_init ( state ) = = - 1 )
return 0 ;
/* for small len, copy to input buffer, otherwise compress directly */
if ( len < state - > size ) {
/* copy to input buffer, compress when full */
do {
if ( strm - > avail_in = = 0 )
strm - > next_in = state - > in ;
n = state - > size - strm - > avail_in ;
if ( n > len )
n = len ;
memcpy ( strm - > next_in + strm - > avail_in , buf , n ) ;
strm - > avail_in + = n ;
state - > pos + = n ;
2013-07-23 23:34:45 +00:00
buf = ( const char * ) buf + n ;
2011-04-11 21:33:22 +00:00
len - = n ;
if ( len & & gz_comp ( state , Z_NO_FLUSH ) = = - 1 )
return 0 ;
} while ( len ) ;
}
else {
/* consume whatever's left in the input buffer */
if ( strm - > avail_in & & gz_comp ( state , Z_NO_FLUSH ) = = - 1 )
return 0 ;
/* directly compress user buffer to file */
strm - > avail_in = len ;
2014-07-23 10:26:05 +00:00
# if ZLIB_CONST
strm - > next_in = ( z_const Bytef * ) buf ;
# else
2013-03-19 19:02:25 +00:00
strm - > next_in = ( Bytef * ) buf ;
2014-07-23 10:26:05 +00:00
# endif
2011-04-11 21:33:22 +00:00
state - > pos + = len ;
if ( gz_comp ( state , Z_NO_FLUSH ) = = - 1 )
return 0 ;
}
/* input was all buffered or compressed (put will fit in int) */
return ( int ) put ;
}
/* Flush out what we've written so far. Returns -1, and sets state->err,
on failure ; returns 0 on success . */
int
gzwfile_flush ( GZWFILE_T state )
{
/* check that there's no error */
if ( state - > err ! = Z_OK )
return - 1 ;
/* compress remaining data with Z_SYNC_FLUSH */
gz_comp ( state , Z_SYNC_FLUSH ) ;
if ( state - > err ! = Z_OK )
return - 1 ;
return 0 ;
}
/* Flush out all data written, and close the file. Returns a Wiretap
error on failure ; returns 0 on success . */
int
gzwfile_close ( GZWFILE_T state )
{
int ret = 0 ;
/* flush, free memory, and close file */
if ( gz_comp ( state , Z_FINISH ) = = - 1 & & ret = = 0 )
ret = state - > err ;
( void ) deflateEnd ( & ( state - > strm ) ) ;
g_free ( state - > out ) ;
g_free ( state - > in ) ;
state - > err = Z_OK ;
if ( close ( state - > fd ) = = - 1 & & ret = = 0 )
ret = errno ;
g_free ( state ) ;
return ret ;
}
int
gzwfile_geterr ( GZWFILE_T state )
{
return state - > err ;
}
# endif
2014-09-10 16:07:04 +00:00
/*
* Editor modelines - http : //www.wireshark.org/tools/modelines.html
*
* Local variables :
* c - basic - offset : 4
* tab - width : 8
* indent - tabs - mode : nil
* End :
*
* vi : set shiftwidth = 4 tabstop = 8 expandtab :
* : indentSize = 4 : tabSize = 8 : noTabs = true :
*/