Ethereal-dev: Re: [ethereal-dev] RE: Correct sniffdecomp.c attached

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Guy Harris <gharris@xxxxxxxxxxxx>
Date: Wed, 24 May 2000 00:40:03 -0700
Here's a new version of the patch (against the current CVS tree) that
skips uncompressed records, and handles the blob length, as per your
recommendations.
? errs
? tethereal.SAVE
? ethereal.SAVE
? wiretap/ngsniffer.c.SAVE
? wiretap/ngsniffer.c.SAVE2
Index: wiretap/file.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/wiretap/file.c,v
retrieving revision 1.52
diff -c -r1.52 file.c
*** file.c	2000/05/19 23:06:48	1.52
--- file.c	2000/05/24 07:32:31
***************
*** 169,174 ****
--- 169,175 ----
  	/* initialization */
  	wth->file_encap = WTAP_ENCAP_UNKNOWN;
  	wth->data_offset = 0;
+ 	wth->subtype_sequential_close = NULL;
  	wth->subtype_close = NULL;
  
  	/* Try all file types */
***************
*** 236,244 ****
  	{ "Novell LANalyzer", NULL,
  	  NULL, NULL },
  
! 	/* WTAP_FILE_NGSNIFFER */
  	{ "Network Associates Sniffer (DOS-based)", "ngsniffer",
  	  ngsniffer_dump_can_write_encap, ngsniffer_dump_open },
  
  	/* WTAP_FILE_SNOOP */
  	{ "Sun snoop", "snoop",
--- 237,249 ----
  	{ "Novell LANalyzer", NULL,
  	  NULL, NULL },
  
! 	/* WTAP_FILE_NGSNIFFER_UNCOMPRESSED */
  	{ "Network Associates Sniffer (DOS-based)", "ngsniffer",
  	  ngsniffer_dump_can_write_encap, ngsniffer_dump_open },
+ 
+ 	/* WTAP_FILE_NGSNIFFER_COMPRESSED */
+ 	{ "Network Associates Sniffer (DOS-based), compressed", "ngsniffer_comp",
+ 	  NULL, NULL },
  
  	/* WTAP_FILE_SNOOP */
  	{ "Sun snoop", "snoop",
Index: wiretap/ngsniffer.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/wiretap/ngsniffer.c,v
retrieving revision 1.42
diff -c -r1.42 ngsniffer.c
*** ngsniffer.c	2000/05/19 23:06:59	1.42
--- ngsniffer.c	2000/05/24 07:32:35
***************
*** 84,93 ****
  
  /*
   * Sniffer version record format.
-  *
-  * XXX - the Sniffer documentation doesn't say what the compression stuff
-  * means.  The manual says "IMPORTANT: You must save the file uncompressed
-  * to use this format specification."
   */
  struct vers_rec {
  	gint16	maj_vers;	/* major version number */
--- 84,89 ----
***************
*** 96,102 ****
  	gint16	date;		/* DOS-format date */
  	gint8	type;		/* what type of records follow */
  	guint8	network;	/* network type */
! 	gint8	format;		/* format version (we only support version 1!) */
  	guint8	timeunit;	/* timestamp units */
  	gint8	cmprs_vers;	/* compression version */
  	gint8	cmprs_level;	/* compression level */
--- 92,98 ----
  	gint16	date;		/* DOS-format date */
  	gint8	type;		/* what type of records follow */
  	guint8	network;	/* network type */
! 	gint8	format;		/* format version */
  	guint8	timeunit;	/* timestamp units */
  	gint8	cmprs_vers;	/* compression version */
  	gint8	cmprs_level;	/* compression level */
***************
*** 246,269 ****
  #define NUM_NGSNIFF_TIMEUNITS 7
  static double Usec[] = { 15.0, 0.838096, 15.0, 0.5, 2.0, 1.0, 0.1 };
  
  static int ngsniffer_read(wtap *wth, int *err);
  static int ngsniffer_seek_read(wtap *wth, int seek_off,
      union wtap_pseudo_header *pseudo_header, u_char *pd, int packet_size);
! static int ngsniffer_read_rec_header(FILE_T fh, guint16 *typep,
!     guint16 *lengthp, int *err);
! static int ngsniffer_read_frame2(FILE_T fh, struct frame2_rec *frame2,
      int *err);
  static void set_pseudo_header_frame2(union wtap_pseudo_header *pseudo_header,
      struct frame2_rec *frame2);
! static int ngsniffer_read_frame4(FILE_T fh, struct frame4_rec *frame4,
!     int *err);
  static void set_pseudo_header_frame4(union wtap_pseudo_header *pseudo_header,
      struct frame4_rec *frame4);
! static int ngsniffer_read_rec_data(FILE_T fh, char *pd, int length, int *err);
  static void ngsniffer_close(wtap *wth);
  static gboolean ngsniffer_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
  	const union wtap_pseudo_header *pseudo_header, const u_char *pd, int *err);
  static gboolean ngsniffer_dump_close(wtap_dumper *wdh, int *err);
  
  int ngsniffer_open(wtap *wth, int *err)
  {
--- 242,275 ----
  #define NUM_NGSNIFF_TIMEUNITS 7
  static double Usec[] = { 15.0, 0.838096, 15.0, 0.5, 2.0, 1.0, 0.1 };
  
+ static int skip_uncompressed_records(wtap *wth, int *err);
  static int ngsniffer_read(wtap *wth, int *err);
  static int ngsniffer_seek_read(wtap *wth, int seek_off,
      union wtap_pseudo_header *pseudo_header, u_char *pd, int packet_size);
! static int ngsniffer_read_rec_header(wtap *wth, FILE_T fh,
!     ngsniffer_comp_stream_t *comp_stream, guint16 *typep, guint16 *lengthp,
      int *err);
+ static int ngsniffer_read_frame2(wtap *wth, FILE_T fh,
+     ngsniffer_comp_stream_t *comp_stream, struct frame2_rec *frame2, int *err);
  static void set_pseudo_header_frame2(union wtap_pseudo_header *pseudo_header,
      struct frame2_rec *frame2);
! static int ngsniffer_read_frame4(wtap *wth, FILE_T fh,
!     ngsniffer_comp_stream_t *comp_stream, struct frame4_rec *frame4, int *err);
  static void set_pseudo_header_frame4(union wtap_pseudo_header *pseudo_header,
      struct frame4_rec *frame4);
! static int ngsniffer_read_rec_data(wtap *wth, FILE_T fh,
!     ngsniffer_comp_stream_t *comp_stream, char *pd, int length, int *err);
! static void ngsniffer_sequential_close(wtap *wth);
  static void ngsniffer_close(wtap *wth);
  static gboolean ngsniffer_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
  	const union wtap_pseudo_header *pseudo_header, const u_char *pd, int *err);
  static gboolean ngsniffer_dump_close(wtap_dumper *wdh, int *err);
+ static int SnifferDecompress( unsigned char * inbuf, size_t inlen,
+         unsigned char * outbuf, size_t outlen, int *err );
+ static int ng_file_read(void *buffer, size_t elementsize, size_t numelements,
+     wtap *wth, FILE_T infile, ngsniffer_comp_stream_t *comp_stream, int *err);
+ static long ng_file_seek(wtap *wth, FILE_T infile,
+     ngsniffer_comp_stream_t *comp_stream, long offset, int whence);
  
  int ngsniffer_open(wtap *wth, int *err)
  {
***************
*** 271,278 ****
  	char magic[sizeof ngsniffer_magic];
  	char record_type[2];
  	char record_length[4]; /* only the first 2 bytes are length,
! 							  the last 2 are "reserved" and are thrown away */
! 	guint16 type, length = 0;
  	struct vers_rec version;
  	guint16	start_date;
  	guint16	start_time;
--- 277,284 ----
  	char magic[sizeof ngsniffer_magic];
  	char record_type[2];
  	char record_length[4]; /* only the first 2 bytes are length,
! 				  the last 2 are "reserved" and are thrown away */
! 	guint16 type, length;
  	struct vers_rec version;
  	guint16	start_date;
  	guint16	start_time;
***************
*** 343,355 ****
  	}
  	wth->data_offset += sizeof version;
  
- 	/* Make sure this is an uncompressed Sniffer file */
- 	if (version.format != 1) {
- 		g_message("ngsniffer: Compressed Sniffer files are not supported");
- 		*err = WTAP_ERR_UNSUPPORTED;
- 		return -1;
- 	}
- 
  	/* Check the data link type.
  	   If "version.network" is 7, that's "Internetwork analyzer";
  	   Sniffers appear to write out both LAPB and PPP captures
--- 349,354 ----
***************
*** 380,390 ****
  		return -1;
  	}
  
  	/* This is a ngsniffer file */
- 	wth->file_type = WTAP_FILE_NGSNIFFER;
  	wth->capture.ngsniffer = g_malloc(sizeof(ngsniffer_t));
  	wth->subtype_read = ngsniffer_read;
  	wth->subtype_seek_read = ngsniffer_seek_read;
  	wth->subtype_close = ngsniffer_close;
  	wth->snapshot_length = 16384;	/* not available in header, only in frame */
  	wth->capture.ngsniffer->timeunit = Usec[version.timeunit];
--- 379,439 ----
  		return -1;
  	}
  
+ 	/* compressed or uncompressed Sniffer file? */
+ 	if (version.format != 1) {
+ 		wth->file_type = WTAP_FILE_NGSNIFFER_COMPRESSED;
+ 
+ 		/*
+ 		 * Compressed Sniffer files may have some uncompressed
+ 		 * records at the beginning, containing various bits of
+ 		 * header information.
+ 		 *
+ 		 * We skip over them, so we're positioned at the beginning
+ 		 * of the compressed data; records for packet data are in
+ 		 * the compressed part of the file, and the code to
+ 		 * read sequentially through the packet data, and
+ 		 * the code to seek to the beginning of a packet record
+ 		 * and read it, work, in a compressed file, only in
+ 		 * the compressed region of the file.
+ 		 *
+ 		 * We read and ignore all records with record types
+ 		 * in the range 0-16; if we see a "record" with a
+ 		 * type outside that range, we assume it's a compressed
+ 		 * blob, with the the 2-byte field at the beginning
+ 		 * being the blob size rather than being a record type.
+ 		 */
+ 		if (skip_uncompressed_records(wth, err) < 0)
+ 			return -1;
+ 	} else {
+ 		wth->file_type = WTAP_FILE_NGSNIFFER_UNCOMPRESSED;
+ 	}
+ 
+ 	/*
+ 	 * Now position the random stream to the same location, which
+ 	 * should be the beginning of the real data, and should
+ 	 * be the beginning of the compressed data.
+ 	 *
+ 	 * XXX - will we see any records other than REC_FRAME2, REC_FRAME4,
+ 	 * or REC_EOF after this?  If not, we can get rid of the loop in
+ 	 * "ngsniffer_read()".
+ 	 */
+ 	file_seek(wth->random_fh, wth->data_offset, SEEK_SET);
+ 
  	/* This is a ngsniffer file */
  	wth->capture.ngsniffer = g_malloc(sizeof(ngsniffer_t));
+ 
+ 	/* We haven't allocated any uncompression buffers yet. */
+ 	wth->capture.ngsniffer->seq.file_outbuf = NULL;
+ 	wth->capture.ngsniffer->rand.file_outbuf = NULL;
+ 
+ 	/* Set the current file offset. */
+ 	wth->capture.ngsniffer->data_offset = wth->data_offset;
+ 	wth->capture.ngsniffer->seq.offset = wth->data_offset;
+ 	wth->capture.ngsniffer->rand.offset = wth->data_offset;
+ 
  	wth->subtype_read = ngsniffer_read;
  	wth->subtype_seek_read = ngsniffer_seek_read;
+ 	wth->subtype_sequential_close = ngsniffer_sequential_close;
  	wth->subtype_close = ngsniffer_close;
  	wth->snapshot_length = 16384;	/* not available in header, only in frame */
  	wth->capture.ngsniffer->timeunit = Usec[version.timeunit];
***************
*** 426,431 ****
--- 475,532 ----
  	return 1;
  }
  
+ static int
+ skip_uncompressed_records(wtap *wth, int *err)
+ {
+ 	int bytes_read;
+ 	char record_type[2];
+ 	char record_length[4]; /* only the first 2 bytes are length,
+ 				  the last 2 are "reserved" and are thrown away */
+ 	guint16 type, length;
+ 
+ 	for (;;) {
+ 		errno = WTAP_ERR_CANT_READ;
+ 		bytes_read = file_read(record_type, 1, 2, wth->fh);
+ 		if (bytes_read != 2) {
+ 			*err = file_error(wth->fh);
+ 			if (*err != 0)
+ 				return -1;
+ 			if (bytes_read != 0) {
+ 				*err = WTAP_ERR_SHORT_READ;
+ 				return -1;
+ 			}
+ 			return 0;	/* EOF */
+ 		}
+ 
+ 		type = pletohs(record_type);
+ 		if (type > 16) {
+ 			/*
+ 			 * Well, this is probably the length of a
+ 			 * compressed blob.  Seek backwards over the
+ 			 * two bytes we read, and return.
+ 			 */
+ 			file_seek(wth->fh, -2, SEEK_CUR);
+ 			return 0;
+ 		}
+ 
+ 		errno = WTAP_ERR_CANT_READ;
+ 		bytes_read = file_read(record_length, 1, 4, wth->fh);
+ 		if (bytes_read != 4) {
+ 			*err = file_error(wth->fh);
+ 			if (*err == 0)
+ 				*err = WTAP_ERR_SHORT_READ;
+ 			return -1;
+ 		}
+ 		wth->data_offset += 6;
+ 
+ 		length = pletohs(record_length);
+ 
+ 		/* OK, now skip over it the data. */
+ 		file_seek(wth->fh, length, SEEK_CUR);
+ 		wth->data_offset += length;
+ 	}
+ }
+ 
  /* Read the next packet */
  static int ngsniffer_read(wtap *wth, int *err)
  {
***************
*** 443,449 ****
  		 * Read the record header.
  		 */
  		record_offset = wth->data_offset;
! 		ret = ngsniffer_read_rec_header(wth->fh, &type, &length, err);
  		if (ret <= 0) {
  			/* Read error or EOF */
  			return ret;
--- 544,551 ----
  		 * Read the record header.
  		 */
  		record_offset = wth->data_offset;
! 		ret = ngsniffer_read_rec_header(wth, wth->fh,
! 		    &wth->capture.ngsniffer->seq, &type, &length, err);
  		if (ret <= 0) {
  			/* Read error or EOF */
  			return ret;
***************
*** 464,470 ****
  			}
  
  			/* Read the f_frame2_struct */
! 			ret = ngsniffer_read_frame2(wth->fh, &frame2, err);
  			if (ret < 0) {
  				/* Read error */
  				return ret;
--- 566,573 ----
  			}
  
  			/* Read the f_frame2_struct */
! 			ret = ngsniffer_read_frame2(wth, wth->fh,
! 			    &wth->capture.ngsniffer->seq, &frame2, err);
  			if (ret < 0) {
  				/* Read error */
  				return ret;
***************
*** 496,502 ****
  			}
  
  			/* Read the f_frame4_struct */
! 			ret = ngsniffer_read_frame4(wth->fh, &frame4, err);
  			wth->data_offset += sizeof frame4;
  			time_low = pletohs(&frame4.time_low);
  			time_med = pletohs(&frame4.time_med);
--- 599,606 ----
  			}
  
  			/* Read the f_frame4_struct */
! 			ret = ngsniffer_read_frame4(wth, wth->fh,
! 			    &wth->capture.ngsniffer->seq, &frame4, err);
  			wth->data_offset += sizeof frame4;
  			time_low = pletohs(&frame4.time_low);
  			time_med = pletohs(&frame4.time_med);
***************
*** 531,537 ****
  		 * it is but can't handle it.  Skip past the data
  		 * portion, and keep looping.
  		 */
! 		file_seek(wth->fh, length, SEEK_CUR);
  		wth->data_offset += length;
  	}
  
--- 635,642 ----
  		 * it is but can't handle it.  Skip past the data
  		 * portion, and keep looping.
  		 */
! 		ng_file_seek(wth, wth->fh, &wth->capture.ngsniffer->seq,
! 		    length, SEEK_CUR);
  		wth->data_offset += length;
  	}
  
***************
*** 544,550 ****
  	 */
  	buffer_assure_space(wth->frame_buffer, length);
  	pd = buffer_start_ptr(wth->frame_buffer);
! 	if (ngsniffer_read_rec_data(wth->fh, pd, length, err) < 0)
  		return -1;	/* Read error */
  	wth->data_offset += length;
  
--- 649,656 ----
  	 */
  	buffer_assure_space(wth->frame_buffer, length);
  	pd = buffer_start_ptr(wth->frame_buffer);
! 	if (ngsniffer_read_rec_data(wth, wth->fh,
! 	    &wth->capture.ngsniffer->seq, pd, length, err) < 0)
  		return -1;	/* Read error */
  	wth->data_offset += length;
  
***************
*** 585,593 ****
  	struct frame2_rec frame2;
  	struct frame4_rec frame4;
  
! 	file_seek(wth->random_fh, seek_off, SEEK_SET);
  
! 	ret = ngsniffer_read_rec_header(wth->random_fh, &type, &length, &err);
  	if (ret <= 0) {
  		/* Read error or EOF */
  		return ret;
--- 691,701 ----
  	struct frame2_rec frame2;
  	struct frame4_rec frame4;
  
! 	ng_file_seek(wth, wth->random_fh, &wth->capture.ngsniffer->rand,
! 	    seek_off, SEEK_SET);
  
! 	ret = ngsniffer_read_rec_header(wth, wth->random_fh,
! 	    &wth->capture.ngsniffer->rand, &type, &length, &err);
  	if (ret <= 0) {
  		/* Read error or EOF */
  		return ret;
***************
*** 597,603 ****
  
  	case REC_FRAME2:
  		/* Read the f_frame2_struct */
! 		ret = ngsniffer_read_frame2(wth->random_fh, &frame2, &err);
  		if (ret < 0) {
  			/* Read error */
  			return ret;
--- 705,712 ----
  
  	case REC_FRAME2:
  		/* Read the f_frame2_struct */
! 		ret = ngsniffer_read_frame2(wth, wth->random_fh,
! 		    &wth->capture.ngsniffer->rand, &frame2, &err);
  		if (ret < 0) {
  			/* Read error */
  			return ret;
***************
*** 610,616 ****
  
  	case REC_FRAME4:
  		/* Read the f_frame4_struct */
! 		ret = ngsniffer_read_frame4(wth->random_fh, &frame4, &err);
  
  		length -= sizeof frame4;	/* we already read that much */
  
--- 719,726 ----
  
  	case REC_FRAME4:
  		/* Read the f_frame4_struct */
! 		ret = ngsniffer_read_frame4(wth, wth->random_fh,
! 		    &wth->capture.ngsniffer->rand, &frame4, &err);
  
  		length -= sizeof frame4;	/* we already read that much */
  
***************
*** 628,638 ****
  	/*
  	 * Got the pseudo-header (if any), now get the data.
  	 */
! 	return ngsniffer_read_rec_data(wth->random_fh, pd, packet_size, &err);
  }
  
! static int ngsniffer_read_rec_header(FILE_T fh, guint16 *typep,
!     guint16 *lengthp, int *err)
  {
  	int	bytes_read;
  	char	record_type[2];
--- 738,750 ----
  	/*
  	 * Got the pseudo-header (if any), now get the data.
  	 */
! 	return ngsniffer_read_rec_data(wth, wth->random_fh,
! 	    &wth->capture.ngsniffer->rand, pd, packet_size, &err);
  }
  
! static int ngsniffer_read_rec_header(wtap *wth, FILE_T fh,
!     ngsniffer_comp_stream_t *comp_stream, guint16 *typep, guint16 *lengthp,
!     int *err)
  {
  	int	bytes_read;
  	char	record_type[2];
***************
*** 641,650 ****
  	/*
  	 * Read the record header.
  	 */
! 	errno = WTAP_ERR_CANT_READ;
! 	bytes_read = file_read(record_type, 1, 2, fh);
  	if (bytes_read != 2) {
- 		*err = file_error(fh);
  		if (*err != 0)
  			return -1;
  		if (bytes_read != 0) {
--- 753,760 ----
  	/*
  	 * Read the record header.
  	 */
! 	bytes_read = ng_file_read(record_type, 1, 2, wth, fh, comp_stream, err);
  	if (bytes_read != 2) {
  		if (*err != 0)
  			return -1;
  		if (bytes_read != 0) {
***************
*** 653,662 ****
  		}
  		return 0;
  	}
! 	errno = WTAP_ERR_CANT_READ;
! 	bytes_read = file_read(record_length, 1, 4, fh);
  	if (bytes_read != 4) {
- 		*err = file_error(fh);
  		if (*err == 0)
  			*err = WTAP_ERR_SHORT_READ;
  		return -1;
--- 763,771 ----
  		}
  		return 0;
  	}
! 	bytes_read = ng_file_read(record_length, 1, 4, wth, fh, comp_stream,
! 	    err);
  	if (bytes_read != 4) {
  		if (*err == 0)
  			*err = WTAP_ERR_SHORT_READ;
  		return -1;
***************
*** 667,682 ****
  	return 1;	/* success */
  }
  
! static int ngsniffer_read_frame2(FILE_T fh, struct frame2_rec *frame2,
!     int *err)
  {
  	int bytes_read;
  
  	/* Read the f_frame2_struct */
! 	errno = WTAP_ERR_CANT_READ;
! 	bytes_read = file_read(frame2, 1, sizeof *frame2, fh);
  	if (bytes_read != sizeof *frame2) {
- 		*err = file_error(fh);
  		if (*err == 0)
  			*err = WTAP_ERR_SHORT_READ;
  		return -1;
--- 776,790 ----
  	return 1;	/* success */
  }
  
! static int ngsniffer_read_frame2(wtap *wth, FILE_T fh,
!     ngsniffer_comp_stream_t *comp_stream, struct frame2_rec *frame2, int *err)
  {
  	int bytes_read;
  
  	/* Read the f_frame2_struct */
! 	bytes_read = ng_file_read(frame2, 1, sizeof *frame2, wth, fh,
! 	    comp_stream, err);
  	if (bytes_read != sizeof *frame2) {
  		if (*err == 0)
  			*err = WTAP_ERR_SHORT_READ;
  		return -1;
***************
*** 711,726 ****
  	pseudo_header->x25.flags = (frame2->fs & 0x80) ? 0x00 : 0x80;
  }
  
! static int ngsniffer_read_frame4(FILE_T fh, struct frame4_rec *frame4,
!     int *err)
  {
  	int bytes_read;
  
  	/* Read the f_frame4_struct */
! 	errno = WTAP_ERR_CANT_READ;
! 	bytes_read = file_read(frame4, 1, sizeof *frame4, fh);
  	if (bytes_read != sizeof *frame4) {
- 		*err = file_error(fh);
  		if (*err == 0)
  			*err = WTAP_ERR_SHORT_READ;
  		return -1;
--- 819,833 ----
  	pseudo_header->x25.flags = (frame2->fs & 0x80) ? 0x00 : 0x80;
  }
  
! static int ngsniffer_read_frame4(wtap *wth, FILE_T fh,
!     ngsniffer_comp_stream_t *comp_stream, struct frame4_rec *frame4, int *err)
  {
  	int bytes_read;
  
  	/* Read the f_frame4_struct */
! 	bytes_read = ng_file_read(frame4, 1, sizeof *frame4, wth, fh,
! 	    comp_stream, err);
  	if (bytes_read != sizeof *frame4) {
  		if (*err == 0)
  			*err = WTAP_ERR_SHORT_READ;
  		return -1;
***************
*** 742,756 ****
  	pseudo_header->ngsniffer_atm.aal5t_chksum = pletohl(&frame4->atm_info.Trailer.aal5t_chksum);
  }
  
! static int ngsniffer_read_rec_data(FILE_T fh, char *pd, int length, int *err)
  {
  	int	bytes_read;
  
! 	errno = WTAP_ERR_CANT_READ;
! 	bytes_read = file_read(pd, 1, length, fh);
  
  	if (bytes_read != length) {
- 		*err = file_error(fh);
  		if (*err == 0)
  			*err = WTAP_ERR_SHORT_READ;
  		return -1;
--- 849,862 ----
  	pseudo_header->ngsniffer_atm.aal5t_chksum = pletohl(&frame4->atm_info.Trailer.aal5t_chksum);
  }
  
! static int ngsniffer_read_rec_data(wtap *wth, FILE_T fh,
!     ngsniffer_comp_stream_t *comp_stream, char *pd, int length, int *err)
  {
  	int	bytes_read;
  
! 	bytes_read = ng_file_read(pd, 1, length, wth, fh, comp_stream, err);
  
  	if (bytes_read != length) {
  		if (*err == 0)
  			*err = WTAP_ERR_SHORT_READ;
  		return -1;
***************
*** 758,765 ****
--- 864,885 ----
  	return 0;
  }
  
+ /* Throw away the buffers used by the sequential I/O stream, but not
+    those used by the random I/O stream. */
+ static void ngsniffer_sequential_close(wtap *wth)
+ {
+ 	if (wth->capture.ngsniffer->seq.file_outbuf != NULL) {
+ 		g_free(wth->capture.ngsniffer->seq.file_outbuf);
+ 		wth->capture.ngsniffer->seq.file_outbuf = NULL;
+ 	}
+ }
+ 
  static void ngsniffer_close(wtap *wth)
  {
+ 	if (wth->capture.ngsniffer->seq.file_outbuf != NULL)
+ 		g_free(wth->capture.ngsniffer->seq.file_outbuf);
+ 	if (wth->capture.ngsniffer->rand.file_outbuf != NULL)
+ 		g_free(wth->capture.ngsniffer->rand.file_outbuf);
  	g_free(wth->capture.ngsniffer);
  }
  
***************
*** 951,954 ****
--- 1071,1457 ----
  	return FALSE;
      }
      return TRUE;
+ }
+ 
+ /*
+    SnifferDecompress() decompresses a blob of compressed data from a
+          Sniffer(R) capture file.
+ 
+    This function is Copyright (c) 1999-2999 Tim Farley
+ 
+    Parameters
+       inbuf - buffer of compressed bytes from file, not including
+          the preceding length word
+       inlen - length of inbuf in bytes
+       outbuf - decompressed contents, could contain a partial Sniffer
+          record at the end.
+       outlen - length of outbuf.
+ 
+    Return value is the number of bytes in outbuf on return.
+ */
+ static int
+ SnifferDecompress( unsigned char * inbuf, size_t inlen, 
+                        unsigned char * outbuf, size_t outlen, int *err )
+ {
+    unsigned char * pin = inbuf;
+    unsigned char * pout = outbuf;
+    unsigned char * pin_end = pin + inlen;
+    unsigned char * pout_end = pout + outlen;
+    unsigned int bit_mask;  /* one bit is set in this, to mask with bit_value */
+    unsigned int bit_value = 0; /* cache the last 16 coding bits we retrieved */
+    unsigned int code_type; /* encoding type, from high 4 bits of byte */
+    unsigned int code_low;  /* other 4 bits from encoding byte */
+    int length;             /* length of RLE sequence or repeated string */
+    int offset;             /* offset of string to repeat */
+ 
+    bit_mask  = 0;  /* don't have any bits yet */
+    while (1)
+    {
+       /* Shift down the bit mask we use to see whats encoded */
+       bit_mask = bit_mask >> 1;
+ 
+       /* If there are no bits left, time to get another 16 bits */
+       if ( 0 == bit_mask )
+       {
+          bit_mask  = 0x8000;  /* start with the high bit */
+          bit_value = pletohs(pin);   /* get the next 16 bits */
+          pin += 2;          /* skip over what we just grabbed */
+          if ( pin >= pin_end )
+          {
+             *err = WTAP_ERR_UNC_TRUNCATED;	 /* data was oddly truncated */
+             return ( -1 );
+          }
+       }
+ 
+       /* Use the bits in bit_value to see what's encoded and what is raw data */
+       if ( !(bit_mask & bit_value) )
+       {
+          /* bit not set - raw byte we just copy */
+          *(pout++) = *(pin++);
+       }
+       else
+       {
+          /* bit set - next item is encoded.  Peel off high nybble
+             of next byte to see the encoding type.  Set aside low
+             nybble while we are at it */
+          code_type = (unsigned int) ((*pin) >> 4 ) & 0xF;
+          code_low  = (unsigned int) ((*pin) & 0xF );
+          pin++;   /* increment over the code byte we just retrieved */
+          if ( pin >= pin_end )
+          {
+             *err = WTAP_ERR_UNC_TRUNCATED;	 /* data was oddly truncated */
+             return ( -1 );
+          }
+ 
+          /* Based on the code type, decode the compressed string */
+          switch ( code_type )
+          {
+             case 0  :   /* RLE short runs */
+                 /*
+                     Run length is the low nybble of the first code byte.
+                     Byte to repeat immediately follows.
+                     Total code size: 2 bytes.
+                 */    
+                 length = code_low + 3;
+                 /* If length would put us past end of output, avoid overflow */
+                 if ( pout + length > pout_end )
+                 {
+                     *err = WTAP_ERR_UNC_OVERFLOW;
+                     return ( -1 );
+                 }
+ 
+                 /* generate the repeated series of bytes */
+                 memset( pout, *pin++, length );
+                 pout += length;
+                 break;
+             case 1  :   /* RLE long runs */
+                 /*
+                     Low 4 bits of run length is the low nybble of the 
+                     first code byte, upper 8 bits of run length is in 
+                     the next byte.
+                     Byte to repeat immediately follows.
+                     Total code size: 3 bytes.
+                 */    
+                 length = code_low + ((unsigned int)(*pin++) << 4) + 19;
+                 /* If we are already at end of input, there is no byte
+                    to repeat */
+                 if ( pin >= pin_end )
+                 {
+                     *err = WTAP_ERR_UNC_TRUNCATED;	 /* data was oddly truncated */
+                     return ( -1 );
+                 }
+                 /* If length would put us past end of output, avoid overflow */
+                 if ( pout + length > pout_end )
+                 {
+                     *err = WTAP_ERR_UNC_OVERFLOW;
+                     return ( -1 );
+                 }
+ 
+                 /* generate the repeated series of bytes */
+                 memset( pout, *pin++, length );
+                 pout += length;
+                 break;
+             case 2  :   /* LZ77 long strings */
+                 /*
+                     Low 4 bits of offset to string is the low nybble of the 
+                     first code byte, upper 8 bits of offset is in 
+                     the next byte.
+                     Length of string immediately follows.
+                     Total code size: 3 bytes.
+                 */    
+                 offset = code_low + ((unsigned int)(*pin++) << 4) + 3;
+                 /* If we are already at end of input, there is no byte
+                    to repeat */
+                 if ( pin >= pin_end )
+                 {
+                     *err = WTAP_ERR_UNC_TRUNCATED;	 /* data was oddly truncated */
+                     return ( -1 );
+                 }
+                 /* Check if offset would put us back past begin of buffer */
+                 if ( pout - offset < outbuf )
+                 {
+                     *err = WTAP_ERR_UNC_BAD_OFFSET;
+                     return ( -1 );
+                 }
+ 
+                 /* get length from next byte, make sure it won't overrun buf */
+                 length = (unsigned int)(*pin++) + 16;
+                 if ( pout + length > pout_end )
+                 {
+                     *err = WTAP_ERR_UNC_OVERFLOW;
+                     return ( -1 );
+                 }
+ 
+                 /* Copy the string from previous text to output position,
+                    advance output pointer */
+                 memcpy( pout, pout - offset, length );
+                 pout += length;
+                 break;
+             default :   /* (3 to 15): LZ77 short strings */
+                 /*
+                     Low 4 bits of offset to string is the low nybble of the 
+                     first code byte, upper 8 bits of offset is in 
+                     the next byte.
+                     Length of string to repeat is overloaded into code_type.
+                     Total code size: 2 bytes.
+                 */    
+                 offset = code_low + ((unsigned int)(*pin++) << 4) + 3;
+                 /* Check if offset would put us back past begin of buffer */
+                 if ( pout - offset < outbuf )
+                 {
+                     *err = WTAP_ERR_UNC_BAD_OFFSET;
+                     return ( -1 );
+                 }
+ 
+                 /* get length from code_type, make sure it won't overrun buf */
+                 length = code_type;
+                 if ( pout + length > pout_end )
+                 {
+                     *err = WTAP_ERR_UNC_OVERFLOW;
+                     return ( -1 );
+                 }
+ 
+                 /* Copy the string from previous text to output position,
+                    advance output pointer */
+                 memcpy( pout, pout - offset, length );
+                 pout += length;
+                 break;
+          }
+       }
+ 
+       /* If we've consumed all the input, we are done */
+       if ( pin >= pin_end )
+          break;
+    }
+ 
+    return ( pout - outbuf );  /* return length of expanded text */
+ }
+ 
+ /*
+  * XXX - is there any guarantee that this is big enough to hold the
+  * uncompressed data from any blob?
+  */
+ #define	OUTBUF_SIZE	65536
+ 
+ static int
+ ng_file_read(void *buffer, size_t elementsize, size_t numelements, wtap *wth,
+     FILE_T infile, ngsniffer_comp_stream_t *comp_stream, int *err)
+ {
+     unsigned char file_inbuf[65536];
+     unsigned char *file_outbuf;
+     int copybytes = elementsize * numelements; /* bytes left to be copied */
+     int copied_bytes = 0; /* bytes already copied */
+     unsigned char* outbuffer = buffer; /* where to write next decompressed data */
+     unsigned short blob_len;
+     gint16 blob_len_host;
+     size_t in_len;
+     size_t read_len;
+     gboolean uncompressed;
+     int out_len;
+     int bytes_to_copy;
+ 
+     if ( wth->file_type == WTAP_FILE_NGSNIFFER_UNCOMPRESSED ) {
+ 	errno = WTAP_ERR_CANT_READ;
+ 	copied_bytes = file_read( buffer, 1, copybytes, infile);
+ 	if (copied_bytes != copybytes)
+ 	    *err = file_error(infile);
+ 	return copied_bytes;
+     }
+ 
+     /* Allocate the stream buffer if it hasn't already been allocated. */
+     if (comp_stream->file_outbuf == NULL) {
+ 	comp_stream->file_outbuf = g_malloc(OUTBUF_SIZE);
+ 	comp_stream->nextout = comp_stream->file_outbuf;
+ 	comp_stream->outbuf_nbytes = 0;
+     }
+     file_outbuf = comp_stream->file_outbuf;
+     while (copybytes > 0) {
+    	if (comp_stream->outbuf_nbytes == 0) {
+ 	    /* There's no decompressed stuff to copy; get some more. */
+ 
+ 	    /* Read one 16-bit word which is length of next compressed blob */
+ 	    errno = WTAP_ERR_CANT_READ;
+ 	    read_len = file_read( &blob_len, 1, 2, infile );
+ 	    if ( 2 != read_len ) {
+ 		*err = file_error(infile);
+ 		return( -1 );
+ 	    }
+ 	    blob_len_host = pletohs(&blob_len);
+ 
+ 	    /* Compressed or uncompressed? */
+ 	    if ( blob_len_host < 0 ) {
+ 	    	/* Uncompressed blob; blob length is absolute value
+ 		   of the number. */
+ 		in_len = -blob_len_host;
+ 		uncompressed = TRUE;
+ 	    } else {
+ 	    	in_len = blob_len_host;
+ 		uncompressed = FALSE;
+ 	    }
+ 
+ 	    /* Read the blob */
+ 	    errno = WTAP_ERR_CANT_READ;
+ 	    read_len = file_read( file_inbuf, 1, in_len, infile );
+ 	    if ( in_len != read_len ) {
+ 		*err = file_error(infile);
+ 		return( -1 );
+ 	    }
+ 
+ 	    if ( uncompressed ) {
+ 		memcpy( file_outbuf, file_inbuf, in_len );
+ 		out_len = in_len;
+ 	    } else {
+ 		/* Decompress the blob */
+ 		out_len = SnifferDecompress( file_inbuf, in_len,
+ 						file_outbuf, OUTBUF_SIZE, err );
+ 		if (out_len < 0)
+ 		    return( -1 );
+ 	    }
+ 	    comp_stream->nextout = file_outbuf;
+ 	    comp_stream->outbuf_nbytes = out_len;
+ 	}
+    	    
+ 	bytes_to_copy = copybytes;
+ 	if (bytes_to_copy > comp_stream->outbuf_nbytes)
+ 	    bytes_to_copy = comp_stream->outbuf_nbytes;
+ 	memcpy( outbuffer, comp_stream->nextout, bytes_to_copy );
+ 	copybytes -= bytes_to_copy;
+ 	copied_bytes += bytes_to_copy;
+ 	outbuffer += bytes_to_copy;
+ 	comp_stream->nextout += bytes_to_copy;
+ 	comp_stream->outbuf_nbytes -= bytes_to_copy;
+ 	comp_stream->offset += bytes_to_copy;
+     }
+     return( copied_bytes );
+ }
+ 
+ static long
+ ng_file_seek(wtap *wth, FILE_T infile, ngsniffer_comp_stream_t *comp_stream,
+     long offset, int whence)
+ {
+    long delta;
+    char buf[65536];
+    long amount_to_read;
+    int err;
+ 
+    if ( wth->file_type == WTAP_FILE_NGSNIFFER_UNCOMPRESSED )
+ 	return file_seek(infile, offset, whence);
+ 
+    /* OK, seeking in a compressed data stream is a pain - especially
+       given that the compressed Sniffer data stream we're reading
+       may actually be further compressed by gzip.
+ 
+       For now, we implement random access the same way zlib does:
+ 
+ 	compute the target position (we don't support relative-to-end);
+ 
+ 	if the target position is ahead of where we are, read and throw
+ 	away the number of bytes ahead it is;
+ 
+ 	if the target position is behind where we are, seek backward
+ 	to the beginning of the compressed part of the data (i.e.,
+ 	seek backward to the stuff after the header), and then recompute
+ 	the relative position based on the new position and seek forward
+ 	by reading and throwing away data. */
+ 
+     switch (whence) {
+ 
+     case SEEK_SET:
+     	break;		/* "offset" is the target offset */
+ 
+     case SEEK_CUR:
+ 	offset += comp_stream->offset;
+ 	break;		/* "offset" is relative to the current offset */
+ 
+     case SEEK_END:
+ 	g_assert_not_reached();	/* "offset" is relative to the end of the file... */
+ 	break;		/* ...but we don't know where that is. */
+     }
+ 
+     delta = offset - comp_stream->offset;
+     if (delta < 0) {
+ 	/* Oh, dear, we're going backwards.  That's a pain.
+ 
+ 	   Is the place to which we're seeking within the current buffer? */
+ 
+ 	if (comp_stream->nextout - comp_stream->file_outbuf >= -delta) {
+ 	   /* Yes.  Just adjust "comp_stream->nextout" to point to
+ 	      the place to which we're seeking, adjust
+ 	      "comp_stream->outbuf_nbytes" to add back the appropriate
+ 	      number of bytes, and adjust "comp_stream->offset" to be
+ 	      the destination offset. */
+ 	   comp_stream->nextout += delta;
+ 	   comp_stream->outbuf_nbytes -= delta;
+ 	   comp_stream->offset += delta;
+ 	   delta = 0;	/* no skipping necessary */
+ 	} else {
+ 	    /* No.  Seek back to the beginning of the compressed data. */
+ 	    if (file_seek(infile, wth->capture.ngsniffer->data_offset, SEEK_SET) == -1)
+ 		return -1;
+ 	    comp_stream->offset = wth->capture.ngsniffer->data_offset;
+ 	    delta = offset - comp_stream->offset;
+ 	    if (delta < 0) {
+ 		/* "I'm sorry, Dave, I can't do that."
+ 		    After doing a seek, we can only read stuff from the
+ 		    possibly-compressed region, as we expect compressed
+ 		    blob lengths. */
+ 		g_assert_not_reached();
+ 	    }
+ 
+ 	    /* Reset the output buffer. */
+ 	    comp_stream->nextout = comp_stream->file_outbuf;
+ 	    comp_stream->outbuf_nbytes = 0;
+ 	}
+     }
+ 
+     /* Ok, now read and discard "delta" bytes. */
+     while (delta != 0) {
+ 	amount_to_read = delta;
+ 	if (amount_to_read > sizeof buf)
+ 	    amount_to_read = sizeof buf;
+ 	if (ng_file_read(buf, 1, amount_to_read, wth, infile, comp_stream, &err) < 0)
+ 	    return -1;	/* error */
+ 	delta -= amount_to_read;
+     }
+     return offset;
  }
Index: wiretap/wtap-int.h
===================================================================
RCS file: /usr/local/cvsroot/ethereal/wiretap/wtap-int.h,v
retrieving revision 1.1
diff -c -r1.1 wtap-int.h
*** wtap-int.h	2000/05/19 23:07:04	1.1
--- wtap-int.h	2000/05/24 07:32:35
***************
*** 47,56 ****
--- 47,67 ----
  
  #include "wtap.h"
  
+ /* Information for a compressed Sniffer data stream. */
  typedef struct {
+ 	unsigned char *file_outbuf;
+ 	unsigned char *nextout;
+ 	size_t	outbuf_nbytes;
+ 	long	offset;
+ } ngsniffer_comp_stream_t;
+ 
+ typedef struct {
  	double	timeunit;
  	time_t	start;
  	int	is_atm;
+ 	ngsniffer_comp_stream_t seq;	/* sequential access */
+ 	ngsniffer_comp_stream_t rand;	/* random access */
+ 	long	data_offset;		/* start of possibly-compressed stuff */
  } ngsniffer_t;
  
  typedef struct {
***************
*** 126,131 ****
--- 137,143 ----
  
  	subtype_read_func	subtype_read;
  	subtype_seek_read_func	subtype_seek_read;
+ 	void			(*subtype_sequential_close)(struct wtap*);
  	void			(*subtype_close)(struct wtap*);
  	int			file_encap;	/* per-file, for those
  						   file formats that have
Index: wiretap/wtap.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/wiretap/wtap.c,v
retrieving revision 1.43
diff -c -r1.43 wtap.c
*** wtap.c	2000/05/19 23:07:04	1.43
--- wtap.c	2000/05/24 07:32:36
***************
*** 155,161 ****
  	NULL,
  	"Less data was read than was expected",
  	"File contains a record that's not valid",
! 	"Less data was written than was requested"
  };
  #define	WTAP_ERRLIST_SIZE	(sizeof wtap_errlist / sizeof wtap_errlist[0])
  
--- 155,164 ----
  	NULL,
  	"Less data was read than was expected",
  	"File contains a record that's not valid",
! 	"Less data was written than was requested",
! 	"Uncompression error: data oddly truncated",
! 	"Uncompression error: data would overflow buffer",
! 	"Uncompression error: bad LZ77 offset",
  };
  #define	WTAP_ERRLIST_SIZE	(sizeof wtap_errlist / sizeof wtap_errlist[0])
  
***************
*** 186,196 ****
  }
  
  /* Close only the sequential side, freeing up memory it uses.
     Note that we do *not* want to call the subtype's close function,
     as it would free any per-subtype data, and that data may be
!    needed by the random-access side. */
  void wtap_sequential_close(wtap *wth)
  {
  	if (wth->fh != NULL) {
  		file_close(wth->fh);
  		wth->fh = NULL;
--- 189,206 ----
  }
  
  /* Close only the sequential side, freeing up memory it uses.
+ 
     Note that we do *not* want to call the subtype's close function,
     as it would free any per-subtype data, and that data may be
!    needed by the random-access side.
!    
!    Instead, if the subtype has a "sequential close" function, we call it,
!    to free up stuff used only by the sequential side. */
  void wtap_sequential_close(wtap *wth)
  {
+ 	if (wth->subtype_sequential_close != NULL)
+ 		(*wth->subtype_sequential_close)(wth);
+ 
  	if (wth->fh != NULL) {
  		file_close(wth->fh);
  		wth->fh = NULL;
Index: wiretap/wtap.h
===================================================================
RCS file: /usr/local/cvsroot/ethereal/wiretap/wtap.h,v
retrieving revision 1.71
diff -c -r1.71 wtap.h
*** wtap.h	2000/05/19 23:07:04	1.71
--- wtap.h	2000/05/24 07:32:36
***************
*** 106,128 ****
  #define WTAP_FILE_PCAP_MODIFIED			3
  #define WTAP_FILE_PCAP_RH_6_1			4
  #define WTAP_FILE_LANALYZER			5
! #define WTAP_FILE_NGSNIFFER			6
! #define WTAP_FILE_SNOOP				7
! #define WTAP_FILE_IPTRACE_1_0			8
! #define WTAP_FILE_IPTRACE_2_0			9
! #define WTAP_FILE_NETMON_1_x			10
! #define WTAP_FILE_NETMON_2_x			11
! #define WTAP_FILE_NETXRAY_1_0			12
! #define WTAP_FILE_NETXRAY_1_1			13
! #define WTAP_FILE_NETXRAY_2_001			14
! #define WTAP_FILE_RADCOM			15
! #define WTAP_FILE_ASCEND			16
! #define WTAP_FILE_NETTL				17
! #define WTAP_FILE_TOSHIBA			18
! #define WTAP_FILE_I4BTRACE			19
  
  /* last WTAP_FILE_ value + 1 */
! #define WTAP_NUM_FILE_TYPES			20
  
  /*
   * Maximum packet size we'll support.
--- 106,129 ----
  #define WTAP_FILE_PCAP_MODIFIED			3
  #define WTAP_FILE_PCAP_RH_6_1			4
  #define WTAP_FILE_LANALYZER			5
! #define WTAP_FILE_NGSNIFFER_UNCOMPRESSED	6
! #define WTAP_FILE_NGSNIFFER_COMPRESSED		7
! #define WTAP_FILE_SNOOP				8
! #define WTAP_FILE_IPTRACE_1_0			9
! #define WTAP_FILE_IPTRACE_2_0			10
! #define WTAP_FILE_NETMON_1_x			11
! #define WTAP_FILE_NETMON_2_x			12
! #define WTAP_FILE_NETXRAY_1_0			13
! #define WTAP_FILE_NETXRAY_1_1			14
! #define WTAP_FILE_NETXRAY_2_001			15
! #define WTAP_FILE_RADCOM			16
! #define WTAP_FILE_ASCEND			17
! #define WTAP_FILE_NETTL				18
! #define WTAP_FILE_TOSHIBA			19
! #define WTAP_FILE_I4BTRACE			20
  
  /* last WTAP_FILE_ value + 1 */
! #define WTAP_NUM_FILE_TYPES			21
  
  /*
   * Maximum packet size we'll support.
***************
*** 336,341 ****
--- 337,348 ----
  	/* We read an invalid record */
  #define	WTAP_ERR_SHORT_WRITE			-12
  	/* An attempt to write wrote less data than it should have */
+ #define	WTAP_ERR_UNC_TRUNCATED			-13
+ 	/* Sniffer compressed data was oddly truncated */
+ #define	WTAP_ERR_UNC_OVERFLOW			-14
+ 	/* Uncompressing Sniffer data would overflow buffer */
+ #define	WTAP_ERR_UNC_BAD_OFFSET			-15
+ 	/* LZ77 compressed data has bad offset to string */
  
  /* Errors from zlib; zlib error Z_xxx turns into Wiretap error
     WTAP_ERR_ZLIB + Z_xxx.