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