epan/dissectors/packet-xml.c try to decrypt data, but the data doesn't look correct yet
[metze/wireshark/wip.git] / wiretap / dbs-etherwatch.c
1 /* dbs-etherwatch.c
2  *
3  * Wiretap Library
4  * Copyright (c) 2001 by Marc Milgram <ethereal@mmilgram.NOSPAMmail.net>
5  *
6  * SPDX-License-Identifier: GPL-2.0-or-later
7  */
8
9 #include "config.h"
10 #include "wtap-int.h"
11 #include "dbs-etherwatch.h"
12 #include "file_wrappers.h"
13
14 #include <stdlib.h>
15 #include <string.h>
16
17 /* This module reads the text output of the 'DBS-ETHERTRACE' command in VMS
18  * It was initially based on vms.c.
19  */
20
21 /*
22    Example 'ETHERWATCH' output data (with "printable" characters in the
23    "printable characters" section of the output replaced by "." if they have
24    the 8th bit set, so as not to upset compilers that are expecting text
25    in comments to be in a particular character encoding that can't handle
26    those values):
27 ETHERWATCH  X5-008
28 42 names and addresses were loaded
29 Reading recorded data from PERSISTENCE
30 ------------------------------------------------------------------------------
31 From 00-D0-C0-D2-4D-60 [MF1] to AA-00-04-00-FC-94 [PSERVB]
32 Protocol 08-00 00 00-00-00-00-00,   60 byte buffer at 10-OCT-2001 10:20:45.16
33   [E..<8...........]-    0-[45 00 00 3C 38 93 00 00 1D 06 D2 12 80 93 11 1A]
34   [.........(......]-   16-[80 93 80 D6 02 D2 02 03 00 28 A4 90 00 00 00 00]
35   [................]-   32-[A0 02 FF FF 95 BD 00 00 02 04 05 B4 03 03 04 01]
36   [............    ]-   48-[01 01 08 0A 90 90 E5 14 00 00 00 00]
37 ------------------------------------------------------------------------------
38 From 00-D0-C0-D2-4D-60 [MF1] to AA-00-04-00-FC-94 [PSERVB]
39 Protocol 08-00 00 00-00-00-00-00,   50 byte buffer at 10-OCT-2001 10:20:45.17
40   [E..(8......%....]-    0-[45 00 00 28 38 94 00 00 1D 06 D2 25 80 93 11 1A]
41   [.........(..Z.4w]-   16-[80 93 80 D6 02 D2 02 03 00 28 A4 91 5A 1C 34 77]
42   [P.#(.s..........]-   32-[50 10 23 28 C1 73 00 00 02 04 05 B4 03 03 00 00]
43   [..              ]-   48-[02 04]
44
45
46 Alternative HEX only output, slightly more efficient and all wireshark needs:
47 ------------------------------------------------------------------------------
48 From 00-D0-C0-D2-4D-60 [MF1] to AA-00-04-00-FC-94 [PSERVB]
49 Protocol 08-00 00 00-00-00-00-00,   50 byte buffer at 10-OCT-2001 10:20:45.17
50      0-[45 00 00 28 38 9B 00 00 1D 06 D2 1E 80 93 11 1A 80 93 80 D6]
51     20-[02 D2 02 03 00 28 A4 BF 5A 1C 34 79 50 10 23 28 C1 43 00 00]
52     40-[03 30 30 30 30 30 00 00 03 30]
53  */
54
55 /* Magic text to check for DBS-ETHERWATCH-ness of file */
56 static const char dbs_etherwatch_hdr_magic[]  =
57 { 'E', 'T', 'H', 'E', 'R', 'W', 'A', 'T', 'C', 'H', ' '};
58 #define DBS_ETHERWATCH_HDR_MAGIC_SIZE  \
59         (sizeof dbs_etherwatch_hdr_magic  / sizeof dbs_etherwatch_hdr_magic[0])
60
61 /* Magic text for start of packet */
62 static const char dbs_etherwatch_rec_magic[]  =
63 {'F', 'r', 'o', 'm', ' '};
64 #define DBS_ETHERWATCH_REC_MAGIC_SIZE \
65     (sizeof dbs_etherwatch_rec_magic  / sizeof dbs_etherwatch_rec_magic[0])
66
67 /*
68  * Default packet size - maximum normal Ethernet packet size, without an
69  * FCS.
70  */
71 #define DBS_ETHERWATCH_MAX_ETHERNET_PACKET_LEN   1514
72
73 static gboolean dbs_etherwatch_read(wtap *wth, int *err, gchar **err_info,
74     gint64 *data_offset);
75 static gboolean dbs_etherwatch_seek_read(wtap *wth, gint64 seek_off,
76     wtap_rec *rec, Buffer *buf, int *err, gchar **err_info);
77 static gboolean parse_dbs_etherwatch_packet(FILE_T fh, wtap_rec *rec,
78     Buffer* buf, int *err, gchar **err_info);
79 static guint parse_single_hex_dump_line(char* rec, guint8 *buf,
80     int byte_offset);
81 static guint parse_hex_dump(char* dump, guint8 *buf, char seperator, char end);
82
83 /* Seeks to the beginning of the next packet, and returns the
84    byte offset.  Returns -1 on failure, and sets "*err" to the error
85    and "*err_info" to null or an additional error string. */
86 static gint64 dbs_etherwatch_seek_next_packet(wtap *wth, int *err,
87                                               gchar **err_info)
88 {
89     int byte;
90     unsigned int level = 0;
91     gint64 cur_off;
92
93     while ((byte = file_getc(wth->fh)) != EOF) {
94         if (byte == dbs_etherwatch_rec_magic[level]) {
95             level++;
96             if (level >= DBS_ETHERWATCH_REC_MAGIC_SIZE) {
97                 /* note: we're leaving file pointer right after the magic characters */
98                 cur_off = file_tell(wth->fh);
99                 if (cur_off == -1) {
100                     /* Error. */
101                     *err = file_error(wth->fh, err_info);
102                     return -1;
103                 }
104                 return cur_off + 1;
105             }
106         } else {
107             level = 0;
108         }
109     }
110     /* EOF or error. */
111     *err = file_error(wth->fh, err_info);
112     return -1;
113 }
114
115 #define DBS_ETHERWATCH_HEADER_LINES_TO_CHECK    200
116 #define DBS_ETHERWATCH_LINE_LENGTH      240
117
118 /* Look through the first part of a file to see if this is
119  * a DBS Ethertrace text trace file.
120  *
121  * Returns TRUE if it is, FALSE if it isn't or if we get an I/O error;
122  * if we get an I/O error, "*err" will be set to a non-zero value and
123  * "*err_info" will be set to null or an error string.
124  */
125 static gboolean dbs_etherwatch_check_file_type(wtap *wth, int *err,
126     gchar **err_info)
127 {
128     char    buf[DBS_ETHERWATCH_LINE_LENGTH];
129     int line, byte;
130     gsize   reclen;
131     unsigned int i, level;
132
133     buf[DBS_ETHERWATCH_LINE_LENGTH-1] = 0;
134
135     for (line = 0; line < DBS_ETHERWATCH_HEADER_LINES_TO_CHECK; line++) {
136         if (file_gets(buf, DBS_ETHERWATCH_LINE_LENGTH, wth->fh) == NULL) {
137             /* EOF or error. */
138             *err = file_error(wth->fh, err_info);
139             return FALSE;
140         }
141
142         reclen = strlen(buf);
143         if (reclen < DBS_ETHERWATCH_HDR_MAGIC_SIZE)
144             continue;
145
146         level = 0;
147         for (i = 0; i < reclen; i++) {
148             byte = buf[i];
149             if (byte == dbs_etherwatch_hdr_magic[level]) {
150                 level++;
151                 if (level >=
152                       DBS_ETHERWATCH_HDR_MAGIC_SIZE) {
153                     return TRUE;
154                 }
155             }
156             else
157                 level = 0;
158         }
159     }
160     *err = 0;
161     return FALSE;
162 }
163
164
165 wtap_open_return_val dbs_etherwatch_open(wtap *wth, int *err, gchar **err_info)
166 {
167     /* Look for DBS ETHERWATCH header */
168     if (!dbs_etherwatch_check_file_type(wth, err, err_info)) {
169         if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
170             return WTAP_OPEN_ERROR;
171         return WTAP_OPEN_NOT_MINE;
172     }
173
174     wth->file_encap = WTAP_ENCAP_ETHERNET;
175     wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_DBS_ETHERWATCH;
176     wth->snapshot_length = 0;   /* not known */
177     wth->subtype_read = dbs_etherwatch_read;
178     wth->subtype_seek_read = dbs_etherwatch_seek_read;
179     wth->file_tsprec = WTAP_TSPREC_CSEC;
180
181     return WTAP_OPEN_MINE;
182 }
183
184 /* Find the next packet and parse it; called from wtap_read(). */
185 static gboolean dbs_etherwatch_read(wtap *wth, int *err, gchar **err_info,
186     gint64 *data_offset)
187 {
188     gint64  offset;
189
190     /* Find the next packet */
191     offset = dbs_etherwatch_seek_next_packet(wth, err, err_info);
192     if (offset < 1)
193         return FALSE;
194     *data_offset = offset;
195
196     /* Parse the packet */
197     return parse_dbs_etherwatch_packet(wth->fh, &wth->rec,
198          wth->rec_data, err, err_info);
199 }
200
201 /* Used to read packets in random-access fashion */
202 static gboolean
203 dbs_etherwatch_seek_read(wtap *wth, gint64 seek_off,
204     wtap_rec *rec, Buffer *buf, int *err, gchar **err_info)
205 {
206     if (file_seek(wth->random_fh, seek_off - 1, SEEK_SET, err) == -1)
207         return FALSE;
208
209     return parse_dbs_etherwatch_packet(wth->random_fh, rec, buf, err,
210         err_info);
211 }
212
213 /* Parse a packet */
214 /*
215 Packet header:
216           1         2         3         4
217 0123456789012345678901234567890123456789012345
218 From 00-D0-C0-D2-4D-60 [MF1] to AA-00-04-00-FC-94 [PSERVB]
219 Protocol 08-00 00 00-00-00-00-00,   50 byte buffer at 10-OCT-2001 10:20:45.17
220 */
221 #define MAC_ADDR_LENGTH     6           /* Length MAC address */
222 #define DEST_MAC_PREFIX     "] to "     /* Prefix to the dest. MAC address */
223 #define PROTOCOL_LENGTH     2           /* Length protocol */
224 #define PROTOCOL_POS        9           /* Position protocol */
225 #define SAP_LENGTH          2           /* Length DSAP+SSAP */
226 #define SAP_POS             9           /* Position DSAP+SSAP */
227 #define CTL_UNNUMB_LENGTH   1           /* Length unnumbered control field */
228 #define CTL_NUMB_LENGTH     2           /* Length numbered control field */
229 #define CTL_POS             15          /* Position control field */
230 #define PID_LENGTH          5           /* Length PID */
231 #define PID_POS             18          /* Position PID */
232 #define LENGTH_POS          33          /* Position length */
233 #define HEX_HDR_SPR         '-'         /* Seperator char header hex values */
234 #define HEX_HDR_END         ' '         /* End char hdr. hex val. except PID */
235 #define HEX_PID_END         ','         /* End char PID hex value */
236 #define IEEE802_LEN_LEN     2           /* Length of the IEEE 802 len. field */
237 /*
238 To check whether it is Ethernet II or IEEE 802 we check the values of the
239 control field and PID, when they are all 0's we assume it is Ethernet II
240 else IEEE 802. In IEEE 802 the DSAP and SSAP are behind protocol, the
241 length in the IEEE data we have to construct.
242 */
243 #define ETH_II_CHECK_POS    15
244 #define ETH_II_CHECK_STR    "00 00-00-00-00-00,"
245 /*
246 To check whether it IEEE 802.3 with SNAP we check that both the DSAP & SSAP
247 values are 0xAA and the control field 0x03.
248 */
249 #define SNAP_CHECK_POS      9
250 #define SNAP_CHECK_STR      "AA-AA 03"
251 /*
252 To check whether the control field is 1 or two octets we check if it is
253 unnumbered. Unnumbered has length 1, numbered 2.
254 */
255 #define CTL_UNNUMB_MASK     0x03
256 #define CTL_UNNUMB_VALUE    0x03
257 static gboolean
258 parse_dbs_etherwatch_packet(FILE_T fh, wtap_rec *rec, Buffer* buf,
259     int *err, gchar **err_info)
260 {
261     guint8 *pd;
262     char    line[DBS_ETHERWATCH_LINE_LENGTH];
263     int num_items_scanned;
264     int eth_hdr_len, pkt_len, csec;
265     int length_pos, length_from, length;
266     struct tm tm;
267     char mon[4] = "xxx";
268     gchar *p;
269     static const gchar months[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
270     int count, line_count;
271
272     /* Make sure we have enough room for a regular Ethernet packet */
273     ws_buffer_assure_space(buf, DBS_ETHERWATCH_MAX_ETHERNET_PACKET_LEN);
274     pd = ws_buffer_start_ptr(buf);
275
276     eth_hdr_len = 0;
277     memset(&tm, 0, sizeof(tm));
278     /* Our file pointer should be on the first line containing the
279      * summary information for a packet. Read in that line and
280      * extract the useful information
281      */
282     if (file_gets(line, DBS_ETHERWATCH_LINE_LENGTH, fh) == NULL) {
283         *err = file_error(fh, err_info);
284         if (*err == 0) {
285             *err = WTAP_ERR_SHORT_READ;
286         }
287         return FALSE;
288     }
289
290     /* Get the destination address */
291     p = strstr(line, DEST_MAC_PREFIX);
292     if(!p) {
293         *err = WTAP_ERR_BAD_FILE;
294         *err_info = g_strdup("dbs_etherwatch: destination address not found");
295         return FALSE;
296     }
297     p += strlen(DEST_MAC_PREFIX);
298     if(parse_hex_dump(p, &pd[eth_hdr_len], HEX_HDR_SPR, HEX_HDR_END)
299                 != MAC_ADDR_LENGTH) {
300         *err = WTAP_ERR_BAD_FILE;
301         *err_info = g_strdup("dbs_etherwatch: destination address not valid");
302         return FALSE;
303     }
304     eth_hdr_len += MAC_ADDR_LENGTH;
305
306     /* Get the source address */
307     /*
308      * Since the first part of the line is already skipped in order to find
309      * the start of the record we cannot index, just look for the first
310      * 'HEX' character
311      */
312     p = line;
313     while(!g_ascii_isxdigit(*p)) {
314         p++;
315     }
316     if(parse_hex_dump(p, &pd[eth_hdr_len], HEX_HDR_SPR,
317         HEX_HDR_END) != MAC_ADDR_LENGTH) {
318         *err = WTAP_ERR_BAD_FILE;
319         *err_info = g_strdup("dbs_etherwatch: source address not valid");
320         return FALSE;
321     }
322     eth_hdr_len += MAC_ADDR_LENGTH;
323
324     /* Read the next line of the record header */
325     if (file_gets(line, DBS_ETHERWATCH_LINE_LENGTH, fh) == NULL) {
326         *err = file_error(fh, err_info);
327         if (*err == 0) {
328             *err = WTAP_ERR_SHORT_READ;
329         }
330         return FALSE;
331     }
332
333     /* Check the lines is as least as long as the length position */
334     if(strlen(line) < LENGTH_POS) {
335         *err = WTAP_ERR_BAD_FILE;
336         *err_info = g_strdup("dbs_etherwatch: line too short");
337         return FALSE;
338     }
339
340     num_items_scanned = sscanf(line + LENGTH_POS,
341                 "%9d byte buffer at %2d-%3s-%4d %2d:%2d:%2d.%9d",
342                 &pkt_len,
343                 &tm.tm_mday, mon,
344                 &tm.tm_year, &tm.tm_hour, &tm.tm_min,
345                 &tm.tm_sec, &csec);
346
347     if (num_items_scanned != 8) {
348         *err = WTAP_ERR_BAD_FILE;
349         *err_info = g_strdup("dbs_etherwatch: header line not valid");
350         return FALSE;
351     }
352
353     if (pkt_len < 0) {
354         *err = WTAP_ERR_BAD_FILE;
355         *err_info = g_strdup("dbs_etherwatch: packet header has a negative packet length");
356         return FALSE;
357     }
358
359     /* Determine whether it is Ethernet II or IEEE 802 */
360     if(strncmp(&line[ETH_II_CHECK_POS], ETH_II_CHECK_STR,
361         strlen(ETH_II_CHECK_STR)) == 0) {
362         /* Ethernet II */
363         /* Get the Protocol */
364         if(parse_hex_dump(&line[PROTOCOL_POS], &pd[eth_hdr_len], HEX_HDR_SPR,
365                     HEX_HDR_END) != PROTOCOL_LENGTH) {
366             *err = WTAP_ERR_BAD_FILE;
367             *err_info = g_strdup("dbs_etherwatch: Ethernet II protocol value not valid");
368             return FALSE;
369         }
370         eth_hdr_len += PROTOCOL_LENGTH;
371     } else {
372         /* IEEE 802 */
373         /* Remember where to put the length in the header */
374         length_pos = eth_hdr_len;
375         /* Leave room in the header for the length */
376         eth_hdr_len += IEEE802_LEN_LEN;
377         /* Remember how much of the header should not be added to the length */
378         length_from = eth_hdr_len;
379         /* Get the DSAP + SSAP */
380         if(parse_hex_dump(&line[SAP_POS], &pd[eth_hdr_len], HEX_HDR_SPR,
381                     HEX_HDR_END) != SAP_LENGTH) {
382             *err = WTAP_ERR_BAD_FILE;
383             *err_info = g_strdup("dbs_etherwatch: 802.2 DSAP+SSAP value not valid");
384             return FALSE;
385         }
386         eth_hdr_len += SAP_LENGTH;
387         /* Get the (first part of the) control field */
388         if(parse_hex_dump(&line[CTL_POS], &pd[eth_hdr_len], HEX_HDR_SPR,
389                     HEX_HDR_END) != CTL_UNNUMB_LENGTH) {
390             *err = WTAP_ERR_BAD_FILE;
391             *err_info = g_strdup("dbs_etherwatch: 802.2 control field first part not valid");
392             return FALSE;
393         }
394         /* Determine whether the control is numbered, and thus longer */
395         if((pd[eth_hdr_len] & CTL_UNNUMB_MASK) != CTL_UNNUMB_VALUE) {
396             /* Get the rest of the control field, the first octet in the PID */
397             if(parse_hex_dump(&line[PID_POS],
398                         &pd[eth_hdr_len + CTL_UNNUMB_LENGTH], HEX_HDR_END,
399                         HEX_HDR_SPR) != CTL_NUMB_LENGTH - CTL_UNNUMB_LENGTH) {
400                 *err = WTAP_ERR_BAD_FILE;
401                 *err_info = g_strdup("dbs_etherwatch: 802.2 control field second part value not valid");
402                 return FALSE;
403             }
404             eth_hdr_len += CTL_NUMB_LENGTH;
405         } else {
406             eth_hdr_len += CTL_UNNUMB_LENGTH;
407         }
408         /* Determine whether it is SNAP */
409         if(strncmp(&line[SNAP_CHECK_POS], SNAP_CHECK_STR,
410                 strlen(SNAP_CHECK_STR)) == 0) {
411             /* Get the PID */
412             if(parse_hex_dump(&line[PID_POS], &pd[eth_hdr_len], HEX_HDR_SPR,
413                         HEX_PID_END) != PID_LENGTH) {
414                 *err = WTAP_ERR_BAD_FILE;
415                 *err_info = g_strdup("dbs_etherwatch: 802.2 PID value not valid");
416                 return FALSE;
417             }
418             eth_hdr_len += PID_LENGTH;
419         }
420         /* Write the length in the header */
421         length = eth_hdr_len - length_from + pkt_len;
422         pd[length_pos] = (length) >> 8;
423         pd[length_pos+1] = (length) & 0xFF;
424     }
425
426     rec->rec_type = REC_TYPE_PACKET;
427     rec->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
428
429     p = strstr(months, mon);
430     if (p)
431         tm.tm_mon = (int)(p - months) / 3;
432     tm.tm_year -= 1900;
433
434     tm.tm_isdst = -1;
435     rec->ts.secs = mktime(&tm);
436     rec->ts.nsecs = csec * 10000000;
437     rec->rec_header.packet_header.caplen = eth_hdr_len + pkt_len;
438     rec->rec_header.packet_header.len = eth_hdr_len + pkt_len;
439
440     if (rec->rec_header.packet_header.caplen > WTAP_MAX_PACKET_SIZE_STANDARD) {
441         /*
442          * Probably a corrupt capture file; return an error,
443          * so that our caller doesn't blow up trying to allocate
444          * space for an immensely-large packet.
445          */
446         *err = WTAP_ERR_BAD_FILE;
447         *err_info = g_strdup_printf("dbs_etherwatch: File has %u-byte packet, bigger than maximum of %u",
448                                     rec->rec_header.packet_header.caplen, WTAP_MAX_PACKET_SIZE_STANDARD);
449         return FALSE;
450     }
451
452     /* Make sure we have enough room, even for an oversized Ethernet packet */
453     ws_buffer_assure_space(buf, rec->rec_header.packet_header.caplen);
454     pd = ws_buffer_start_ptr(buf);
455
456     /*
457      * We don't have an FCS in this frame.
458      */
459     rec->rec_header.packet_header.pseudo_header.eth.fcs_len = 0;
460
461     /* Parse the hex dump */
462     count = 0;
463     while (count < pkt_len) {
464         if (file_gets(line, DBS_ETHERWATCH_LINE_LENGTH, fh) == NULL) {
465             *err = file_error(fh, err_info);
466             if (*err == 0) {
467                 *err = WTAP_ERR_SHORT_READ;
468             }
469             return FALSE;
470         }
471         if (!(line_count = parse_single_hex_dump_line(line,
472                 &pd[eth_hdr_len + count], count))) {
473             *err = WTAP_ERR_BAD_FILE;
474             *err_info = g_strdup("dbs_etherwatch: packet data value not valid");
475             return FALSE;
476         }
477         count += line_count;
478         if (count > pkt_len) {
479             *err = WTAP_ERR_BAD_FILE;
480             *err_info = g_strdup("dbs_etherwatch: packet data value has too many bytes");
481             return FALSE;
482         }
483     }
484     return TRUE;
485 }
486
487 /* Parse a hex dump line */
488 /*
489 /DISPLAY=BOTH output:
490
491           1         2         3         4
492 0123456789012345678901234567890123456789012345
493   [E..(8...........]-    0-[45 00 00 28 38 9B 00 00 1D 06 D2 1E 80 93 11 1A]
494   [.........(..Z.4y]-   16-[80 93 80 D6 02 D2 02 03 00 28 A4 BF 5A 1C 34 79]
495   [P.#(.C...00000..]-   32-[50 10 23 28 C1 43 00 00 03 30 30 30 30 30 00 00]
496   [.0              ]-   48-[03 30]
497
498 /DISPLAY=HEXADECIMAL output:
499
500           1         2         3         4
501 0123456789012345678901234567890123456789012345
502      0-[45 00 00 28 38 9B 00 00 1D 06 D2 1E 80 93 11 1A 80 93 80 D6]
503     20-[02 D2 02 03 00 28 A4 BF 5A 1C 34 79 50 10 23 28 C1 43 00 00]
504     40-[03 30 30 30 30 30 00 00 03 30]
505
506 */
507
508 #define TYPE_CHECK_POS      2   /* Position to check the type of hex dump */
509 #define TYPE_CHECK_BOTH     '[' /* Value at pos. that indicates BOTH type */
510 #define COUNT_POS_BOTH      21  /* Count position BOTH type */
511 #define COUNT_POS_HEX       1   /* Count position HEX type */
512 #define COUNT_SIZE      5   /* Length counter */
513 #define HEX_DUMP_START      '[' /* Start char */
514 #define HEX_DUMP_SPR        ' ' /* Seperator char */
515 #define HEX_DUMP_END        ']' /* End char */
516
517 /* Take a string representing one line from a hex dump and converts the
518  * text to binary data. We check the printed offset with the offset
519  * we are passed to validate the record. We place the bytes in the buffer
520  * at the specified offset.
521  *
522  * Returns length parsed if a good hex dump, 0 if bad.
523  */
524 static guint
525 parse_single_hex_dump_line(char* rec, guint8 *buf, int byte_offset) {
526
527     int     pos, i;
528     int     value;
529
530
531     /* Check that the record is as least as long as the check offset */
532     for(i = 0; i < TYPE_CHECK_POS; i++)
533     {
534         if(rec[i] == '\0') {
535             return 0;
536         }
537     }
538     /* determine the format and thus the counter offset and hex dump length */
539     if(rec[TYPE_CHECK_POS] == TYPE_CHECK_BOTH)
540     {
541         pos = COUNT_POS_BOTH;
542     }
543     else
544     {
545         pos = COUNT_POS_HEX;
546     }
547
548     /* Check that the record is as least as long as the start position */
549     while(i < pos)
550     {
551         if(rec[i] == '\0') {
552             return 0;
553         }
554         i++;
555     }
556
557     /* Get the byte_offset directly from the record */
558     value = 0;
559     for(i = 0; i < COUNT_SIZE; i++) {
560         if(!g_ascii_isspace(rec[pos])) {
561             if(g_ascii_isdigit(rec[pos])) {
562                 value *= 10;
563                 value += rec[pos] - '0';
564             } else {
565                 return 0;
566             }
567         }
568         pos++;
569     }
570
571     if (value != byte_offset) {
572         return 0;
573     }
574
575     /* find the start of the hex dump */
576     while(rec[pos] != HEX_DUMP_START) {
577         if(rec[pos] == '\0') {
578             return 0;
579         }
580         pos++;
581     }
582     pos++;
583     return parse_hex_dump(&rec[pos], buf, HEX_DUMP_SPR, HEX_DUMP_END);
584 }
585
586 /* Parse a hex dump */
587 static guint
588 parse_hex_dump(char* dump, guint8 *buf, char seperator, char end) {
589     int     pos, count;
590
591     /* Parse the hex dump */
592     pos = 0;
593     count = 0;
594     while(dump[pos] != end) {
595         /* Check the hex value */
596         if(!(g_ascii_isxdigit(dump[pos]) &&
597             g_ascii_isxdigit(dump[pos + 1]))) {
598             return 0;
599         }
600         /* Get the hex value value */
601         if(g_ascii_isdigit(dump[pos])) {
602             buf[count] = (dump[pos] - '0') << 4;
603         } else {
604             buf[count] = (g_ascii_toupper(dump[pos]) - 'A' + 10) << 4;
605         }
606         pos++;
607         if(g_ascii_isdigit(dump[pos])) {
608             buf[count] += dump[pos] - '0';
609         } else {
610             buf[count] += g_ascii_toupper(dump[pos]) - 'A' + 10;
611         }
612         pos++;
613         count++;
614         /* Skip the seperator characters */
615         while(dump[pos] == seperator) {
616             pos++;
617         }
618     }
619     return count;
620 }
621
622 /*
623  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
624  *
625  * Local variables:
626  * c-basic-offset: 4
627  * tab-width: 8
628  * indent-tabs-mode: nil
629  * End:
630  *
631  * vi: set shiftwidth=4 tabstop=8 expandtab:
632  * :indentSize=4:tabSize=8:noTabs=true:
633  */