Document that ProtoField INT64 and UINT64 does not support value string.
[metze/wireshark/wip.git] / epan / tvbparse.c
1 /* tvbparse.c
2  *
3  * Copyright 2005, Luis E. Garcia Ontanon <luis@ontanon.org>
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24  */
25
26 #include "config.h"
27
28 #include <stdlib.h>
29 #include <string.h>
30 #include <glib.h>
31
32 #include <epan/emem.h>
33 #include <epan/proto.h>
34 #include <epan/packet_info.h>
35 #include <epan/tvbparse.h>
36
37
38 #define TVBPARSE_DEBUG_ALL 0xffffffff
39
40 #if 0
41 #define TVBPARSE_DEBUG_ 0x80000000
42 #define TVBPARSE_DEBUG_ 0x40000000
43 #define TVBPARSE_DEBUG_ 0x20000000
44 #define TVBPARSE_DEBUG_ 0x10000000
45 #endif
46
47 #define TVBPARSE_DEBUG_CHAR 0x08000000
48 #define TVBPARSE_DEBUG_CHARS 0x04000000
49 #define TVBPARSE_DEBUG_NOT_CHAR 0x02000000
50 #define TVBPARSE_DEBUG_NOT_CHARS 0x01000000
51 #define TVBPARSE_DEBUG_STRING 0x00800000
52 #define TVBPARSE_DEBUG_CASESTRING 0x00400000
53 #define TVBPARSE_DEBUG_ONEOF 0x00200000
54 #define TVBPARSE_DEBUG_HASH 0x00100000
55 #define TVBPARSE_DEBUG_SEQ 0x00080000
56 #define TVBPARSE_DEBUG_SOME 0x00040000
57 #define TVBPARSE_DEBUG_UNTIL 0x00020000
58 #if 0
59 #define TVBPARSE_DEBUG_ 0x00010000
60 #define TVBPARSE_DEBUG_ 0x00008000
61 #define TVBPARSE_DEBUG_ 0x00004000
62 #define TVBPARSE_DEBUG_ 0x00002000
63 #define TVBPARSE_DEBUG_ 0x00001000
64 #endif
65 #define TVBPARSE_DEBUG_TT 0x00000800
66 #define TVBPARSE_DEBUG_CB 0x00000400
67 #define TVBPARSE_DEBUG_GET 0x00000200
68 #define TVBPARSE_DEBUG_FIND 0x00000100
69 #define TVBPARSE_DEBUG_NEWTOK 0x00000080
70 #define TVBPARSE_DEBUG_IGNORE 0x00000040
71 #define TVBPARSE_DEBUG_PEEK 0x00000020
72 #if 0
73 #define TVBPARSE_DEBUG_ 0x00000010
74 #define TVBPARSE_DEBUG_ 0x00000008
75 #define TVBPARSE_DEBUG_ 0x00000004
76 #define TVBPARSE_DEBUG_ 0x00000002
77 #define TVBPARSE_DEBUG_ 0x00000001
78 #endif
79
80 /*
81 #define TVBPARSE_DEBUG (TVBPARSE_DEBUG_SOME)
82 */
83
84 static tvbparse_elem_t* new_tok(tvbparse_t* tt,
85                                 int id,
86                                 int offset,
87                                 int len,
88                                 const tvbparse_wanted_t* wanted) {
89     tvbparse_elem_t* tok;
90
91 #ifdef TVBPARSE_DEBUG
92     if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_NEWTOK) g_warning("new_tok: id=%i offset=%u len=%u",id,offset,len);
93 #endif
94
95     tok = (tvbparse_elem_t *)ep_alloc(sizeof(tvbparse_elem_t));
96
97     tok->tvb = tt->tvb;
98     tok->id = id;
99     tok->offset = offset;
100     tok->len = len;
101     tok->data = NULL;
102     tok->sub = NULL;
103     tok->next = NULL;
104     tok->wanted = wanted;
105     tok->last = tok;
106
107     return tok;
108 }
109
110 static int ignore_fcn(tvbparse_t* tt, int offset) {
111     int len = 0;
112     int consumed;
113     tvbparse_elem_t* ignored = NULL;
114
115     if (!tt->ignore) return 0;
116
117 #ifdef TVBPARSE_DEBUG
118     if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_IGNORE) g_warning("ignore: enter");
119 #endif
120
121     while ((consumed = tt->ignore->condition(tt,offset,tt->ignore,&ignored)) > 0) {
122         len += consumed;
123         offset += consumed;
124 #ifdef TVBPARSE_DEBUG
125         if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_IGNORE) g_warning("ignore: consumed=%i",consumed);
126 #endif
127
128     }
129
130 #ifdef TVBPARSE_DEBUG
131     if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_IGNORE) g_warning("ignore: len=%i",len);
132 #endif
133
134     return len;
135 }
136
137
138 static int cond_char (tvbparse_t* tt, const int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
139     gchar c,t;
140     guint i;
141
142 #ifdef TVBPARSE_DEBUG
143     if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CHAR) g_warning("cond_char: control='%s'",wanted->control.str);
144 #endif
145
146     if ( offset + 1 > tt->end_offset )
147         return -1;
148
149     t = (gchar) tvb_get_guint8(tt->tvb,offset);
150
151     for(i = 0; (c = wanted->control.str[i]) && offset <= tt->end_offset; i++) {
152         if ( c == t ) {
153             *tok =  new_tok(tt,wanted->id,offset,1,wanted);
154 #ifdef TVBPARSE_DEBUG
155             if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CHAR) g_warning("cond_char: GOT: '%c'",c);
156 #endif
157             return 1;
158         }
159     }
160
161     return -1;
162 }
163
164 tvbparse_wanted_t* tvbparse_char(const int id,
165                                  const gchar* chr,
166                                  const void* data,
167                                  tvbparse_action_t before_cb,
168                                  tvbparse_action_t after_cb) {
169     tvbparse_wanted_t* w = (tvbparse_wanted_t *)g_malloc0(sizeof(tvbparse_wanted_t));
170
171     w->condition = cond_char;
172     w->id = id;
173     w->control.str = chr;
174     w->len = 1;
175     w->data = data;
176     w->before = before_cb;
177     w->after = after_cb;
178
179     return w;
180 }
181
182 static int cond_chars (tvbparse_t* tt, int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
183     guint length = 0;
184     int start = offset;
185     int left = tt->end_offset - offset;
186
187 #ifdef TVBPARSE_DEBUG
188     if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CHARS) g_warning("cond_chars: control='%s'",wanted->control.str);
189 #endif
190
191     if ( offset + (int)wanted->min > tt->end_offset )
192         return -1;
193
194     left = left < (int) wanted->max ? left :  (int) wanted->max;
195
196     while( left > 0 ) {
197         gchar t = (gchar) tvb_get_guint8(tt->tvb,offset++);
198         gchar c;
199         guint i = 0;
200
201         while ( (c = wanted->control.str[i++]) ) {
202             if (c == t) goto next_char;
203         }
204
205         break;
206
207 next_char:
208         length++;
209         left--;
210     };
211
212     if (length < wanted->min) {
213         return  -1;
214     } else {
215         *tok = new_tok(tt,wanted->id,start,length,wanted);
216 #ifdef TVBPARSE_DEBUG
217         if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CHARS) g_warning("cond_chars: GOT len=%i",length);
218 #endif
219         return length;
220     }
221 }
222
223 tvbparse_wanted_t* tvbparse_chars(const int id,
224                                   const guint min_len,
225                                   const guint max_len,
226                                   const gchar* chr,
227                                   const void* data,
228                                   tvbparse_action_t before_cb,
229                                   tvbparse_action_t after_cb) {
230     tvbparse_wanted_t* w = (tvbparse_wanted_t *)g_malloc0(sizeof(tvbparse_wanted_t));
231
232     w->condition = cond_chars;
233     w->id = id;
234     w->control.str = chr;
235     w->min = min_len ? min_len : 1;
236     w->max = max_len ? max_len : G_MAXINT/2;
237     w->data = data;
238     w->before = before_cb;
239     w->after = after_cb;
240
241     return w;
242 }
243
244
245 static int cond_not_char(tvbparse_t* tt, const int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
246     gchar c, t;
247     guint i;
248     gboolean not_matched = FALSE;
249
250 #ifdef TVBPARSE_DEBUG
251     if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_NOT_CHAR) g_warning("cond_not_char: control='%s'",wanted->control.str);
252 #endif
253
254     if (! offset < tt->end_offset ) {
255         return -1;
256     }
257
258     t = (gchar) tvb_get_guint8(tt->tvb,offset);
259
260     for(i = 0; (c = wanted->control.str[i]); i++) {
261         if ( c == t ) {
262             not_matched = TRUE;
263         }
264     }
265
266     if (not_matched) {
267         return -1;
268     } else {
269         *tok =  new_tok(tt,wanted->id,offset,1,wanted);
270 #ifdef TVBPARSE_DEBUG
271         if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_NOT_CHAR) g_warning("cond_not_char: GOT='%c'",t);
272 #endif
273         return 1;
274     }
275 }
276
277 tvbparse_wanted_t* tvbparse_not_char(const int id,
278                                      const gchar* chr,
279                                      const void* data,
280                                      tvbparse_action_t before_cb,
281                                      tvbparse_action_t after_cb) {
282     tvbparse_wanted_t* w = (tvbparse_wanted_t *)g_malloc0(sizeof(tvbparse_wanted_t));
283
284     w->condition = cond_not_char;
285     w->id = id;
286     w->control.str = chr;
287     w->data = data;
288     w->before = before_cb;
289     w->after = after_cb;
290
291     return w;
292 }
293
294 static int cond_not_chars(tvbparse_t* tt, int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
295     guint length = 0;
296     int left = tt->end_offset - offset;
297     int start = offset;
298
299 #ifdef TVBPARSE_DEBUG
300     if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_NOT_CHARS) g_warning("cond_not_chars: control='%s'",wanted->control.str);
301 #endif
302
303     if ( offset + (int)wanted->min > tt->end_offset )
304         return -1;
305
306     if (left < (int)wanted->min)
307         return -1;
308
309     left = left <= (int)wanted->max ? left :  (int)wanted->max;
310
311     while( left > 0 ) {
312         gchar c;
313         gchar t = (gchar) tvb_get_guint8(tt->tvb,offset);
314         guint i = 0;
315
316         while ( (c = wanted->control.str[i++]) ) {
317             if (c == t) goto end_not_chars;
318         }
319
320         offset++;
321         length++;
322         left--;
323     }
324 end_not_chars:
325
326     if ( length < wanted->min ) {
327         return -1;
328     } else {
329         *tok = new_tok(tt,wanted->id,start,length,wanted);
330 #ifdef TVBPARSE_DEBUG
331         if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_NOT_CHARS) g_warning("cond_not_chars: GOT len=%i",length);
332 #endif
333         return length;
334     }
335 }
336
337 tvbparse_wanted_t* tvbparse_not_chars(const int id,
338                                       const guint min_len,
339                                       const guint max_len,
340                                       const gchar* chr,
341                                       const void* data,
342                                       tvbparse_action_t before_cb,
343                                       tvbparse_action_t after_cb){
344     tvbparse_wanted_t* w = (tvbparse_wanted_t *)g_malloc0(sizeof(tvbparse_wanted_t));
345
346     w->condition = cond_not_chars;
347     w->id = id;
348     w->control.str = chr;
349     w->len = 0;
350     w->min = min_len ? min_len : 1;
351     w->max = max_len ? max_len : G_MAXINT/2;
352     w->data = data;
353     w->before = before_cb;
354     w->after = after_cb;
355
356     return w;
357 }
358
359
360 static int cond_string(tvbparse_t* tt, const int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
361     int len = wanted->len;
362 #ifdef TVBPARSE_DEBUG
363     if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_STRING) g_warning("cond_string: control='%s'",wanted->control.str);
364 #endif
365
366     if ( offset + wanted->len > tt->end_offset )
367         return -1;
368
369     if ( tvb_strneql(tt->tvb, offset, wanted->control.str, len) == 0 ) {
370         *tok = new_tok(tt,wanted->id,offset,len,wanted);
371 #ifdef TVBPARSE_DEBUG
372         if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_STRING) g_warning("cond_string: GOT len=%i",len);
373 #endif
374         return len;
375     } else {
376         return -1;
377     }
378 }
379
380 tvbparse_wanted_t* tvbparse_string(const int id,
381                                    const gchar* str,
382                                    const void* data,
383                                    tvbparse_action_t before_cb,
384                                    tvbparse_action_t after_cb) {
385     tvbparse_wanted_t* w = (tvbparse_wanted_t *)g_malloc0(sizeof(tvbparse_wanted_t));
386
387     w->condition = cond_string;
388     w->id = id;
389     w->control.str = str;
390     w->len = (int) strlen(str);
391     w->data = data;
392     w->before = before_cb;
393     w->after = after_cb;
394
395     return w;
396 }
397
398 static int cond_casestring(tvbparse_t* tt, const int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
399     int len = wanted->len;
400 #ifdef TVBPARSE_DEBUG
401     if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CASESTRING) g_warning("cond_casestring: control='%s'",wanted->control.str);
402 #endif
403
404     if ( offset + len > tt->end_offset )
405         return -1;
406
407     if ( tvb_strncaseeql(tt->tvb, offset, wanted->control.str, len) == 0 ) {
408         *tok = new_tok(tt,wanted->id,offset,len,wanted);
409 #ifdef TVBPARSE_DEBUG
410         if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CASESTRING) g_warning("cond_casestring: GOT len=%i",len);
411 #endif
412         return len;
413     } else {
414         *tok = NULL;
415         return -1;
416     }
417 }
418
419 tvbparse_wanted_t* tvbparse_casestring(const int id,
420                                        const gchar* str,
421                                        const void* data,
422                                        tvbparse_action_t before_cb,
423                                        tvbparse_action_t after_cb) {
424     tvbparse_wanted_t* w = (tvbparse_wanted_t *)g_malloc0(sizeof(tvbparse_wanted_t));
425
426     w->condition = cond_casestring;
427     w->id = id;
428     w->control.str = str;
429     w->len = (int) strlen(str);
430     w->data = data;
431     w->before = before_cb;
432     w->after = after_cb;
433
434     return w;
435 }
436
437 static int cond_one_of(tvbparse_t* tt, const int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
438     guint i;
439 #ifdef TVBPARSE_DEBUG
440     if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_ONEOF) g_warning("cond_one_of: START");
441 #endif
442
443     if ( offset > tt->end_offset )
444         return -1;
445
446     for(i=0; i < wanted->control.elems->len; i++) {
447         tvbparse_wanted_t* w = (tvbparse_wanted_t *)g_ptr_array_index(wanted->control.elems,i);
448         tvbparse_elem_t* new_elem = NULL;
449         int curr_len;
450
451         if ( offset + w->len > tt->end_offset )
452             continue;
453
454         curr_len = w->condition(tt, offset, w,  &new_elem);
455
456         if (curr_len >= 0) {
457             *tok = new_tok(tt, wanted->id, new_elem->offset, new_elem->len, wanted);
458             (*tok)->sub = new_elem;
459 #ifdef TVBPARSE_DEBUG
460             if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_ONEOF) g_warning("cond_one_of: GOT len=%i",curr_len);
461 #endif
462             return curr_len;
463         }
464     }
465
466     return -1;
467 }
468
469 tvbparse_wanted_t* tvbparse_set_oneof(const int id,
470                                       const void* data,
471                                       tvbparse_action_t before_cb,
472                                       tvbparse_action_t after_cb,
473                                       ...) {
474     tvbparse_wanted_t* w = (tvbparse_wanted_t *)g_malloc0(sizeof(tvbparse_wanted_t));
475     tvbparse_t* el;
476     va_list ap;
477
478     w->condition = cond_one_of;
479     w->id = id;
480     w->data = data;
481     w->before = before_cb;
482     w->after = after_cb;
483     w->control.elems = g_ptr_array_new();
484
485     va_start(ap,after_cb);
486
487     while(( el = va_arg(ap,tvbparse_t*) )) {
488         g_ptr_array_add(w->control.elems,el);
489     };
490
491     va_end(ap);
492
493     return w;
494 }
495
496 static int cond_hash(tvbparse_t* tt, const int offset, const tvbparse_wanted_t* wanted, tvbparse_elem_t** tok) {
497     int key_len;
498     gchar* key = NULL;
499     tvbparse_elem_t* key_elem = NULL;
500     tvbparse_wanted_t* value_wanted = NULL;
501     int value_len;
502     tvbparse_elem_t* value_elem = NULL;
503     int tot_len;
504     tvbparse_elem_t* ret_tok;
505
506 #ifdef TVBPARSE_DEBUG
507     if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_HASH) g_warning("cond_hash: START");
508 #endif
509
510     if ( offset > tt->end_offset )
511         return -1;
512
513     key_len = wanted->control.hash.key->condition(tt, offset, wanted->control.hash.key,  &key_elem);
514
515     if (key_len < 0)
516         return -1;
517
518     key = tvb_get_ephemeral_string(key_elem->tvb,key_elem->offset,key_elem->len);
519 #ifdef TVBPARSE_DEBUG
520     if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_HASH) g_warning("cond_hash: got key='%s'",key);
521 #endif
522
523     if ((value_wanted = (tvbparse_wanted_t *)g_hash_table_lookup(wanted->control.hash.table,key))) {
524         value_len = value_wanted->condition(tt, offset + key_len, value_wanted,  &value_elem);
525     } else if (wanted->control.hash.other) {
526         value_len = wanted->control.hash.other->condition(tt, offset+key_len, wanted->control.hash.other,  &value_elem);
527         if (value_len < 0)
528             return -1;
529     } else {
530         return -1;
531     }
532
533     tot_len = key_len + value_len;
534
535     ret_tok = new_tok(tt, value_elem->id, offset, tot_len, wanted);
536     ret_tok->sub = key_elem;
537     ret_tok->sub->last->next = value_elem;
538
539     *tok = ret_tok;
540 #ifdef TVBPARSE_DEBUG
541     if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_HASH) g_warning("cond_hash: GOT len=%i",tot_len);
542 #endif
543
544     return tot_len;
545 }
546
547 tvbparse_wanted_t* tvbparse_hashed(const int id,
548                                    const void* data,
549                                    tvbparse_action_t before_cb,
550                                    tvbparse_action_t after_cb,
551                                    tvbparse_wanted_t* key,
552                                    tvbparse_wanted_t* other,
553                                    ...) {
554     tvbparse_wanted_t* w = (tvbparse_wanted_t *)g_malloc0(sizeof(tvbparse_wanted_t));
555     gchar* name;
556     tvbparse_wanted_t* el;
557     va_list ap;
558
559     w->condition = cond_hash;
560     w->id = id;
561     w->data = data;
562     w->before = before_cb;
563     w->after = after_cb;
564     w->control.hash.table = g_hash_table_new(g_str_hash,g_str_equal);
565     w->control.hash.key = key;
566     w->control.hash.other = other;
567
568     va_start(ap,other);
569
570     while(( name = va_arg(ap,gchar*) )) {
571         el = va_arg(ap,tvbparse_wanted_t*);
572         g_hash_table_insert(w->control.hash.table,name,el);
573     }
574
575     va_end(ap);
576
577     return w;
578 }
579
580 void tvbparse_hashed_add(tvbparse_wanted_t* w, ...) {
581     tvbparse_wanted_t* el;
582     va_list ap;
583     gchar* name;
584
585     va_start(ap,w);
586
587     while (( name = va_arg(ap,gchar*) )) {
588         el = va_arg(ap,tvbparse_wanted_t*);
589         g_hash_table_insert(w->control.hash.table,name,el);
590     }
591
592     va_end(ap);
593 }
594
595 static int cond_seq(tvbparse_t* tt, int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
596     guint i;
597     int len = 0;
598     int start = offset;
599     tvbparse_elem_t* ret_tok = NULL;
600
601     if ( offset > tt->end_offset )
602         return -1;
603 #ifdef TVBPARSE_DEBUG
604     if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_SEQ) g_warning("cond_seq: START");
605 #endif
606
607     for(i=0; i < wanted->control.elems->len; i++) {
608         tvbparse_wanted_t* w = (tvbparse_wanted_t *)g_ptr_array_index(wanted->control.elems,i);
609         tvbparse_elem_t* new_elem = NULL;
610
611         if ( offset + w->len > tt->end_offset )
612             return -1;
613
614
615         len = w->condition(tt, offset, w, &new_elem);
616
617         if (len >= 0) {
618             if (ret_tok) {
619                 ret_tok->len = (new_elem->offset - ret_tok->offset) + new_elem->len;
620                 ret_tok->sub->last->next = new_elem;
621                 ret_tok->sub->last = new_elem;
622             } else {
623                 ret_tok = new_tok(tt, wanted->id, new_elem->offset, new_elem->len, wanted);
624                 ret_tok->sub = new_elem;
625                 new_elem->last = new_elem;
626             }
627         } else {
628             return -1;
629         }
630
631         offset += len;
632         offset += ignore_fcn(tt,offset);
633     }
634
635     *tok = ret_tok;
636
637 #ifdef TVBPARSE_DEBUG
638     if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_SEQ) g_warning("cond_seq: GOT len=%i",offset - start);
639 #endif
640
641     return offset - start;
642 }
643
644
645 tvbparse_wanted_t* tvbparse_set_seq(const int id,
646                                     const void* data,
647                                     tvbparse_action_t before_cb,
648                                     tvbparse_action_t after_cb,
649                                     ...) {
650     tvbparse_wanted_t* w = (tvbparse_wanted_t *)g_malloc0(sizeof(tvbparse_wanted_t));
651     tvbparse_wanted_t*  el = NULL;
652     va_list ap;
653
654     w->condition = cond_seq;
655     w->id = id;
656     w->data = data;
657     w->before = before_cb;
658     w->after = after_cb;
659     w->control.elems = g_ptr_array_new();
660
661     va_start(ap,after_cb);
662
663     while(( el = va_arg(ap,tvbparse_wanted_t*) )) {
664         g_ptr_array_add(w->control.elems,el);
665     };
666
667     va_end(ap);
668     return w;
669 }
670
671 static int cond_some(tvbparse_t* tt, int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
672     guint got_so_far = 0;
673     int start = offset;
674     tvbparse_elem_t* ret_tok = NULL;
675 #ifdef TVBPARSE_DEBUG
676     if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_SOME) g_warning("cond_some: START");
677 #endif
678
679     if ( offset > tt->end_offset )
680         return -1;
681
682     if ( wanted->min == 0 ) {
683         ret_tok = new_tok(tt,wanted->id,offset,0,wanted);
684     }
685
686     while (got_so_far < wanted->max) {
687         tvbparse_elem_t* new_elem = NULL;
688         int consumed;
689
690         if ( offset > tt->end_offset )
691             return -1;
692
693         consumed = wanted->control.subelem->condition(tt, offset, wanted->control.subelem, &new_elem);
694
695         if(consumed >= 0) {
696             if (ret_tok) {
697                 ret_tok->len = (new_elem->offset - ret_tok->offset) + new_elem->len;
698
699                 if (ret_tok->sub) {
700                     ret_tok->sub->last->next = new_elem;
701                     ret_tok->sub->last = new_elem;
702                 } else {
703                     ret_tok->sub = new_elem;
704                 }
705             } else {
706                 ret_tok = new_tok(tt, wanted->id, new_elem->offset, new_elem->len, wanted);
707                 ret_tok->sub = new_elem;
708             }
709         } else {
710             break;
711         }
712
713         offset += consumed;
714         got_so_far++;
715     }
716
717 #ifdef TVBPARSE_DEBUG
718     if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_SOME) g_warning("cond_some: got num=%u",got_so_far);
719 #endif
720
721     if(got_so_far < wanted->min) {
722         return -1;
723     }
724
725     *tok = ret_tok;
726 #ifdef TVBPARSE_DEBUG
727     if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_SOME) g_warning("cond_some: GOT len=%i",offset - start);
728 #endif
729     return offset - start;
730 }
731
732 tvbparse_wanted_t* tvbparse_some(const int id,
733                                  const guint from,
734                                  const guint to,
735                                  const void* data,
736                                  tvbparse_action_t before_cb,
737                                  tvbparse_action_t after_cb,
738                                  const tvbparse_wanted_t* el) {
739
740     tvbparse_wanted_t* w = (tvbparse_wanted_t *)g_malloc0(sizeof(tvbparse_wanted_t));
741
742     g_assert(from <= to);
743
744     w->condition = cond_some;
745     w->id = id;
746     w->min = from;
747     w->max = to;
748     w->data = data;
749     w->before = before_cb;
750     w->after = after_cb;
751     w->control.subelem = el;
752
753     return w;
754 }
755
756
757 static int cond_until(tvbparse_t* tt, const int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
758     tvbparse_elem_t* new_elem = NULL;
759     int len = 0;
760     int target_offset = offset;
761 #ifdef TVBPARSE_DEBUG
762     if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_UNTIL) g_warning("cond_until: START");
763 #endif
764
765     if ( offset + wanted->control.until.subelem->len > tt->end_offset )
766         return -1;
767
768     do {
769         len = wanted->control.until.subelem->condition(tt, target_offset++, wanted->control.until.subelem,  &new_elem);
770     } while(len < 0  && target_offset+1 < tt->end_offset);
771
772     if (len >= 0) {
773
774         new_elem->id = wanted->id;
775         new_elem->next = NULL;
776         new_elem->last = NULL;
777         new_elem->wanted = wanted;
778         new_elem->offset = offset;
779
780         (*tok) = new_elem;
781
782         switch (wanted->control.until.mode) {
783             case TP_UNTIL_INCLUDE:
784                 new_elem->len = target_offset - offset - 1 + len;
785 #ifdef TVBPARSE_DEBUG
786                 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_UNTIL) g_warning("cond_until: GOT len=%i",target_offset - offset -1 + len);
787 #endif
788                 return target_offset - offset -1 + len;
789             case TP_UNTIL_SPEND:
790                 new_elem->len = target_offset - offset - 1;
791 #ifdef TVBPARSE_DEBUG
792                 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_UNTIL) g_warning("cond_until: GOT len=%i",target_offset - offset -1 + len);
793 #endif
794                 return target_offset - offset - 1 + len;
795             case TP_UNTIL_LEAVE:
796                 new_elem->len = target_offset - offset - 1;
797 #ifdef TVBPARSE_DEBUG
798                 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_UNTIL) g_warning("cond_until: GOT len=%i",target_offset - offset -1);
799 #endif
800                 return target_offset - offset -1;
801             default:
802                 DISSECTOR_ASSERT_NOT_REACHED();
803                 return -1;
804         }
805
806     } else {
807         return -1;
808     }
809 }
810
811 tvbparse_wanted_t* tvbparse_until(const int id,
812                                   const void* data,
813                                   tvbparse_action_t before_cb,
814                                   tvbparse_action_t after_cb,
815                                   const tvbparse_wanted_t* el,
816                                   until_mode_t until_mode) {
817     tvbparse_wanted_t* w = (tvbparse_wanted_t *)g_malloc0(sizeof(tvbparse_wanted_t));
818
819     w->condition = cond_until;
820     w->control.until.mode = until_mode;
821     w->control.until.subelem = el;
822     w->id = id;
823     w->data = data;
824     w->before = before_cb;
825     w->after = after_cb;
826
827     return w;
828 }
829
830 static int cond_handle(tvbparse_t* tt, const int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
831     tvbparse_wanted_t* w = *(wanted->control.handle);
832     int len = w->condition(tt, offset, w,  tok);
833
834     if (len >= 0) {
835         return len;
836     } else {
837         return -1;
838     }
839 }
840
841 tvbparse_wanted_t* tvbparse_handle(tvbparse_wanted_t** handle) {
842     tvbparse_wanted_t* w = (tvbparse_wanted_t *)g_malloc0(sizeof(tvbparse_wanted_t));
843
844     w->condition = cond_handle;
845     w->control.handle = handle;
846
847     return w;
848 }
849
850 static int cond_end(tvbparse_t* tt, const int offset, const tvbparse_wanted_t * wanted _U_, tvbparse_elem_t** tok) {
851     if (offset == tt->end_offset) {
852         *tok = new_tok(tt,wanted->id,offset,0,wanted);
853         return 0;
854     } else {
855         return -1;
856     }
857 }
858
859 tvbparse_wanted_t* tvbparse_end_of_buffer(const int id,
860                                           const void* data,
861                                           tvbparse_action_t before_cb,
862                                           tvbparse_action_t after_cb) {
863     tvbparse_wanted_t* w = (tvbparse_wanted_t *)g_malloc0(sizeof(tvbparse_wanted_t));
864
865     w->id = id;
866     w->condition = cond_end;
867     w->after = after_cb;
868     w->before = before_cb;
869     w->data = data;
870     return w;
871
872 }
873
874
875 #if 0
876 /* these extract binary values */
877
878 static int cond_ft(tvbparse_t* tt, int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
879     guint len = 0;
880
881     if ( offset + wanted->len > tt->end_offset )
882         return -1;
883
884     if (wanted->len) {
885         return wanted->len;
886     } else if (wanted->control.ftenum == FT_STRINGZ) {
887         if (( len = tvb_find_guint8(tt->tvb,offset,tt->end_offset - offset,'\0') >= 0 )) {
888             *tok = new_tok(tt,wanted->id,offset,len,wanted);
889             return len;
890         } else {
891             return -1;
892         }
893     } else {
894         return -2;
895     }
896 }
897
898 gint ft_lens[] = {-1,-1,-1, 1, 2, 3, 4, 8, 1, 2, 3, 4, 8, 4, 8,-1,-1,-1, 0, -1, 6, -1, -1, 4, sizeof(struct e_in6_addr), -1, -1, -1, -1 };
899
900 tvbparse_wanted_t* tvbparse_ft(int id,
901                                const void* data,
902                                tvbparse_action_t before_cb,
903                                tvbparse_action_t after_cb,
904                                enum ftenum ftenum) {
905     gint len = ft_lens[ftenum];
906
907     if (len >= 0) {
908         tvbparse_wanted_t* w = g_malloc0(sizeof(tvbparse_wanted_t));
909
910         w->id = id;
911         w->condition = cond_ft;
912         w->len = len;
913         w->control.ftenum = ftenum;
914         w->after = after_cb;
915         w->before = before_cb;
916         w->data = data;
917
918         return w;
919     } else {
920         g_assert(! "unsupported ftenum" );
921         return NULL;
922     }
923 }
924
925 static int cond_ft_comp(tvbparse_t* tt, int offset, const tvbparse_wanted_t * wanted _U_, tvbparse_elem_t** tok) {
926     void* l = wanted->control.number.extract(tt->tvb,offset);
927     const void* r = &(wanted->control.number.value);
928
929     if ( offset + wanted->len > tt->end_offset )
930         return -1;
931
932     if ( wanted->control.number.comp(&l,&r) ) {
933         *tok = new_tok(tt,wanted->id,offset,wanted->len,wanted);
934         return wanted->len;
935     } else {
936         return -1;
937     }
938 }
939
940 static gboolean comp_gt_i(void* lp, const void* rp) { return ( *((gint64*)lp) > *((gint64*)rp) ); }
941 static gboolean comp_ge_i(void* lp, const void* rp) { return ( *((gint64*)lp) >= *((gint64*)rp) ); }
942 static gboolean comp_eq_i(void* lp, const void* rp) { return ( *((gint64*)lp) == *((gint64*)rp) ); }
943 static gboolean comp_ne_i(void* lp, const void* rp) { return ( *((gint64*)lp) != *((gint64*)rp) ); }
944 static gboolean comp_le_i(void* lp, const void* rp) { return ( *((gint64*)lp) <= *((gint64*)rp) ); }
945 static gboolean comp_lt_i(void* lp, const void* rp) { return ( *((gint64*)lp) < *((gint64*)rp) ); }
946
947 static gboolean comp_gt_u(void* lp, const void* rp) { return ( *((guint64*)lp) > *((guint64*)rp) ); }
948 static gboolean comp_ge_u(void* lp, const void* rp) { return ( *((guint64*)lp) >= *((guint64*)rp) ); }
949 static gboolean comp_eq_u(void* lp, const void* rp) { return ( *((guint64*)lp) == *((guint64*)rp) ); }
950 static gboolean comp_ne_u(void* lp, const void* rp) { return ( *((guint64*)lp) != *((guint64*)rp) ); }
951 static gboolean comp_le_u(void* lp, const void* rp) { return ( *((guint64*)lp) <= *((guint64*)rp) ); }
952 static gboolean comp_lt_u(void* lp, const void* rp) { return ( *((guint64*)lp) < *((guint64*)rp) ); }
953
954 static gboolean comp_gt_f(void* lp, const void* rp) { return ( *((gdouble*)lp) > *((gdouble*)rp) ); }
955 static gboolean comp_ge_f(void* lp, const void* rp) { return ( *((gdouble*)lp) >= *((gdouble*)rp) ); }
956 static gboolean comp_eq_f(void* lp, const void* rp) { return ( *((gdouble*)lp) == *((gdouble*)rp) ); }
957 static gboolean comp_ne_f(void* lp, const void* rp) { return ( *((gdouble*)lp) != *((gdouble*)rp) ); }
958 static gboolean comp_le_f(void* lp, const void* rp) { return ( *((gdouble*)lp) <= *((gdouble*)rp) ); }
959 static gboolean comp_lt_f(void* lp, const void* rp) { return ( *((gdouble*)lp) < *((gdouble*)rp) ); }
960
961 static void* extract_u8(tvbuff_t* tvb, guint offset) {
962     guint64* p = ep_new(guint64);
963     *p = tvb_get_guint8(tvb,offset);
964     return p;
965 }
966
967 static void* extract_uns(tvbuff_t* tvb, guint offset) {
968     guint64* p = ep_new(guint64);
969     *p = tvb_get_ntohs(tvb,offset);
970     return p;
971 }
972
973 static void* extract_un24(tvbuff_t* tvb, guint offset) {
974     guint64* p = ep_new(guint64);
975     *p = tvb_get_ntoh24(tvb,offset);
976     return p;
977 }
978
979 static void* extract_unl(tvbuff_t* tvb, guint offset) {
980     guint64* p = ep_new(guint64);
981     *p = tvb_get_ntohl(tvb,offset);
982     return p;
983 }
984
985 static void* extract_un64(tvbuff_t* tvb, guint offset) {
986     guint64* p = ep_new(guint64);
987     *p = tvb_get_ntoh64(tvb,offset);
988     return p;
989 }
990
991 static void* extract_ules(tvbuff_t* tvb, guint offset) {
992     guint64* p = ep_new(guint64);
993     *p = tvb_get_letohs(tvb,offset);
994     return p;
995 }
996
997 static void* extract_ule24(tvbuff_t* tvb, guint offset) {
998     guint64* p = ep_new(guint64);
999     *p = tvb_get_letoh24(tvb,offset);
1000     return p;
1001 }
1002
1003 static void* extract_ulel(tvbuff_t* tvb, guint offset) {
1004     guint64* p = ep_new(guint64);
1005     *p = tvb_get_letohl(tvb,offset);
1006     return p;
1007 }
1008
1009 static void* extract_ule64(tvbuff_t* tvb, guint offset) {
1010     guint64* p = ep_new(guint64);
1011     *p = tvb_get_letoh64(tvb,offset);
1012     return p;
1013 }
1014
1015 static void* extract_ins(tvbuff_t* tvb, guint offset) {
1016     guint64* p = ep_new(guint64);
1017     *p = tvb_get_ntohs(tvb,offset);
1018     return p;
1019 }
1020
1021 static void* extract_in24(tvbuff_t* tvb, guint offset) {
1022     guint64* p = ep_new(guint64);
1023     *p = tvb_get_ntoh24(tvb,offset);
1024     return p;
1025 }
1026
1027 static void* extract_inl(tvbuff_t* tvb, guint offset) {
1028     guint64* p = ep_new(guint64);
1029     *p = tvb_get_ntohl(tvb,offset);
1030     return p;
1031 }
1032
1033 static void* extract_in64(tvbuff_t* tvb, guint offset) {
1034     guint64* p = ep_new(guint64);
1035     *p = tvb_get_ntoh64(tvb,offset);
1036     return p;
1037 }
1038
1039 static void* extract_iles(tvbuff_t* tvb, guint offset) {
1040     guint64* p = ep_new(guint64);
1041     *p = tvb_get_letohs(tvb,offset);
1042     return p;
1043 }
1044
1045 static void* extract_ile24(tvbuff_t* tvb, guint offset) {
1046     guint64* p = ep_new(guint64);
1047     *p = tvb_get_letoh24(tvb,offset);
1048     return p;
1049 }
1050
1051 static void* extract_ilel(tvbuff_t* tvb, guint offset) {
1052     guint64* p = ep_new(guint64);
1053     *p = tvb_get_letohl(tvb,offset);
1054     return p;
1055 }
1056
1057 static void* extract_ile64(tvbuff_t* tvb, guint offset) {
1058     guint64* p = ep_new(guint64);
1059     *p = tvb_get_letoh64(tvb,offset);
1060     return p;
1061 }
1062
1063 static void* extract_inf(tvbuff_t* tvb, guint offset) {
1064     gdouble* p = ep_new(gdouble);
1065     *p = tvb_get_ntohieee_float(tvb,offset);
1066     return p;
1067 }
1068
1069 static void* extract_ind(tvbuff_t* tvb, guint offset) {
1070     gdouble* p = ep_new(gdouble);
1071     *p = tvb_get_ntohieee_double(tvb,offset);
1072     return p;
1073 }
1074
1075 static void* extract_ilef(tvbuff_t* tvb, guint offset) {
1076     gdouble* p = ep_new(gdouble);
1077     *p = tvb_get_letohieee_float(tvb,offset);
1078     return p;
1079 }
1080
1081 static void* extract_iled(tvbuff_t* tvb, guint offset) {
1082     gdouble* p = ep_new(gdouble);
1083     *p = tvb_get_letohieee_double(tvb,offset);
1084     return p;
1085 }
1086
1087
1088
1089 static gboolean (*comps_u[])(void*, const void*) = {comp_gt_u,comp_ge_u,comp_eq_u,comp_ne_u,comp_le_u,comp_lt_u};
1090 static gboolean (*comps_i[])(void*, const void*) = {comp_gt_i,comp_ge_i,comp_eq_i,comp_ne_i,comp_le_i,comp_lt_i};
1091 static gboolean (*comps_f[])(void*, const void*) = {comp_gt_f,comp_ge_f,comp_eq_f,comp_ne_f,comp_le_f,comp_lt_f};
1092
1093 static gboolean (**comps[])(void*, const void*) = {comps_u,comps_i,comps_f};
1094
1095 static void* (*extract_n[])(tvbuff_t* tvb, guint offset)  =  {
1096     NULL, NULL, NULL, extract_u8, extract_uns, extract_un24, extract_unl,
1097     extract_un64, extract_u8, extract_ins, extract_in24, extract_inl,
1098     extract_in64, extract_inf, extract_ind, NULL, NULL, NULL, NULL, NULL, NULL,
1099     NULL, NULL, NULL, NULL, NULL, NULL,NULL, NULL
1100 };
1101 static void* (*extract_le[])(tvbuff_t* tvb, guint offset)  =  {
1102     NULL, NULL, NULL, extract_u8, extract_ules, extract_ule24, extract_ulel,
1103     extract_ule64, extract_u8, extract_iles, extract_ile24, extract_ilel,
1104     extract_ile64, extract_ilef, extract_iled, NULL, NULL, NULL, NULL, NULL,
1105     NULL, NULL, NULL, NULL, NULL, NULL, NULL,NULL, NULL
1106 };
1107
1108 static void* (**extracts[])(tvbuff_t* tvb, guint offset) = { extract_n, extract_le};
1109
1110
1111 tvbparse_wanted_t* tvbparse_ft_numcmp(int id,
1112                                       const void* data,
1113                                       tvbparse_action_t before_cb,
1114                                       tvbparse_action_t after_cb,
1115                                       enum ftenum ftenum,
1116                                       int little_endian,
1117                                       enum ft_cmp_op ft_cmp_op,
1118                                       ... ) {
1119     tvbparse_wanted_t* w = g_malloc0(sizeof(tvbparse_wanted_t));
1120     va_list ap;
1121
1122     va_start(ap,ft_cmp_op);
1123
1124     switch (ftenum) {
1125         case FT_UINT8:
1126         case FT_UINT16:
1127         case FT_UINT24:
1128         case FT_UINT32:
1129             w->control.number.comp = comps[0][ft_cmp_op];
1130             w->control.number.value.u = va_arg(ap,guint32);
1131             break;
1132         case FT_UINT64:
1133             w->control.number.comp = comps[0][ft_cmp_op];
1134             w->control.number.value.u = va_arg(ap,guint64);
1135             break;
1136         case FT_INT8:
1137         case FT_INT16:
1138         case FT_INT24:
1139         case FT_INT32:
1140             w->control.number.comp = comps[1][ft_cmp_op];
1141             w->control.number.value.i = va_arg(ap,gint32);
1142             break;
1143         case FT_INT64:
1144             w->control.number.comp = comps[1][ft_cmp_op];
1145             w->control.number.value.i = va_arg(ap,gint64);
1146             break;
1147         case FT_FLOAT:
1148         case FT_DOUBLE:
1149             w->control.number.comp = comps[1][ft_cmp_op];
1150             w->control.number.value.i = va_arg(ap,gdouble);
1151             break;
1152         default:
1153             g_assert(! "comparison unsupported");
1154     }
1155
1156     w->control.number.extract = extracts[little_endian][ftenum];
1157
1158     g_assert(w->control.number.extract && "extraction unsupported");
1159
1160     w->id = id;
1161     w->condition = cond_ft_comp;
1162     w->after = after_cb;
1163     w->before = before_cb;
1164     w->data = data;
1165
1166     return w;
1167 }
1168
1169 #endif
1170
1171
1172 tvbparse_wanted_t* tvbparse_quoted(const int id,
1173                                    const void* data,
1174                                    tvbparse_action_t before_cb,
1175                                    tvbparse_action_t after_cb,
1176                                    const char quote,
1177                                    const char esc) {
1178
1179     gchar* esc_quot = g_strdup_printf("%c%c",esc,quote);
1180     gchar* quot = g_strdup_printf("%c",quote);
1181     tvbparse_wanted_t* want_quot = tvbparse_char(-1,quot,NULL,NULL,NULL);
1182
1183     return tvbparse_set_oneof(id, data, before_cb, after_cb,
1184                               tvbparse_set_seq(-1, NULL, NULL, NULL,
1185                                                want_quot,
1186                                                tvbparse_set_seq(-1,NULL,NULL,NULL,
1187                                                                 tvbparse_set_oneof(-1, NULL, NULL, NULL,
1188                                                                                    tvbparse_string(-1,esc_quot,NULL,NULL,NULL),
1189                                                                                    tvbparse_not_chars(-1,0,0,quot,NULL,NULL,NULL),
1190                                                                                    NULL),
1191                                                                 NULL),
1192                                                want_quot,
1193                                                NULL),
1194                               tvbparse_set_seq(-1, NULL, NULL, NULL,
1195                                                want_quot,
1196                                                want_quot,
1197                                                NULL),
1198                               NULL);
1199 }
1200
1201 void tvbparse_shrink_token_cb(void* tvbparse_data _U_,
1202                               const void* wanted_data _U_,
1203                               tvbparse_elem_t* tok) {
1204     tok->offset += 1;
1205     tok->len -= 2;
1206 }
1207
1208 tvbparse_t* tvbparse_init(tvbuff_t* tvb,
1209                           const int offset,
1210                           int len,
1211                           void* data,
1212                           const tvbparse_wanted_t* ignore) {
1213     tvbparse_t* tt = (tvbparse_t *)ep_alloc(sizeof(tvbparse_t));
1214
1215 #ifdef TVBPARSE_DEBUG
1216     if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_TT) g_warning("tvbparse_init: offset=%i len=%i",offset,len);
1217 #endif
1218
1219
1220     tt->tvb = tvb;
1221     tt->offset = offset;
1222     len = (len == -1) ? (int) tvb_length(tvb) : len;
1223     tt->end_offset = offset + len;
1224     tt->data = data;
1225     tt->ignore = ignore;
1226     return tt;
1227 }
1228
1229 gboolean tvbparse_reset(tvbparse_t* tt,
1230                         const int offset,
1231                         int len) {
1232
1233 #ifdef TVBPARSE_DEBUG
1234     if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_TT) g_warning("tvbparse_init: offset=%i len=%i",offset,len);
1235 #endif
1236
1237     len = (len == -1) ? (int) tvb_length(tt->tvb) : len;
1238
1239     if( tvb_length_remaining(tt->tvb, offset) >= len) {
1240         tt->offset = offset;
1241         tt->end_offset = offset + len;
1242         return TRUE;
1243     } else {
1244         return FALSE;
1245     }
1246 }
1247
1248 guint tvbparse_curr_offset(tvbparse_t* tt) {
1249     return tt->offset;
1250 }
1251
1252 static void execute_callbacks(tvbparse_t* tt, tvbparse_elem_t* curr) {
1253     ep_stack_t stack = ep_stack_new();
1254
1255     while (curr) {
1256         if(curr->wanted->before) {
1257 #ifdef TVBPARSE_DEBUG
1258             if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CB) g_warning("execute_callbacks: BEFORE: id=%i offset=%i len=%i",curr->id,curr->offset,curr->len);
1259 #endif
1260             curr->wanted->before(tt->data, curr->wanted->data, curr);
1261         }
1262
1263         if(curr->sub) {
1264             ep_stack_push(stack,curr);
1265             curr = curr->sub;
1266             continue;
1267         } else {
1268 #ifdef TVBPARSE_DEBUG
1269             if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CB) g_warning("execute_callbacks: AFTER: id=%i offset=%i len=%i",curr->id,curr->offset,curr->len);
1270 #endif
1271             if(curr->wanted->after) curr->wanted->after(tt->data, curr->wanted->data, curr);
1272         }
1273
1274         curr = curr->next;
1275
1276         while( !curr && ep_stack_peek(stack) ) {
1277             curr = (tvbparse_elem_t *)ep_stack_pop(stack);
1278 #ifdef TVBPARSE_DEBUG
1279             if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CB) g_warning("execute_callbacks: AFTER: id=%i offset=%i len=%i",curr->id,curr->offset,curr->len);
1280 #endif
1281             if( curr->wanted->after ) curr->wanted->after(tt->data, curr->wanted->data, curr);
1282             curr = curr->next;
1283         }
1284     }
1285
1286 }
1287
1288 gboolean tvbparse_peek(tvbparse_t* tt,
1289                        const tvbparse_wanted_t* wanted) {
1290     tvbparse_elem_t* tok = NULL;
1291     int consumed;
1292     int offset = tt->offset;
1293
1294 #ifdef TVBPARSE_DEBUG
1295     if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_PEEK) g_warning("tvbparse_peek: ENTER offset=%i",offset);
1296 #endif
1297
1298     offset += ignore_fcn(tt,offset);
1299
1300 #ifdef TVBPARSE_DEBUG
1301     if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_PEEK) g_warning("tvbparse_peek: after ignore offset=%i",offset);
1302 #endif
1303
1304     consumed = wanted->condition(tt,offset,wanted,&tok);
1305
1306     if (consumed >= 0) {
1307 #ifdef TVBPARSE_DEBUG
1308         if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_PEEK) g_warning("tvbparse_peek: GOT len=%i",consumed);
1309 #endif
1310         return TRUE;
1311     } else {
1312 #ifdef TVBPARSE_DEBUG
1313         if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_PEEK) g_warning("tvbparse_peek: NOT GOT");
1314 #endif
1315         return FALSE;
1316     }
1317
1318 }
1319
1320 tvbparse_elem_t* tvbparse_get(tvbparse_t* tt,
1321                               const tvbparse_wanted_t* wanted) {
1322     tvbparse_elem_t* tok = NULL;
1323     int consumed;
1324     int offset = tt->offset;
1325
1326 #ifdef TVBPARSE_DEBUG
1327     if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_GET) g_warning("tvbparse_get: ENTER offset=%i",offset);
1328 #endif
1329
1330     offset += ignore_fcn(tt,offset);
1331
1332 #ifdef TVBPARSE_DEBUG
1333     if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_GET) g_warning("tvbparse_get: after ignore offset=%i",offset);
1334 #endif
1335
1336     consumed = wanted->condition(tt,offset,wanted,&tok);
1337
1338     if (consumed >= 0) {
1339 #ifdef TVBPARSE_DEBUG
1340         if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_GET) g_warning("tvbparse_get: GOT len=%i",consumed);
1341 #endif
1342         execute_callbacks(tt,tok);
1343         tt->offset = offset + consumed;
1344 #ifdef TVBPARSE_DEBUG
1345         if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_GET) g_warning("tvbparse_get: DONE offset=%i", tt->offset);
1346 #endif
1347         return tok;
1348     } else {
1349         return NULL;
1350     }
1351
1352 }
1353
1354
1355 tvbparse_elem_t* tvbparse_find(tvbparse_t* tt, const tvbparse_wanted_t* wanted) {
1356     tvbparse_elem_t* tok = NULL;
1357     int len = 0;
1358     int offset = tt->offset;
1359     int target_offset = offset -1;
1360
1361 #ifdef TVBPARSE_DEBUG
1362     if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_FIND) g_warning("tvbparse_get: ENTER offset=%i", tt->offset);
1363 #endif
1364
1365     do {
1366         len = wanted->condition(tt, target_offset+1, wanted,  &tok);
1367     } while(len < 0  && ++target_offset < tt->end_offset);
1368
1369     if (len >= 0) {
1370 #ifdef TVBPARSE_DEBUG
1371         if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_FIND) g_warning("tvbparse_get: FOUND offset=%i len=%i", target_offset,len);
1372 #endif
1373         execute_callbacks(tt,tok);
1374         tt->offset = target_offset + len;
1375
1376 #ifdef TVBPARSE_DEBUG
1377         if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_FIND) g_warning("tvbparse_get: DONE offset=%i", tt->offset);
1378 #endif
1379         return tok;
1380     } else {
1381 #ifdef TVBPARSE_DEBUG
1382         if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_FIND) g_warning("tvbparse_get: NOT FOUND");
1383 #endif
1384         return NULL;
1385     }
1386 }
1387
1388 struct _elem_tree_stack_frame {
1389     proto_tree* tree;
1390     tvbparse_elem_t* elem;
1391 };
1392
1393 void tvbparse_tree_add_elem(proto_tree* tree, tvbparse_elem_t* curr) {
1394     ep_stack_t stack = ep_stack_new();
1395     struct _elem_tree_stack_frame* frame = (struct _elem_tree_stack_frame *)ep_alloc(sizeof(struct _elem_tree_stack_frame));
1396     proto_item* pi;
1397     frame->tree = tree;
1398     frame->elem = curr;
1399
1400     while (curr) {
1401         pi = proto_tree_add_text(frame->tree,curr->tvb,curr->offset,curr->len,"%s",tvb_format_text(curr->tvb,curr->offset,curr->len));
1402
1403         if(curr->sub) {
1404             frame->elem = curr;
1405             ep_stack_push(stack,frame);
1406             frame = (struct _elem_tree_stack_frame *)ep_alloc(sizeof(struct _elem_tree_stack_frame));
1407             frame->tree = proto_item_add_subtree(pi,0);
1408             curr = curr->sub;
1409             continue;
1410         }
1411
1412         curr = curr->next;
1413
1414         while( !curr && ep_stack_peek(stack) ) {
1415             frame = (struct _elem_tree_stack_frame *)ep_stack_pop(stack);
1416             curr = frame->elem->next;
1417         }
1418
1419     }
1420 }
1421