Have "wtap_seek_read()" return 0 on success and -1 on failure, and take
[obnox/wireshark/wip.git] / wiretap / ngsniffer.c
1 /* ngsniffer.c
2  *
3  * $Id: ngsniffer.c,v 1.75 2002/03/05 05:58:40 guy Exp $
4  *
5  * Wiretap Library
6  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
7  * 
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  * 
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  * 
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  */
22
23 /* The code in ngsniffer.c that decodes the time fields for each packet in the
24  * Sniffer trace originally came from code from TCPVIEW:
25  *
26  * TCPVIEW
27  *
28  * Author:      Martin Hunt
29  *              Networks and Distributed Computing
30  *              Computing & Communications
31  *              University of Washington
32  *              Administration Building, AG-44
33  *              Seattle, WA  98195
34  *              Internet: martinh@cac.washington.edu
35  *
36  *
37  * Copyright 1992 by the University of Washington
38  *
39  * Permission to use, copy, modify, and distribute this software and its
40  * documentation for any purpose and without fee is hereby granted, provided
41  * that the above copyright notice appears in all copies and that both the
42  * above copyright notice and this permission notice appear in supporting
43  * documentation, and that the name of the University of Washington not be
44  * used in advertising or publicity pertaining to distribution of the software
45  * without specific, written prior permission.  This software is made
46  * available "as is", and
47  * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
48  * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
49  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
50  * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
51  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
52  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
53  * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
54  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
55  *
56  */
57 #ifdef HAVE_CONFIG_H
58 #include "config.h"
59 #endif
60
61 #include <stdlib.h>
62 #include <errno.h>
63 #include <string.h>
64 #include "wtap-int.h"
65 #include "file_wrappers.h"
66 #include "buffer.h"
67 #include "ngsniffer.h"
68
69 /* Magic number in Sniffer files. */
70 static const char ngsniffer_magic[] = {
71         'T', 'R', 'S', 'N', 'I', 'F', 'F', ' ', 'd', 'a', 't', 'a',
72         ' ', ' ', ' ', ' ', 0x1a
73 };
74
75 /*
76  * Sniffer record types.
77  */
78 #define REC_VERS        1       /* Version record (f_vers) */
79 #define REC_FRAME2      4       /* Frame data (f_frame2) */
80 #define REC_FRAME4      8       /* Frame data (f_frame4) */
81 #define REC_FRAME6      12      /* Frame data (f_frame6) (see below) */
82 #define REC_EOF         3       /* End-of-file record (no data follows) */
83 /*
84  * and now for some unknown header types
85  */
86 #define REC_HEADER1     6       /* Header containing serial numbers? */
87 #define REC_HEADER2     7       /* Header containing ??? */
88 #define REC_V2DESC      8       /* In version 2 sniffer traces contains
89                                  * infos about this capturing session.
90                                  * Collides with REC_FRAME4 */
91 #define REC_HEADER3     13      /* Retransmission counts? */
92 #define REC_HEADER4     14      /* ? */
93 #define REC_HEADER5     15      /* ? */
94 #define REC_HEADER6     16      /* More broadcast/retransmission counts? */
95 #define REC_HEADER7     17      /* ? */
96
97
98 /*
99  * Sniffer version record format.
100  */
101 struct vers_rec {
102         gint16  maj_vers;       /* major version number */
103         gint16  min_vers;       /* minor version number */
104         gint16  time;           /* DOS-format time */
105         gint16  date;           /* DOS-format date */
106         gint8   type;           /* what type of records follow */
107         guint8  network;        /* network type */
108         gint8   format;         /* format version */
109         guint8  timeunit;       /* timestamp units */
110         gint8   cmprs_vers;     /* compression version */
111         gint8   cmprs_level;    /* compression level */
112         gint16  rsvd[2];        /* reserved */
113 };
114
115 /*
116  * Sniffer type 2 data record format - followed by frame data.
117  */
118 struct frame2_rec {
119         guint16 time_low;       /* low part of time stamp */
120         guint16 time_med;       /* middle part of time stamp */
121         guint16 time_high;      /* high part of time stamp */
122         gint16  size;           /* number of bytes of data */
123         guint8  fs;             /* frame error status bits */
124         guint8  flags;          /* buffer flags */
125         gint16  true_size;      /* size of original frame, in bytes */
126         gint16  rsvd;           /* reserved */
127 };
128
129 /*
130  * Sniffer type 4 data record format - followed by frame data.
131  *
132  * XXX - the manual says that the "flags" field holds "buffer flags;
133  * BF_xxxx", but doesn't say what the BF_xxxx flags are.
134  *
135  * XXX - the manual also says there's an 8-byte "ATMTimeStamp" driver
136  * time stamp at the end of "ATMSaveInfo", but, from an ATM Sniffer capture
137  * file I've looked at, that appears not to be the case.
138  */
139
140 /*
141  * Fields from the AAL5 trailer for the frame, if it's an AAL5 frame
142  * rather than a cell.
143  */
144 typedef struct _ATM_AAL5Trailer {
145         guint16 aal5t_u2u;      /* user-to-user indicator */
146         guint16 aal5t_len;      /* length of the packet */
147         guint32 aal5t_chksum; /* checksum for AAL5 packet */
148 } ATM_AAL5Trailer;
149
150 typedef struct _ATMTimeStamp {
151         guint32 msw;    /* most significant word */
152         guint32 lsw;    /* least significant word */
153 } ATMTimeStamp;
154
155 typedef struct _ATMSaveInfo {
156         guint32 StatusWord;     /* status word from driver */
157         ATM_AAL5Trailer Trailer; /* AAL5 trailer */
158         guint8  AppTrafType;    /* traffic type */
159         guint8  AppHLType;      /* protocol type */
160         guint16 AppReserved;    /* reserved */
161         guint16 Vpi;            /* virtual path identifier */
162         guint16 Vci;            /* virtual circuit identifier */
163         guint16 channel;        /* link: 0 for DCE, 1 for DTE */
164         guint16 cells;          /* number of cells */
165         guint32 AppVal1;        /* type-dependent */
166         guint32 AppVal2;        /* type-dependent */
167 } ATMSaveInfo;
168
169 /*
170  * Bits in StatusWord.
171  */
172 #define SW_ERRMASK              0x0F    /* Error mask: */
173 #define SW_RX_FIFO_UNDERRUN     0x01    /* Receive FIFO underrun */
174 #define SW_RX_FIFO_OVERRUN      0x02    /* Receive FIFO overrun */
175 #define SW_RX_PKT_TOO_LONG      0x03    /* Received packet > max size */
176 #define SW_CRC_ERROR            0x04    /* CRC error */
177 #define SW_USER_ABORTED_RX      0x05    /* User aborted receive */
178 #define SW_BUF_LEN_TOO_LONG     0x06    /* buffer len > max buf */
179 #define SW_INTERNAL_T1_ERROR    0x07    /* Internal T1 error */
180 #define SW_RX_CHANNEL_DEACTIV8  0x08    /* Rx channel deactivate */
181
182 #define SW_ERROR                0x80    /* Error indicator */
183 #define SW_CONGESTION           0x40    /* Congestion indicator */
184 #define SW_CLP                  0x20    /* Cell loss priority indicator */
185 #define SW_RAW_CELL             0x100   /* RAW cell indicator */
186 #define SW_OAM_CELL             0x200   /* OAM cell indicator */
187
188 /*
189  * Bits in AppTrafType.
190  *
191  * For AAL types other than AAL5, the packet data is presumably for a
192  * single cell, not a reassembled frame, as the ATM Sniffer manual says
193  * it dosn't reassemble cells other than AAL5 cells.
194  */
195 #define ATT_AALTYPE             0x0F    /* AAL type: */
196 #define ATT_AAL_UNKNOWN         0x00    /* Unknown AAL */
197 #define ATT_AAL1                0x01    /* AAL1 */
198 #define ATT_AAL3_4              0x02    /* AAL3/4 */
199 #define ATT_AAL5                0x03    /* AAL5 */
200 #define ATT_AAL_USER            0x04    /* User AAL */
201 #define ATT_AAL_SIGNALLING      0x05    /* Signaling AAL */
202 #define ATT_OAMCELL             0x06    /* OAM cell */
203
204 #define ATT_HLTYPE              0xF0    /* Higher-layer type: */
205 #define ATT_HL_UNKNOWN          0x00    /* unknown */
206 #define ATT_HL_LLCMX            0x10    /* LLC multiplexed (probably RFC 1483) */
207 #define ATT_HL_VCMX             0x20    /* VC multiplexed (probably RFC 1483) */
208 #define ATT_HL_LANE             0x30    /* LAN Emulation */
209 #define ATT_HL_ILMI             0x40    /* ILMI */
210 #define ATT_HL_FRMR             0x50    /* Frame Relay */
211 #define ATT_HL_SPANS            0x60    /* FORE SPANS */
212 #define ATT_HL_IPSILON          0x70    /* Ipsilon */
213
214 /*
215  * Values for AppHLType; the interpretation depends on the ATT_HLTYPE
216  * bits in AppTrafType.
217  */
218 #define AHLT_UNKNOWN            0x0
219 #define AHLT_VCMX_802_3_FCS     0x1     /* VCMX: 802.3 FCS */
220 #define AHLT_LANE_LE_CTRL       0x1     /* LANE: LE Ctrl */
221 #define AHLT_IPSILON_FT0        0x1     /* Ipsilon: Flow Type 0 */
222 #define AHLT_VCMX_802_4_FCS     0x2     /* VCMX: 802.4 FCS */
223 #define AHLT_LANE_802_3         0x2     /* LANE: 802.3 */
224 #define AHLT_IPSILON_FT1        0x2     /* Ipsilon: Flow Type 1 */
225 #define AHLT_VCMX_802_5_FCS     0x3     /* VCMX: 802.5 FCS */
226 #define AHLT_LANE_802_5         0x3     /* LANE: 802.5 */
227 #define AHLT_IPSILON_FT2        0x3     /* Ipsilon: Flow Type 2 */
228 #define AHLT_VCMX_FDDI_FCS      0x4     /* VCMX: FDDI FCS */
229 #define AHLT_LANE_802_3_MC      0x4     /* LANE: 802.3 multicast */
230 #define AHLT_VCMX_802_6_FCS     0x5     /* VCMX: 802.6 FCS */
231 #define AHLT_LANE_802_5_MC      0x5     /* LANE: 802.5 multicast */
232 #define AHLT_VCMX_802_3         0x7     /* VCMX: 802.3 */
233 #define AHLT_VCMX_802_4         0x8     /* VCMX: 802.4 */
234 #define AHLT_VCMX_802_5         0x9     /* VCMX: 802.5 */
235 #define AHLT_VCMX_FDDI          0xa     /* VCMX: FDDI */
236 #define AHLT_VCMX_802_6         0xb     /* VCMX: 802.6 */
237 #define AHLT_VCMX_FRAGMENTS     0xc     /* VCMX: Fragments */
238 #define AHLT_VCMX_BPDU          0xe     /* VCMX: BPDU */
239
240 struct frame4_rec {
241         guint16 time_low;       /* low part of time stamp */
242         guint16 time_med;       /* middle part of time stamp */
243         gint8   time_high;      /* high part of time stamp */
244         gint8   time_day;       /* time in days since start of capture */
245         gint16  size;           /* number of bytes of data */
246         gint8   fs;             /* frame error status bits */
247         gint8   flags;          /* buffer flags */
248         gint16  true_size;      /* size of original frame, in bytes */
249         gint16  rsvd3;          /* reserved */
250         gint16  atm_pad;        /* pad to 4-byte boundary */
251         ATMSaveInfo atm_info;   /* ATM-specific stuff */
252 };
253
254 /*
255  * XXX - I have a version 5.50 file with a bunch of token ring
256  * records listed as type "12".  The record format below was
257  * derived from frame4_rec and a bit of experimentation.
258  * - Gerald
259  */
260 struct frame6_rec {
261         guint16 time_low;       /* low part of time stamp */
262         guint16 time_med;       /* middle part of time stamp */
263         gint8   time_high;      /* high part of time stamp */
264         gint8   time_day;       /* time in days since start of capture */
265         gint16  size;           /* number of bytes of data */
266         gint8   fs;             /* frame error status bits */
267         gint8   flags;          /* buffer flags */
268         gint16  true_size;      /* size of original frame, in bytes */
269         guint8  chemical_x[22]; /* ? */
270 };
271
272 /*
273  * Network type values in type 7 records.
274  */
275 #define NET_SDLC        0
276 #define NET_HDLC        1
277 #define NET_FRAME_RELAY 2
278 #define NET_ROUTER      3       /* what's this? */
279 #define NET_PPP         4
280 #define NET_SMDS        5
281
282 /* values for V.timeunit */
283 #define NUM_NGSNIFF_TIMEUNITS 7
284 static double Usec[] = { 15.0, 0.838096, 15.0, 0.5, 2.0, 1.0, 0.1 };
285
286 static int skip_header_records(wtap *wth, int *err, gint16 version);
287 static gboolean ngsniffer_read(wtap *wth, int *err, long *data_offset);
288 static int ngsniffer_seek_read(wtap *wth, long seek_off,
289     union wtap_pseudo_header *pseudo_header, u_char *pd, int packet_size,
290     int *err);
291 static int ngsniffer_read_rec_header(wtap *wth, gboolean is_random,
292     guint16 *typep, guint16 *lengthp, int *err);
293 static int ngsniffer_read_frame2(wtap *wth, gboolean is_random,
294     struct frame2_rec *frame2, int *err);
295 static void set_pseudo_header_frame2(union wtap_pseudo_header *pseudo_header,
296     struct frame2_rec *frame2);
297 static int ngsniffer_read_frame4(wtap *wth, gboolean is_random,
298     struct frame4_rec *frame4, int *err);
299 static void set_pseudo_header_frame4(union wtap_pseudo_header *pseudo_header,
300     struct frame4_rec *frame4);
301 static int ngsniffer_read_frame6(wtap *wth, gboolean is_random,
302     struct frame6_rec *frame6, int *err);
303 static void set_pseudo_header_frame6(union wtap_pseudo_header *pseudo_header,
304     struct frame6_rec *frame6);
305 static int ngsniffer_read_rec_data(wtap *wth, gboolean is_random, u_char *pd,
306     int length, int *err);
307 static void fix_pseudo_header(wtap *wth,
308     union wtap_pseudo_header *pseudo_header);
309 static void ngsniffer_sequential_close(wtap *wth);
310 static void ngsniffer_close(wtap *wth);
311 static gboolean ngsniffer_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
312         const union wtap_pseudo_header *pseudo_header, const u_char *pd, int *err);
313 static gboolean ngsniffer_dump_close(wtap_dumper *wdh, int *err);
314 static int SnifferDecompress( unsigned char * inbuf, size_t inlen,
315         unsigned char * outbuf, size_t outlen, int *err );
316 static int ng_file_read(void *buffer, size_t elementsize, size_t numelements,
317     wtap *wth, gboolean is_random, int *err);
318 static int read_blob(FILE_T infile, ngsniffer_comp_stream_t *comp_stream,
319     int *err);
320 static long ng_file_seek_seq(wtap *wth, long offset, int whence, int *err);
321 static long ng_file_seek_rand(wtap *wth, long offset, int whence, int *err);
322
323 int ngsniffer_open(wtap *wth, int *err)
324 {
325         int bytes_read;
326         char magic[sizeof ngsniffer_magic];
327         char record_type[2];
328         char record_length[4]; /* only the first 2 bytes are length,
329                                   the last 2 are "reserved" and are thrown away */
330         guint16 type, length;
331         struct vers_rec version;
332         guint16 start_date;
333         guint16 start_time;
334         static const int sniffer_encap[] = {
335                 WTAP_ENCAP_TOKEN_RING,
336                 WTAP_ENCAP_ETHERNET,
337                 WTAP_ENCAP_ARCNET,
338                 WTAP_ENCAP_UNKNOWN,     /* StarLAN */
339                 WTAP_ENCAP_UNKNOWN,     /* PC Network broadband */
340                 WTAP_ENCAP_UNKNOWN,     /* LocalTalk */
341                 WTAP_ENCAP_UNKNOWN,     /* Znet */
342                 WTAP_ENCAP_UNKNOWN,     /* Internetwork analyzer (synchronous) */
343                 WTAP_ENCAP_UNKNOWN,     /* Internetwork analyzer (asynchronous) */
344                 WTAP_ENCAP_FDDI_BITSWAPPED,
345                 WTAP_ENCAP_ATM_SNIFFER
346         };
347         #define NUM_NGSNIFF_ENCAPS (sizeof sniffer_encap / sizeof sniffer_encap[0])
348         struct tm tm;
349
350         /* Read in the string that should be at the start of a Sniffer file */
351         errno = WTAP_ERR_CANT_READ;
352         bytes_read = file_read(magic, 1, sizeof magic, wth->fh);
353         if (bytes_read != sizeof magic) {
354                 *err = file_error(wth->fh);
355                 if (*err != 0)
356                         return -1;
357                 return 0;
358         }
359         wth->data_offset += sizeof magic;
360
361         if (memcmp(magic, ngsniffer_magic, sizeof ngsniffer_magic)) {
362                 return 0;
363         }
364
365         /*
366          * Read the first record, which the manual says is a version
367          * record.
368          */
369         errno = WTAP_ERR_CANT_READ;
370         bytes_read = file_read(record_type, 1, 2, wth->fh);
371         bytes_read += file_read(record_length, 1, 4, wth->fh);
372         if (bytes_read != 6) {
373                 *err = file_error(wth->fh);
374                 if (*err != 0)
375                         return -1;
376                 return 0;
377         }
378         wth->data_offset += 6;
379
380         type = pletohs(record_type);
381         length = pletohs(record_length);
382
383         if (type != REC_VERS) {
384                 g_message("ngsniffer: Sniffer file doesn't start with a version record");
385                 *err = WTAP_ERR_BAD_RECORD;
386                 return -1;
387         }
388
389         errno = WTAP_ERR_CANT_READ;
390         bytes_read = file_read(&version, 1, sizeof version, wth->fh);
391         if (bytes_read != sizeof version) {
392                 *err = file_error(wth->fh);
393                 if (*err != 0)
394                         return -1;
395                 return 0;
396         }
397         wth->data_offset += sizeof version;
398
399         /* Check the data link type.
400            If "version.network" is 7, that's "Internetwork analyzer";
401            Sniffers appear to write out LAPB, LAPD and PPP captures
402            (and perhaps other types of captures) in that fashion,
403            and, so far, the only way we know of distinguishing them
404            is to look at the first byte of the packet - if it's 0xFF,
405            it's PPP, otherwise if it's odd, it's LAPB else it's LAPD.
406            Therefore, we treat it as WTAP_ENCAP_UNKNOWN for now, but
407            don't treat that as an error.
408
409            In one PPP capture, the two 16-bit words of the "rsvd" field
410            were 1 and 3, respectively, and in one X.25 capture, they
411            were both 0.  That's too small a sample from which to
412            conclude anything, however.... */
413         if (version.network >= NUM_NGSNIFF_ENCAPS
414             || (sniffer_encap[version.network] == WTAP_ENCAP_UNKNOWN
415                && version.network != 7)) {
416                 g_message("ngsniffer: network type %u unknown or unsupported",
417                     version.network);
418                 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
419                 return -1;
420         }
421
422         /* Check the time unit */
423         if (version.timeunit >= NUM_NGSNIFF_TIMEUNITS) {
424                 g_message("ngsniffer: Unknown timeunit %u", version.timeunit);
425                 *err = WTAP_ERR_UNSUPPORTED;
426                 return -1;
427         }
428
429         /* compressed or uncompressed Sniffer file? */
430         if (version.format != 1) {
431                 wth->file_type = WTAP_FILE_NGSNIFFER_COMPRESSED;
432
433         } else {
434                 wth->file_type = WTAP_FILE_NGSNIFFER_UNCOMPRESSED;
435         }
436
437         /* Set encap type before reading header records because the
438          * header record may change encap type.
439          */
440         wth->file_encap = sniffer_encap[version.network];
441
442         /*
443          * We don't know how to handle the remaining header record types,
444          * so we just skip them - except for REC_HEADER2 records, which
445          * we look at, for "Internetwork analyzer" captures, to attempt to
446          * determine what the link-layer encapsulation is.
447          */
448         if (skip_header_records(wth, err, version.maj_vers) < 0)
449                 return -1;
450
451         /*
452          * Now, if we have a random stream open, position it to the same
453          * location, which should be the beginning of the real data, and
454          * should be the beginning of the compressed data.
455          *
456          * XXX - will we see any records other than REC_FRAME2, REC_FRAME4,
457          * or REC_EOF after this?  If not, we can get rid of the loop in
458          * "ngsniffer_read()".
459          */
460         if (wth->random_fh != NULL) {
461                 if (file_seek(wth->random_fh, wth->data_offset, SEEK_SET) == -1) {
462                         *err = file_error(wth->random_fh);
463                         return -1;
464                 }
465         }
466
467         /* This is a ngsniffer file */
468         wth->capture.ngsniffer = g_malloc(sizeof(ngsniffer_t));
469
470         /* We haven't allocated any uncompression buffers yet. */
471         wth->capture.ngsniffer->seq.buf = NULL;
472         wth->capture.ngsniffer->rand.buf = NULL;
473
474         /* Set the current file offset; the offset in the compressed file
475            and in the uncompressed data stream currently the same. */
476         wth->capture.ngsniffer->seq.uncomp_offset = wth->data_offset;
477         wth->capture.ngsniffer->seq.comp_offset = wth->data_offset;
478         wth->capture.ngsniffer->rand.uncomp_offset = wth->data_offset;
479         wth->capture.ngsniffer->rand.comp_offset = wth->data_offset;
480
481         /* We don't yet have any list of compressed blobs. */
482         wth->capture.ngsniffer->first_blob = NULL;
483         wth->capture.ngsniffer->last_blob = NULL;
484         wth->capture.ngsniffer->current_blob = NULL;
485
486         wth->subtype_read = ngsniffer_read;
487         wth->subtype_seek_read = ngsniffer_seek_read;
488         wth->subtype_sequential_close = ngsniffer_sequential_close;
489         wth->subtype_close = ngsniffer_close;
490         wth->snapshot_length = 0;       /* not available in header, only in frame */
491         wth->capture.ngsniffer->timeunit = Usec[version.timeunit];
492         wth->capture.ngsniffer->is_atm =
493             (wth->file_encap == WTAP_ENCAP_ATM_SNIFFER);
494
495         /* Get capture start time */
496         start_time = pletohs(&version.time);
497         start_date = pletohs(&version.date);
498         tm.tm_year = ((start_date&0xfe00)>>9) + 1980 - 1900;
499         tm.tm_mon = ((start_date&0x1e0)>>5) - 1;
500         tm.tm_mday = (start_date&0x1f);
501         /* The time does not appear to act as an offset; only the date
502         tm.tm_hour = (start_time&0xf800)>>11;
503         tm.tm_min = (start_time&0x7e0)>>5;
504         tm.tm_sec = (start_time&0x1f)<<1;*/
505         tm.tm_hour = 0;
506         tm.tm_min = 0;
507         tm.tm_sec = 0;
508         tm.tm_isdst = -1;
509         wth->capture.ngsniffer->start = mktime(&tm);
510         /*
511          * XXX - what if "secs" is -1?  Unlikely,
512          * but if the capture was done in a time
513          * zone that switches between standard and
514          * summer time sometime other than when we
515          * do, and thus the time was one that doesn't
516          * exist here because a switch from standard
517          * to summer time zips over it, it could
518          * happen.
519          *
520          * On the other hand, if the capture was done
521          * in a different time zone, this won't work
522          * right anyway; unfortunately, the time zone
523          * isn't stored in the capture file.
524          */
525
526         return 1;
527 }
528
529 static int
530 skip_header_records(wtap *wth, int *err, gint16 version)
531 {
532         int bytes_read;
533         char record_type[2];
534         char record_length[4]; /* only the first 2 bytes are length,
535                                   the last 2 are "reserved" and are thrown away */
536         guint16 type, length;
537         int bytes_to_read;
538         unsigned char buffer[32];
539
540         for (;;) {
541                 errno = WTAP_ERR_CANT_READ;
542                 bytes_read = file_read(record_type, 1, 2, wth->fh);
543                 if (bytes_read != 2) {
544                         *err = file_error(wth->fh);
545                         if (*err != 0)
546                                 return -1;
547                         if (bytes_read != 0) {
548                                 *err = WTAP_ERR_SHORT_READ;
549                                 return -1;
550                         }
551                         return 0;       /* EOF */
552                 }
553
554                 type = pletohs(record_type);
555                 if ((type != REC_HEADER1) && (type != REC_HEADER2)
556                         && (type != REC_HEADER3) && (type != REC_HEADER4)
557                         && (type != REC_HEADER5) && (type != REC_HEADER6)
558                         && (type != REC_HEADER7)
559                         && ((type != REC_V2DESC) || (version > 2)) ) {
560                         /*
561                          * Well, this is either some unknown header type
562                          * (we ignore this case), an uncompressed data
563                          * frame or the length of a compressed blob
564                          * which implies data. Seek backwards over the
565                          * two bytes we read, and return.
566                          */
567                         if (file_seek(wth->fh, -2, SEEK_CUR) == -1) {
568                                 *err = file_error(wth->fh);
569                                 return -1;
570                         }
571                         return 0;
572                 }
573
574                 errno = WTAP_ERR_CANT_READ;
575                 bytes_read = file_read(record_length, 1, 4, wth->fh);
576                 if (bytes_read != 4) {
577                         *err = file_error(wth->fh);
578                         if (*err == 0)
579                                 *err = WTAP_ERR_SHORT_READ;
580                         return -1;
581                 }
582                 wth->data_offset += 6;
583
584                 length = pletohs(record_length);
585
586                 /*
587                  * Is this a REC_HEADER2 record, and do we not yet know
588                  * the encapsulation type (i.e., is this is an
589                  * "Internetwork analyzer" capture?
590                  *
591                  * If so, the 5th byte of the record appears to specify
592                  * the particular type of network we're on.
593                  */
594                 if (type == REC_HEADER2 &&
595                     wth->file_encap == WTAP_ENCAP_UNKNOWN) {
596                         /*
597                          * Yes, get the first 32 bytes of the record
598                          * data.
599                          */
600                         bytes_to_read = MIN(length, sizeof buffer);
601                         bytes_read = file_read(buffer, 1, bytes_to_read,
602                                 wth->fh);
603                         if (bytes_read != bytes_to_read) {
604                                 *err = file_error(wth->fh);
605                                 if (*err == 0) {
606                                         *err = WTAP_ERR_SHORT_READ;
607                                         return -1;
608                                 }
609                         }
610                         /*
611                          * Skip the rest of the record.
612                          */
613                         if (length > sizeof buffer) {
614                                 if (file_seek(wth->fh, length - sizeof buffer,
615                                     SEEK_CUR) == -1) {
616                                         *err = file_error(wth->fh);
617                                         return -1;
618                                 }
619                         }
620
621                         /*
622                          * XXX - what about LAPB and LAPD?  At least one
623                          * X.25 capture has a type of NET_HDLC, but one 
624                          * might also consider LAPD to be an HDLC
625                          * variant; if it also has a type of NET_HDLC,
626                          * we'd have to look at some other data to
627                          * distinguish them.
628                          *
629                          * I have no LAPD captures, so I can't check
630                          * various fields of this record (and I'd
631                          * need multiple captures of both LAPB/X.25
632                          * and LAPD/ISDN to be reasonable certain
633                          * where the magic key is).
634                          *
635                          * So, for now, we don't set the encapsulation
636                          * for NET_HDLC.
637                          */
638                         switch (buffer[4]) {
639
640                         case NET_FRAME_RELAY:
641                                 wth->file_encap = WTAP_ENCAP_FRELAY;
642                                 break;
643
644                         case NET_PPP:
645                                 wth->file_encap = WTAP_ENCAP_PPP;
646                                 break;
647                         }
648
649                 } else {
650                         /* Nope, just skip over the data. */
651                         if (file_seek(wth->fh, length, SEEK_CUR) == -1) {
652                                 *err = file_error(wth->fh);
653                                 return -1;
654                         }
655                 }
656                 wth->data_offset += length;
657         }
658 }
659
660 /* Read the next packet */
661 static gboolean ngsniffer_read(wtap *wth, int *err, long *data_offset)
662 {
663         int     ret;
664         guint16 type, length;
665         struct frame2_rec frame2;
666         struct frame4_rec frame4;
667         struct frame6_rec frame6;
668         double  t;
669         guint16 time_low, time_med, time_high, true_size, size;
670         u_char  *pd;
671
672         for (;;) {
673                 /*
674                  * Read the record header.
675                  */
676                 *data_offset = wth->data_offset;
677                 ret = ngsniffer_read_rec_header(wth, FALSE, &type, &length,
678                     err);
679                 if (ret <= 0) {
680                         /* Read error or EOF */
681                         return FALSE;
682                 }
683                 wth->data_offset += 6;
684
685                 switch (type) {
686
687                 case REC_FRAME2:
688                         if (wth->capture.ngsniffer->is_atm) {
689                                 /*
690                                  * We shouldn't get a frame2 record in
691                                  * an ATM capture.
692                                  */
693                                 g_message("ngsniffer: REC_FRAME2 record in an ATM Sniffer file");
694                                 *err = WTAP_ERR_BAD_RECORD;
695                                 return FALSE;
696                         }
697
698                         /* Read the f_frame2_struct */
699                         ret = ngsniffer_read_frame2(wth, FALSE, &frame2, err);
700                         if (ret < 0) {
701                                 /* Read error */
702                                 return FALSE;
703                         }
704                         wth->data_offset += sizeof frame2;
705                         time_low = pletohs(&frame2.time_low);
706                         time_med = pletohs(&frame2.time_med);
707                         time_high = pletohs(&frame2.time_high);
708                         size = pletohs(&frame2.size);
709                         true_size = pletohs(&frame2.true_size);
710
711                         length -= sizeof frame2;        /* we already read that much */
712
713                         t = (double)time_low+(double)(time_med)*65536.0 +
714                             (double)time_high*4294967296.0;
715
716                         set_pseudo_header_frame2(&wth->pseudo_header, &frame2);
717                         goto found;
718
719                 case REC_FRAME4:
720                         if (!wth->capture.ngsniffer->is_atm) {
721                                 /*
722                                  * We shouldn't get a frame2 record in
723                                  * a non-ATM capture.
724                                  */
725                                 g_message("ngsniffer: REC_FRAME4 record in a non-ATM Sniffer file");
726                                 *err = WTAP_ERR_BAD_RECORD;
727                                 return FALSE;
728                         }
729
730                         /* Read the f_frame4_struct */
731                         ret = ngsniffer_read_frame4(wth, FALSE, &frame4, err);
732                         wth->data_offset += sizeof frame4;
733                         time_low = pletohs(&frame4.time_low);
734                         time_med = pletohs(&frame4.time_med);
735                         time_high = frame4.time_high;
736                         size = pletohs(&frame4.size);
737                         true_size = pletohs(&frame4.true_size);
738
739                         length -= sizeof frame4;        /* we already read that much */
740
741                         /*
742                          * XXX - use the "time_day" field?  Is that for captures
743                          * that take a *really* long time?
744                          */
745                         t = (double)time_low+(double)(time_med)*65536.0 +
746                             (double)time_high*4294967296.0;
747
748                         set_pseudo_header_frame4(&wth->pseudo_header, &frame4);
749                         goto found;
750
751                 case REC_FRAME6:
752                         /* XXX - Is this test valid? */
753                         if (wth->capture.ngsniffer->is_atm) {
754                                 g_message("ngsniffer: REC_FRAME6 record in an ATM Sniffer file");
755                                 *err = WTAP_ERR_BAD_RECORD;
756                                 return FALSE;
757                         }
758
759                         /* Read the f_frame6_struct */
760                         ret = ngsniffer_read_frame6(wth, FALSE, &frame6, err);
761                         wth->data_offset += sizeof frame6;
762                         time_low = pletohs(&frame6.time_low);
763                         time_med = pletohs(&frame6.time_med);
764                         time_high = frame6.time_high;
765                         size = pletohs(&frame6.size);
766                         true_size = pletohs(&frame6.true_size);
767
768                         length -= sizeof frame6;        /* we already read that much */
769
770                         /*
771                          * XXX - use the "time_day" field?  Is that for captures
772                          * that take a *really* long time?
773                          */
774                         t = (double)time_low+(double)(time_med)*65536.0 +
775                             (double)time_high*4294967296.0;
776
777                         set_pseudo_header_frame6(&wth->pseudo_header, &frame6);
778                         goto found;
779
780                 case REC_EOF:
781                         /*
782                          * End of file.  Return an EOF indication.
783                          */
784                         *err = 0;       /* EOF, not error */
785                         return FALSE;
786
787                 default:
788                         break;  /* unknown type, skip it */
789                 }
790
791                 /*
792                  * Well, we don't know what it is, or we know what
793                  * it is but can't handle it.  Skip past the data
794                  * portion, and keep looping.
795                  */
796                 if (ng_file_seek_seq(wth, length, SEEK_CUR, err) == -1)
797                         return FALSE;
798                 wth->data_offset += length;
799         }
800
801 found:
802         /*
803          * OK, is the frame data size greater than than what's left of the
804          * record?
805          */
806         if (size > length) {
807                 /*
808                  * Yes - treat this as an error.
809                  */
810                 g_message("ngsniffer: Record length is less than packet size");
811                 *err = WTAP_ERR_BAD_RECORD;
812                 return FALSE;
813         }
814
815         wth->phdr.len = true_size ? true_size : size;
816         wth->phdr.caplen = size;
817
818         /*
819          * Read the packet data.
820          */
821         buffer_assure_space(wth->frame_buffer, length);
822         pd = buffer_start_ptr(wth->frame_buffer);
823         if (ngsniffer_read_rec_data(wth, FALSE, pd, length, err) < 0)
824                 return FALSE;   /* Read error */
825         wth->data_offset += length;
826
827         if (wth->file_encap == WTAP_ENCAP_UNKNOWN) {
828                 /*
829                  * OK, this is from an "Internetwork analyzer", and
830                  * we either didn't see a type 7 record or it had
831                  * a network type such as NET_HDLC that doesn't
832                  * tell us which *particular* HDLC derivative this
833                  * is; let's look at the first byte of the packet,
834                  * and figure out whether it's LAPB, LAPD, PPP, or
835                  * Frame Relay.
836                  */
837                 if (pd[0] == 0xFF) {
838                         /*
839                          * PPP.
840                          */
841                         wth->file_encap = WTAP_ENCAP_PPP;
842                 } else if (pd[0] == 0x34 || pd[0] == 0x28) {
843                         /*
844                          * Frame Relay.
845                          */
846                         wth->file_encap = WTAP_ENCAP_FRELAY;
847                 } else if (pd[0] & 1) {
848                         /*
849                          * LAPB.
850                          */
851                         wth->file_encap = WTAP_ENCAP_LAPB;
852                 } else {
853                         /*
854                          * LAPD.
855                          */
856                         wth->file_encap = WTAP_ENCAP_LAPD;
857                 }
858         }
859
860         /*
861          * Fix up the pseudo-header; we may have set "x25.flags",
862          * but, for some traffic, we should set "p2p.sent" instead.
863          */
864         fix_pseudo_header(wth, &wth->pseudo_header);
865
866         t = t/1000000.0 * wth->capture.ngsniffer->timeunit; /* t = # of secs */
867         t += wth->capture.ngsniffer->start;
868         wth->phdr.ts.tv_sec = (long)t;
869         wth->phdr.ts.tv_usec = (unsigned long)((t-(double)(wth->phdr.ts.tv_sec))
870                         *1.0e6);
871         wth->phdr.pkt_encap = wth->file_encap;
872         return TRUE;
873 }
874
875 static int ngsniffer_seek_read(wtap *wth, long seek_off,
876     union wtap_pseudo_header *pseudo_header, u_char *pd, int packet_size,
877     int *err)
878 {
879         int     ret;
880         guint16 type, length;
881         struct frame2_rec frame2;
882         struct frame4_rec frame4;
883         struct frame6_rec frame6;
884
885         if (ng_file_seek_rand(wth, seek_off, SEEK_SET, err) == -1)
886                 return -1;
887
888         ret = ngsniffer_read_rec_header(wth, TRUE, &type, &length, err);
889         if (ret <= 0) {
890                 /* Read error or EOF */
891                 if (ret == 0) {
892                         /* EOF means "short read" in random-access mode */
893                         *err = WTAP_ERR_SHORT_READ;
894                 }
895                 return -1;
896         }
897
898         switch (type) {
899
900         case REC_FRAME2:
901                 /* Read the f_frame2_struct */
902                 ret = ngsniffer_read_frame2(wth, TRUE, &frame2, err);
903                 if (ret < 0) {
904                         /* Read error */
905                         return ret;
906                 }
907
908                 length -= sizeof frame2;        /* we already read that much */
909
910                 set_pseudo_header_frame2(pseudo_header, &frame2);
911                 break;
912
913         case REC_FRAME4:
914                 /* Read the f_frame4_struct */
915                 ret = ngsniffer_read_frame4(wth, TRUE, &frame4, err);
916
917                 length -= sizeof frame4;        /* we already read that much */
918
919                 set_pseudo_header_frame4(pseudo_header, &frame4);
920                 break;
921
922         case REC_FRAME6:
923                 /* Read the f_frame6_struct */
924                 ret = ngsniffer_read_frame6(wth, TRUE, &frame6, err);
925
926                 length -= sizeof frame6;        /* we already read that much */
927
928                 set_pseudo_header_frame6(pseudo_header, &frame6);
929                 break;
930
931         default:
932                 /*
933                  * "Can't happen".
934                  */
935                 g_assert_not_reached();
936                 return -1;
937         }
938
939         /*
940          * Fix up the pseudo-header; we may have set "x25.flags",
941          * but, for some traffic, we should set "p2p.sent" instead.
942          */
943         fix_pseudo_header(wth, pseudo_header);
944
945         /*
946          * Got the pseudo-header (if any), now get the data.
947          */
948         return ngsniffer_read_rec_data(wth, TRUE, pd, packet_size, err);
949 }
950
951 static int ngsniffer_read_rec_header(wtap *wth, gboolean is_random,
952     guint16 *typep, guint16 *lengthp, int *err)
953 {
954         int     bytes_read;
955         char    record_type[2];
956         char    record_length[4]; /* only 1st 2 bytes are length */
957
958         /*
959          * Read the record header.
960          */
961         bytes_read = ng_file_read(record_type, 1, 2, wth, is_random, err);
962         if (bytes_read != 2) {
963                 if (*err != 0)
964                         return -1;
965                 if (bytes_read != 0) {
966                         *err = WTAP_ERR_SHORT_READ;
967                         return -1;
968                 }
969                 return 0;
970         }
971         bytes_read = ng_file_read(record_length, 1, 4, wth, is_random, err);
972         if (bytes_read != 4) {
973                 if (*err == 0)
974                         *err = WTAP_ERR_SHORT_READ;
975                 return -1;
976         }
977
978         *typep = pletohs(record_type);
979         *lengthp = pletohs(record_length);
980         return 1;       /* success */
981 }
982
983 static int ngsniffer_read_frame2(wtap *wth, gboolean is_random,
984     struct frame2_rec *frame2, int *err)
985 {
986         int bytes_read;
987
988         /* Read the f_frame2_struct */
989         bytes_read = ng_file_read(frame2, 1, sizeof *frame2, wth, is_random,
990             err);
991         if (bytes_read != sizeof *frame2) {
992                 if (*err == 0)
993                         *err = WTAP_ERR_SHORT_READ;
994                 return -1;
995         }
996         return 0;
997 }
998
999 static void set_pseudo_header_frame2(union wtap_pseudo_header *pseudo_header,
1000     struct frame2_rec *frame2)
1001 {
1002         /*
1003          * In one PPP "Internetwork analyzer" capture,
1004          * the only bit seen in "fs" is the 0x80 bit,
1005          * which probably indicates the packet's
1006          * direction; all other bits were zero.
1007          * All bits in "frame2.flags" were zero.
1008          *
1009          * In one X.25 "Interenetwork analyzer" capture,
1010          * the only bit seen in "fs" is the 0x80 bit,
1011          * which probably indicates the packet's
1012          * direction; all other bits were zero.
1013          * "frame2.flags" was always 0x18.
1014          *
1015          * In one Ethernet capture, "fs" was always 0,
1016          * and "flags" was either 0 or 0x18, with no
1017          * obvious correlation with anything.
1018          *
1019          * In one Token Ring capture, "fs" was either 0
1020          * or 0xcc, and "flags" was either 0 or 0x18,
1021          * with no obvious correlation with anything.
1022          */
1023         pseudo_header->x25.flags = (frame2->fs & 0x80) ? 0x00 : 0x80;
1024 }
1025
1026 static int ngsniffer_read_frame4(wtap *wth, gboolean is_random,
1027     struct frame4_rec *frame4, int *err)
1028 {
1029         int bytes_read;
1030
1031         /* Read the f_frame4_struct */
1032         bytes_read = ng_file_read(frame4, 1, sizeof *frame4, wth, is_random,
1033             err);
1034         if (bytes_read != sizeof *frame4) {
1035                 if (*err == 0)
1036                         *err = WTAP_ERR_SHORT_READ;
1037                 return -1;
1038         }
1039         return 0;
1040 }
1041
1042 static void set_pseudo_header_frame4(union wtap_pseudo_header *pseudo_header,
1043     struct frame4_rec *frame4)
1044 {
1045         pseudo_header->ngsniffer_atm.AppTrafType = frame4->atm_info.AppTrafType;
1046         pseudo_header->ngsniffer_atm.AppHLType = frame4->atm_info.AppHLType;
1047         pseudo_header->ngsniffer_atm.Vpi = pletohs(&frame4->atm_info.Vpi);
1048         pseudo_header->ngsniffer_atm.Vci = pletohs(&frame4->atm_info.Vci);
1049         pseudo_header->ngsniffer_atm.channel = pletohs(&frame4->atm_info.channel);
1050         pseudo_header->ngsniffer_atm.cells = pletohs(&frame4->atm_info.cells);
1051         pseudo_header->ngsniffer_atm.aal5t_u2u = pletohs(&frame4->atm_info.Trailer.aal5t_u2u);
1052         pseudo_header->ngsniffer_atm.aal5t_len = pletohs(&frame4->atm_info.Trailer.aal5t_len);
1053         pseudo_header->ngsniffer_atm.aal5t_chksum = pletohl(&frame4->atm_info.Trailer.aal5t_chksum);
1054 }
1055
1056 static int ngsniffer_read_frame6(wtap *wth, gboolean is_random,
1057     struct frame6_rec *frame6, int *err)
1058 {
1059         int bytes_read;
1060
1061         /* Read the f_frame6_struct */
1062         bytes_read = ng_file_read(frame6, 1, sizeof *frame6, wth, is_random,
1063             err);
1064         if (bytes_read != sizeof *frame6) {
1065                 if (*err == 0)
1066                         *err = WTAP_ERR_SHORT_READ;
1067                 return -1;
1068         }
1069         return 0;
1070 }
1071
1072 static void set_pseudo_header_frame6(
1073         union wtap_pseudo_header *pseudo_header _U_,
1074         struct frame6_rec *frame6 _U_)
1075 {
1076         /* XXX - Once the frame format is divined, something will most likely go here */
1077 }
1078
1079 static int ngsniffer_read_rec_data(wtap *wth, gboolean is_random, u_char *pd,
1080     int length, int *err)
1081 {
1082         int     bytes_read;
1083
1084         bytes_read = ng_file_read(pd, 1, length, wth, is_random, err);
1085
1086         if (bytes_read != length) {
1087                 if (*err == 0)
1088                         *err = WTAP_ERR_SHORT_READ;
1089                 return -1;
1090         }
1091         return 0;
1092 }
1093
1094 static void fix_pseudo_header(wtap *wth,
1095     union wtap_pseudo_header *pseudo_header)
1096 {
1097         switch (wth->file_encap) {
1098
1099         case WTAP_ENCAP_LAPD:
1100                 if (pseudo_header->x25.flags == 0x00)
1101                         pseudo_header->p2p.sent = TRUE;
1102                 else
1103                         pseudo_header->p2p.sent = FALSE;
1104                 break;
1105         }
1106 }
1107
1108 /* Throw away the buffers used by the sequential I/O stream, but not
1109    those used by the random I/O stream. */
1110 static void ngsniffer_sequential_close(wtap *wth)
1111 {
1112         if (wth->capture.ngsniffer->seq.buf != NULL) {
1113                 g_free(wth->capture.ngsniffer->seq.buf);
1114                 wth->capture.ngsniffer->seq.buf = NULL;
1115         }
1116 }
1117
1118 static void free_blob(gpointer data, gpointer user_data _U_)
1119 {
1120         g_free(data);
1121 }
1122
1123 static void ngsniffer_close(wtap *wth)
1124 {
1125         if (wth->capture.ngsniffer->seq.buf != NULL)
1126                 g_free(wth->capture.ngsniffer->seq.buf);
1127         if (wth->capture.ngsniffer->rand.buf != NULL)
1128                 g_free(wth->capture.ngsniffer->rand.buf);
1129         if (wth->capture.ngsniffer->first_blob != NULL) {
1130                 g_list_foreach(wth->capture.ngsniffer->first_blob, free_blob, NULL);
1131                 g_list_free(wth->capture.ngsniffer->first_blob);
1132         }
1133         g_free(wth->capture.ngsniffer);
1134 }
1135
1136 static const int wtap_encap[] = {
1137     -1,         /* WTAP_ENCAP_UNKNOWN -> unsupported */
1138     1,          /* WTAP_ENCAP_ETHERNET */
1139     0,          /* WTAP_ENCAP_TOKEN_RING */
1140     -1,         /* WTAP_ENCAP_SLIP -> unsupported */
1141     7,          /* WTAP_ENCAP_PPP -> Internetwork analyzer (synchronous) FIXME ! */
1142     9,          /* WTAP_ENCAP_FDDI */
1143     9,          /* WTAP_ENCAP_FDDI_BITSWAPPED */
1144     -1,         /* WTAP_ENCAP_RAW_IP -> unsupported */
1145     2,          /* WTAP_ENCAP_ARCNET */
1146     -1,         /* WTAP_ENCAP_ATM_RFC1483 */
1147     -1,         /* WTAP_ENCAP_LINUX_ATM_CLIP */
1148     7,          /* WTAP_ENCAP_LAPB -> Internetwork analyzer (synchronous) */
1149     -1,         /* WTAP_ENCAP_ATM_SNIFFER */
1150     -1          /* WTAP_ENCAP_NULL -> unsupported */
1151 };
1152 #define NUM_WTAP_ENCAPS (sizeof wtap_encap / sizeof wtap_encap[0])
1153
1154 /* Returns 0 if we could write the specified encapsulation type,
1155    an error indication otherwise. */
1156 int ngsniffer_dump_can_write_encap(int encap)
1157 {
1158     /* Per-packet encapsulations aren't supported. */
1159     if (encap == WTAP_ENCAP_PER_PACKET)
1160         return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
1161
1162     if (encap < 0 || (unsigned)encap >= NUM_WTAP_ENCAPS || wtap_encap[encap] == -1)
1163         return WTAP_ERR_UNSUPPORTED_ENCAP;
1164
1165     return 0;
1166 }
1167
1168 /* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
1169    failure */
1170 gboolean ngsniffer_dump_open(wtap_dumper *wdh, int *err)
1171 {
1172     size_t nwritten;
1173     char buf[6] = {REC_VERS, 0x00, 0x12, 0x00, 0x00, 0x00}; /* version record */
1174
1175     /* This is a sniffer file */
1176     wdh->subtype_write = ngsniffer_dump;
1177     wdh->subtype_close = ngsniffer_dump_close;
1178
1179     wdh->dump.ngsniffer = g_malloc(sizeof(ngsniffer_dump_t));
1180     wdh->dump.ngsniffer->first_frame = TRUE;
1181     wdh->dump.ngsniffer->start = 0;
1182
1183     /* Write the file header. */
1184     nwritten = fwrite(ngsniffer_magic, 1, sizeof ngsniffer_magic, wdh->fh);
1185     if (nwritten != sizeof ngsniffer_magic) {
1186         if (nwritten == 0 && ferror(wdh->fh))
1187             *err = errno;
1188         else
1189             *err = WTAP_ERR_SHORT_WRITE;
1190         return FALSE;
1191     }
1192     nwritten = fwrite(buf, 1, 6, wdh->fh);
1193     if (nwritten != 6) {
1194         if (nwritten == 0 && ferror(wdh->fh))
1195             *err = errno;
1196         else
1197             *err = WTAP_ERR_SHORT_WRITE;
1198         return FALSE;
1199     }
1200
1201     return TRUE;
1202 }
1203
1204 /* Write a record for a packet to a dump file.
1205    Returns TRUE on success, FALSE on failure. */
1206 static gboolean ngsniffer_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
1207     const union wtap_pseudo_header *pseudo_header, const u_char *pd, int *err)
1208 {
1209     ngsniffer_dump_t *priv = wdh->dump.ngsniffer;
1210     struct frame2_rec rec_hdr;
1211     size_t nwritten;
1212     char buf[6];
1213     double t;
1214     guint16 t_low, t_med, t_high;
1215     struct vers_rec version;
1216     gint16 maj_vers, min_vers;
1217     guint16 start_date;
1218     struct tm *tm;
1219
1220     /* Sniffer files have a capture start date in the file header, and
1221        have times relative to the beginning of that day in the packet
1222        headers; pick the date of the first packet as the capture start
1223        date. */
1224     if (priv->first_frame) {
1225         priv->first_frame=FALSE;
1226         tm = localtime(&phdr->ts.tv_sec);
1227         if (tm != NULL) {
1228           start_date = (tm->tm_year - (1980 - 1900)) << 9;
1229           start_date |= (tm->tm_mon + 1) << 5;
1230           start_date |= tm->tm_mday;
1231           /* record the start date, not the start time */
1232           priv->start = phdr->ts.tv_sec - (3600*tm->tm_hour + 60*tm->tm_min + tm->tm_sec);
1233         } else {
1234           start_date = 0;
1235           priv->start = 0;
1236         }
1237
1238         /* "sniffer" version ? */
1239         maj_vers = 4;
1240         min_vers = 0;
1241         version.maj_vers = htoles(maj_vers);
1242         version.min_vers = htoles(min_vers);
1243         version.time = 0;
1244         version.date = htoles(start_date);
1245         version.type = 4;
1246         version.network = wtap_encap[wdh->encap];
1247         version.format = 1;
1248         version.timeunit = 1; /* 0.838096 */
1249         version.cmprs_vers = 0;
1250         version.cmprs_level = 0;
1251         version.rsvd[0] = 0;
1252         version.rsvd[1] = 0;
1253         nwritten = fwrite(&version, 1, sizeof version, wdh->fh);
1254         if (nwritten != sizeof version) {
1255             if (nwritten == 0 && ferror(wdh->fh))
1256                 *err = errno;
1257             else
1258                 *err = WTAP_ERR_SHORT_WRITE;
1259             return FALSE;
1260         }
1261     }
1262
1263     buf[0] = REC_FRAME2;
1264     buf[1] = 0x00;
1265     buf[2] = (char)((phdr->caplen + sizeof(struct frame2_rec))%256);
1266     buf[3] = (char)((phdr->caplen + sizeof(struct frame2_rec))/256);
1267     buf[4] = 0x00;
1268     buf[5] = 0x00;
1269     nwritten = fwrite(buf, 1, 6, wdh->fh);
1270     if (nwritten != 6) {
1271         if (nwritten == 0 && ferror(wdh->fh))
1272             *err = errno;
1273         else
1274             *err = WTAP_ERR_SHORT_WRITE;
1275         return FALSE;
1276     }
1277     t = (double)phdr->ts.tv_sec + (double)phdr->ts.tv_usec/1.0e6; /* # of secs */
1278     t = (t - priv->start)*1.0e6 / Usec[1]; /* timeunit = 1 */
1279     t_low = (guint16)(t-(double)((guint32)(t/65536.0))*65536.0);
1280     t_med = (guint16)((guint32)(t/65536.0) % 65536);
1281     t_high = (guint16)(t/4294967296.0);
1282     rec_hdr.time_low = htoles(t_low);
1283     rec_hdr.time_med = htoles(t_med);
1284     rec_hdr.time_high = htoles(t_high);
1285     rec_hdr.size = htoles(phdr->caplen);
1286     if (wdh->encap == WTAP_ENCAP_LAPB || wdh->encap == WTAP_ENCAP_PPP)
1287         rec_hdr.fs = (pseudo_header->x25.flags & 0x80) ? 0x00 : 0x80;
1288     else
1289         rec_hdr.fs = 0;
1290     rec_hdr.flags = 0;
1291     rec_hdr.true_size = phdr->len != phdr->caplen ? htoles(phdr->len) : 0;
1292     rec_hdr.rsvd = 0;
1293     nwritten = fwrite(&rec_hdr, 1, sizeof rec_hdr, wdh->fh);
1294     if (nwritten != sizeof rec_hdr) {
1295         if (nwritten == 0 && ferror(wdh->fh))
1296             *err = errno;
1297         else
1298             *err = WTAP_ERR_SHORT_WRITE;
1299         return FALSE;
1300     }
1301     nwritten = fwrite(pd, 1, phdr->caplen, wdh->fh);
1302     if (nwritten != phdr->caplen) {
1303         if (nwritten == 0 && ferror(wdh->fh))
1304             *err = errno;
1305         else
1306             *err = WTAP_ERR_SHORT_WRITE;
1307         return FALSE;
1308     }
1309     return TRUE;
1310 }
1311
1312 /* Finish writing to a dump file.
1313    Returns TRUE on success, FALSE on failure. */
1314 static gboolean ngsniffer_dump_close(wtap_dumper *wdh, int *err)
1315 {
1316     /* EOF record */
1317     char buf[6] = {REC_EOF, 0x00, 0x00, 0x00, 0x00, 0x00};
1318     size_t nwritten;
1319
1320     nwritten = fwrite(buf, 1, 6, wdh->fh);
1321     if (nwritten != 6) {
1322         if (nwritten == 0 && ferror(wdh->fh))
1323             *err = errno;
1324         else
1325             *err = WTAP_ERR_SHORT_WRITE;
1326         return FALSE;
1327     }
1328     return TRUE;
1329 }
1330
1331 /*
1332    SnifferDecompress() decompresses a blob of compressed data from a
1333          Sniffer(R) capture file.
1334
1335    This function is Copyright (c) 1999-2999 Tim Farley
1336
1337    Parameters
1338       inbuf - buffer of compressed bytes from file, not including
1339          the preceding length word
1340       inlen - length of inbuf in bytes
1341       outbuf - decompressed contents, could contain a partial Sniffer
1342          record at the end.
1343       outlen - length of outbuf.
1344
1345    Return value is the number of bytes in outbuf on return.
1346 */
1347 static int
1348 SnifferDecompress( unsigned char * inbuf, size_t inlen, 
1349                        unsigned char * outbuf, size_t outlen, int *err )
1350 {
1351    unsigned char * pin = inbuf;
1352    unsigned char * pout = outbuf;
1353    unsigned char * pin_end = pin + inlen;
1354    unsigned char * pout_end = pout + outlen;
1355    unsigned int bit_mask;  /* one bit is set in this, to mask with bit_value */
1356    unsigned int bit_value = 0; /* cache the last 16 coding bits we retrieved */
1357    unsigned int code_type; /* encoding type, from high 4 bits of byte */
1358    unsigned int code_low;  /* other 4 bits from encoding byte */
1359    int length;             /* length of RLE sequence or repeated string */
1360    int offset;             /* offset of string to repeat */
1361
1362    bit_mask  = 0;  /* don't have any bits yet */
1363    while (1)
1364    {
1365       /* Shift down the bit mask we use to see whats encoded */
1366       bit_mask = bit_mask >> 1;
1367
1368       /* If there are no bits left, time to get another 16 bits */
1369       if ( 0 == bit_mask )
1370       {
1371          bit_mask  = 0x8000;  /* start with the high bit */
1372          bit_value = pletohs(pin);   /* get the next 16 bits */
1373          pin += 2;          /* skip over what we just grabbed */
1374          if ( pin >= pin_end )
1375          {
1376             *err = WTAP_ERR_UNC_TRUNCATED;       /* data was oddly truncated */
1377             return ( -1 );
1378          }
1379       }
1380
1381       /* Use the bits in bit_value to see what's encoded and what is raw data */
1382       if ( !(bit_mask & bit_value) )
1383       {
1384          /* bit not set - raw byte we just copy */
1385          *(pout++) = *(pin++);
1386       }
1387       else
1388       {
1389          /* bit set - next item is encoded.  Peel off high nybble
1390             of next byte to see the encoding type.  Set aside low
1391             nybble while we are at it */
1392          code_type = (unsigned int) ((*pin) >> 4 ) & 0xF;
1393          code_low  = (unsigned int) ((*pin) & 0xF );
1394          pin++;   /* increment over the code byte we just retrieved */
1395          if ( pin >= pin_end )
1396          {
1397             *err = WTAP_ERR_UNC_TRUNCATED;       /* data was oddly truncated */
1398             return ( -1 );
1399          }
1400
1401          /* Based on the code type, decode the compressed string */
1402          switch ( code_type )
1403          {
1404             case 0  :   /* RLE short runs */
1405                 /*
1406                     Run length is the low nybble of the first code byte.
1407                     Byte to repeat immediately follows.
1408                     Total code size: 2 bytes.
1409                 */    
1410                 length = code_low + 3;
1411                 /* If length would put us past end of output, avoid overflow */
1412                 if ( pout + length > pout_end )
1413                 {
1414                     *err = WTAP_ERR_UNC_OVERFLOW;
1415                     return ( -1 );
1416                 }
1417
1418                 /* generate the repeated series of bytes */
1419                 memset( pout, *pin++, length );
1420                 pout += length;
1421                 break;
1422             case 1  :   /* RLE long runs */
1423                 /*
1424                     Low 4 bits of run length is the low nybble of the 
1425                     first code byte, upper 8 bits of run length is in 
1426                     the next byte.
1427                     Byte to repeat immediately follows.
1428                     Total code size: 3 bytes.
1429                 */    
1430                 length = code_low + ((unsigned int)(*pin++) << 4) + 19;
1431                 /* If we are already at end of input, there is no byte
1432                    to repeat */
1433                 if ( pin >= pin_end )
1434                 {
1435                     *err = WTAP_ERR_UNC_TRUNCATED;       /* data was oddly truncated */
1436                     return ( -1 );
1437                 }
1438                 /* If length would put us past end of output, avoid overflow */
1439                 if ( pout + length > pout_end )
1440                 {
1441                     *err = WTAP_ERR_UNC_OVERFLOW;
1442                     return ( -1 );
1443                 }
1444
1445                 /* generate the repeated series of bytes */
1446                 memset( pout, *pin++, length );
1447                 pout += length;
1448                 break;
1449             case 2  :   /* LZ77 long strings */
1450                 /*
1451                     Low 4 bits of offset to string is the low nybble of the 
1452                     first code byte, upper 8 bits of offset is in 
1453                     the next byte.
1454                     Length of string immediately follows.
1455                     Total code size: 3 bytes.
1456                 */    
1457                 offset = code_low + ((unsigned int)(*pin++) << 4) + 3;
1458                 /* If we are already at end of input, there is no byte
1459                    to repeat */
1460                 if ( pin >= pin_end )
1461                 {
1462                     *err = WTAP_ERR_UNC_TRUNCATED;       /* data was oddly truncated */
1463                     return ( -1 );
1464                 }
1465                 /* Check if offset would put us back past begin of buffer */
1466                 if ( pout - offset < outbuf )
1467                 {
1468                     *err = WTAP_ERR_UNC_BAD_OFFSET;
1469                     return ( -1 );
1470                 }
1471
1472                 /* get length from next byte, make sure it won't overrun buf */
1473                 length = (unsigned int)(*pin++) + 16;
1474                 if ( pout + length > pout_end )
1475                 {
1476                     *err = WTAP_ERR_UNC_OVERFLOW;
1477                     return ( -1 );
1478                 }
1479
1480                 /* Copy the string from previous text to output position,
1481                    advance output pointer */
1482                 memcpy( pout, pout - offset, length );
1483                 pout += length;
1484                 break;
1485             default :   /* (3 to 15): LZ77 short strings */
1486                 /*
1487                     Low 4 bits of offset to string is the low nybble of the 
1488                     first code byte, upper 8 bits of offset is in 
1489                     the next byte.
1490                     Length of string to repeat is overloaded into code_type.
1491                     Total code size: 2 bytes.
1492                 */    
1493                 offset = code_low + ((unsigned int)(*pin++) << 4) + 3;
1494                 /* Check if offset would put us back past begin of buffer */
1495                 if ( pout - offset < outbuf )
1496                 {
1497                     *err = WTAP_ERR_UNC_BAD_OFFSET;
1498                     return ( -1 );
1499                 }
1500
1501                 /* get length from code_type, make sure it won't overrun buf */
1502                 length = code_type;
1503                 if ( pout + length > pout_end )
1504                 {
1505                     *err = WTAP_ERR_UNC_OVERFLOW;
1506                     return ( -1 );
1507                 }
1508
1509                 /* Copy the string from previous text to output position,
1510                    advance output pointer */
1511                 memcpy( pout, pout - offset, length );
1512                 pout += length;
1513                 break;
1514          }
1515       }
1516
1517       /* If we've consumed all the input, we are done */
1518       if ( pin >= pin_end )
1519          break;
1520    }
1521
1522    return ( pout - outbuf );  /* return length of expanded text */
1523 }
1524
1525 /*
1526  * XXX - is there any guarantee that this is big enough to hold the
1527  * uncompressed data from any blob?
1528  */
1529 #define OUTBUF_SIZE     65536
1530
1531 /* Information about a compressed blob; we save the offset in the
1532    underlying compressed file, and the offset in the uncompressed data
1533    stream, of the blob. */
1534 typedef struct {
1535         long    blob_comp_offset;
1536         long    blob_uncomp_offset;
1537 } blob_info_t;
1538
1539 static int
1540 ng_file_read(void *buffer, size_t elementsize, size_t numelements, wtap *wth,
1541     gboolean is_random, int *err)
1542 {
1543     FILE_T infile;
1544     ngsniffer_comp_stream_t *comp_stream;
1545     int copybytes = elementsize * numelements; /* bytes left to be copied */
1546     int copied_bytes = 0; /* bytes already copied */
1547     unsigned char *outbuffer = buffer; /* where to write next decompressed data */
1548     blob_info_t *blob;
1549     int bytes_to_copy;
1550     int bytes_left;
1551
1552     if (is_random) {
1553         infile = wth->random_fh;
1554         comp_stream = &wth->capture.ngsniffer->rand;
1555     } else {
1556         infile = wth->fh;
1557         comp_stream = &wth->capture.ngsniffer->seq;
1558     }
1559
1560     if (wth->file_type == WTAP_FILE_NGSNIFFER_UNCOMPRESSED) {
1561         errno = WTAP_ERR_CANT_READ;
1562         copied_bytes = file_read(buffer, 1, copybytes, infile);
1563         if (copied_bytes != copybytes)
1564             *err = file_error(infile);
1565         return copied_bytes;
1566     }
1567
1568     /* Allocate the stream buffer if it hasn't already been allocated. */
1569     if (comp_stream->buf == NULL) {
1570         comp_stream->buf = g_malloc(OUTBUF_SIZE);
1571
1572         if (is_random) {
1573             /* This is the first read of the random file, so we're at
1574                the beginning of the sequence of blobs in the file
1575                (as we've not done any random reads yet to move the
1576                current position in the random stream); set the
1577                current blob to be the first blob. */
1578             wth->capture.ngsniffer->current_blob =
1579                 wth->capture.ngsniffer->first_blob;
1580         } else {
1581             /* This is the first sequential read; if we also have a
1582                random stream open, allocate the first element for the
1583                list of blobs, and make it the last element as well. */
1584             if (wth->random_fh != NULL) {
1585                 g_assert(wth->capture.ngsniffer->first_blob == NULL);
1586                 blob = g_malloc(sizeof (blob_info_t));
1587                 blob->blob_comp_offset = comp_stream->comp_offset;
1588                 blob->blob_uncomp_offset = comp_stream->uncomp_offset;
1589                 wth->capture.ngsniffer->first_blob =
1590                         g_list_append(wth->capture.ngsniffer->first_blob, blob);
1591                 wth->capture.ngsniffer->last_blob =
1592                         wth->capture.ngsniffer->first_blob;
1593             }
1594         }
1595
1596         /* Now read the first blob into the buffer. */
1597         if (read_blob(infile, comp_stream, err) < 0)
1598             return -1;
1599     }
1600     while (copybytes > 0) {
1601         bytes_left = comp_stream->nbytes - comp_stream->nextout;
1602         if (bytes_left == 0) {
1603             /* There's no decompressed stuff left to copy from the current
1604                blob; get the next blob. */
1605
1606             if (is_random) {
1607                 /* Move to the next blob in the list. */
1608                 wth->capture.ngsniffer->current_blob =
1609                         g_list_next(wth->capture.ngsniffer->current_blob);
1610                 blob = wth->capture.ngsniffer->current_blob->data;
1611             } else {
1612                 /* If we also have a random stream open, add a new element,
1613                    for this blob, to the list of blobs; we know the list is
1614                    non-empty, as we initialized it on the first sequential
1615                    read, so we just add the new element at the end, and
1616                    adjust the pointer to the last element to refer to it. */
1617                 if (wth->random_fh != NULL) {
1618                     blob = g_malloc(sizeof (blob_info_t));
1619                     blob->blob_comp_offset = comp_stream->comp_offset;
1620                     blob->blob_uncomp_offset = comp_stream->uncomp_offset;
1621                     wth->capture.ngsniffer->last_blob =
1622                         g_list_append(wth->capture.ngsniffer->last_blob, blob);
1623                 }
1624             }
1625
1626             if (read_blob(infile, comp_stream, err) < 0)
1627                 return -1;
1628             bytes_left = comp_stream->nbytes - comp_stream->nextout;
1629         }
1630             
1631         bytes_to_copy = copybytes;
1632         if (bytes_to_copy > bytes_left)
1633             bytes_to_copy = bytes_left;
1634         memcpy(outbuffer, &comp_stream->buf[comp_stream->nextout],
1635                 bytes_to_copy);
1636         copybytes -= bytes_to_copy;
1637         copied_bytes += bytes_to_copy;
1638         outbuffer += bytes_to_copy;
1639         comp_stream->nextout += bytes_to_copy;
1640         comp_stream->uncomp_offset += bytes_to_copy;
1641     }
1642     return copied_bytes;
1643 }
1644
1645 /* Read a blob from a compressed stream.
1646    Return -1 and set "*err" on error, otherwise return 0. */
1647 static int
1648 read_blob(FILE_T infile, ngsniffer_comp_stream_t *comp_stream, int *err)
1649 {
1650     size_t in_len;
1651     size_t read_len;
1652     unsigned short blob_len;
1653     gint16 blob_len_host;
1654     gboolean uncompressed;
1655     unsigned char file_inbuf[65536];
1656     int out_len;
1657
1658     /* Read one 16-bit word which is length of next compressed blob */
1659     errno = WTAP_ERR_CANT_READ;
1660     read_len = file_read(&blob_len, 1, 2, infile);
1661     if (2 != read_len) {
1662         *err = file_error(infile);
1663         return -1;
1664     }
1665     comp_stream->comp_offset += 2;
1666     blob_len_host = pletohs(&blob_len);
1667
1668     /* Compressed or uncompressed? */
1669     if (blob_len_host < 0) {
1670         /* Uncompressed blob; blob length is absolute value of the number. */
1671         in_len = -blob_len_host;
1672         uncompressed = TRUE;
1673     } else {
1674         in_len = blob_len_host;
1675         uncompressed = FALSE;
1676     }
1677
1678     /* Read the blob */
1679     errno = WTAP_ERR_CANT_READ;
1680     read_len = file_read(file_inbuf, 1, in_len, infile);
1681     if (in_len != read_len) {
1682         *err = file_error(infile);
1683         return -1;
1684     }
1685     comp_stream->comp_offset += in_len;
1686
1687     if (uncompressed) {
1688         memcpy(comp_stream->buf, file_inbuf, in_len);
1689         out_len = in_len;
1690     } else {
1691         /* Decompress the blob */
1692         out_len = SnifferDecompress(file_inbuf, in_len,
1693                                 comp_stream->buf, OUTBUF_SIZE, err);
1694         if (out_len < 0)
1695             return -1;
1696     }
1697     comp_stream->nextout = 0;
1698     comp_stream->nbytes = out_len;
1699     return 0;
1700 }
1701
1702 /* Seek in the sequential data stream; we can only seek forward, and we
1703    do it on compressed files by skipping forward. */
1704 static long
1705 ng_file_seek_seq(wtap *wth, long offset, int whence, int *err)
1706 {
1707     long ret;
1708     long delta;
1709     char buf[65536];
1710     long amount_to_read;
1711
1712     if (wth->file_type == WTAP_FILE_NGSNIFFER_UNCOMPRESSED) {
1713         ret = file_seek(wth->fh, offset, whence);
1714         if (ret == -1)
1715                 *err = file_error(wth->fh);
1716         return ret;
1717     }
1718
1719     switch (whence) {
1720
1721     case SEEK_SET:
1722         break;          /* "offset" is the target offset */
1723
1724     case SEEK_CUR:
1725         offset += wth->capture.ngsniffer->seq.uncomp_offset;
1726         break;          /* "offset" is relative to the current offset */
1727
1728     case SEEK_END:
1729         g_assert_not_reached(); /* "offset" is relative to the end of the file... */
1730         break;          /* ...but we don't know where that is. */
1731     }
1732
1733     delta = offset - wth->capture.ngsniffer->seq.uncomp_offset;
1734     g_assert(delta >= 0);
1735
1736     /* Ok, now read and discard "delta" bytes. */
1737     while (delta != 0) {
1738         amount_to_read = delta;
1739         if ((unsigned long)amount_to_read > sizeof buf)
1740             amount_to_read = sizeof buf;
1741         if (ng_file_read(buf, 1, amount_to_read, wth, FALSE, err) < 0)
1742             return -1;  /* error */
1743         delta -= amount_to_read;
1744     }
1745     return offset;
1746 }
1747
1748 /* Seek in the random data stream.
1749
1750    On compressed files, we see whether we're seeking to a position within
1751    the blob we currently have in memory and, if not, we find in the list
1752    of blobs the last blob that starts at or before the position to which
1753    we're seeking, and read that blob in.  We can then move to the appropriate
1754    position within the blob we have in memory (whether it's the blob we
1755    already had in memory or, if necessary, the one we read in). */
1756 static long
1757 ng_file_seek_rand(wtap *wth, long offset, int whence, int *err)
1758 {
1759     long ret;
1760     ngsniffer_t *ngsniffer;
1761     long delta;
1762     GList *new, *next;
1763     blob_info_t *next_blob, *new_blob;
1764
1765     if (wth->file_type == WTAP_FILE_NGSNIFFER_UNCOMPRESSED) {
1766         ret = file_seek(wth->random_fh, offset, whence);
1767         if (ret == -1)
1768                 *err = file_error(wth->random_fh);
1769         return ret;
1770     }
1771
1772     ngsniffer = wth->capture.ngsniffer;
1773
1774     switch (whence) {
1775
1776     case SEEK_SET:
1777         break;          /* "offset" is the target offset */
1778
1779     case SEEK_CUR:
1780         offset += ngsniffer->rand.uncomp_offset;
1781         break;          /* "offset" is relative to the current offset */
1782
1783     case SEEK_END:
1784         g_assert_not_reached(); /* "offset" is relative to the end of the file... */
1785         break;          /* ...but we don't know where that is. */
1786     }
1787
1788     delta = offset - ngsniffer->rand.uncomp_offset;
1789
1790     /* Is the place to which we're seeking within the current buffer, or
1791        will we have to read a different blob into the buffer? */
1792     new = NULL;
1793     if (delta > 0) {
1794         /* We're going forwards.
1795            Is the place to which we're seeking within the current buffer? */
1796         if ((unsigned)ngsniffer->rand.nextout + delta >= ngsniffer->rand.nbytes) {
1797             /* No.  Search for a blob that contains the target offset in
1798                the uncompressed byte stream, starting with the blob
1799                following the current blob. */
1800             new = g_list_next(ngsniffer->current_blob);
1801             for (;;) {
1802                 next = g_list_next(new);
1803                 if (next == NULL) {
1804                     /* No more blobs; the current one is it. */
1805                     break;
1806                 }
1807
1808                 next_blob = next->data;
1809                 /* Does the next blob start after the target offset?
1810                    If so, the current blob is the one we want. */
1811                 if (next_blob->blob_uncomp_offset > offset)
1812                     break;
1813
1814                 new = next;
1815             }
1816         }
1817     } else if (delta < 0) {
1818         /* We're going backwards.
1819            Is the place to which we're seeking within the current buffer? */
1820         if (ngsniffer->rand.nextout + delta < 0) {
1821             /* No.  Search for a blob that contains the target offset in
1822                the uncompressed byte stream, starting with the blob
1823                preceding the current blob. */
1824             new = g_list_previous(ngsniffer->current_blob);
1825             for (;;) {
1826                 /* Does this blob start at or before the target offset?
1827                    If so, the current blob is the one we want. */
1828                 new_blob = new->data;
1829                 if (new_blob->blob_uncomp_offset <= offset)
1830                     break;
1831
1832                 /* It doesn't - skip to the previous blob. */
1833                 new = g_list_previous(new);
1834             }
1835         }
1836     }
1837
1838     if (new != NULL) {
1839         /* The place to which we're seeking isn't in the current buffer;
1840            move to a new blob. */
1841         new_blob = new->data;
1842
1843         /* Seek in the compressed file to the offset in the compressed file
1844            of the beginning of that blob. */
1845         if (file_seek(wth->random_fh, new_blob->blob_comp_offset, SEEK_SET) == -1) {
1846             *err = file_error(wth->random_fh);
1847             return -1;
1848         }
1849
1850         /* Make the blob we found the current one. */
1851         ngsniffer->current_blob = new;
1852
1853         /* Now set the current offsets to the offsets of the beginning
1854            of the blob. */
1855         ngsniffer->rand.uncomp_offset = new_blob->blob_uncomp_offset;
1856         ngsniffer->rand.comp_offset = new_blob->blob_comp_offset;
1857
1858         /* Now fill the buffer. */
1859         if (read_blob(wth->random_fh, &ngsniffer->rand, err) < 0)
1860             return -1;
1861
1862         /* Set "delta" to the amount to move within this blob; it had
1863            better be >= 0, and < the amount of uncompressed data in
1864            the blob, as otherwise it'd mean we need to seek before
1865            the beginning or after the end of this blob. */
1866         delta = offset - ngsniffer->rand.uncomp_offset;
1867         g_assert(delta >= 0 && (unsigned long)delta < ngsniffer->rand.nbytes);
1868     }
1869
1870     /* OK, the place to which we're seeking is in the buffer; adjust
1871        "ngsniffer->rand.nextout" to point to the place to which
1872        we're seeking, and adjust "ngsniffer->rand.uncomp_offset" to be
1873        the destination offset. */
1874     ngsniffer->rand.nextout += delta;
1875     ngsniffer->rand.uncomp_offset += delta;
1876
1877     return offset;
1878 }