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