add a debugging function that creates a tree exploding the parsed elements
[metze/wireshark/wip.git] / epan / tvbparse.c
1 /* tvbparse.c
2 *
3 * Copyright 2005, Luis E. Garcia Ontanon <luis.ontanon@gmail.com>
4 *
5 * $Id$
6 *
7 * Ethereal - Network traffic analyzer
8 * By Gerald Combs <gerald@ethereal.com>
9 * Copyright 1998 Gerald Combs
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
15
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 * GNU General Public License for more details.
20
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include <stdlib.h>
31 #include <string.h>
32 #include <glib.h>
33
34 #include <epan/emem.h>
35 #include <epan/proto.h>
36 #include <epan/tvbparse.h>
37
38 typedef enum _tvbparse_wanted_type_t {
39         TVBPARSE_WANTED_NONE, /* currently unused */
40         
41         /* simple tokens */
42         TVBPARSE_WANTED_SIMPLE_CHAR, /* just one matching char */
43         TVBPARSE_WANTED_SIMPLE_CHARS, /* a sequence of matching chars */
44         TVBPARSE_WANTED_SIMPLE_NOT_CHAR, /* one non matching char */ 
45         TVBPARSE_WANTED_SIMPLE_NOT_CHARS, /* a sequence of non matching chars */
46         TVBPARSE_WANTED_SIMPLE_STRING, /* a string */
47         TVBPARSE_WANTED_SIMPLE_CASESTRING, /* a caseless string */
48         TVBPARSE_WANTED_UNTIL, /* all the characters until the first matching token */
49         
50         /* composed tokens */
51         TVBPARSE_WANTED_SET_ONEOF, /* one of the given types */
52         TVBPARSE_WANTED_SET_SEQ, /* an exact sequence of tokens of the given types */
53         TVBPARSE_WANTED_CARDINALITY, /* one or more tokens of the given type */ 
54     TVBPARSE_WANTED_HANDLE,  /* a handle to another one */
55     
56 } tvbparse_type_t;
57
58 struct _tvbparse_t {
59         tvbuff_t* tvb;
60         int offset;
61         int max_len;
62         void* data;
63         const tvbparse_wanted_t* ignore;
64         guint depth;
65 };
66
67 struct _tvbparse_wanted_t {
68         int id;
69         tvbparse_type_t type;
70         
71         union {
72         const gchar* str;
73         guint val;
74         struct _tvbparse_wanted_t** handle;
75     } control;
76     
77         int len;
78         
79         guint min;
80         guint max;
81         
82         const void* data;
83         tvbparse_action_t before;
84         tvbparse_action_t after;
85         
86         GPtrArray* elems;
87 };
88
89
90 tvbparse_wanted_t* tvbparse_char(int id,
91                                                   const gchar* chr,
92                                                   const void* data,
93                                                   tvbparse_action_t before_cb,
94                                                   tvbparse_action_t after_cb) {
95         tvbparse_wanted_t* w = g_malloc(sizeof(tvbparse_wanted_t));
96         
97         w->id = id;
98         w->type = TVBPARSE_WANTED_SIMPLE_CHAR;
99         w->control.str = chr;
100         w->len = 1;
101         w->min = 0;
102         w->max = 0;
103         w->data = data;
104         w->before = before_cb;
105         w->after = after_cb;
106         w->elems = g_ptr_array_new();
107         
108         return w;
109 }
110
111 tvbparse_wanted_t* tvbparse_chars(int id,
112                                                                   guint min_len,
113                                                                   guint max_len,
114                                                                   const gchar* chr,
115                                                                   const void* data,
116                                                                   tvbparse_action_t before_cb,
117                                                                   tvbparse_action_t after_cb) {
118         tvbparse_wanted_t* w = g_malloc(sizeof(tvbparse_wanted_t));
119         
120         w->id = id;
121         w->type = TVBPARSE_WANTED_SIMPLE_CHARS;
122         w->control.str = chr;
123         w->len = 0;
124         w->min = min_len ? min_len : 1;
125         w->max = max_len ? max_len : G_MAXINT;
126         w->data = data;
127         w->before = before_cb;
128         w->after = after_cb;
129         w->elems = g_ptr_array_new();
130         
131         return w;
132 }
133
134 tvbparse_wanted_t* tvbparse_not_char(int id,
135                                                           const gchar* chr,
136                                                           const void* data,
137                                                           tvbparse_action_t before_cb,
138                                                           tvbparse_action_t after_cb) {
139         tvbparse_wanted_t* w = g_malloc(sizeof(tvbparse_wanted_t));
140         
141         w->id = id;
142         w->type = TVBPARSE_WANTED_SIMPLE_NOT_CHAR;
143         w->control.str = chr;
144         w->len = 0;
145         w->min = 0;
146         w->max = 0;
147         w->data = data;
148         w->before = before_cb;
149         w->after = after_cb;
150         w->elems = g_ptr_array_new();
151         
152         return w;
153 }
154
155 tvbparse_wanted_t* tvbparse_not_chars(int id,
156                                                                           guint min_len,
157                                                                           guint max_len,
158                                                                           const gchar* chr,
159                                                                           const void* data,
160                                                                           tvbparse_action_t before_cb,
161                                                                           tvbparse_action_t after_cb){
162         tvbparse_wanted_t* w = g_malloc(sizeof(tvbparse_wanted_t));
163         
164         w->id = id;
165         w->type = TVBPARSE_WANTED_SIMPLE_NOT_CHARS;
166         w->control.str = chr;
167         w->len = 0;
168         w->min = min_len ? min_len : 1;
169         w->max = max_len ? max_len : G_MAXINT;
170         w->data = data;
171         w->before = before_cb;
172         w->after = after_cb;
173         w->elems = g_ptr_array_new();
174         
175         return w;
176 }
177
178
179 tvbparse_wanted_t* tvbparse_string(int id,
180                                                                    const gchar* str,
181                                                                    const void* data,
182                                                                    tvbparse_action_t before_cb,
183                                                                    tvbparse_action_t after_cb) {
184         tvbparse_wanted_t* w = g_malloc(sizeof(tvbparse_wanted_t));
185         
186         w->id = id;
187         w->type = TVBPARSE_WANTED_SIMPLE_STRING;
188         w->control.str = str;
189         w->len = strlen(str);
190         w->min = 0;
191         w->max = 0;
192         w->data = data;
193         w->before = before_cb;
194         w->after = after_cb;
195         w->elems = g_ptr_array_new();
196         
197         return w;
198 }
199
200 tvbparse_wanted_t* tvbparse_casestring(int id,
201                                                                    const gchar* str,
202                                                                    const void* data,
203                                                                    tvbparse_action_t before_cb,
204                                                                    tvbparse_action_t after_cb) {
205         tvbparse_wanted_t* w = g_malloc(sizeof(tvbparse_wanted_t));
206         
207         w->id = id;
208         w->type = TVBPARSE_WANTED_SIMPLE_CASESTRING;
209         w->control.str = str;
210         w->len = strlen(str);
211         w->min = 0;
212         w->max = 0;
213         w->data = data;
214         w->before = before_cb;
215         w->after = after_cb;
216         w->elems = g_ptr_array_new();
217         
218         return w;
219 }
220
221
222 tvbparse_wanted_t* tvbparse_set_oneof(int id,
223                                                            const void* data, 
224                                                            tvbparse_action_t before_cb,
225                                                            tvbparse_action_t after_cb,
226                                                            ...) {
227         tvbparse_wanted_t* w = g_malloc(sizeof(tvbparse_wanted_t));
228         tvbparse_t* el;
229         va_list ap;
230         
231         w->id = id;
232         w->type = TVBPARSE_WANTED_SET_ONEOF;
233         w->control.val = 0;
234         w->len = 0;
235         w->min = 0;
236         w->max = 0;
237         w->data = data;
238         w->before = before_cb;
239         w->after = after_cb;
240         w->elems = g_ptr_array_new();
241         
242         va_start(ap,after_cb);
243         
244         while(( el = va_arg(ap,tvbparse_t*) )) {
245                 g_ptr_array_add(w->elems,el);
246         };
247         
248         va_end(ap);
249         
250         return w;
251 }
252
253 tvbparse_wanted_t* tvbparse_set_seq(int id,
254                                                          const void* data,
255                                                          tvbparse_action_t before_cb,
256                                                          tvbparse_action_t after_cb,
257                                                          ...) {
258         tvbparse_wanted_t* w = g_malloc(sizeof(tvbparse_wanted_t));
259         tvbparse_wanted_t*  el = NULL;
260         va_list ap;
261         
262         w->id = id;
263         w->type = TVBPARSE_WANTED_SET_SEQ;
264         w->control.val = 0;
265         w->len = 0;
266         w->min = 0;
267         w->max = 0;
268         w->data = data;
269         w->before = before_cb;
270         w->after = after_cb;
271         w->elems = g_ptr_array_new();
272         
273         va_start(ap,after_cb);
274         
275         while(( el = va_arg(ap,tvbparse_wanted_t*) )) {
276                 g_ptr_array_add(w->elems,el);
277         };
278         
279         va_end(ap);
280         return w;
281 }
282
283
284 tvbparse_wanted_t* tvbparse_some(int id,
285                                                                  guint from,
286                                                                  guint to,
287                                                                  const void* data,
288                                                                  tvbparse_action_t before_cb,
289                                                                  tvbparse_action_t after_cb,
290                                                                  const tvbparse_wanted_t* el) {
291         
292         tvbparse_wanted_t* w = g_malloc(sizeof(tvbparse_wanted_t));
293         
294         g_assert(from <= to);
295         
296         w->id = id;
297         w->type = TVBPARSE_WANTED_CARDINALITY;
298         w->control.val = 0;
299         w->len = 0;
300         w->min = from;
301         w->max = to;
302         w->data = data;
303         w->before = before_cb;
304         w->after = after_cb;
305         w->elems = g_ptr_array_new();
306         
307         g_ptr_array_add(w->elems,(gpointer)el);
308         
309         return w;
310 }
311
312 tvbparse_wanted_t* tvbparse_until(int id,
313                                                    const void* data,
314                                                    tvbparse_action_t before_cb,
315                                                    tvbparse_action_t after_cb,
316                                                    const tvbparse_wanted_t* el,
317                                                    int op_mode) {
318         tvbparse_wanted_t* w = g_malloc(sizeof(tvbparse_wanted_t));
319         
320         w->id = id;
321         w->type = TVBPARSE_WANTED_UNTIL;
322         
323         w->control.val = op_mode;
324         
325         w->len = 0;
326         w->min = 0;
327         w->max = 0;
328         w->data = data;
329         w->before = before_cb;
330         w->after = after_cb;
331         w->elems = g_ptr_array_new();
332         
333         g_ptr_array_add(w->elems,(gpointer)el);
334         
335         return w;
336 }
337
338 tvbparse_wanted_t* tvbparse_handle(tvbparse_wanted_t** handle) {
339         tvbparse_wanted_t* w = g_malloc(sizeof(tvbparse_wanted_t));
340         
341         w->id = 0;
342         w->type = TVBPARSE_WANTED_HANDLE;
343         
344         w->control.handle = handle;
345         
346         w->len = 0;
347         w->min = 0;
348         w->max = 0;
349         w->data = NULL;
350         w->before = NULL;
351         w->after = NULL;
352         w->elems = NULL;
353         
354         return w;
355 }
356
357
358 tvbparse_wanted_t* tvbparse_quoted(int id,
359                                                                    const void* data,
360                                                                    tvbparse_action_t before_cb,
361                                                                    tvbparse_action_t after_cb,
362                                                                    char quote,
363                                                                    char esc) {
364         
365         gchar* esc_quot = g_strdup_printf("%c%c",esc,quote);
366         gchar* quot = g_strdup_printf("%c",quote);
367         tvbparse_wanted_t* want_quot = tvbparse_char(-1,quot,NULL,NULL,NULL);
368         
369         return tvbparse_set_oneof(id, data, before_cb, after_cb,
370                                                           tvbparse_set_seq(-1, NULL, NULL, NULL,
371                                                                                            want_quot,
372                                                                                            tvbparse_set_seq(-1,NULL,NULL,NULL,
373                                                                                                                                 tvbparse_set_oneof(-1, NULL, NULL, NULL,
374                                                                                                                                                                    tvbparse_string(-1,esc_quot,NULL,NULL,NULL),
375                                                                                                                                                                    tvbparse_not_chars(-1,0,0,quot,NULL,NULL,NULL),
376                                                                                                                                                                    NULL),
377                                                                                                                                 NULL),
378                                                                                            want_quot,
379                                                                                            NULL),
380                                                           tvbparse_set_seq(-1, NULL, NULL, NULL,
381                                                                                            want_quot,
382                                                                                            want_quot,
383                                                                                            NULL),                                                                                                               
384                                                           NULL);
385         
386 }
387
388 void tvbparse_shrink_token_cb(void* tvbparse_data _U_,
389                                                           const void* wanted_data _U_,
390                                                           tvbparse_elem_t* tok) {
391         tok->offset += 1;
392         tok->len -= 2;
393 }
394
395 tvbparse_t* tvbparse_init(tvbuff_t* tvb,
396                                                   int offset,
397                                                   int len,
398                                                   void* data,
399                                                   const tvbparse_wanted_t* ignore) {
400         tvbparse_t* tt = ep_alloc(sizeof(tvbparse_t));
401         
402         tt->tvb = tvb;
403         tt->offset = offset;
404         tt->max_len = (len == -1) ? (int) tvb_length(tvb) : len;
405         tt->data = data;
406         tt->ignore = ignore;
407         tt->depth = 0;
408         return tt;
409 }
410
411 gboolean tvbparse_reset(tvbparse_t* tt,
412                                                 int offset,
413                                                 int len) {
414         
415         len = (len == -1) ? (int) tvb_length(tt->tvb) : len;
416         
417         if( tvb_length_remaining(tt->tvb, offset) >= len) {
418                 tt->offset = offset;
419                 tt->max_len = len;
420                 tt->depth = 0;
421                 return TRUE;
422         } else {
423                 tt->depth = 0;
424                 return FALSE;
425         }
426 }
427
428 static tvbparse_elem_t* new_tok(tvbparse_t* tt,
429                                                            int id,
430                                                            int offset,
431                                                            int len,
432                                                            const tvbparse_wanted_t* wanted) {
433         tvbparse_elem_t* tok = ep_alloc(sizeof(tvbparse_elem_t));
434         
435         tok->tvb = tt->tvb;
436         tok->id = id;
437         tok->offset = offset;
438         tok->len = len;
439         tok->data = NULL;
440         tok->sub = NULL;
441         tok->next = NULL;
442         tok->wanted = wanted;
443         tok->last = tok;
444         
445         return tok;
446 }
447
448 guint tvbparse_curr_offset(tvbparse_t* tt) {
449     return tt->offset;
450 }
451 guint tvbparse_len_left(tvbparse_t* tt) {
452     return tt->max_len;
453 }
454
455 tvbparse_elem_t* tvbparse_get(tvbparse_t* tt,
456                                                                   const tvbparse_wanted_t* wanted) {
457         tvbparse_elem_t* tok = NULL;
458         int save_offset = tt->offset;
459         int save_len = tt->max_len;
460         
461         tt->depth++;
462         
463         if (tt->ignore && tt->ignore != wanted) {
464                 tvbparse_wanted_t* save = (void*)tt->ignore;
465                 tt->ignore = NULL;
466                 while ( tvbparse_get(tt,save) )  {
467                         ;
468                 }
469                 tt->ignore = save;
470         }
471         
472         switch(wanted->type) {
473                 case TVBPARSE_WANTED_NONE:
474                         goto reject;
475                 case TVBPARSE_WANTED_SIMPLE_NOT_CHAR:
476                 {
477                         gchar c, t;
478                         guint i;
479                         gboolean not_matched = FALSE;
480                         
481                         if (! tt->max_len )
482                                 goto reject;
483                         
484                         t = (gchar) tvb_get_guint8(tt->tvb,tt->offset);
485                         
486                         for(i = 0; (c = wanted->control.str[i]) && tt->max_len; i++) {
487                                 if ( c == t ) {
488                                         not_matched = TRUE;
489                                 }
490                         }
491                         
492                         if (not_matched) {
493                                 goto reject;
494                         } else {
495                                 tt->offset++;
496                                 tt->max_len--;
497                                 tok =  new_tok(tt,wanted->id,tt->offset-1,1,wanted);
498                                 goto accept;
499                         }
500                 }
501                 case TVBPARSE_WANTED_SIMPLE_CHAR:
502                 {
503                         gchar c,t;
504                         guint i;
505                         
506                         if (! tt->max_len )
507                                 goto reject;
508                         
509                         t = (gchar) tvb_get_guint8(tt->tvb,tt->offset);
510                         
511                         for(i = 0; (c = wanted->control.str[i]) && tt->max_len; i++) {
512                                 if ( c == t ) {
513                                         tt->offset++;
514                                         tt->max_len--;
515                                         tok =  new_tok(tt,wanted->id,tt->offset-1,1,wanted);
516                                         goto accept;
517                                 }
518                         }
519                         goto reject;
520                 }
521                 case TVBPARSE_WANTED_SIMPLE_NOT_CHARS:
522                 {
523                         gchar c, t;
524                         guint i;
525                         guint offset = tt->offset;
526                         guint length = 0;
527                         
528                         while( tt->max_len && length < wanted->max) {
529                                 gboolean not_matched = FALSE;
530                                 t = (gchar) tvb_get_guint8(tt->tvb,tt->offset);
531                                 i = 0;
532                                 
533                                 while ( (c = wanted->control.str[i]) && tt->max_len ) {
534                                         
535                                         if (c == t) {
536                                                 not_matched = TRUE;
537                                         }
538                                         
539                                         i++;
540                                 }
541                                 
542                                 if ( not_matched )
543                                         break;
544
545                                 length++;
546                                 tt->offset++;
547                                 tt->max_len--;
548                         };
549                         
550                         if ( length < wanted->min ) {
551                                 goto reject;
552                         } else {
553                                 tok = new_tok(tt,wanted->id,offset,length,wanted);
554                                 goto accept;                    
555                         }
556                 }
557                 case TVBPARSE_WANTED_SIMPLE_CHARS:
558                 {
559                         gchar c, t;
560                         guint i;
561                         guint offset = tt->offset;
562                         guint length = 0;
563                         
564                         while( tt->max_len && length < wanted->max) {
565                                 gboolean matched = FALSE;
566                                 t = (gchar) tvb_get_guint8(tt->tvb,tt->offset);
567                                 i = 0;
568                                 
569                                 while ( (c = wanted->control.str[i]) && tt->max_len ) {
570                                         
571                                         if (c == t) {
572                                                 matched = TRUE;
573                                                 break;
574                                         }
575                                         
576                                         i++;
577                                 }
578                                 
579                                 if (! matched )
580                                         break;
581                                 
582                                 length++;
583                                 tt->offset++;
584                                 tt->max_len--;
585                         };
586                         
587                         if (length < wanted->min) {
588                                 goto reject;
589                         } else {
590                                 tok = new_tok(tt,wanted->id,offset,length,wanted);
591                                 goto accept;                    
592                         }
593                 }
594                 case TVBPARSE_WANTED_SIMPLE_STRING:
595                 {
596                         if ( tvb_strneql(tt->tvb, tt->offset, wanted->control.str, wanted->len) == 0 ) {
597                                 int offset = tt->offset;
598                                 tt->offset += wanted->len;
599                                 tt->max_len -= wanted->len;
600                                 tok = new_tok(tt,wanted->id,offset,wanted->len,wanted);
601                                 goto accept;
602                         } else {
603                                 goto reject;
604                         }
605                 }
606                 case TVBPARSE_WANTED_SIMPLE_CASESTRING:
607                 {
608                         if ( tvb_strncaseeql(tt->tvb, tt->offset, wanted->control.str, wanted->len) == 0 ) {
609                                 int offset = tt->offset;
610                                 tt->offset += wanted->len;
611                                 tt->max_len -= wanted->len;
612                                 tok = new_tok(tt,wanted->id,offset,wanted->len,wanted);
613                                 goto accept;
614                         } else {
615                                 goto reject;
616                         }
617                 }
618                 case TVBPARSE_WANTED_SET_ONEOF:
619                 {
620                         guint i;
621                         
622                         for(i=0; i < wanted->elems->len; i++) {
623                                 tvbparse_wanted_t* w = g_ptr_array_index(wanted->elems,i);
624                                 tvbparse_elem_t* new = tvbparse_get(tt, w);
625                                 
626                                 if (new) {
627                                         tok = new_tok(tt, wanted->id, new->offset, new->len, wanted);
628                                         tok->sub = new;
629                                         goto accept;                    
630                                 }
631                         }
632                         goto reject;
633                 }
634                 case TVBPARSE_WANTED_SET_SEQ:
635                 {
636                         guint i;
637                         
638                         for(i=0; i < wanted->elems->len; i++) {
639                                 tvbparse_wanted_t* w = g_ptr_array_index(wanted->elems,i);
640                                 tvbparse_elem_t* new = tvbparse_get(tt, w);
641                                 
642                                 if (new) {
643                                         if (tok) {
644                                                 tok->len = (new->offset - tok->offset) + new->len;
645                                                 tok->sub->last->next = new;
646                                                 tok->sub->last = new;
647                                         } else {
648                                                 tok = new_tok(tt, wanted->id, new->offset, new->len, wanted);
649                                                 tok->sub = new;
650                                         }
651                                 } else {
652                                         goto reject;
653                                 }
654                                 
655                         }
656                         
657                         goto accept;                    
658                 }
659                 case TVBPARSE_WANTED_CARDINALITY:
660                 {
661                         guint got_so_far = 0;
662                         tvbparse_wanted_t* w = g_ptr_array_index(wanted->elems,0);
663                         
664             if ( wanted->min == 0 ) {
665                 new_tok(tt,wanted->id,tt->offset,0,wanted);
666             }
667             
668                         while (got_so_far < wanted->max) {
669                                 tvbparse_elem_t* new = tvbparse_get(tt, w);
670                                 
671                                 if(new) {
672                                         if (tok) {
673                                                 tok->len = (new->offset - tok->offset) + new->len;
674                                                 tok->sub->last->next = new;
675                                                 tok->sub->last = new;
676                                         } else {
677                                                 tok = new_tok(tt, wanted->id, new->offset, new->len, wanted);
678                                                 tok->sub = new;
679                                         }
680                                 } else {
681                                         break;
682                                 }
683                                 
684                                 got_so_far++;
685                         }
686                         
687                         if(got_so_far < wanted->min) {
688                                 goto reject;
689                         }
690                         
691                         goto accept;                    
692                 }
693                 case TVBPARSE_WANTED_UNTIL:
694                 {
695                         int offset = tt->offset;
696                         tvbparse_wanted_t* w = g_ptr_array_index(wanted->elems,0);
697                         tvbparse_elem_t* new = tvbparse_find(tt, w);
698                         
699                         if (new) {
700                                 tok = new;
701                                 
702                                 switch (wanted->control.val) {
703                     case TP_UNTIL_INCLUDE:
704                         tok->len = (tok->offset - offset) + tok->len;
705                         break;
706                     case TP_UNTIL_LEAVE:
707                         tt->offset -= tok->len;
708                         tt->max_len += tok->len;
709                         /* fall through */
710                     case TP_UNTIL_SPEND:
711                         tok->len = (tok->offset - offset);
712                         break;
713                     default:
714                         DISSECTOR_ASSERT_NOT_REACHED();
715                                 }
716                                 
717                                 tok->offset = offset;
718                                 tok->id = wanted->id;
719                                 tok->next = NULL;
720                                 tok->last = tok;
721                                 tok->wanted = wanted;
722                                 
723                                 goto accept;
724                         } else {
725                                 goto reject;
726                         }
727                 }
728         case TVBPARSE_WANTED_HANDLE:
729         {
730             tok = tvbparse_get(tt, *(wanted->control.handle));
731             if (tok) {
732                 goto accept;
733             } else {
734                 goto reject;
735             }
736         }
737         }
738         
739         DISSECTOR_ASSERT_NOT_REACHED();
740         return NULL;
741         
742 accept:
743                 if (tok) {
744                         if( tt->depth == 1 ) {
745                                 GPtrArray* stack = g_ptr_array_new();
746                                 tvbparse_elem_t* curr = tok;
747                                 
748                                 while (curr) {
749                                         
750                                         if(curr->wanted->before) {
751                                                 curr->wanted->before(tt->data, curr->wanted->data, curr);
752                                         }
753                                         
754                                         if(curr->sub) {
755                                                 g_ptr_array_add(stack,curr);
756                                                 curr = curr->sub;
757                                                 continue;
758                                         } else {
759                                                 if(curr->wanted->after) curr->wanted->after(tt->data, curr->wanted->data, curr);
760                                         }
761                                         
762                                         curr = curr->next;
763                                         
764                                         while( !curr && stack->len ) {
765                                                 curr = g_ptr_array_remove_index_fast(stack,stack->len - 1);
766                                                 if( curr->wanted->after ) curr->wanted->after(tt->data, curr->wanted->data, curr);
767                                                 curr = curr->next;
768                                         }
769                                         
770                                 }
771                                 
772                                 g_ptr_array_free(stack,TRUE);
773                         }
774                         
775                         tt->depth--;
776                         return tok; 
777                 }
778         
779 reject:
780                 tt->offset = save_offset;
781         tt->max_len = save_len;
782         tt->depth--;
783         return NULL;
784                                 
785 }
786
787
788 tvbparse_elem_t* tvbparse_find(tvbparse_t* tt, const tvbparse_wanted_t* wanted) {
789         int save_offset = tt->offset;
790         int save_len = tt->max_len;
791         tvbparse_elem_t* tok = NULL;
792         
793         while ( tvb_length_remaining(tt->tvb,tt->offset) >= wanted->len ) {
794                 if (( tok = tvbparse_get(tt, wanted) )) {
795                         return tok;
796                 }
797                 tt->offset++;
798                 tt->max_len--;
799         }
800         
801         tt->offset = save_offset;
802         tt->max_len = save_len;
803         
804         return NULL;
805 }
806
807
808 static void tvbparse_tree_add_elem(proto_tree* tree, tvbparse_elem_t* curr) {
809     GPtrArray* stack = g_ptr_array_new();
810     struct _elem_tree_stack_frame* frame = ep_alloc(sizeof(struct _elem_tree_stack_frame));
811     proto_item* pi;
812     frame->tree = tree;
813     frame->elem = curr;
814     
815     while (curr) {
816         pi = proto_tree_add_text(frame->tree,curr->tvb,curr->offset,curr->len,"%s",tvb_format_text(curr->tvb,curr->offset,curr->len));
817         
818         if(curr->sub) {
819             frame->elem = curr;
820             g_ptr_array_add(stack,frame);
821             frame = ep_alloc(sizeof(struct _elem_tree_stack_frame));
822             frame->tree = proto_item_add_subtree(pi,0);
823             curr = curr->sub;
824             continue;
825         }
826         
827         curr = curr->next;
828         
829         while( !curr && stack->len ) {
830             frame = g_ptr_array_remove_index_fast(stack,stack->len - 1);
831             curr = frame->elem->next;
832         }
833         
834     }
835     
836     g_ptr_array_free(stack,TRUE);
837 }
838