in tvbparse:
[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     
55 } tvbparse_type_t;
56
57 struct _tvbparse_t {
58         tvbuff_t* tvb;
59         int offset;
60         int max_len;
61         void* data;
62         const tvbparse_wanted_t* ignore;
63         guint depth;
64 };
65
66 struct _tvbparse_wanted_t {
67         int id;
68         tvbparse_type_t type;
69         
70         const gchar* ctl;
71         int len;
72         
73         guint min;
74         guint max;
75         
76         const void* data;
77         tvbparse_action_t before;
78         tvbparse_action_t after;
79         
80         GPtrArray* elems;
81 };
82
83
84 tvbparse_wanted_t* tvbparse_char(int id,
85                                                   const gchar* chr,
86                                                   const void* data,
87                                                   tvbparse_action_t before_cb,
88                                                   tvbparse_action_t after_cb) {
89         tvbparse_wanted_t* w = g_malloc(sizeof(tvbparse_wanted_t));
90         
91         w->id = id;
92         w->type = TVBPARSE_WANTED_SIMPLE_CHAR;
93         w->ctl = chr;
94         w->len = 1;
95         w->min = 0;
96         w->max = 0;
97         w->data = data;
98         w->before = before_cb;
99         w->after = after_cb;
100         w->elems = g_ptr_array_new();
101         
102         return w;
103 }
104
105 tvbparse_wanted_t* tvbparse_chars(int id,
106                                                                   guint min_len,
107                                                                   guint max_len,
108                                                                   const gchar* chr,
109                                                                   const void* data,
110                                                                   tvbparse_action_t before_cb,
111                                                                   tvbparse_action_t after_cb) {
112         tvbparse_wanted_t* w = g_malloc(sizeof(tvbparse_wanted_t));
113         
114         w->id = id;
115         w->type = TVBPARSE_WANTED_SIMPLE_CHARS;
116         w->ctl = chr;
117         w->len = 0;
118         w->min = min_len ? min_len : 1;
119         w->max = max_len ? max_len : G_MAXINT;
120         w->data = data;
121         w->before = before_cb;
122         w->after = after_cb;
123         w->elems = g_ptr_array_new();
124         
125         return w;
126 }
127
128 tvbparse_wanted_t* tvbparse_not_char(int id,
129                                                           const gchar* chr,
130                                                           const void* data,
131                                                           tvbparse_action_t before_cb,
132                                                           tvbparse_action_t after_cb) {
133         tvbparse_wanted_t* w = g_malloc(sizeof(tvbparse_wanted_t));
134         
135         w->id = id;
136         w->type = TVBPARSE_WANTED_SIMPLE_NOT_CHAR;
137         w->ctl = chr;
138         w->len = 0;
139         w->min = 0;
140         w->max = 0;
141         w->data = data;
142         w->before = before_cb;
143         w->after = after_cb;
144         w->elems = g_ptr_array_new();
145         
146         return w;
147 }
148
149 tvbparse_wanted_t* tvbparse_not_chars(int id,
150                                                                           guint min_len,
151                                                                           guint max_len,
152                                                                           const gchar* chr,
153                                                                           const void* data,
154                                                                           tvbparse_action_t before_cb,
155                                                                           tvbparse_action_t after_cb){
156         tvbparse_wanted_t* w = g_malloc(sizeof(tvbparse_wanted_t));
157         
158         w->id = id;
159         w->type = TVBPARSE_WANTED_SIMPLE_NOT_CHARS;
160         w->ctl = chr;
161         w->len = 0;
162         w->min = min_len ? min_len : 1;
163         w->max = max_len ? max_len : G_MAXINT;
164         w->data = data;
165         w->before = before_cb;
166         w->after = after_cb;
167         w->elems = g_ptr_array_new();
168         
169         return w;
170 }
171
172
173 tvbparse_wanted_t* tvbparse_string(int id,
174                                                                    const gchar* str,
175                                                                    const void* data,
176                                                                    tvbparse_action_t before_cb,
177                                                                    tvbparse_action_t after_cb) {
178         tvbparse_wanted_t* w = g_malloc(sizeof(tvbparse_wanted_t));
179         
180         w->id = id;
181         w->type = TVBPARSE_WANTED_SIMPLE_STRING;
182         w->ctl = str;
183         w->len = strlen(str);
184         w->min = 0;
185         w->max = 0;
186         w->data = data;
187         w->before = before_cb;
188         w->after = after_cb;
189         w->elems = g_ptr_array_new();
190         
191         return w;
192 }
193
194 tvbparse_wanted_t* tvbparse_casestring(int id,
195                                                                    const gchar* str,
196                                                                    const void* data,
197                                                                    tvbparse_action_t before_cb,
198                                                                    tvbparse_action_t after_cb) {
199         tvbparse_wanted_t* w = g_malloc(sizeof(tvbparse_wanted_t));
200         
201         w->id = id;
202         w->type = TVBPARSE_WANTED_SIMPLE_CASESTRING;
203         w->ctl = str;
204         w->len = strlen(str);
205         w->min = 0;
206         w->max = 0;
207         w->data = data;
208         w->before = before_cb;
209         w->after = after_cb;
210         w->elems = g_ptr_array_new();
211         
212         return w;
213 }
214
215
216 tvbparse_wanted_t* tvbparse_set_oneof(int id,
217                                                            const void* data, 
218                                                            tvbparse_action_t before_cb,
219                                                            tvbparse_action_t after_cb,
220                                                            ...) {
221         tvbparse_wanted_t* w = g_malloc(sizeof(tvbparse_wanted_t));
222         tvbparse_t* el;
223         va_list ap;
224         
225         w->id = id;
226         w->type = TVBPARSE_WANTED_SET_ONEOF;
227         w->ctl = NULL;
228         w->len = 0;
229         w->min = 0;
230         w->max = 0;
231         w->data = data;
232         w->before = before_cb;
233         w->after = after_cb;
234         w->elems = g_ptr_array_new();
235         
236         va_start(ap,after_cb);
237         
238         while(( el = va_arg(ap,tvbparse_t*) )) {
239                 g_ptr_array_add(w->elems,el);
240         };
241         
242         va_end(ap);
243         
244         return w;
245 }
246
247 tvbparse_wanted_t* tvbparse_set_seq(int id,
248                                                          const void* data,
249                                                          tvbparse_action_t before_cb,
250                                                          tvbparse_action_t after_cb,
251                                                          ...) {
252         tvbparse_wanted_t* w = g_malloc(sizeof(tvbparse_wanted_t));
253         tvbparse_wanted_t*  el = NULL;
254         va_list ap;
255         
256         w->id = id;
257         w->type = TVBPARSE_WANTED_SET_SEQ;
258         w->ctl = NULL;
259         w->len = 0;
260         w->min = 0;
261         w->max = 0;
262         w->data = data;
263         w->before = before_cb;
264         w->after = after_cb;
265         w->elems = g_ptr_array_new();
266         
267         va_start(ap,after_cb);
268         
269         while(( el = va_arg(ap,tvbparse_wanted_t*) )) {
270                 g_ptr_array_add(w->elems,el);
271         };
272         
273         va_end(ap);
274         return w;
275 }
276
277
278 tvbparse_wanted_t* tvbparse_some(int id,
279                                                                  guint from,
280                                                                  guint to,
281                                                                  const void* data,
282                                                                  tvbparse_action_t before_cb,
283                                                                  tvbparse_action_t after_cb,
284                                                                  const tvbparse_wanted_t* el) {
285         
286         tvbparse_wanted_t* w = g_malloc(sizeof(tvbparse_wanted_t));
287         
288         g_assert(from <= to);
289         
290         w->id = id;
291         w->type = TVBPARSE_WANTED_CARDINALITY;
292         w->ctl = NULL;
293         w->len = 0;
294         w->min = from;
295         w->max = to;
296         w->data = data;
297         w->before = before_cb;
298         w->after = after_cb;
299         w->elems = g_ptr_array_new();
300         
301         g_ptr_array_add(w->elems,(gpointer)el);
302         
303         return w;
304 }
305
306 tvbparse_wanted_t* tvbparse_until(int id,
307                                                    const void* data,
308                                                    tvbparse_action_t before_cb,
309                                                    tvbparse_action_t after_cb,
310                                                    const tvbparse_wanted_t* el,
311                                                    gboolean include_term) {
312         tvbparse_wanted_t* w = g_malloc(sizeof(tvbparse_wanted_t));
313         
314         w->id = id;
315         w->type = TVBPARSE_WANTED_UNTIL;
316         
317         /* XXX this is ugly */
318         w->ctl = include_term ? "include" : "do not include";
319         
320         w->len = 0;
321         w->min = 0;
322         w->max = 0;
323         w->data = data;
324         w->before = before_cb;
325         w->after = after_cb;
326         w->elems = g_ptr_array_new();
327         
328         g_ptr_array_add(w->elems,(gpointer)el);
329         
330         return w;
331 }
332
333
334 tvbparse_wanted_t* tvbparse_quoted(int id,
335                                                                    const void* data,
336                                                                    tvbparse_action_t before_cb,
337                                                                    tvbparse_action_t after_cb,
338                                                                    char quote,
339                                                                    char esc) {
340         
341         gchar* esc_quot = g_strdup_printf("%c%c",esc,quote);
342         gchar* quot = g_strdup_printf("%c",quote);
343         tvbparse_wanted_t* want_quot = tvbparse_char(-1,quot,NULL,NULL,NULL);
344         
345         return tvbparse_set_oneof(id, data, before_cb, after_cb,
346                                                           tvbparse_set_seq(-1, NULL, NULL, NULL,
347                                                                                            want_quot,
348                                                                                            tvbparse_set_seq(-1,NULL,NULL,NULL,
349                                                                                                                                 tvbparse_set_oneof(-1, NULL, NULL, NULL,
350                                                                                                                                                                    tvbparse_string(-1,esc_quot,NULL,NULL,NULL),
351                                                                                                                                                                    tvbparse_not_chars(-1,0,0,quot,NULL,NULL,NULL),
352                                                                                                                                                                    NULL),
353                                                                                                                                 NULL),
354                                                                                            want_quot,
355                                                                                            NULL),
356                                                           tvbparse_set_seq(-1, NULL, NULL, NULL,
357                                                                                            want_quot,
358                                                                                            want_quot,
359                                                                                            NULL),                                                                                                               
360                                                           NULL);
361         
362 }
363
364 void tvbparse_shrink_token_cb(void* tvbparse_data _U_,
365                                                           const void* wanted_data _U_,
366                                                           tvbparse_elem_t* tok) {
367         tok->offset += 1;
368         tok->len -= 2;
369 }
370
371 tvbparse_t* tvbparse_init(tvbuff_t* tvb,
372                                                   int offset,
373                                                   int len,
374                                                   void* data,
375                                                   const tvbparse_wanted_t* ignore) {
376         tvbparse_t* tt = ep_alloc(sizeof(tvbparse_t));
377         
378         tt->tvb = tvb;
379         tt->offset = offset;
380         tt->max_len = (len == -1) ? (int) tvb_length(tvb) : len;
381         tt->data = data;
382         tt->ignore = ignore;
383         tt->depth = 0;
384         return tt;
385 }
386
387 gboolean tvbparse_reset(tvbparse_t* tt,
388                                                 int offset,
389                                                 int len) {
390         
391         len = (len == -1) ? (int) tvb_length(tt->tvb) : len;
392         
393         if( tvb_length_remaining(tt->tvb, offset) >= len) {
394                 tt->offset = offset;
395                 tt->max_len = len;
396                 tt->depth = 0;
397                 return TRUE;
398         } else {
399                 tt->depth = 0;
400                 return FALSE;
401         }
402 }
403
404 static tvbparse_elem_t* new_tok(tvbparse_t* tt,
405                                                            int id,
406                                                            int offset,
407                                                            int len,
408                                                            const tvbparse_wanted_t* wanted) {
409         tvbparse_elem_t* tok = ep_alloc(sizeof(tvbparse_elem_t));
410         
411         tok->tvb = tt->tvb;
412         tok->id = id;
413         tok->offset = offset;
414         tok->len = len;
415         tok->data = NULL;
416         tok->sub = NULL;
417         tok->next = NULL;
418         tok->wanted = wanted;
419         tok->last = tok;
420         
421         return tok;
422 }
423
424 guint tvbparse_curr_offset(tvbparse_t* tt) {
425     return tt->offset;
426 }
427 guint tvbparse_len_left(tvbparse_t* tt) {
428     return tt->max_len;
429 }
430
431 tvbparse_elem_t* tvbparse_get(tvbparse_t* tt,
432                                                                   const tvbparse_wanted_t* wanted) {
433         tvbparse_elem_t* tok = NULL;
434         int save_offset = tt->offset;
435         int save_len = tt->max_len;
436         
437         tt->depth++;
438         
439         if (tt->ignore && tt->ignore != wanted) {
440                 tvbparse_wanted_t* save = (void*)tt->ignore;
441                 tt->ignore = NULL;
442                 while ( tvbparse_get(tt,save) )  {
443                         ;
444                 }
445                 tt->ignore = save;
446         }
447         
448         switch(wanted->type) {
449                 case TVBPARSE_WANTED_NONE:
450                         goto reject;
451                 case TVBPARSE_WANTED_SIMPLE_NOT_CHAR:
452                 {
453                         gchar c, t;
454                         guint i;
455                         gboolean not_matched = FALSE;
456                         
457                         if (! tt->max_len )
458                                 goto reject;
459                         
460                         t = (gchar) tvb_get_guint8(tt->tvb,tt->offset);
461                         
462                         for(i = 0; (c = wanted->ctl[i]) && tt->max_len; i++) {
463                                 if ( c == t ) {
464                                         not_matched = TRUE;
465                                 }
466                         }
467                         
468                         if (not_matched) {
469                                 goto reject;
470                         } else {
471                                 tt->offset++;
472                                 tt->max_len--;
473                                 tok =  new_tok(tt,wanted->id,tt->offset-1,1,wanted);
474                                 goto accept;
475                         }
476                 }
477                 case TVBPARSE_WANTED_SIMPLE_CHAR:
478                 {
479                         gchar c,t;
480                         guint i;
481                         
482                         if (! tt->max_len )
483                                 goto reject;
484                         
485                         t = (gchar) tvb_get_guint8(tt->tvb,tt->offset);
486                         
487                         for(i = 0; (c = wanted->ctl[i]) && tt->max_len; i++) {
488                                 if ( c == t ) {
489                                         tt->offset++;
490                                         tt->max_len--;
491                                         tok =  new_tok(tt,wanted->id,tt->offset-1,1,wanted);
492                                         goto accept;
493                                 }
494                         }
495                         goto reject;
496                 }
497                 case TVBPARSE_WANTED_SIMPLE_NOT_CHARS:
498                 {
499                         gchar c, t;
500                         guint i;
501                         guint offset = tt->offset;
502                         guint length = 0;
503                         
504                         while( tt->max_len && length < wanted->max) {
505                                 gboolean not_matched = FALSE;
506                                 t = (gchar) tvb_get_guint8(tt->tvb,tt->offset);
507                                 i = 0;
508                                 
509                                 while ( (c = wanted->ctl[i]) && tt->max_len ) {
510                                         
511                                         if (c == t) {
512                                                 not_matched = TRUE;
513                                         }
514                                         
515                                         i++;
516                                 }
517                                 
518                                 if ( not_matched )
519                                         break;
520
521                                 length++;
522                                 tt->offset++;
523                                 tt->max_len--;
524                         };
525                         
526                         if ( length < wanted->min ) {
527                                 goto reject;
528                         } else {
529                                 tok = new_tok(tt,wanted->id,offset,length,wanted);
530                                 goto accept;                    
531                         }
532                 }
533                 case TVBPARSE_WANTED_SIMPLE_CHARS:
534                 {
535                         gchar c, t;
536                         guint i;
537                         guint offset = tt->offset;
538                         guint length = 0;
539                         
540                         while( tt->max_len && length < wanted->max) {
541                                 gboolean matched = FALSE;
542                                 t = (gchar) tvb_get_guint8(tt->tvb,tt->offset);
543                                 i = 0;
544                                 
545                                 while ( (c = wanted->ctl[i]) && tt->max_len ) {
546                                         
547                                         if (c == t) {
548                                                 matched = TRUE;
549                                                 break;
550                                         }
551                                         
552                                         i++;
553                                 }
554                                 
555                                 if (! matched )
556                                         break;
557                                 
558                                 length++;
559                                 tt->offset++;
560                                 tt->max_len--;
561                         };
562                         
563                         if (length < wanted->min) {
564                                 goto reject;
565                         } else {
566                                 tok = new_tok(tt,wanted->id,offset,length,wanted);
567                                 goto accept;                    
568                         }
569                 }
570                 case TVBPARSE_WANTED_SIMPLE_STRING:
571                 {
572                         if ( tvb_strneql(tt->tvb, tt->offset, wanted->ctl, wanted->len) == 0 ) {
573                                 int offset = tt->offset;
574                                 tt->offset += wanted->len;
575                                 tt->max_len -= wanted->len;
576                                 tok = new_tok(tt,wanted->id,offset,wanted->len,wanted);
577                                 goto accept;
578                         } else {
579                                 goto reject;
580                         }
581                 }
582                 case TVBPARSE_WANTED_SIMPLE_CASESTRING:
583                 {
584                         if ( tvb_strncaseeql(tt->tvb, tt->offset, wanted->ctl, wanted->len) == 0 ) {
585                                 int offset = tt->offset;
586                                 tt->offset += wanted->len;
587                                 tt->max_len -= wanted->len;
588                                 tok = new_tok(tt,wanted->id,offset,wanted->len,wanted);
589                                 goto accept;
590                         } else {
591                                 goto reject;
592                         }
593                 }
594                 case TVBPARSE_WANTED_SET_ONEOF:
595                 {
596                         guint i;
597                         
598                         for(i=0; i < wanted->elems->len; i++) {
599                                 tvbparse_wanted_t* w = g_ptr_array_index(wanted->elems,i);
600                                 tvbparse_elem_t* new = tvbparse_get(tt, w);
601                                 
602                                 if (new) {
603                                         tok = new_tok(tt, wanted->id, new->offset, new->len, wanted);
604                                         tok->sub = new;
605                                         goto accept;                    
606                                 }
607                         }
608                         goto reject;
609                 }
610                 case TVBPARSE_WANTED_SET_SEQ:
611                 {
612                         guint i;
613                         
614                         for(i=0; i < wanted->elems->len; i++) {
615                                 tvbparse_wanted_t* w = g_ptr_array_index(wanted->elems,i);
616                                 tvbparse_elem_t* new = tvbparse_get(tt, w);
617                                 
618                                 if (new) {
619                                         if (tok) {
620                                                 tok->len = (new->offset - tok->offset) + new->len;
621                                                 tok->sub->last->next = new;
622                                                 tok->sub->last = new;
623                                         } else {
624                                                 tok = new_tok(tt, wanted->id, new->offset, new->len, wanted);
625                                                 tok->sub = new;
626                                         }
627                                 } else {
628                                         goto reject;
629                                 }
630                                 
631                         }
632                         
633                         goto accept;                    
634                 }
635                 case TVBPARSE_WANTED_CARDINALITY:
636                 {
637                         guint got_so_far = 0;
638                         tvbparse_wanted_t* w = g_ptr_array_index(wanted->elems,0);
639                         
640             if ( wanted->min == 0 ) {
641                 new_tok(tt,wanted->id,tt->offset,0,wanted);
642             }
643             
644                         while (got_so_far < wanted->max) {
645                                 tvbparse_elem_t* new = tvbparse_get(tt, w);
646                                 
647                                 if(new) {
648                                         if (tok) {
649                                                 tok->len = (new->offset - tok->offset) + new->len;
650                                                 tok->sub->last->next = new;
651                                                 tok->sub->last = new;
652                                         } else {
653                                                 tok = new_tok(tt, wanted->id, new->offset, new->len, wanted);
654                                                 tok->sub = new;
655                                         }
656                                 } else {
657                                         break;
658                                 }
659                                 
660                                 got_so_far++;
661                         }
662                         
663                         if(got_so_far < wanted->min) {
664                                 goto reject;
665                         }
666                         
667                         goto accept;                    
668                 }
669                 case TVBPARSE_WANTED_UNTIL:
670                 {
671                         int offset = tt->offset;
672                         tvbparse_wanted_t* w = g_ptr_array_index(wanted->elems,0);
673                         tvbparse_elem_t* new = tvbparse_find(tt, w);
674                         
675                         if (new) {
676                                 tok = new;
677                                 
678                                 /* XXX this is ugly */
679                                 if (*(wanted->ctl) == 'i' ) {
680                                         tok->len = (tok->offset - offset) + tok->len;
681                                 } else {
682                                         tok->len = (tok->offset - offset);
683                                         
684                                         tt->offset = save_offset + tok->len;
685                                         tt->max_len = save_len - tok->len;
686                                 }
687                                 
688                                 tok->offset = offset;
689                                 tok->id = wanted->id;
690                                 tok->next = NULL;
691                                 tok->last = tok;
692                                 tok->wanted = wanted;
693                                 
694                                 goto accept;
695                         } else {
696                                 goto reject;
697                         }
698                 }
699         }
700         
701         DISSECTOR_ASSERT_NOT_REACHED();
702         return NULL;
703         
704 accept:
705                 if (tok) {
706                         if( tt->depth == 1 ) {
707                                 GPtrArray* stack = g_ptr_array_new();
708                                 tvbparse_elem_t* curr = tok;
709                                 
710                                 while (curr) {
711                                         
712                                         if(curr->wanted->before) {
713                                                 curr->wanted->before(tt->data, curr->wanted->data, curr);
714                                         }
715                                         
716                                         if(curr->sub) {
717                                                 g_ptr_array_add(stack,curr);
718                                                 curr = curr->sub;
719                                                 continue;
720                                         } else {
721                                                 if(curr->wanted->after) curr->wanted->after(tt->data, curr->wanted->data, curr);
722                                         }
723                                         
724                                         curr = curr->next;
725                                         
726                                         while( !curr && stack->len ) {
727                                                 curr = g_ptr_array_remove_index_fast(stack,stack->len - 1);
728                                                 if( curr->wanted->after ) curr->wanted->after(tt->data, curr->wanted->data, curr);
729                                                 curr = curr->next;
730                                         }
731                                         
732                                 }
733                                 
734                                 g_ptr_array_free(stack,FALSE);
735                         }
736                         
737                         tt->depth--;
738                         return tok; 
739                 }
740         
741 reject:
742                 tt->offset = save_offset;
743         tt->max_len = save_len;
744         tt->depth--;
745         return NULL;
746                                 
747 }
748
749
750 tvbparse_elem_t* tvbparse_find(tvbparse_t* tt, const tvbparse_wanted_t* wanted) {
751         int save_offset = tt->offset;
752         int save_len = tt->max_len;
753         tvbparse_elem_t* tok = NULL;
754         
755         while ( tvb_length_remaining(tt->tvb,tt->offset) >= wanted->len ) {
756                 if (( tok = tvbparse_get(tt, wanted) )) {
757                         return tok;
758                 }
759                 tt->offset++;
760                 tt->max_len--;
761         }
762         
763         tt->offset = save_offset;
764         tt->max_len = save_len;
765         
766         return NULL;
767 }
768