Ethereal-dev: [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: Joerg Mayer <jmayer@xxxxxxxxxxxxxxxxxxxxxx>
Date: Sat, 22 Apr 2000 03:43:44 +0200 (MET DST)
Hello Tim (+ ethereal-dev),

I'm currently stuck with the seek code but I hope to get some implementation
done for this during the next two days. I *think* I got the rest right but
without seek I can't be sure (I don't get any output). I have attached a
diff versus 0.8.7 that contains all the changes I have made. Feel free to
comment/make suggenstions!

 Ciao
     Joerg

PS: All testing done with *t*ethereal.
PPS: I will probably copy ng_file_read to ng_file_skip and
  write the seek code around that function.

On Thu, 20 Apr 2000, Farley, Tim (ISSAtlanta) wrote:

> Did you get the C source code and doc files I sent you on the compressed
> Sniffer format?  Have you had any time to integrate it into Ethereal?
> 
> If you need any help with it, feel free to ask.

--
Joerg Mayer                                 eMail: <jmayer@xxxxxxxxxxxxx>
Give an engineer a problem and a curious form of time dilation occurs /AC
--- ethereal-0.8.7/wiretap/ngsniffer.c.distrib	Mon Apr 17 09:35:54 2000
+++ ethereal-0.8.7/wiretap/ngsniffer.c	Sat Apr 22 03:29:26 2000
@@ -85,6 +85,7 @@
 /*
  * Sniffer version record format.
  *
+ * FIXME: The comment below is no longer valid
  * 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."
@@ -246,6 +247,10 @@
 #define NUM_NGSNIFF_TIMEUNITS 7
 static double Usec[] = { 15.0, 0.838096, 15.0, 0.5, 2.0, 1.0, 0.1 };
 
+static int ng_file_read(void *buffer, size_t elementsize, size_t numelements,
+        wtap *wth);
+static int SnifferDecompress( unsigned char * inbuf, size_t inlen,
+        unsigned char * outbuf, size_t outlen );
 static int ngsniffer_read(wtap *wth, int *err);
 static void ngsniffer_close(wtap *wth);
 static gboolean ngsniffer_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
@@ -330,13 +335,6 @@
 	}
 	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
@@ -368,8 +366,16 @@
 	}
 
 	/* This is a ngsniffer file */
-	wth->file_type = WTAP_FILE_NGSNIFFER;
 	wth->capture.ngsniffer = g_malloc(sizeof(ngsniffer_t));
+	/* compressed or uncompressed Sniffer file? */
+	if (version.format != 1) {
+		wth->file_type = WTAP_FILE_NGSNIFFER_COMPRESSED;
+fprintf( stderr, "open: compressed\n" );
+	} else {
+		wth->file_type = WTAP_FILE_NGSNIFFER_UNCOMPRESSED;
+fprintf( stderr, "open: uncompressed\n" );
+	}
+
 	wth->subtype_read = ngsniffer_read;
 	wth->subtype_close = ngsniffer_close;
 	wth->snapshot_length = 16384;	/* not available in header, only in frame */
@@ -431,7 +437,7 @@
 		 * Read the record header.
 		 */
 		errno = WTAP_ERR_CANT_READ;
-		bytes_read = file_read(record_type, 1, 2, wth->fh);
+		bytes_read = ng_file_read(record_type, 1, 2, wth);
 		if (bytes_read != 2) {
 			*err = file_error(wth->fh);
 			if (*err != 0)
@@ -444,7 +450,7 @@
 		}
 		wth->data_offset += 2;
 		errno = WTAP_ERR_CANT_READ;
-		bytes_read = file_read(record_length, 1, 4, wth->fh);
+		bytes_read = ng_file_read(record_length, 1, 4, wth);
 		if (bytes_read != 4) {
 			*err = file_error(wth->fh);
 			if (*err == 0)
@@ -471,7 +477,7 @@
 
 			/* Read the f_frame2_struct */
 			errno = WTAP_ERR_CANT_READ;
-			bytes_read = file_read(&frame2, 1, sizeof frame2, wth->fh);
+			bytes_read = ng_file_read(&frame2, 1, sizeof frame2, wth);
 			if (bytes_read != sizeof frame2) {
 				*err = file_error(wth->fh);
 				if (*err == 0)
@@ -529,7 +535,7 @@
 
 			/* Read the f_frame4_struct */
 			errno = WTAP_ERR_CANT_READ;
-			bytes_read = file_read(&frame4, 1, sizeof frame4, wth->fh);
+			bytes_read = ng_file_read(&frame4, 1, sizeof frame4, wth);
 			if (bytes_read != sizeof frame4) {
 				*err = file_error(wth->fh);
 				if (*err == 0)
@@ -602,7 +608,7 @@
 	data_offset = wth->data_offset;
 	errno = WTAP_ERR_CANT_READ;
 	pd = buffer_start_ptr(wth->frame_buffer);
-	bytes_read = file_read(pd, 1, length, wth->fh);
+	bytes_read = ng_file_read(pd, 1, length, wth);
 
 	if (bytes_read != length) {
 		*err = file_error(wth->fh);
@@ -834,4 +840,299 @@
 	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 )
+{
+   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 */
+   int truncated = 0;      /* input appeared truncated */
+   int overflow = 0;       /* attempt to overflow output buffer */
+   int bad_offset = 0;     /* LZ string offset was bad */
+
+   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 )
+         {
+            truncated = 1; /* if we break here, data was oddly truncated */
+            break;
+         }
+      }
+
+      /* 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 )
+         {
+            truncated = 1; /* if we break here, data was oddly truncated */
+            break;
+         }
+
+         /* 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 )
+                {
+                    overflow = 1;
+                    break;
+                }
+
+                /* 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 )
+                {
+                   truncated = 1; /* if we break here, data was oddly truncated */
+                   break;
+                }
+                /* If length would put us past end of output, avoid overflow */
+                if ( pout + length > pout_end )
+                {
+                    overflow = 1;
+                    break;
+                }
+
+                /* 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 )
+                {
+                   truncated = 1; /* if we break here, data was oddly truncated */
+                   break;
+                }
+                /* Check if offset would put us back past begin of buffer */
+                if ( pout - offset < outbuf )
+                {
+                   bad_offset = 1;
+                   break;
+                }
+
+                /* get length from next byte, make sure it won't overrun buf */
+                length = (unsigned int)(*pin++) + 16;
+                if ( pout + length > pout_end )
+                {
+                    overflow = 1;
+                    break;
+                }
+
+                /* 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 )
+                {
+                   bad_offset = 1;
+                   break;
+                }
+
+                /* get length from code_type, make sure it won't overrun buf */
+                length = code_type;
+                if ( pout + length > pout_end )
+                {
+                    overflow = 1;
+                    break;
+                }
+
+                /* Copy the string from previous text to output position,
+                   advance output pointer */
+                memcpy( pout, pout - offset, length );
+                pout += length;
+                break;
+         }
+
+         /* Propagate a break from inside switch to break the while() too */
+         if ( truncated || overflow || bad_offset )
+            break;
+      }
+
+      /* If we've consumed all the input, we are done */
+      if ( pin >= pin_end )
+         break;
+   }
+
+/* FIXME: Use symbolic errors */
+   if ( truncated )
+      return ( -1 );
+
+   if ( overflow )
+      return ( -2 );
+
+   if ( bad_offset )
+      return ( -3 );
+   
+   return ( pout - outbuf );  /* return length of expanded text */
+}
+
+static unsigned char file_inbuf[65536];
+static unsigned char file_outbuf[65536];
+static unsigned char* nextout;
+
+static int
+ng_file_read(void *buffer, size_t elementsize, size_t numelements, wtap *wth)
+{
+   FILE* infile = wth->fh;
+   int copybytes = elementsize * numelements; /* bytes still to be copied */
+   int copied_bytes = 0; /* bytes already copied */
+   unsigned char* outbuffer = buffer; /* where to write next decompressed data */
+   size_t out_len = 0; /* Number of bytes in outbuffer */
+   unsigned short blob_len;
+   size_t in_len;
+   size_t read_len;
+   int uncompressed;
+
+   if ( wth->file_type == WTAP_FILE_NGSNIFFER_UNCOMPRESSED ) {
+	if ( copybytes != (copied_bytes =
+	   file_read( buffer, 1, copybytes, infile))) {
+	   /* FIXME: Errorhandling */
+fprintf( stderr, "error copying plain data from file\n" );
+	}
+	goto error;
+   }
+
+fprintf( stderr, "compressed\n" );
+   while ( copybytes > out_len ) {
+        /* nothing happens on entry, we only fill outbuffer  */
+        memcpy( outbuffer, nextout, out_len );
+        copybytes -= out_len;
+        outbuffer += out_len;
+	copied_bytes += out_len;
+
+        /* Fill buffer */
+        /* Read one 16-bit word which is length of next compressed blob */
+        if ( 2 != (read_len = file_read( &blob_len, 1, 2, infile )) )
+        {
+	   /* FIXME: Errorhandling */
+fprintf( stderr, "error reading blob length from file (read %d bytes instead of 2\n", read_len );
+	   goto error;
+           break;
+        }        
+        in_len = (size_t)pletohs(&blob_len);
+
+        /* Uncompressed blob */
+        uncompressed = 0;
+        if ( 49152 == in_len )
+        {
+           in_len = 16384;
+           uncompressed = 1;
+        }
+
+        /* Read the compressed blob */
+        if ( in_len != ( read_len = file_read( file_inbuf, 1, in_len, infile ) ) )
+        {
+	   /* FIXME: Errorhandling */
+fprintf( stderr, "error reading blob of %d bytes (got %d bytes) from file\n", pletohs(&blob_len), read_len );
+           break;
+        }                                           
+
+        if ( uncompressed ) {
+            memcpy( file_outbuf, file_inbuf, in_len );
+        } else {
+           /* Decompress the blob */
+	   /* FIXME: Errorhandling */
+           out_len = SnifferDecompress( file_inbuf, pletohs(&blob_len),
+               file_outbuf, sizeof(file_outbuf) );
+	   nextout = file_outbuf;
+        }
+   }
+   memcpy( outbuffer, nextout, copybytes);
+   nextout += copybytes;
+   out_len -= copybytes;
+   copied_bytes += copybytes;
+error:
+   return( copied_bytes );
+}
+
+int ngsniffer_compressed_seek_read (FILE *fh, int seek_off, guint8 *pd, int len)
+{
+   return (-1);
 }
--- ethereal-0.8.7/wiretap/wtap.h.distrib	Mon Apr 17 09:35:54 2000
+++ ethereal-0.8.7/wiretap/wtap.h	Sat Apr 22 02:53:47 2000
@@ -106,7 +106,7 @@
 #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_NGSNIFFER_COMPRESSED		6
 #define WTAP_FILE_SNOOP				7
 #define WTAP_FILE_IPTRACE_1_0			8
 #define WTAP_FILE_IPTRACE_2_0			9
@@ -120,9 +120,10 @@
 #define WTAP_FILE_NETTL				17
 #define WTAP_FILE_TOSHIBA			18
 #define WTAP_FILE_I4BTRACE			19
+#define WTAP_FILE_NGSNIFFER_UNCOMPRESSED	20
 
 /* last WTAP_FILE_ value + 1 */
-#define WTAP_NUM_FILE_TYPES			20
+#define WTAP_NUM_FILE_TYPES			21
 
 /*
  * Maximum packet size we'll support.
--- ethereal-0.8.7/wiretap/wtap.c.distrib	Sat Apr 22 02:07:49 2000
+++ ethereal-0.8.7/wiretap/wtap.c	Sat Apr 22 03:17:50 2000
@@ -31,6 +31,7 @@
 #include "buffer.h"
 #include "ascend.h"
 #include "toshiba.h"
+#include "ngsniffer.h"
 
 FILE* wtap_file(wtap *wth)
 {
@@ -233,6 +234,9 @@
 
 	case WTAP_FILE_TOSHIBA:
 		return toshiba_seek_read(fh, seek_off, pd, len);
+
+	case WTAP_FILE_NGSNIFFER_COMPRESSED:
+		return ngsniffer_compressed_seek_read(fh, seek_off, pd, len);
 
 	default:
 		return wtap_def_seek_read(fh, seek_off, pd, len);
--- ethereal-0.8.7/wiretap/ngsniffer.h.distrib	Sat Apr 22 02:10:40 2000
+++ ethereal-0.8.7/wiretap/ngsniffer.h	Sat Apr 22 02:51:57 2000
@@ -22,5 +22,6 @@
  */
 
 int ngsniffer_open(wtap *wth, int *err);
+int ngsniffer_compressed_seek_read (FILE *fh, int seek_off, guint8 *pd, int len);
 gboolean ngsniffer_dump_open(wtap_dumper *wdh, int *err);
 int ngsniffer_dump_can_write_encap(int filetype, int encap);
--- ethereal-0.8.7/tethereal.c.distrib	Mon Apr 17 09:35:54 2000
+++ ethereal-0.8.7/tethereal.c	Mon Apr 17 09:36:57 2000
@@ -130,14 +130,14 @@
   fprintf(stderr, "This is GNU t%s %s, compiled with %s\n", PACKAGE,
 	  VERSION, comp_info_str);
 #ifdef HAVE_LIBPCAP
-  fprintf(stderr, "t%s [ -vVh ] [ -c count ] [ -D ] [ -f <filter expression> ]\n", PACKAGE);
+  fprintf(stderr, "t%s [ -vVh ] [ -c count ] [ -D ] [ -f <capture filter expression> ]\n", PACKAGE);
   fprintf(stderr, "\t[ -F <capture file type> ] [ -i iface ] [ -n ] [ -r infile ]\n");
-  fprintf(stderr, "\t[ -R <filter expression> ] [ -s snaplen ] [ -t <time stamp format> ]\n");
-  fprintf(stderr, "\t[ -w savefile ] [ -x ]\n");
+  fprintf(stderr, "\t[ -R <read filter expression> ] [ -s snaplen ]\n");
+  fprintf(stderr, "\t[ -t <time stamp format> ] [ -w savefile ] [ -x ]\n");
 #else
   fprintf(stderr, "t%s [ -vVh ] [ -D ] [ -F <capture file type> ] [ -n ] [ -r infile ]\n", PACKAGE);
-  fprintf(stderr, "\t[ -R <filter expression> ] [ -t <time stamp format> ] [ -w savefile ]\n");
-  fprintf(stderr, "\t[ -x ]\n");
+  fprintf(stderr, "\t[ -R <read filter expression> ] [ -t <time stamp format> ]\n");
+  fprintf(stderr, "\t[ -w savefile ] [ -x ]\n");
 #endif
   fprintf(stderr, "Valid file type arguments to the \"-F\" flag:\n");
   for (i = 0; i < WTAP_NUM_FILE_TYPES; i++) {