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: Sun, 21 May 2000 01:37:30 -0700
On Sat, May 20, 2000 at 04:05:02AM -0700, Guy Harris wrote:
> There appear, at least in the compressed Sniffer file in question, to be
> *three* records at the beginning of the file, *none* of which are
> compressed - the type 1 (REC_VERS) record, a record with a type of 7 and
> a small amount of presumably-binary data, and a record with a type of 6
> and a bunch of text data plus some presumably-binary data.  That stuff
> has to be read without going through the compression code.

Well, other captures - uncompressed - don't have those, so I've attached
a new version of the patch (this is a patch against the current CVS
tree, as was the previous one) which only reads and discards those
records if the file is compressed.
Index: wiretap/file.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/wiretap/file.c,v
retrieving revision 1.52
diff -c -r1.52 wiretap/file.c
*** wiretap/file.c	2000/05/19 23:06:48	1.52
--- wiretap/file.c	2000/05/21 08:33:31
***************
*** 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",
--- 236,248 ----
  	{ "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 wiretap/ngsniffer.c
*** wiretap/ngsniffer.c	2000/05/19 23:06:59	1.42
--- wiretap/ngsniffer.c	2000/05/21 08:33:34
***************
*** 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,274 ----
  #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_record(wtap *wth, guint16 expected_type, 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_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,277 ****
  	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;
--- 276,282 ----
  	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;
***************
*** 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
--- 348,353 ----
***************
*** 380,388 ****
  		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;
--- 378,429 ----
  		return -1;
  	}
  
+ 	/* compressed or uncompressed Sniffer file? */
+ 	if (version.format != 1) {
+ 		wth->file_type = WTAP_FILE_NGSNIFFER_COMPRESSED;
+ 
+ 		/*
+ 		 * In at least one compressed capture file I've seen,
+ 		 * following the version record there are two
+ 		 * uncompressed records, the first of which is a "type 7"
+ 		 * record containing some binary data, and the second of
+ 		 * which is a "type 6" record, containing a bunch of text
+ 		 * and some binary data.
+ 		 *
+ 		 * Skip over them, so that we are positioned at the
+ 		 * beginning of the compressed data.
+ 		 */
+ 		if (skip_uncompressed_record(wth, 7, err) < 0)
+ 			return -1;
+ 		if (skip_uncompressed_record(wth, 6, 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_close = ngsniffer_close;
***************
*** 426,431 ****
--- 467,508 ----
  	return 1;
  }
  
+ static int
+ skip_uncompressed_record(wtap *wth, guint16 expected_type, 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 = 0;
+ 
+ 	errno = WTAP_ERR_CANT_READ;
+ 	bytes_read = file_read(record_type, 1, 2, wth->fh);
+ 	bytes_read += file_read(record_length, 1, 4, wth->fh);
+ 	if (bytes_read != 6) {
+ 		*err = file_error(wth->fh);
+ 		if (*err == 0)
+ 			*err = WTAP_ERR_SHORT_READ;
+ 		return -1;
+ 	}
+ 	wth->data_offset += 6;
+ 
+ 	type = pletohs(record_type);
+ 	length = pletohs(record_length);
+ 
+ 	if (type != expected_type) {
+ 		g_message("ngsniffer: Header in Sniffer file is a type %u record, not a type %u record",
+ 		    type, expected_type);
+ 		*err = WTAP_ERR_BAD_RECORD;
+ 		return -1;
+ 	}
+ 
+ 	/* OK, now skip over it. */
+ 	file_seek(wth->fh, length, SEEK_CUR);
+ 	wth->data_offset += length;
+ 	return 0;
+ }
+ 
  /* 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;
--- 520,527 ----
  		 * 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;
--- 542,549 ----
  			}
  
  			/* 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);
--- 575,582 ----
  			}
  
  			/* 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;
  	}
  
--- 611,618 ----
  		 * 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;
  
--- 625,632 ----
  	 */
  	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;
--- 667,677 ----
  	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;
--- 681,688 ----
  
  	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 */
  
--- 695,702 ----
  
  	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];
--- 714,726 ----
  	/*
  	 * 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) {
--- 729,736 ----
  	/*
  	 * 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;
--- 739,747 ----
  		}
  		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;
--- 752,766 ----
  	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;
--- 795,809 ----
  	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;
--- 825,838 ----
  	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;
***************
*** 760,765 ****
--- 842,853 ----
  
  static void ngsniffer_close(wtap *wth)
  {
+ 	/* XXX - we want to free the sequential buffers when we close
+ 	   the sequential side. */
+ 	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 ****
--- 1039,1411 ----
  	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 */
+     size_t in_len;
+     size_t read_len;
+     gboolean uncompressed;
+     unsigned short blob_len;
+     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 );
+ 	    }
+ 	    in_len = (size_t)pletohs(&blob_len);
+ 
+ 	    /* Compressed or uncompressed?
+ 	       XXX - 49152 is 0xC000, and 16384 is 0x4000;
+ 	       is the high-order bit of the blob length a flag that's
+ 	       set if the blob is uncompressed and clear if it's
+ 	       compressed, and does this mean the biggest blob is
+ 	       32767 bytes long?  Does it also mean you can have an
+ 	       uncompressed blob that's not 16384 bytes long? */
+ 	    uncompressed = FALSE;
+ 	    if ( 49152 == in_len ) {
+ 		in_len = 16384;
+ 		uncompressed = TRUE;
+ 	    }
+ 
+ 	    /* 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.
+ 	   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 wiretap/wtap-int.h
*** wiretap/wtap-int.h	2000/05/19 23:07:04	1.1
--- wiretap/wtap-int.h	2000/05/21 08:33:34
***************
*** 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 {
Index: wiretap/wtap.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/wiretap/wtap.c,v
retrieving revision 1.43
diff -c -r1.43 wiretap/wtap.c
*** wiretap/wtap.c	2000/05/19 23:07:04	1.43
--- wiretap/wtap.c	2000/05/21 08:33:35
***************
*** 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])
  
Index: wiretap/wtap.h
===================================================================
RCS file: /usr/local/cvsroot/ethereal/wiretap/wtap.h,v
retrieving revision 1.71
diff -c -r1.71 wiretap/wtap.h
*** wiretap/wtap.h	2000/05/19 23:07:04	1.71
--- wiretap/wtap.h	2000/05/21 08:33: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.