dcerpc-netlogon: improve NetrLogonGetCapabilities dissection
[wireshark-sm.git] / epan / tvbparse.c
blob57c304808179ca38cb6eb2a59020511c5797faf6
1 /* tvbparse.c
3 * Copyright 2005, Luis E. Garcia Ontanon <luis@ontanon.org>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
12 #include "config.h"
14 #include <stdlib.h>
15 #include <string.h>
16 #include <glib.h>
18 #include <epan/wmem_scopes.h>
19 #include <epan/proto.h>
20 #include <epan/packet_info.h>
21 #include <epan/tvbparse.h>
22 #include <wsutil/ws_assert.h>
25 #define TVBPARSE_DEBUG_ALL 0xffffffff
27 #if 0
28 #define TVBPARSE_DEBUG_ 0x80000000
29 #define TVBPARSE_DEBUG_ 0x40000000
30 #define TVBPARSE_DEBUG_ 0x20000000
31 #define TVBPARSE_DEBUG_ 0x10000000
32 #endif
34 #define TVBPARSE_DEBUG_CHAR 0x08000000
35 #define TVBPARSE_DEBUG_CHARS 0x04000000
36 #define TVBPARSE_DEBUG_NOT_CHAR 0x02000000
37 #define TVBPARSE_DEBUG_NOT_CHARS 0x01000000
38 #define TVBPARSE_DEBUG_STRING 0x00800000
39 #define TVBPARSE_DEBUG_CASESTRING 0x00400000
40 #define TVBPARSE_DEBUG_ONEOF 0x00200000
41 #define TVBPARSE_DEBUG_HASH 0x00100000
42 #define TVBPARSE_DEBUG_SEQ 0x00080000
43 #define TVBPARSE_DEBUG_SOME 0x00040000
44 #define TVBPARSE_DEBUG_UNTIL 0x00020000
45 #if 0
46 #define TVBPARSE_DEBUG_ 0x00010000
47 #define TVBPARSE_DEBUG_ 0x00008000
48 #define TVBPARSE_DEBUG_ 0x00004000
49 #define TVBPARSE_DEBUG_ 0x00002000
50 #define TVBPARSE_DEBUG_ 0x00001000
51 #endif
52 #define TVBPARSE_DEBUG_TT 0x00000800
53 #define TVBPARSE_DEBUG_CB 0x00000400
54 #define TVBPARSE_DEBUG_GET 0x00000200
55 #define TVBPARSE_DEBUG_FIND 0x00000100
56 #define TVBPARSE_DEBUG_NEWTOK 0x00000080
57 #define TVBPARSE_DEBUG_IGNORE 0x00000040
58 #define TVBPARSE_DEBUG_PEEK 0x00000020
59 #if 0
60 #define TVBPARSE_DEBUG_ 0x00000010
61 #define TVBPARSE_DEBUG_ 0x00000008
62 #define TVBPARSE_DEBUG_ 0x00000004
63 #define TVBPARSE_DEBUG_ 0x00000002
64 #define TVBPARSE_DEBUG_ 0x00000001
65 #endif
68 #define TVBPARSE_DEBUG (TVBPARSE_DEBUG_SOME)
71 #define TVBPARSE_MAX_RECURSION_DEPTH 100 // Arbitrary. Matches DAAP and PNIO.
73 static tvbparse_elem_t* new_tok(tvbparse_t* tt,
74 int id,
75 int offset,
76 int len,
77 const tvbparse_wanted_t* wanted) {
78 tvbparse_elem_t* tok;
80 #ifdef TVBPARSE_DEBUG
81 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_NEWTOK) ws_warning("new_tok: id=%i offset=%u len=%u",id,offset,len);
82 #endif
84 tok = wmem_new(tt->scope, tvbparse_elem_t);
86 tok->parser = tt;
87 tok->tvb = tt->tvb;
88 tok->id = id;
89 tok->offset = offset;
90 tok->len = len;
91 tok->data = NULL;
92 tok->sub = NULL;
93 tok->next = NULL;
94 tok->wanted = wanted;
95 tok->last = tok;
97 return tok;
100 static int ignore_fcn(tvbparse_t* tt, int offset) {
101 int len = 0;
102 int consumed;
103 tvbparse_elem_t* ignored = NULL;
105 if (!tt->ignore) return 0;
107 #ifdef TVBPARSE_DEBUG
108 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_IGNORE) ws_warning("ignore: enter");
109 #endif
111 while ((consumed = tt->ignore->condition(tt,offset,tt->ignore,&ignored)) > 0) {
112 len += consumed;
113 offset += consumed;
114 #ifdef TVBPARSE_DEBUG
115 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_IGNORE) ws_warning("ignore: consumed=%i",consumed);
116 #endif
120 #ifdef TVBPARSE_DEBUG
121 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_IGNORE) ws_warning("ignore: len=%i",len);
122 #endif
124 return len;
128 static int cond_char (tvbparse_t* tt, const int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
129 char c,t;
130 unsigned i;
132 #ifdef TVBPARSE_DEBUG
133 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CHAR) ws_warning("cond_char: control='%s'",wanted->control.str);
134 #endif
136 if ( offset + 1 > tt->end_offset )
137 return -1;
139 t = (char) tvb_get_uint8(tt->tvb,offset);
141 for(i = 0; (c = wanted->control.str[i]) && offset <= tt->end_offset; i++) {
142 if ( c == t ) {
143 *tok = new_tok(tt,wanted->id,offset,1,wanted);
144 #ifdef TVBPARSE_DEBUG
145 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CHAR) ws_warning("cond_char: GOT: '%c'",c);
146 #endif
147 return 1;
151 return -1;
154 tvbparse_wanted_t* tvbparse_char(const int id,
155 const char* chr,
156 const void* data,
157 tvbparse_action_t before_cb,
158 tvbparse_action_t after_cb) {
159 tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
161 w->condition = cond_char;
162 w->id = id;
163 w->control.str = chr;
164 w->len = 1;
165 w->data = data;
166 w->before = before_cb;
167 w->after = after_cb;
169 return w;
172 static int cond_chars_common(tvbparse_t* tt, int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
173 unsigned length = 0;
174 int start = offset;
175 int left = tt->end_offset - offset;
177 #ifdef TVBPARSE_DEBUG
178 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CHARS) ws_warning("cond_chars_common: control='%s'",wanted->control.str);
179 #endif
181 if ( offset + (int)wanted->min > tt->end_offset )
182 return -1;
184 left = left < (int) wanted->max ? left : (int) wanted->max;
186 while( left > 0 ) {
187 uint8_t t = tvb_get_uint8(tt->tvb,offset++);
189 if (!wanted->control.str[t])
190 break;
192 length++;
193 left--;
196 if (length < wanted->min) {
197 return -1;
198 } else {
199 *tok = new_tok(tt,wanted->id,start,length,wanted);
200 #ifdef TVBPARSE_DEBUG
201 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CHARS) ws_warning("cond_chars_common: GOT len=%i",length);
202 #endif
203 return length;
207 tvbparse_wanted_t* tvbparse_chars(const int id,
208 const unsigned min_len,
209 const unsigned max_len,
210 const char* chr,
211 const void* data,
212 tvbparse_action_t before_cb,
213 tvbparse_action_t after_cb)
215 tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
216 char *accept_str;
217 size_t i;
219 accept_str = (char *)wmem_alloc(wmem_epan_scope(), 256);
220 memset(accept_str, 0x00, 256);
221 for (i = 0; chr[i]; i++)
222 accept_str[(unsigned)chr[i]] = (char)0xFF;
224 w->condition = cond_chars_common;
225 w->id = id;
226 w->control.str = accept_str;
227 w->min = min_len ? min_len : 1;
228 w->max = max_len ? max_len : INT_MAX/2;
229 w->data = data;
230 w->before = before_cb;
231 w->after = after_cb;
233 return w;
237 static int cond_not_char(tvbparse_t* tt, const int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
238 char c, t;
239 unsigned i;
240 bool not_matched = false;
242 #ifdef TVBPARSE_DEBUG
243 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_NOT_CHAR) ws_warning("cond_not_char: control='%s'",wanted->control.str);
244 #endif
246 if ( offset >= tt->end_offset ) {
247 return -1;
250 t = (char) tvb_get_uint8(tt->tvb,offset);
252 for(i = 0; (c = wanted->control.str[i]); i++) {
253 if ( c == t ) {
254 not_matched = true;
258 if (not_matched) {
259 return -1;
260 } else {
261 *tok = new_tok(tt,wanted->id,offset,1,wanted);
262 #ifdef TVBPARSE_DEBUG
263 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_NOT_CHAR) ws_warning("cond_not_char: GOT='%c'",t);
264 #endif
265 return 1;
269 tvbparse_wanted_t* tvbparse_not_char(const int id,
270 const char* chr,
271 const void* data,
272 tvbparse_action_t before_cb,
273 tvbparse_action_t after_cb) {
274 tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
276 w->condition = cond_not_char;
277 w->id = id;
278 w->control.str = chr;
279 w->data = data;
280 w->before = before_cb;
281 w->after = after_cb;
283 return w;
286 tvbparse_wanted_t* tvbparse_not_chars(const int id,
287 const unsigned min_len,
288 const unsigned max_len,
289 const char* chr,
290 const void* data,
291 tvbparse_action_t before_cb,
292 tvbparse_action_t after_cb)
294 tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
295 char *accept_str;
296 size_t i;
298 /* cond_chars_common() use accept string, so mark all elements with, and later unset from reject */
299 accept_str = (char *)wmem_alloc(wmem_epan_scope(), 256);
300 memset(accept_str, 0xFF, 256);
301 for (i = 0; chr[i]; i++)
302 accept_str[(unsigned) chr[i]] = '\0';
304 w->condition = cond_chars_common;
305 w->id = id;
306 w->control.str = accept_str;
307 w->len = 0;
308 w->min = min_len ? min_len : 1;
309 w->max = max_len ? max_len : INT_MAX/2;
310 w->data = data;
311 w->before = before_cb;
312 w->after = after_cb;
314 return w;
318 static int cond_string(tvbparse_t* tt, const int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
319 int len = wanted->len;
320 #ifdef TVBPARSE_DEBUG
321 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_STRING) ws_warning("cond_string: control='%s'",wanted->control.str);
322 #endif
324 if ( offset + wanted->len > tt->end_offset )
325 return -1;
327 if ( tvb_strneql(tt->tvb, offset, wanted->control.str, len) == 0 ) {
328 *tok = new_tok(tt,wanted->id,offset,len,wanted);
329 #ifdef TVBPARSE_DEBUG
330 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_STRING) ws_warning("cond_string: GOT len=%i",len);
331 #endif
332 return len;
333 } else {
334 return -1;
338 tvbparse_wanted_t* tvbparse_string(const int id,
339 const char* str,
340 const void* data,
341 tvbparse_action_t before_cb,
342 tvbparse_action_t after_cb) {
343 tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
345 w->condition = cond_string;
346 w->id = id;
347 w->control.str = str;
348 w->len = (int) strlen(str);
349 w->data = data;
350 w->before = before_cb;
351 w->after = after_cb;
353 return w;
356 static int cond_casestring(tvbparse_t* tt, const int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
357 int len = wanted->len;
358 #ifdef TVBPARSE_DEBUG
359 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CASESTRING) ws_warning("cond_casestring: control='%s'",wanted->control.str);
360 #endif
362 if ( offset + len > tt->end_offset )
363 return -1;
365 if ( tvb_strncaseeql(tt->tvb, offset, wanted->control.str, len) == 0 ) {
366 *tok = new_tok(tt,wanted->id,offset,len,wanted);
367 #ifdef TVBPARSE_DEBUG
368 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CASESTRING) ws_warning("cond_casestring: GOT len=%i",len);
369 #endif
370 return len;
371 } else {
372 *tok = NULL;
373 return -1;
377 tvbparse_wanted_t* tvbparse_casestring(const int id,
378 const char* str,
379 const void* data,
380 tvbparse_action_t before_cb,
381 tvbparse_action_t after_cb) {
382 tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
384 w->condition = cond_casestring;
385 w->id = id;
386 w->control.str = str;
387 w->len = (int) strlen(str);
388 w->data = data;
389 w->before = before_cb;
390 w->after = after_cb;
392 return w;
395 static int cond_one_of(tvbparse_t* tt, const int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
396 unsigned i;
397 #ifdef TVBPARSE_DEBUG
398 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_ONEOF) ws_warning("cond_one_of: START");
399 #endif
401 if ( offset > tt->end_offset )
402 return -1;
404 if (++tt->recursion_depth > TVBPARSE_MAX_RECURSION_DEPTH)
405 return -1;
407 for(i=0; i < wanted->control.elems->len; i++) {
408 tvbparse_wanted_t* w = (tvbparse_wanted_t *)g_ptr_array_index(wanted->control.elems,i);
409 tvbparse_elem_t* new_elem = NULL;
410 int curr_len;
412 if ( offset + w->len > tt->end_offset )
413 continue;
415 curr_len = w->condition(tt, offset, w, &new_elem);
417 if (curr_len >= 0) {
418 *tok = new_tok(tt, wanted->id, new_elem->offset, new_elem->len, wanted);
419 (*tok)->sub = new_elem;
420 #ifdef TVBPARSE_DEBUG
421 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_ONEOF) ws_warning("cond_one_of: GOT len=%i",curr_len);
422 #endif
423 tt->recursion_depth--;
424 return curr_len;
428 tt->recursion_depth--;
429 return -1;
432 static bool
433 tvbparse_wanted_cleanup_cb(wmem_allocator_t* allocator _U_, wmem_cb_event_t event _U_, void *user_data)
435 tvbparse_wanted_t* w = (tvbparse_wanted_t *)user_data;
436 g_ptr_array_free(w->control.elems, true);
437 return false;
440 tvbparse_wanted_t* tvbparse_set_oneof(const int id,
441 const void* data,
442 tvbparse_action_t before_cb,
443 tvbparse_action_t after_cb,
444 ...) {
445 tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
446 tvbparse_t* el;
447 va_list ap;
449 w->condition = cond_one_of;
450 w->id = id;
451 w->data = data;
452 w->before = before_cb;
453 w->after = after_cb;
454 w->control.elems = g_ptr_array_new();
455 wmem_register_callback(wmem_epan_scope(), tvbparse_wanted_cleanup_cb, w);
457 va_start(ap,after_cb);
459 while(( el = va_arg(ap,tvbparse_t*) )) {
460 g_ptr_array_add(w->control.elems,el);
463 va_end(ap);
465 return w;
468 static int cond_hash(tvbparse_t* tt, const int offset, const tvbparse_wanted_t* wanted, tvbparse_elem_t** tok) {
469 int key_len;
470 char* key = NULL;
471 tvbparse_elem_t* key_elem = NULL;
472 tvbparse_wanted_t* value_wanted = NULL;
473 int value_len;
474 tvbparse_elem_t* value_elem = NULL;
475 int tot_len;
476 tvbparse_elem_t* ret_tok;
478 #ifdef TVBPARSE_DEBUG
479 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_HASH) ws_warning("cond_hash: START");
480 #endif
482 if ( offset > tt->end_offset )
483 return -1;
485 if (++tt->recursion_depth > TVBPARSE_MAX_RECURSION_DEPTH)
486 return -1;
488 key_len = wanted->control.hash.key->condition(tt, offset, wanted->control.hash.key, &key_elem);
490 if (key_len < 0) {
491 tt->recursion_depth--;
492 return -1;
495 key = tvb_get_string_enc(tt->scope,key_elem->parser->tvb,key_elem->offset,key_elem->len, ENC_ASCII);
496 #ifdef TVBPARSE_DEBUG
497 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_HASH) ws_warning("cond_hash: got key='%s'",key);
498 #endif
500 if ((value_wanted = (tvbparse_wanted_t *)wmem_map_lookup(wanted->control.hash.table,key))) {
501 value_len = value_wanted->condition(tt, offset + key_len, value_wanted, &value_elem);
502 } else if (wanted->control.hash.other) {
503 value_len = wanted->control.hash.other->condition(tt, offset+key_len, wanted->control.hash.other, &value_elem);
504 if (value_len < 0) {
505 tt->recursion_depth--;
506 return -1;
508 } else {
509 tt->recursion_depth--;
510 return -1;
513 tt->recursion_depth--;
515 tot_len = key_len + value_len;
517 ret_tok = new_tok(tt, value_elem->id, offset, tot_len, wanted);
518 ret_tok->sub = key_elem;
519 ret_tok->sub->last->next = value_elem;
521 *tok = ret_tok;
522 #ifdef TVBPARSE_DEBUG
523 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_HASH) ws_warning("cond_hash: GOT len=%i",tot_len);
524 #endif
526 return tot_len;
529 tvbparse_wanted_t* tvbparse_hashed(const int id,
530 const void* data,
531 tvbparse_action_t before_cb,
532 tvbparse_action_t after_cb,
533 tvbparse_wanted_t* key,
534 tvbparse_wanted_t* other,
535 ...) {
536 tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
537 char* name;
538 tvbparse_wanted_t* el;
539 va_list ap;
541 w->condition = cond_hash;
542 w->id = id;
543 w->data = data;
544 w->before = before_cb;
545 w->after = after_cb;
546 w->control.hash.table = wmem_map_new(wmem_epan_scope(), g_str_hash,g_str_equal);
547 w->control.hash.key = key;
548 w->control.hash.other = other;
550 va_start(ap,other);
552 while(( name = va_arg(ap,char*) )) {
553 el = va_arg(ap,tvbparse_wanted_t*);
554 wmem_map_insert(w->control.hash.table,name,el);
557 va_end(ap);
559 return w;
562 void tvbparse_hashed_add(tvbparse_wanted_t* w, ...) {
563 tvbparse_wanted_t* el;
564 va_list ap;
565 char* name;
567 va_start(ap,w);
569 while (( name = va_arg(ap,char*) )) {
570 el = va_arg(ap,tvbparse_wanted_t*);
571 wmem_map_insert(w->control.hash.table,name,el);
574 va_end(ap);
577 static int cond_seq(tvbparse_t* tt, int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
578 unsigned i;
579 int len = 0;
580 int start = offset;
581 tvbparse_elem_t* ret_tok = NULL;
583 #ifdef TVBPARSE_DEBUG
584 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_SEQ) ws_warning("cond_seq: START");
585 #endif
587 if ( offset > tt->end_offset )
588 return -1;
590 if (++tt->recursion_depth > TVBPARSE_MAX_RECURSION_DEPTH)
591 return -1;
593 for(i=0; i < wanted->control.elems->len; i++) {
594 tvbparse_wanted_t* w = (tvbparse_wanted_t *)g_ptr_array_index(wanted->control.elems,i);
595 tvbparse_elem_t* new_elem = NULL;
597 if ( offset + w->len > tt->end_offset ) {
598 tt->recursion_depth--;
599 return -1;
602 len = w->condition(tt, offset, w, &new_elem);
604 if (len >= 0) {
605 if (ret_tok) {
606 if (new_elem->len)
607 ret_tok->len = (new_elem->offset - ret_tok->offset) + new_elem->len;
608 ret_tok->sub->last->next = new_elem;
609 ret_tok->sub->last = new_elem;
610 } else {
611 ret_tok = new_tok(tt, wanted->id, new_elem->offset, new_elem->len, wanted);
612 ret_tok->sub = new_elem;
613 new_elem->last = new_elem;
615 } else {
616 tt->recursion_depth--;
617 return -1;
620 offset += len;
621 offset += ignore_fcn(tt,offset);
624 tt->recursion_depth--;
626 *tok = ret_tok;
628 #ifdef TVBPARSE_DEBUG
629 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_SEQ) ws_warning("cond_seq: GOT len=%i",offset - start);
630 #endif
632 return offset - start;
636 tvbparse_wanted_t* tvbparse_set_seq(const int id,
637 const void* data,
638 tvbparse_action_t before_cb,
639 tvbparse_action_t after_cb,
640 ...) {
641 tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
642 tvbparse_wanted_t* el = NULL;
643 va_list ap;
645 w->condition = cond_seq;
646 w->id = id;
647 w->data = data;
648 w->before = before_cb;
649 w->after = after_cb;
650 w->control.elems = g_ptr_array_new();
651 wmem_register_callback(wmem_epan_scope(), tvbparse_wanted_cleanup_cb, w);
653 va_start(ap,after_cb);
655 while(( el = va_arg(ap,tvbparse_wanted_t*) )) {
656 g_ptr_array_add(w->control.elems,el);
659 va_end(ap);
660 return w;
663 static int cond_some(tvbparse_t* tt, int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
664 unsigned got_so_far = 0;
665 int start = offset;
666 tvbparse_elem_t* ret_tok = NULL;
667 #ifdef TVBPARSE_DEBUG
668 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_SOME) ws_warning("cond_some: START");
669 #endif
671 if ( offset > tt->end_offset )
672 return -1;
674 if (++tt->recursion_depth > TVBPARSE_MAX_RECURSION_DEPTH)
675 return -1;
677 if ( wanted->min == 0 ) {
678 ret_tok = new_tok(tt,wanted->id,offset,0,wanted);
681 while (got_so_far < wanted->max) {
682 tvbparse_elem_t* new_elem = NULL;
683 int consumed;
685 if ( offset > tt->end_offset ) {
686 tt->recursion_depth--;
687 return -1;
690 consumed = wanted->control.subelem->condition(tt, offset, wanted->control.subelem, &new_elem);
692 if(consumed >= 0) {
693 if (ret_tok) {
694 if (new_elem->len)
695 ret_tok->len = (new_elem->offset - ret_tok->offset) + new_elem->len;
697 if (ret_tok->sub) {
698 ret_tok->sub->last->next = new_elem;
699 ret_tok->sub->last = new_elem;
700 } else {
701 ret_tok->sub = new_elem;
703 } else {
704 ret_tok = new_tok(tt, wanted->id, new_elem->offset, new_elem->len, wanted);
705 ret_tok->sub = new_elem;
707 } else {
708 break;
711 offset += consumed;
712 got_so_far++;
715 tt->recursion_depth--;
717 #ifdef TVBPARSE_DEBUG
718 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_SOME) ws_warning("cond_some: got num=%u",got_so_far);
719 #endif
721 if(got_so_far < wanted->min) {
722 return -1;
725 *tok = ret_tok;
726 #ifdef TVBPARSE_DEBUG
727 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_SOME) ws_warning("cond_some: GOT len=%i",offset - start);
728 #endif
729 return offset - start;
732 tvbparse_wanted_t* tvbparse_some(const int id,
733 const unsigned from,
734 const unsigned to,
735 const void* data,
736 tvbparse_action_t before_cb,
737 tvbparse_action_t after_cb,
738 const tvbparse_wanted_t* el) {
740 tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
742 ws_assert(from <= to);
744 w->condition = cond_some;
745 w->id = id;
746 w->min = from;
747 w->max = to;
748 w->data = data;
749 w->before = before_cb;
750 w->after = after_cb;
751 w->control.subelem = el;
753 return w;
757 static int cond_until(tvbparse_t* tt, const int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
758 tvbparse_elem_t* new_elem = NULL;
759 int len = 0;
760 int target_offset = offset;
761 #ifdef TVBPARSE_DEBUG
762 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_UNTIL) ws_warning("cond_until: START");
763 #endif
765 if ( offset + wanted->control.until.subelem->len > tt->end_offset )
766 return -1;
768 if (++tt->recursion_depth > TVBPARSE_MAX_RECURSION_DEPTH)
769 return -1;
771 do {
772 len = wanted->control.until.subelem->condition(tt, target_offset++, wanted->control.until.subelem, &new_elem);
773 } while(len < 0 && target_offset+1 < tt->end_offset);
775 tt->recursion_depth--;
777 if (len >= 0) {
779 new_elem->id = wanted->id;
780 new_elem->next = NULL;
781 new_elem->last = NULL;
782 new_elem->wanted = wanted;
783 new_elem->offset = offset;
785 (*tok) = new_elem;
787 switch (wanted->control.until.mode) {
788 case TP_UNTIL_INCLUDE:
789 new_elem->len = target_offset - offset - 1 + len;
790 #ifdef TVBPARSE_DEBUG
791 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_UNTIL) ws_warning("cond_until: GOT len=%i",target_offset - offset -1 + len);
792 #endif
793 return target_offset - offset -1 + len;
794 case TP_UNTIL_SPEND:
795 new_elem->len = target_offset - offset - 1;
796 #ifdef TVBPARSE_DEBUG
797 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_UNTIL) ws_warning("cond_until: GOT len=%i",target_offset - offset -1 + len);
798 #endif
799 return target_offset - offset - 1 + len;
800 case TP_UNTIL_LEAVE:
801 new_elem->len = target_offset - offset - 1;
802 #ifdef TVBPARSE_DEBUG
803 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_UNTIL) ws_warning("cond_until: GOT len=%i",target_offset - offset -1);
804 #endif
805 return target_offset - offset -1;
806 default:
807 DISSECTOR_ASSERT_NOT_REACHED();
808 return -1;
811 } else {
812 return -1;
816 tvbparse_wanted_t* tvbparse_until(const int id,
817 const void* data,
818 tvbparse_action_t before_cb,
819 tvbparse_action_t after_cb,
820 const tvbparse_wanted_t* el,
821 until_mode_t until_mode) {
822 tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
824 w->condition = cond_until;
825 w->control.until.mode = until_mode;
826 w->control.until.subelem = el;
827 w->id = id;
828 w->data = data;
829 w->before = before_cb;
830 w->after = after_cb;
832 return w;
835 tvbparse_wanted_t* tvbparse_quoted(const int id,
836 const void* data,
837 tvbparse_action_t before_cb,
838 tvbparse_action_t after_cb,
839 const char quote,
840 const char esc) {
842 char* esc_quot = wmem_strdup_printf(wmem_epan_scope(), "%c%c",esc,quote);
843 char* quot = wmem_strdup_printf(wmem_epan_scope(), "%c",quote);
844 tvbparse_wanted_t* want_quot = tvbparse_char(-1,quot,NULL,NULL,NULL);
846 return tvbparse_set_oneof(id, data, before_cb, after_cb,
847 tvbparse_set_seq(-1, NULL, NULL, NULL,
848 want_quot,
849 tvbparse_set_seq(-1,NULL,NULL,NULL,
850 tvbparse_set_oneof(-1, NULL, NULL, NULL,
851 tvbparse_string(-1,esc_quot,NULL,NULL,NULL),
852 tvbparse_not_chars(-1,0,0,quot,NULL,NULL,NULL),
853 NULL),
854 NULL),
855 want_quot,
856 NULL),
857 tvbparse_set_seq(-1, NULL, NULL, NULL,
858 want_quot,
859 want_quot,
860 NULL),
861 NULL);
864 void tvbparse_shrink_token_cb(void* tvbparse_data _U_,
865 const void* wanted_data _U_,
866 tvbparse_elem_t* tok) {
867 tok->offset += 1;
868 tok->len -= 2;
871 tvbparse_t* tvbparse_init(wmem_allocator_t *scope,
872 tvbuff_t* tvb,
873 const int offset,
874 int len,
875 void* data,
876 const tvbparse_wanted_t* ignore) {
877 tvbparse_t* tt = wmem_new(scope, tvbparse_t);
879 #ifdef TVBPARSE_DEBUG
880 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_TT) ws_warning("tvbparse_init: offset=%i len=%i",offset,len);
881 #endif
883 tt->scope = scope;
884 tt->tvb = tvb;
885 tt->offset = offset;
886 len = (len == -1) ? (int) tvb_captured_length(tvb) : len;
887 tt->end_offset = offset + len;
888 tt->data = data;
889 tt->ignore = ignore;
890 tt->recursion_depth = 0;
891 return tt;
894 bool tvbparse_reset(tvbparse_t* tt,
895 const int offset,
896 int len) {
898 #ifdef TVBPARSE_DEBUG
899 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_TT) ws_warning("tvbparse_init: offset=%i len=%i",offset,len);
900 #endif
902 len = (len == -1) ? (int) tvb_captured_length(tt->tvb) : len;
904 if( tvb_captured_length_remaining(tt->tvb, offset) >= len) {
905 tt->offset = offset;
906 tt->end_offset = offset + len;
907 return true;
908 } else {
909 return false;
913 unsigned tvbparse_curr_offset(tvbparse_t* tt) {
914 return tt->offset;
917 static void execute_callbacks(tvbparse_t* tt, tvbparse_elem_t* curr) {
918 wmem_stack_t *stack = wmem_stack_new(tt->scope);
920 while (curr) {
921 if(curr->wanted->before) {
922 #ifdef TVBPARSE_DEBUG
923 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CB) ws_warning("execute_callbacks: BEFORE: id=%i offset=%i len=%i",curr->id,curr->offset,curr->len);
924 #endif
925 curr->wanted->before(tt->data, curr->wanted->data, curr);
928 if(curr->sub) {
929 wmem_stack_push(stack, curr);
930 curr = curr->sub;
931 continue;
932 } else {
933 #ifdef TVBPARSE_DEBUG
934 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CB) ws_warning("execute_callbacks: AFTER: id=%i offset=%i len=%i",curr->id,curr->offset,curr->len);
935 #endif
936 if(curr->wanted->after) curr->wanted->after(tt->data, curr->wanted->data, curr);
939 curr = curr->next;
941 while( !curr && wmem_stack_count(stack) > 0 ) {
942 curr = (tvbparse_elem_t *)wmem_stack_pop(stack);
943 #ifdef TVBPARSE_DEBUG
944 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CB) ws_warning("execute_callbacks: AFTER: id=%i offset=%i len=%i",curr->id,curr->offset,curr->len);
945 #endif
946 if( curr->wanted->after ) curr->wanted->after(tt->data, curr->wanted->data, curr);
947 curr = curr->next;
953 bool tvbparse_peek(tvbparse_t* tt,
954 const tvbparse_wanted_t* wanted) {
955 tvbparse_elem_t* tok = NULL;
956 int consumed;
957 int offset = tt->offset;
959 #ifdef TVBPARSE_DEBUG
960 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_PEEK) ws_warning("tvbparse_peek: ENTER offset=%i",offset);
961 #endif
963 offset += ignore_fcn(tt,offset);
965 #ifdef TVBPARSE_DEBUG
966 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_PEEK) ws_warning("tvbparse_peek: after ignore offset=%i",offset);
967 #endif
969 consumed = wanted->condition(tt,offset,wanted,&tok);
971 if (consumed >= 0) {
972 #ifdef TVBPARSE_DEBUG
973 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_PEEK) ws_warning("tvbparse_peek: GOT len=%i",consumed);
974 #endif
975 return true;
976 } else {
977 #ifdef TVBPARSE_DEBUG
978 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_PEEK) ws_warning("tvbparse_peek: NOT GOT");
979 #endif
980 return false;
985 tvbparse_elem_t* tvbparse_get(tvbparse_t* tt,
986 const tvbparse_wanted_t* wanted) {
987 tvbparse_elem_t* tok = NULL;
988 int consumed;
989 int offset = tt->offset;
991 #ifdef TVBPARSE_DEBUG
992 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_GET) ws_warning("tvbparse_get: ENTER offset=%i",offset);
993 #endif
995 offset += ignore_fcn(tt,offset);
997 #ifdef TVBPARSE_DEBUG
998 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_GET) ws_warning("tvbparse_get: after ignore offset=%i",offset);
999 #endif
1001 consumed = wanted->condition(tt,offset,wanted,&tok);
1003 if (consumed >= 0) {
1004 #ifdef TVBPARSE_DEBUG
1005 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_GET) ws_warning("tvbparse_get: GOT len=%i",consumed);
1006 #endif
1007 execute_callbacks(tt,tok);
1008 tt->offset = offset + consumed;
1009 #ifdef TVBPARSE_DEBUG
1010 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_GET) ws_warning("tvbparse_get: DONE offset=%i", tt->offset);
1011 #endif
1012 return tok;
1013 } else {
1014 return NULL;
1020 tvbparse_elem_t* tvbparse_find(tvbparse_t* tt, const tvbparse_wanted_t* wanted) {
1021 tvbparse_elem_t* tok = NULL;
1022 int len = 0;
1023 int offset = tt->offset;
1024 int target_offset = offset -1;
1026 #ifdef TVBPARSE_DEBUG
1027 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_FIND) ws_warning("tvbparse_get: ENTER offset=%i", tt->offset);
1028 #endif
1030 do {
1031 len = wanted->condition(tt, target_offset+1, wanted, &tok);
1032 } while(len < 0 && ++target_offset < tt->end_offset);
1034 if (len >= 0) {
1035 #ifdef TVBPARSE_DEBUG
1036 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_FIND) ws_warning("tvbparse_get: FOUND offset=%i len=%i", target_offset,len);
1037 #endif
1038 execute_callbacks(tt,tok);
1039 tt->offset = target_offset + len;
1041 #ifdef TVBPARSE_DEBUG
1042 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_FIND) ws_warning("tvbparse_get: DONE offset=%i", tt->offset);
1043 #endif
1044 return tok;
1045 } else {
1046 #ifdef TVBPARSE_DEBUG
1047 if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_FIND) ws_warning("tvbparse_get: NOT FOUND");
1048 #endif
1049 return NULL;
1053 struct _elem_tree_stack_frame {
1054 proto_tree* tree;
1055 tvbparse_elem_t* elem;
1058 void tvbparse_tree_add_elem(proto_tree* tree, tvbparse_elem_t* curr) {
1059 wmem_stack_t *stack = wmem_stack_new(curr->parser->scope);
1060 struct _elem_tree_stack_frame* frame = wmem_new(curr->parser->scope, struct _elem_tree_stack_frame);
1061 proto_item* pi;
1062 frame->tree = tree;
1063 frame->elem = curr;
1065 while (curr) {
1066 pi = proto_tree_add_format_text(frame->tree,curr->parser->tvb,curr->offset,curr->len);
1068 if(curr->sub) {
1069 frame->elem = curr;
1070 wmem_stack_push(stack, frame);
1071 frame = wmem_new(curr->parser->scope, struct _elem_tree_stack_frame);
1072 frame->tree = proto_item_add_subtree(pi,0);
1073 curr = curr->sub;
1074 continue;
1077 curr = curr->next;
1079 while( !curr && wmem_stack_count(stack) > 0 ) {
1080 frame = (struct _elem_tree_stack_frame *)wmem_stack_pop(stack);
1081 curr = frame->elem->next;
1088 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1090 * Local variables:
1091 * c-basic-offset: 4
1092 * tab-width: 8
1093 * indent-tabs-mode: nil
1094 * End:
1096 * vi: set shiftwidth=4 tabstop=8 expandtab:
1097 * :indentSize=4:tabSize=8:noTabs=true: