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