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