67e8a2cd47cd99e626d8781ab6c6a7783c6b1e74
[openafs.git] / src / tests / parsetag.c
1 /*
2  * CMUCS AFStools
3  * dumpscan - routines for scanning and manipulating AFS volume dumps
4  *
5  * Copyright (c) 1998 Carnegie Mellon University
6  * All Rights Reserved.
7  *
8  * Permission to use, copy, modify and distribute this software and its
9  * documentation is hereby granted, provided that both the copyright
10  * notice and this permission notice appear in all copies of the
11  * software, derivative works or modified versions, and any portions
12  * thereof, and that both notices appear in supporting documentation.
13  *
14  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
15  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
16  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
17  *
18  * Carnegie Mellon requests users of this software to return to
19  *
20  *  Software Distribution Coordinator  or  Software_Distribution@CS.CMU.EDU
21  *  School of Computer Science
22  *  Carnegie Mellon University
23  *  Pittsburgh PA 15213-3890
24  *
25  * any improvements or extensions that they make and grant Carnegie Mellon
26  * the rights to redistribute these changes.
27  */
28
29 /* parsetag.c - Parse a tagged data stream */
30
31 #include "dumpscan.h"
32 #include "dumpscan_errs.h"
33
34 /* If a parser function is defined, it will be called after the data value
35  * (if any) is read.  The parser is called as follows:
36  *
37  *   parser(input_file, &tag, &field_rec, value, g_refcon, l_refcon);
38  *
39  * - input_file is the FILE * for the input stream
40  * - field_rec is a pointer to the field record for the field just read
41  * - g_refcon and l_refcon are as passed in to ParseTaggedData
42  * - For integer types, value is the integer value
43  * - For DKIND_STRING, tag is a pointer to the string just read
44  * - For DKIND_SPEACH, tag is a pointer to the place to put the next tag.
45  *
46  * If the field type is DKIND_SPECIAL, the parser is expected to read its
47  * own data from the input stream, and return when ParseTaggedData is supposed
48  * to take over, with the next tag to process in *tag.  At no other time
49  * should the parser read, write, or reposition the input stream.
50  *
51  * The parser routine should return 0 on success, non-0 on failure.  If the
52  * data type is DKIND_STRING, the parser may return DSERR_KEEP to indicate
53  * that the memory allocated for the value should not be freed.
54  */
55
56 /* Parse a file containing tagged data and attributes **/
57 afs_uint32
58 ParseTaggedData(XFILE * X, tagged_field * fields, unsigned char *tag,
59                 tag_parse_info * pi, void *g_refcon, void *l_refcon)
60 {
61     int i = -1;
62     afs_uint32 r, val;
63     afs_uint16 val16;
64     unsigned char val8;
65     unsigned char *strval;
66
67     for (;;) {
68         if (i < 0 || (fields[i].kind & DKIND_MASK) != DKIND_SPECIAL) {
69             /* Need to read in a tag */
70             if ((r = ReadByte(X, tag)))
71                 return r;
72         }
73
74         /* Simple error recovery - if we encounter a 0, it can never be
75          * a valid tag.  If TPFLAG_SKIP is set, we can skip over any
76          * such null bytes, and process whatever tag we find beyond.
77          * In addition, if TPFLAG_RSKIP is set, then the next time
78          * we encounter a 0, try skipping backwards.  That seems to
79          * work much of the time.
80          */
81         if (!*tag && pi->shift_offset && (pi->flags & TPFLAG_RSKIP)) {
82             u_int64 where, tmp64a, tmp64b;
83             char buf1[21], buf2[21], buf3[21];
84             char *p1, *p2, *p3;
85
86             if ((r = xftell(X, &tmp64a)))
87                 return r;
88             sub64_32(where, tmp64a, pi->shift_offset + 1);
89             if ((r = xfseek(X, &where)))
90                 return r;
91             if (pi->cb_error) {
92                 (pi->cb_error) (DSERR_FMT, 0, pi->err_refcon,
93                                 "Inserted %d bytes before offset %d",
94                                 pi->shift_offset, decimate_int64(&where, 0));
95                 add64_32(tmp64a, pi->shift_start, pi->shift_offset);
96                 p1 = decimate_int64(&tmp64a, buf1);
97                 sub64_64(tmp64b, where, tmp64a);
98                 p2 = decimate_int64(&tmp64b, buf2);
99                 p3 = decimate_int64(&pi->shift_start, buf3);
100                 (pi->cb_error) (DSERR_FMT, 0, pi->err_refcon,
101                                 ">>> SHIFT start=%s length=%s target=%s", p1,
102                                 p2, p3);
103             }
104             pi->shift_offset = 0;
105             if ((r = ReadByte(X, tag)))
106                 return r;
107         }
108         if (!*tag && (pi->flags & TPFLAG_SKIP)) {
109             int count = 0;
110             u_int64 where, tmp64a;
111
112             if ((r = xftell(X, &where)))
113                 return r;
114
115             while (!*tag) {
116                 if ((r = ReadByte(X, tag)))
117                     return r;
118                 count++;
119             }
120             pi->shift_offset += count;
121             cp64(pi->shift_start, where);
122             if (pi->cb_error) {
123                 sub64_32(tmp64a, where, 1);
124                 (pi->cb_error) (DSERR_FMT, 0, pi->err_refcon,
125                                 "Skipped %d bytes at offset %s", count,
126                                 decimate_int64(&tmp64a, 0));
127             }
128         }
129
130         for (i = 0; fields[i].tag && fields[i].tag != *tag; i++);
131         if (!fields[i].tag)
132             return 0;
133
134         switch (fields[i].kind & DKIND_MASK) {
135         case DKIND_NOOP:
136             if (fields[i].func) {
137                 r = (fields[i].func) (X, 0, fields + i, 0, pi, g_refcon,
138                                       l_refcon);
139                 if (r)
140                     return r;
141             }
142             break;
143
144         case DKIND_BYTE:
145             if ((r = ReadByte(X, &val8)))
146                 return r;
147             if (fields[i].func) {
148                 r = (fields[i].func) (X, 0, fields + i, val8, pi, g_refcon,
149                                       l_refcon);
150                 if (r)
151                     return r;
152             }
153             break;
154
155         case DKIND_INT16:
156             if ((r = ReadInt16(X, &val16)))
157                 return r;
158             if (fields[i].func) {
159                 r = (fields[i].func) (X, 0, fields + i, val16, pi, g_refcon,
160                                       l_refcon);
161                 if (r)
162                     return r;
163             }
164             break;
165
166         case DKIND_INT32:
167             if ((r = ReadInt32(X, &val)))
168                 return r;
169             if (fields[i].func) {
170                 r = (fields[i].func) (X, 0, fields + i, val, pi, g_refcon,
171                                       l_refcon);
172                 if (r)
173                     return r;
174             }
175             break;
176
177         case DKIND_STRING:
178             if ((r = ReadString(X, &strval)))
179                 return r;
180             if (fields[i].func) {
181                 r = (fields[i].func) (X, strval, fields + i, 0, pi, g_refcon,
182                                       l_refcon);
183                 if (r != DSERR_KEEP)
184                     free(strval);
185                 if (r && r != DSERR_KEEP)
186                     return r;
187             } else
188                 free(strval);
189             break;
190
191         case DKIND_SPECIAL:
192             if (fields[i].func) {
193                 r = (fields[i].func) (X, tag, fields + i, 0, pi, g_refcon,
194                                       l_refcon);
195                 if (r)
196                     return r;
197             } else
198                 i = -1;
199         }
200     }
201 }