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