trafgen: parser: Add 'drnd()' function for proto fields
[netsniff-ng.git] / staging / parse_xml.c
blob2189b8317c3b158fd3d4a0f7da7dcb6095338cf3
1 /*
2 * Mausezahn - A fast versatile traffic generator
3 * Copyright (C) 2008-2010 Herbert Haas
4 *
5 * This program is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU General Public License version 2 as published by the
7 * Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12 * details.
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
20 #include "mz.h"
21 #include "mops.h"
22 #include "cli.h"
26 // Returns integer number for given tag string
27 // For example xml_tag2int("field") => xml_field == 1
28 //
29 // Returns -1 when tag not known
30 int xml_tag2int (char *t)
32 if (!strncasecmp(t, "protocol", XML_MAX_TAG_LEN))
33 return xml_protocol;
35 if (!strncasecmp(t, "field", XML_MAX_TAG_LEN))
36 return xml_field;
38 if (!strncasecmp(t, "name", XML_MAX_TAG_LEN))
39 return xml_name;
41 if (!strncasecmp(t, "desc", XML_MAX_TAG_LEN))
42 return xml_desc;
44 if (!strncasecmp(t, "requires", XML_MAX_TAG_LEN))
45 return xml_requires;
47 if (!strncasecmp(t, "conflicts", XML_MAX_TAG_LEN))
48 return xml_conflicts;
50 if (!strncasecmp(t, "payloadtype", XML_MAX_TAG_LEN))
51 return xml_payloadtype;
53 if (!strncasecmp(t, "payload", XML_MAX_TAG_LEN))
54 return xml_payload;
56 if (!strncasecmp(t, "payloadhex", XML_MAX_TAG_LEN))
57 return xml_payloadhex;
59 if (!strncasecmp(t, "index", XML_MAX_TAG_LEN))
60 return xml_index;
62 if (!strncasecmp(t, "longdesc", XML_MAX_TAG_LEN))
63 return xml_longdesc;
65 if (!strncasecmp(t, "type", XML_MAX_TAG_LEN))
66 return xml_type;
68 if (!strncasecmp(t, "constant", XML_MAX_TAG_LEN))
69 return xml_constant;
71 if (!strncasecmp(t, "value", XML_MAX_TAG_LEN))
72 return xml_value;
74 if (!strncasecmp(t, "valname", XML_MAX_TAG_LEN))
75 return xml_valname;
77 if (!strncasecmp(t, "min", XML_MAX_TAG_LEN))
78 return xml_min;
80 if (!strncasecmp(t, "max", XML_MAX_TAG_LEN))
81 return xml_max;
83 if (!strncasecmp(t, "tlvt", XML_MAX_TAG_LEN))
84 return xml_tlvt;
86 if (!strncasecmp(t, "tlvl", XML_MAX_TAG_LEN))
87 return xml_tlvl;
89 if (!strncasecmp(t, "lshift", XML_MAX_TAG_LEN))
90 return xml_lshift;
92 return -1;
96 // For a given pair of tag t and parent p check
97 // if t is really an allowed child of p.
98 // RETURN VALUE: 0 if correct, -1 otherwise
99 //
100 int xml_check_parent(int t, int p)
102 // For given tag t specify allowed parent p
103 switch (t) {
105 // no parent allowed
106 case xml_protocol:
107 if (p==-1) return 0;
108 break;
110 // has protocol as parent
111 case xml_field:
112 case xml_requires:
113 case xml_conflicts:
114 case xml_payloadtype:
115 case xml_payload:
116 case xml_payloadhex:
117 if (p==xml_protocol) return 0;
118 break;
120 // has field OR protocol as parent
121 case xml_name:
122 case xml_desc:
123 if ((p==xml_protocol)||(p==xml_field)) return 0;
124 break;
126 // has field as parent
127 case xml_longdesc:
128 case xml_type:
129 case xml_constant:
130 case xml_valname:
131 case xml_value:
132 case xml_min:
133 case xml_max:
134 case xml_index:
135 case xml_lshift:
136 case xml_tlvt:
137 case xml_tlvl:
138 if (p==xml_field) return 0;
141 return -1;
145 // Parse a single protocol definition.
146 // The string 'p' must start with '<protocol>' and end with </protocol>
148 // RETURN VALUE: 0 upon success, >0 otherwise.
150 int parse_protocol (char *p)
152 int i;
153 char p_clone[AUTOMOPS_MAX_FILE_SIZE+1];
154 struct automops *new_amp;
156 // Make a local copy of the protocol definition
157 strncpy(p_clone, p, AUTOMOPS_MAX_FILE_SIZE);
158 p_clone[AUTOMOPS_MAX_FILE_SIZE]='\0';
160 // Check if XML form is correct.
161 // I thought that this check should be done separately (and not during
162 // the xml_readin() function) for safety reasons. If read-in plus
163 // validation would be combined, we would have more to clean-up at in
164 // case the XML data is corrupt.
165 i = xml_canonic (p_clone);
167 // If incorrect, tell where error is:
168 if ((!quiet) && (i)) {
169 p_clone[i+1]='\0';
170 fprintf(stderr, "(EE) Mausezahn automops xml parse error:\n"
171 "========================================\n"
172 "%s <<ERROR>>\n", p_clone);
173 fprintf(stderr, "(EE) Error occured at character number %i\n", i);
174 fprintf(stderr," --- (printed all valid data until error position) ---\n");
177 if (verbose) {
178 fprintf(stderr, "...XML verification finished.\n");
181 // XML is correct, now create automops entry
183 if (i==0) {
184 strncpy(p_clone, p, AUTOMOPS_MAX_FILE_SIZE);
185 p_clone[AUTOMOPS_MAX_FILE_SIZE]='\0';
186 new_amp = automops_alloc_protocol(amp_head);
187 i = xml_readin(new_amp, p_clone);
189 if ((!quiet) && (i)) {
190 if (verbose) {
191 p_clone[i+1]='\0';
192 fprintf(stderr, "(EE) Invalid XML data at position %i: %s <<ERROR>>\n",
193 i, p_clone);
194 fprintf(stderr," --- (printed all valid data until error position) ---\n");
196 automops_delete_protocol(new_amp);
199 return i;
204 // Scans p until the next tag is found and stores
205 // tag name in t which must be a string of size
206 // XML_STRLEN (at least).
208 // Returns
209 // >0 if opening tag is found
210 // 0 if no tag is found or other problem
211 // <0 if closing tag is found
213 // If any tag is found the absolut return value
214 // indicates the position AFTER the tag, e. g.
215 // ...<tag>... or ...</tag>...
216 // ^here ^here
218 // Upon problem, the errorness char number is
219 // stored as string within t along with the
220 // error reason as string.
222 int xml_getnext_tag (char *p, char *t)
224 int i=0,j=0,k=0,
225 sign=1,
226 len;
228 // are there non-white characters left?
229 len = strnlen(p, AUTOMOPS_MAX_FILE_SIZE);
230 for (i=0; i<len; i++) if (!isspace(p[i])) j=1; // flag for first non-space character found
231 if (!j) { // no more characters found
232 t[0]=0x00;
233 return 0;
236 // basic length checks
237 i=0; j=0;
238 if ((len<3)||(len==AUTOMOPS_MAX_FILE_SIZE)) { // 3 is minimum tag length
239 snprintf(t, XML_STRLEN, "invalid length (%u)",len);
240 return 0;
244 // find first opening ('<') bracket
245 do {
246 if (p[i]=='<') break;
247 i++;
248 } while (i<len);
250 // tag too close to end
251 if (i>(len-3)) {
252 snprintf(t, XML_STRLEN, "%4i - no end", i);
253 return 0; // no tag found (smallest tag is '<x>')
256 j=++i;
258 // closing tag?
259 if (p[i]=='/') {
260 i++;
261 j++;
262 sign=-1;
265 // find closing bracket
266 // and get tag name
267 do {
268 if (p[i]=='>') {
269 k=i; // =found
270 break;
272 i++;
273 if (i==len) {
274 snprintf(t, XML_STRLEN, "%4i - no end?", i);
275 return 0;
277 } while (i<(j+XML_MAX_TAG_LEN+1));
279 // closing '>' really found?
280 if (!k) {
281 sprintf(t, "%4i - closing bracket missing", i);
282 return 0;
285 // now the tag name is from p[j]..p[k-1]
287 memcpy((void*) t, (void*) &p[j], k-j);
288 t[k-j]='\0';
290 return sign*(k+1);
294 // Copies data between opening and closing XML tags
295 // into 't' and returns the length of the data in bytes
296 // or zero if nothing found
297 // or -1 if protocol or data length is too long
298 // Note: Assumes that *p points to first byte after opening tag!
299 int xml_get_data (char *p, char *t)
301 int i=0, len;
303 // basic length checks
304 len = strnlen(p, AUTOMOPS_MAX_FILE_SIZE);
305 if (len==0) return 0;
307 if (len>AUTOMOPS_MAX_FILE_SIZE) {
308 snprintf(t, XML_STRLEN, "invalid length (%u)",len);
309 return -1;
312 // find closing tag
313 // i. e. next opening ('<') bracket
314 do {
315 if (p[i]=='<') break;
316 i++;
317 } while (i<len);
319 // Set limit on data length
320 if (i>1500) return -1; // TODO: consider more reasonable limit
322 // copy data
323 memcpy((void*) t, (void*) &p[0], i);
324 t[i]='\0';
325 return i;
330 // Make some simple checks whether XML data correct
331 // Currently only checks if
332 // - every opening tag has an ending tag (only via verbose now)
333 // - tags are properly nested (only 1st order tests now)
335 // RETURN VALUE: 0 upon success
336 // or position of mistake
338 int xml_canonic (char *p)
340 int i=0, l, dlen=0, plen, xntag=-1;
341 char t[XML_STRLEN];
342 char d[1500];
344 struct xnstack stack, *s;
346 s=&stack;
347 xnstack_init(s);
349 if (verbose==2) {
350 fprintf(stderr, "Parsing {%s}\n\n", p);
353 plen = strnlen(p, AUTOMOPS_MAX_FILE_SIZE);
355 do {
356 l = xml_getnext_tag (p, t); // Now t contains next tag name and l tells whether open or closing
357 if (l==0) {
358 if (t[0]==0x00) // no more tag found
359 return 0;
360 else { // general failure
361 fprintf(stderr, "%s\n", t);
362 return i;
366 i += abs(l);
367 if (verbose==2) {
368 fprintf(stderr, "%4i %4i stack=%i %s%s>\n",i,l,xnstack_size(s),
369 (l>0) ? "<" : "</", t);
371 if (i>=plen) { // break condition (regular, not an error!)
372 i=plen-1;
374 p+=abs(l); // now p points to first byte after tag
376 if (xml_tag2int(t)<0) {
377 fprintf(stderr, "mz/xml_canonic: UNKNOWN TAG at position %i\n", i);
378 return i;
381 // Closing tag found: does it match last opening tag?
382 if (l<0) {
383 if (xml_tag2int(t)!=xnstack_pop(s)) {
384 if (verbose) {
385 fprintf(stderr, "mz/xml_canonic: Incoherent nesting at position %i\n", i);
387 return i;
391 // Opening tag found: store it in last_tag!
392 if (l>0) {
393 xntag=xml_tag2int(t);
394 // Check if this tag has proper parent
395 if (xml_check_parent(xntag, xnstack_get_top(s))) {
396 fprintf(stderr, "mz/xml_canonic: Wrong parent tag\n");
397 return i;
399 if (xnstack_push(s, xntag)==-1) {
400 if (verbose) {
401 fprintf(stderr, "mz/xml_canonic: max nesting depth exceeded\n");
403 return i;
405 // also print data:
406 dlen = xml_get_data (p, d);
407 if (dlen==-1) {
408 if (verbose) {
409 fprintf(stderr, "mz/xml_canonic: %s\n", d);
411 return i;
413 if ((dlen>0) && (verbose==2)) {
414 fprintf(stderr, " %s\n", d); // the data
419 if (i==plen-1) return 0;
420 } while (l!=0);
422 if (xnstack_size(s)!=0) {
423 fprintf(stderr,"mz/xml_canonic: number of opening and closing tags does not match!\n");
424 return i;
427 return 0;
432 // Copy data elements of *p into struct *amp
433 // =============================================================
434 // NOTE: THE XML STRUCTURE MUST BE CORRECT !!!
435 // NO XML CHECKS ARE DONE TO KEEP THIS FUNCTION SMALL !!!
436 // THEREFORE ALWAYS RUN xml_canonic() FIRST !!!
437 // =============================================================
439 // However, this function checks if the *data* is valid.
441 // RETURN VALUE: 0 upon success,
442 // otherwise character position of wrong data
444 int xml_readin (struct automops *amp, char *p)
446 int i=0, l, dlen=0, plen, xntag=-1, parent=-1, err=0;
447 char t[XML_STRLEN];
448 char d[1500], errmsg[64];
450 struct xnstack stack, *s;
451 struct fields *f=NULL;
453 s=&stack;
454 xnstack_init(s);
456 plen = strnlen(p, AUTOMOPS_MAX_FILE_SIZE);
458 do {
459 l = xml_getnext_tag (p, t); // Now t contains next tag name and l tells whether open or closing
460 if (l==0) {
461 if (t[0]==0x00) return 0;
462 else
463 return i;
465 i += abs(l);
466 if (i>=plen) { // break condition (regular, not an error!)
467 i=plen-1;
469 p+=abs(l); // now p points to first byte after tag
472 // Closing tag found: does it match last opening tag?
473 if (l<0) xnstack_pop(s);
475 // Opening tag found: store it in last_tag!
476 if (l>0) {
477 xntag=xml_tag2int(t);
478 parent=xnstack_get_top(s); // get parent tag;
479 xnstack_push(s, xntag);
480 dlen = xml_get_data (p, d);
482 if (xntag==xml_field) { // Create new field
483 f=automops_add_field(amp);
484 } else
485 // Now copy the data 'd' into (the header & fields of) 'amp'
486 if (dlen>0) {
487 if (parent==xml_protocol) {
488 err = amp_add_pentry(amp, xntag, d);
489 } else
490 if (parent==xml_field) {
491 err = amp_add_fentry(amp, f, xntag, d);
493 if (err) {
494 if (!quiet) {
495 amperr2str(err, errmsg);
496 fprintf(stderr, "WARNING: Automops found '%s' at XML position %i\n", errmsg, i);
498 return i;
502 if (i==(plen-1)) return 0;
504 } while (l!=0);
505 return 0;
523 ///////////////////////////////////////////////////////////////////////////////
524 // //
525 ////////////// ONLY XML NESTING STACK FUNCTIONS BELOW THIS LINE ///////////////
529 void xnstack_init(struct xnstack *s)
531 s->cursize=0;
534 // Returns top data element or -1 if stack empty
535 // Does NOT remove data elements!
536 int xnstack_get_top(struct xnstack *s)
538 if (s->cursize==0) return -1;
539 return s->data[s->cursize-1];
542 // Push data onto stack
543 // Returns -1 if max stack depth exceeded
544 int xnstack_push(struct xnstack *s, int d)
546 if (s->cursize<XN_MAX_STACK)
547 s->data[s->cursize++]=d;
548 else
549 return -1;
550 return 0;
554 // Returns top data element and ALSO REMOVES it from stack
555 // Returns -1 if stack is empty
556 int xnstack_pop(struct xnstack *s)
558 int d;
559 d=xnstack_get_top(s);
560 if (d>=0) s->cursize--;
561 return d;
564 int xnstack_size(struct xnstack *s)
566 return s->cursize;