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