summaryrefslogtreecommitdiffstats
path: root/epan/tvbparse.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
commite4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch)
tree68cb5ef9081156392f1dd62a00c6ccc1451b93df /epan/tvbparse.c
parentInitial commit. (diff)
downloadwireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.tar.xz
wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.zip
Adding upstream version 4.2.2.upstream/4.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'epan/tvbparse.c')
-rw-r--r--epan/tvbparse.c1098
1 files changed, 1098 insertions, 0 deletions
diff --git a/epan/tvbparse.c b/epan/tvbparse.c
new file mode 100644
index 00000000..aaaa6aa0
--- /dev/null
+++ b/epan/tvbparse.c
@@ -0,0 +1,1098 @@
+/* tvbparse.c
+ *
+ * Copyright 2005, Luis E. Garcia Ontanon <luis@ontanon.org>
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+
+#include <epan/wmem_scopes.h>
+#include <epan/proto.h>
+#include <epan/packet_info.h>
+#include <epan/tvbparse.h>
+#include <wsutil/ws_assert.h>
+
+
+#define TVBPARSE_DEBUG_ALL 0xffffffff
+
+#if 0
+#define TVBPARSE_DEBUG_ 0x80000000
+#define TVBPARSE_DEBUG_ 0x40000000
+#define TVBPARSE_DEBUG_ 0x20000000
+#define TVBPARSE_DEBUG_ 0x10000000
+#endif
+
+#define TVBPARSE_DEBUG_CHAR 0x08000000
+#define TVBPARSE_DEBUG_CHARS 0x04000000
+#define TVBPARSE_DEBUG_NOT_CHAR 0x02000000
+#define TVBPARSE_DEBUG_NOT_CHARS 0x01000000
+#define TVBPARSE_DEBUG_STRING 0x00800000
+#define TVBPARSE_DEBUG_CASESTRING 0x00400000
+#define TVBPARSE_DEBUG_ONEOF 0x00200000
+#define TVBPARSE_DEBUG_HASH 0x00100000
+#define TVBPARSE_DEBUG_SEQ 0x00080000
+#define TVBPARSE_DEBUG_SOME 0x00040000
+#define TVBPARSE_DEBUG_UNTIL 0x00020000
+#if 0
+#define TVBPARSE_DEBUG_ 0x00010000
+#define TVBPARSE_DEBUG_ 0x00008000
+#define TVBPARSE_DEBUG_ 0x00004000
+#define TVBPARSE_DEBUG_ 0x00002000
+#define TVBPARSE_DEBUG_ 0x00001000
+#endif
+#define TVBPARSE_DEBUG_TT 0x00000800
+#define TVBPARSE_DEBUG_CB 0x00000400
+#define TVBPARSE_DEBUG_GET 0x00000200
+#define TVBPARSE_DEBUG_FIND 0x00000100
+#define TVBPARSE_DEBUG_NEWTOK 0x00000080
+#define TVBPARSE_DEBUG_IGNORE 0x00000040
+#define TVBPARSE_DEBUG_PEEK 0x00000020
+#if 0
+#define TVBPARSE_DEBUG_ 0x00000010
+#define TVBPARSE_DEBUG_ 0x00000008
+#define TVBPARSE_DEBUG_ 0x00000004
+#define TVBPARSE_DEBUG_ 0x00000002
+#define TVBPARSE_DEBUG_ 0x00000001
+#endif
+
+/*
+#define TVBPARSE_DEBUG (TVBPARSE_DEBUG_SOME)
+*/
+
+#define TVBPARSE_MAX_RECURSION_DEPTH 100 // Arbitrary. Matches DAAP and PNIO.
+
+static tvbparse_elem_t* new_tok(tvbparse_t* tt,
+ int id,
+ int offset,
+ int len,
+ const tvbparse_wanted_t* wanted) {
+ tvbparse_elem_t* tok;
+
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_NEWTOK) ws_warning("new_tok: id=%i offset=%u len=%u",id,offset,len);
+#endif
+
+ tok = wmem_new(tt->scope, tvbparse_elem_t);
+
+ tok->parser = tt;
+ tok->tvb = tt->tvb;
+ tok->id = id;
+ tok->offset = offset;
+ tok->len = len;
+ tok->data = NULL;
+ tok->sub = NULL;
+ tok->next = NULL;
+ tok->wanted = wanted;
+ tok->last = tok;
+
+ return tok;
+}
+
+static int ignore_fcn(tvbparse_t* tt, int offset) {
+ int len = 0;
+ int consumed;
+ tvbparse_elem_t* ignored = NULL;
+
+ if (!tt->ignore) return 0;
+
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_IGNORE) ws_warning("ignore: enter");
+#endif
+
+ while ((consumed = tt->ignore->condition(tt,offset,tt->ignore,&ignored)) > 0) {
+ len += consumed;
+ offset += consumed;
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_IGNORE) ws_warning("ignore: consumed=%i",consumed);
+#endif
+
+ }
+
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_IGNORE) ws_warning("ignore: len=%i",len);
+#endif
+
+ return len;
+}
+
+
+static int cond_char (tvbparse_t* tt, const int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
+ gchar c,t;
+ guint i;
+
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CHAR) ws_warning("cond_char: control='%s'",wanted->control.str);
+#endif
+
+ if ( offset + 1 > tt->end_offset )
+ return -1;
+
+ t = (gchar) tvb_get_guint8(tt->tvb,offset);
+
+ for(i = 0; (c = wanted->control.str[i]) && offset <= tt->end_offset; i++) {
+ if ( c == t ) {
+ *tok = new_tok(tt,wanted->id,offset,1,wanted);
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CHAR) ws_warning("cond_char: GOT: '%c'",c);
+#endif
+ return 1;
+ }
+ }
+
+ return -1;
+}
+
+tvbparse_wanted_t* tvbparse_char(const int id,
+ const gchar* chr,
+ const void* data,
+ tvbparse_action_t before_cb,
+ tvbparse_action_t after_cb) {
+ tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
+
+ w->condition = cond_char;
+ w->id = id;
+ w->control.str = chr;
+ w->len = 1;
+ w->data = data;
+ w->before = before_cb;
+ w->after = after_cb;
+
+ return w;
+}
+
+static int cond_chars_common(tvbparse_t* tt, int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
+ guint length = 0;
+ int start = offset;
+ int left = tt->end_offset - offset;
+
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CHARS) ws_warning("cond_chars_common: control='%s'",wanted->control.str);
+#endif
+
+ if ( offset + (int)wanted->min > tt->end_offset )
+ return -1;
+
+ left = left < (int) wanted->max ? left : (int) wanted->max;
+
+ while( left > 0 ) {
+ guint8 t = tvb_get_guint8(tt->tvb,offset++);
+
+ if (!wanted->control.str[t])
+ break;
+
+ length++;
+ left--;
+ };
+
+ if (length < wanted->min) {
+ return -1;
+ } else {
+ *tok = new_tok(tt,wanted->id,start,length,wanted);
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CHARS) ws_warning("cond_chars_common: GOT len=%i",length);
+#endif
+ return length;
+ }
+}
+
+tvbparse_wanted_t* tvbparse_chars(const int id,
+ const guint min_len,
+ const guint max_len,
+ const gchar* chr,
+ const void* data,
+ tvbparse_action_t before_cb,
+ tvbparse_action_t after_cb)
+{
+ tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
+ char *accept_str;
+ gsize i;
+
+ accept_str = (char *)wmem_alloc(wmem_epan_scope(), 256);
+ memset(accept_str, 0x00, 256);
+ for (i = 0; chr[i]; i++)
+ accept_str[(unsigned)chr[i]] = (char)0xFF;
+
+ w->condition = cond_chars_common;
+ w->id = id;
+ w->control.str = accept_str;
+ w->min = min_len ? min_len : 1;
+ w->max = max_len ? max_len : G_MAXINT/2;
+ w->data = data;
+ w->before = before_cb;
+ w->after = after_cb;
+
+ return w;
+}
+
+
+static int cond_not_char(tvbparse_t* tt, const int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
+ gchar c, t;
+ guint i;
+ gboolean not_matched = FALSE;
+
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_NOT_CHAR) ws_warning("cond_not_char: control='%s'",wanted->control.str);
+#endif
+
+ if ( offset >= tt->end_offset ) {
+ return -1;
+ }
+
+ t = (gchar) tvb_get_guint8(tt->tvb,offset);
+
+ for(i = 0; (c = wanted->control.str[i]); i++) {
+ if ( c == t ) {
+ not_matched = TRUE;
+ }
+ }
+
+ if (not_matched) {
+ return -1;
+ } else {
+ *tok = new_tok(tt,wanted->id,offset,1,wanted);
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_NOT_CHAR) ws_warning("cond_not_char: GOT='%c'",t);
+#endif
+ return 1;
+ }
+}
+
+tvbparse_wanted_t* tvbparse_not_char(const int id,
+ const gchar* chr,
+ const void* data,
+ tvbparse_action_t before_cb,
+ tvbparse_action_t after_cb) {
+ tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
+
+ w->condition = cond_not_char;
+ w->id = id;
+ w->control.str = chr;
+ w->data = data;
+ w->before = before_cb;
+ w->after = after_cb;
+
+ return w;
+}
+
+tvbparse_wanted_t* tvbparse_not_chars(const int id,
+ const guint min_len,
+ const guint max_len,
+ const gchar* chr,
+ const void* data,
+ tvbparse_action_t before_cb,
+ tvbparse_action_t after_cb)
+{
+ tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
+ char *accept_str;
+ gsize i;
+
+ /* cond_chars_common() use accept string, so mark all elements with, and later unset from reject */
+ accept_str = (char *)wmem_alloc(wmem_epan_scope(), 256);
+ memset(accept_str, 0xFF, 256);
+ for (i = 0; chr[i]; i++)
+ accept_str[(unsigned) chr[i]] = '\0';
+
+ w->condition = cond_chars_common;
+ w->id = id;
+ w->control.str = accept_str;
+ w->len = 0;
+ w->min = min_len ? min_len : 1;
+ w->max = max_len ? max_len : G_MAXINT/2;
+ w->data = data;
+ w->before = before_cb;
+ w->after = after_cb;
+
+ return w;
+}
+
+
+static int cond_string(tvbparse_t* tt, const int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
+ int len = wanted->len;
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_STRING) ws_warning("cond_string: control='%s'",wanted->control.str);
+#endif
+
+ if ( offset + wanted->len > tt->end_offset )
+ return -1;
+
+ if ( tvb_strneql(tt->tvb, offset, wanted->control.str, len) == 0 ) {
+ *tok = new_tok(tt,wanted->id,offset,len,wanted);
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_STRING) ws_warning("cond_string: GOT len=%i",len);
+#endif
+ return len;
+ } else {
+ return -1;
+ }
+}
+
+tvbparse_wanted_t* tvbparse_string(const int id,
+ const gchar* str,
+ const void* data,
+ tvbparse_action_t before_cb,
+ tvbparse_action_t after_cb) {
+ tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
+
+ w->condition = cond_string;
+ w->id = id;
+ w->control.str = str;
+ w->len = (int) strlen(str);
+ w->data = data;
+ w->before = before_cb;
+ w->after = after_cb;
+
+ return w;
+}
+
+static int cond_casestring(tvbparse_t* tt, const int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
+ int len = wanted->len;
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CASESTRING) ws_warning("cond_casestring: control='%s'",wanted->control.str);
+#endif
+
+ if ( offset + len > tt->end_offset )
+ return -1;
+
+ if ( tvb_strncaseeql(tt->tvb, offset, wanted->control.str, len) == 0 ) {
+ *tok = new_tok(tt,wanted->id,offset,len,wanted);
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CASESTRING) ws_warning("cond_casestring: GOT len=%i",len);
+#endif
+ return len;
+ } else {
+ *tok = NULL;
+ return -1;
+ }
+}
+
+tvbparse_wanted_t* tvbparse_casestring(const int id,
+ const gchar* str,
+ const void* data,
+ tvbparse_action_t before_cb,
+ tvbparse_action_t after_cb) {
+ tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
+
+ w->condition = cond_casestring;
+ w->id = id;
+ w->control.str = str;
+ w->len = (int) strlen(str);
+ w->data = data;
+ w->before = before_cb;
+ w->after = after_cb;
+
+ return w;
+}
+
+static int cond_one_of(tvbparse_t* tt, const int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
+ guint i;
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_ONEOF) ws_warning("cond_one_of: START");
+#endif
+
+ if ( offset > tt->end_offset )
+ return -1;
+
+ if (++tt->recursion_depth > TVBPARSE_MAX_RECURSION_DEPTH)
+ return -1;
+
+ for(i=0; i < wanted->control.elems->len; i++) {
+ tvbparse_wanted_t* w = (tvbparse_wanted_t *)g_ptr_array_index(wanted->control.elems,i);
+ tvbparse_elem_t* new_elem = NULL;
+ int curr_len;
+
+ if ( offset + w->len > tt->end_offset )
+ continue;
+
+ curr_len = w->condition(tt, offset, w, &new_elem);
+
+ if (curr_len >= 0) {
+ *tok = new_tok(tt, wanted->id, new_elem->offset, new_elem->len, wanted);
+ (*tok)->sub = new_elem;
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_ONEOF) ws_warning("cond_one_of: GOT len=%i",curr_len);
+#endif
+ tt->recursion_depth--;
+ return curr_len;
+ }
+ }
+
+ tt->recursion_depth--;
+ return -1;
+}
+
+static bool
+tvbparse_wanted_cleanup_cb(wmem_allocator_t* allocator _U_, wmem_cb_event_t event _U_, void *user_data)
+{
+ tvbparse_wanted_t* w = (tvbparse_wanted_t *)user_data;
+ g_ptr_array_free(w->control.elems, TRUE);
+ return FALSE;
+}
+
+tvbparse_wanted_t* tvbparse_set_oneof(const int id,
+ const void* data,
+ tvbparse_action_t before_cb,
+ tvbparse_action_t after_cb,
+ ...) {
+ tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
+ tvbparse_t* el;
+ va_list ap;
+
+ w->condition = cond_one_of;
+ w->id = id;
+ w->data = data;
+ w->before = before_cb;
+ w->after = after_cb;
+ w->control.elems = g_ptr_array_new();
+ wmem_register_callback(wmem_epan_scope(), tvbparse_wanted_cleanup_cb, w);
+
+ va_start(ap,after_cb);
+
+ while(( el = va_arg(ap,tvbparse_t*) )) {
+ g_ptr_array_add(w->control.elems,el);
+ };
+
+ va_end(ap);
+
+ return w;
+}
+
+static int cond_hash(tvbparse_t* tt, const int offset, const tvbparse_wanted_t* wanted, tvbparse_elem_t** tok) {
+ int key_len;
+ gchar* key = NULL;
+ tvbparse_elem_t* key_elem = NULL;
+ tvbparse_wanted_t* value_wanted = NULL;
+ int value_len;
+ tvbparse_elem_t* value_elem = NULL;
+ int tot_len;
+ tvbparse_elem_t* ret_tok;
+
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_HASH) ws_warning("cond_hash: START");
+#endif
+
+ if ( offset > tt->end_offset )
+ return -1;
+
+ if (++tt->recursion_depth > TVBPARSE_MAX_RECURSION_DEPTH)
+ return -1;
+
+ key_len = wanted->control.hash.key->condition(tt, offset, wanted->control.hash.key, &key_elem);
+
+ if (key_len < 0) {
+ tt->recursion_depth--;
+ return -1;
+ }
+
+ key = tvb_get_string_enc(tt->scope,key_elem->parser->tvb,key_elem->offset,key_elem->len, ENC_ASCII);
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_HASH) ws_warning("cond_hash: got key='%s'",key);
+#endif
+
+ if ((value_wanted = (tvbparse_wanted_t *)wmem_map_lookup(wanted->control.hash.table,key))) {
+ value_len = value_wanted->condition(tt, offset + key_len, value_wanted, &value_elem);
+ } else if (wanted->control.hash.other) {
+ value_len = wanted->control.hash.other->condition(tt, offset+key_len, wanted->control.hash.other, &value_elem);
+ if (value_len < 0) {
+ tt->recursion_depth--;
+ return -1;
+ }
+ } else {
+ tt->recursion_depth--;
+ return -1;
+ }
+
+ tt->recursion_depth--;
+
+ tot_len = key_len + value_len;
+
+ ret_tok = new_tok(tt, value_elem->id, offset, tot_len, wanted);
+ ret_tok->sub = key_elem;
+ ret_tok->sub->last->next = value_elem;
+
+ *tok = ret_tok;
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_HASH) ws_warning("cond_hash: GOT len=%i",tot_len);
+#endif
+
+ return tot_len;
+}
+
+tvbparse_wanted_t* tvbparse_hashed(const int id,
+ const void* data,
+ tvbparse_action_t before_cb,
+ tvbparse_action_t after_cb,
+ tvbparse_wanted_t* key,
+ tvbparse_wanted_t* other,
+ ...) {
+ tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
+ gchar* name;
+ tvbparse_wanted_t* el;
+ va_list ap;
+
+ w->condition = cond_hash;
+ w->id = id;
+ w->data = data;
+ w->before = before_cb;
+ w->after = after_cb;
+ w->control.hash.table = wmem_map_new(wmem_epan_scope(), g_str_hash,g_str_equal);
+ w->control.hash.key = key;
+ w->control.hash.other = other;
+
+ va_start(ap,other);
+
+ while(( name = va_arg(ap,gchar*) )) {
+ el = va_arg(ap,tvbparse_wanted_t*);
+ wmem_map_insert(w->control.hash.table,name,el);
+ }
+
+ va_end(ap);
+
+ return w;
+}
+
+void tvbparse_hashed_add(tvbparse_wanted_t* w, ...) {
+ tvbparse_wanted_t* el;
+ va_list ap;
+ gchar* name;
+
+ va_start(ap,w);
+
+ while (( name = va_arg(ap,gchar*) )) {
+ el = va_arg(ap,tvbparse_wanted_t*);
+ wmem_map_insert(w->control.hash.table,name,el);
+ }
+
+ va_end(ap);
+}
+
+static int cond_seq(tvbparse_t* tt, int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
+ guint i;
+ int len = 0;
+ int start = offset;
+ tvbparse_elem_t* ret_tok = NULL;
+
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_SEQ) ws_warning("cond_seq: START");
+#endif
+
+ if ( offset > tt->end_offset )
+ return -1;
+
+ if (++tt->recursion_depth > TVBPARSE_MAX_RECURSION_DEPTH)
+ return -1;
+
+ for(i=0; i < wanted->control.elems->len; i++) {
+ tvbparse_wanted_t* w = (tvbparse_wanted_t *)g_ptr_array_index(wanted->control.elems,i);
+ tvbparse_elem_t* new_elem = NULL;
+
+ if ( offset + w->len > tt->end_offset ) {
+ tt->recursion_depth--;
+ return -1;
+ }
+
+ len = w->condition(tt, offset, w, &new_elem);
+
+ if (len >= 0) {
+ if (ret_tok) {
+ if (new_elem->len)
+ ret_tok->len = (new_elem->offset - ret_tok->offset) + new_elem->len;
+ ret_tok->sub->last->next = new_elem;
+ ret_tok->sub->last = new_elem;
+ } else {
+ ret_tok = new_tok(tt, wanted->id, new_elem->offset, new_elem->len, wanted);
+ ret_tok->sub = new_elem;
+ new_elem->last = new_elem;
+ }
+ } else {
+ tt->recursion_depth--;
+ return -1;
+ }
+
+ offset += len;
+ offset += ignore_fcn(tt,offset);
+ }
+
+ tt->recursion_depth--;
+
+ *tok = ret_tok;
+
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_SEQ) ws_warning("cond_seq: GOT len=%i",offset - start);
+#endif
+
+ return offset - start;
+}
+
+
+tvbparse_wanted_t* tvbparse_set_seq(const int id,
+ const void* data,
+ tvbparse_action_t before_cb,
+ tvbparse_action_t after_cb,
+ ...) {
+ tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
+ tvbparse_wanted_t* el = NULL;
+ va_list ap;
+
+ w->condition = cond_seq;
+ w->id = id;
+ w->data = data;
+ w->before = before_cb;
+ w->after = after_cb;
+ w->control.elems = g_ptr_array_new();
+ wmem_register_callback(wmem_epan_scope(), tvbparse_wanted_cleanup_cb, w);
+
+ va_start(ap,after_cb);
+
+ while(( el = va_arg(ap,tvbparse_wanted_t*) )) {
+ g_ptr_array_add(w->control.elems,el);
+ };
+
+ va_end(ap);
+ return w;
+}
+
+static int cond_some(tvbparse_t* tt, int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
+ guint got_so_far = 0;
+ int start = offset;
+ tvbparse_elem_t* ret_tok = NULL;
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_SOME) ws_warning("cond_some: START");
+#endif
+
+ if ( offset > tt->end_offset )
+ return -1;
+
+ if (++tt->recursion_depth > TVBPARSE_MAX_RECURSION_DEPTH)
+ return -1;
+
+ if ( wanted->min == 0 ) {
+ ret_tok = new_tok(tt,wanted->id,offset,0,wanted);
+ }
+
+ while (got_so_far < wanted->max) {
+ tvbparse_elem_t* new_elem = NULL;
+ int consumed;
+
+ if ( offset > tt->end_offset ) {
+ tt->recursion_depth--;
+ return -1;
+ }
+
+ consumed = wanted->control.subelem->condition(tt, offset, wanted->control.subelem, &new_elem);
+
+ if(consumed >= 0) {
+ if (ret_tok) {
+ if (new_elem->len)
+ ret_tok->len = (new_elem->offset - ret_tok->offset) + new_elem->len;
+
+ if (ret_tok->sub) {
+ ret_tok->sub->last->next = new_elem;
+ ret_tok->sub->last = new_elem;
+ } else {
+ ret_tok->sub = new_elem;
+ }
+ } else {
+ ret_tok = new_tok(tt, wanted->id, new_elem->offset, new_elem->len, wanted);
+ ret_tok->sub = new_elem;
+ }
+ } else {
+ break;
+ }
+
+ offset += consumed;
+ got_so_far++;
+ }
+
+ tt->recursion_depth--;
+
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_SOME) ws_warning("cond_some: got num=%u",got_so_far);
+#endif
+
+ if(got_so_far < wanted->min) {
+ return -1;
+ }
+
+ *tok = ret_tok;
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_SOME) ws_warning("cond_some: GOT len=%i",offset - start);
+#endif
+ return offset - start;
+}
+
+tvbparse_wanted_t* tvbparse_some(const int id,
+ const guint from,
+ const guint to,
+ const void* data,
+ tvbparse_action_t before_cb,
+ tvbparse_action_t after_cb,
+ const tvbparse_wanted_t* el) {
+
+ tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
+
+ ws_assert(from <= to);
+
+ w->condition = cond_some;
+ w->id = id;
+ w->min = from;
+ w->max = to;
+ w->data = data;
+ w->before = before_cb;
+ w->after = after_cb;
+ w->control.subelem = el;
+
+ return w;
+}
+
+
+static int cond_until(tvbparse_t* tt, const int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
+ tvbparse_elem_t* new_elem = NULL;
+ int len = 0;
+ int target_offset = offset;
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_UNTIL) ws_warning("cond_until: START");
+#endif
+
+ if ( offset + wanted->control.until.subelem->len > tt->end_offset )
+ return -1;
+
+ if (++tt->recursion_depth > TVBPARSE_MAX_RECURSION_DEPTH)
+ return -1;
+
+ do {
+ len = wanted->control.until.subelem->condition(tt, target_offset++, wanted->control.until.subelem, &new_elem);
+ } while(len < 0 && target_offset+1 < tt->end_offset);
+
+ tt->recursion_depth--;
+
+ if (len >= 0) {
+
+ new_elem->id = wanted->id;
+ new_elem->next = NULL;
+ new_elem->last = NULL;
+ new_elem->wanted = wanted;
+ new_elem->offset = offset;
+
+ (*tok) = new_elem;
+
+ switch (wanted->control.until.mode) {
+ case TP_UNTIL_INCLUDE:
+ new_elem->len = target_offset - offset - 1 + len;
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_UNTIL) ws_warning("cond_until: GOT len=%i",target_offset - offset -1 + len);
+#endif
+ return target_offset - offset -1 + len;
+ case TP_UNTIL_SPEND:
+ new_elem->len = target_offset - offset - 1;
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_UNTIL) ws_warning("cond_until: GOT len=%i",target_offset - offset -1 + len);
+#endif
+ return target_offset - offset - 1 + len;
+ case TP_UNTIL_LEAVE:
+ new_elem->len = target_offset - offset - 1;
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_UNTIL) ws_warning("cond_until: GOT len=%i",target_offset - offset -1);
+#endif
+ return target_offset - offset -1;
+ default:
+ DISSECTOR_ASSERT_NOT_REACHED();
+ return -1;
+ }
+
+ } else {
+ return -1;
+ }
+}
+
+tvbparse_wanted_t* tvbparse_until(const int id,
+ const void* data,
+ tvbparse_action_t before_cb,
+ tvbparse_action_t after_cb,
+ const tvbparse_wanted_t* el,
+ until_mode_t until_mode) {
+ tvbparse_wanted_t* w = wmem_new0(wmem_epan_scope(), tvbparse_wanted_t);
+
+ w->condition = cond_until;
+ w->control.until.mode = until_mode;
+ w->control.until.subelem = el;
+ w->id = id;
+ w->data = data;
+ w->before = before_cb;
+ w->after = after_cb;
+
+ return w;
+}
+
+tvbparse_wanted_t* tvbparse_quoted(const int id,
+ const void* data,
+ tvbparse_action_t before_cb,
+ tvbparse_action_t after_cb,
+ const char quote,
+ const char esc) {
+
+ gchar* esc_quot = wmem_strdup_printf(wmem_epan_scope(), "%c%c",esc,quote);
+ gchar* quot = wmem_strdup_printf(wmem_epan_scope(), "%c",quote);
+ tvbparse_wanted_t* want_quot = tvbparse_char(-1,quot,NULL,NULL,NULL);
+
+ return tvbparse_set_oneof(id, data, before_cb, after_cb,
+ tvbparse_set_seq(-1, NULL, NULL, NULL,
+ want_quot,
+ tvbparse_set_seq(-1,NULL,NULL,NULL,
+ tvbparse_set_oneof(-1, NULL, NULL, NULL,
+ tvbparse_string(-1,esc_quot,NULL,NULL,NULL),
+ tvbparse_not_chars(-1,0,0,quot,NULL,NULL,NULL),
+ NULL),
+ NULL),
+ want_quot,
+ NULL),
+ tvbparse_set_seq(-1, NULL, NULL, NULL,
+ want_quot,
+ want_quot,
+ NULL),
+ NULL);
+}
+
+void tvbparse_shrink_token_cb(void* tvbparse_data _U_,
+ const void* wanted_data _U_,
+ tvbparse_elem_t* tok) {
+ tok->offset += 1;
+ tok->len -= 2;
+}
+
+tvbparse_t* tvbparse_init(wmem_allocator_t *scope,
+ tvbuff_t* tvb,
+ const int offset,
+ int len,
+ void* data,
+ const tvbparse_wanted_t* ignore) {
+ tvbparse_t* tt = wmem_new(scope, tvbparse_t);
+
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_TT) ws_warning("tvbparse_init: offset=%i len=%i",offset,len);
+#endif
+
+ tt->scope = scope;
+ tt->tvb = tvb;
+ tt->offset = offset;
+ len = (len == -1) ? (int) tvb_captured_length(tvb) : len;
+ tt->end_offset = offset + len;
+ tt->data = data;
+ tt->ignore = ignore;
+ tt->recursion_depth = 0;
+ return tt;
+}
+
+gboolean tvbparse_reset(tvbparse_t* tt,
+ const int offset,
+ int len) {
+
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_TT) ws_warning("tvbparse_init: offset=%i len=%i",offset,len);
+#endif
+
+ len = (len == -1) ? (int) tvb_captured_length(tt->tvb) : len;
+
+ if( tvb_captured_length_remaining(tt->tvb, offset) >= len) {
+ tt->offset = offset;
+ tt->end_offset = offset + len;
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+guint tvbparse_curr_offset(tvbparse_t* tt) {
+ return tt->offset;
+}
+
+static void execute_callbacks(tvbparse_t* tt, tvbparse_elem_t* curr) {
+ wmem_stack_t *stack = wmem_stack_new(tt->scope);
+
+ while (curr) {
+ if(curr->wanted->before) {
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CB) ws_warning("execute_callbacks: BEFORE: id=%i offset=%i len=%i",curr->id,curr->offset,curr->len);
+#endif
+ curr->wanted->before(tt->data, curr->wanted->data, curr);
+ }
+
+ if(curr->sub) {
+ wmem_stack_push(stack, curr);
+ curr = curr->sub;
+ continue;
+ } else {
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CB) ws_warning("execute_callbacks: AFTER: id=%i offset=%i len=%i",curr->id,curr->offset,curr->len);
+#endif
+ if(curr->wanted->after) curr->wanted->after(tt->data, curr->wanted->data, curr);
+ }
+
+ curr = curr->next;
+
+ while( !curr && wmem_stack_count(stack) > 0 ) {
+ curr = (tvbparse_elem_t *)wmem_stack_pop(stack);
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CB) ws_warning("execute_callbacks: AFTER: id=%i offset=%i len=%i",curr->id,curr->offset,curr->len);
+#endif
+ if( curr->wanted->after ) curr->wanted->after(tt->data, curr->wanted->data, curr);
+ curr = curr->next;
+ }
+ }
+
+}
+
+gboolean tvbparse_peek(tvbparse_t* tt,
+ const tvbparse_wanted_t* wanted) {
+ tvbparse_elem_t* tok = NULL;
+ int consumed;
+ int offset = tt->offset;
+
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_PEEK) ws_warning("tvbparse_peek: ENTER offset=%i",offset);
+#endif
+
+ offset += ignore_fcn(tt,offset);
+
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_PEEK) ws_warning("tvbparse_peek: after ignore offset=%i",offset);
+#endif
+
+ consumed = wanted->condition(tt,offset,wanted,&tok);
+
+ if (consumed >= 0) {
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_PEEK) ws_warning("tvbparse_peek: GOT len=%i",consumed);
+#endif
+ return TRUE;
+ } else {
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_PEEK) ws_warning("tvbparse_peek: NOT GOT");
+#endif
+ return FALSE;
+ }
+
+}
+
+tvbparse_elem_t* tvbparse_get(tvbparse_t* tt,
+ const tvbparse_wanted_t* wanted) {
+ tvbparse_elem_t* tok = NULL;
+ int consumed;
+ int offset = tt->offset;
+
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_GET) ws_warning("tvbparse_get: ENTER offset=%i",offset);
+#endif
+
+ offset += ignore_fcn(tt,offset);
+
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_GET) ws_warning("tvbparse_get: after ignore offset=%i",offset);
+#endif
+
+ consumed = wanted->condition(tt,offset,wanted,&tok);
+
+ if (consumed >= 0) {
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_GET) ws_warning("tvbparse_get: GOT len=%i",consumed);
+#endif
+ execute_callbacks(tt,tok);
+ tt->offset = offset + consumed;
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_GET) ws_warning("tvbparse_get: DONE offset=%i", tt->offset);
+#endif
+ return tok;
+ } else {
+ return NULL;
+ }
+
+}
+
+
+tvbparse_elem_t* tvbparse_find(tvbparse_t* tt, const tvbparse_wanted_t* wanted) {
+ tvbparse_elem_t* tok = NULL;
+ int len = 0;
+ int offset = tt->offset;
+ int target_offset = offset -1;
+
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_FIND) ws_warning("tvbparse_get: ENTER offset=%i", tt->offset);
+#endif
+
+ do {
+ len = wanted->condition(tt, target_offset+1, wanted, &tok);
+ } while(len < 0 && ++target_offset < tt->end_offset);
+
+ if (len >= 0) {
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_FIND) ws_warning("tvbparse_get: FOUND offset=%i len=%i", target_offset,len);
+#endif
+ execute_callbacks(tt,tok);
+ tt->offset = target_offset + len;
+
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_FIND) ws_warning("tvbparse_get: DONE offset=%i", tt->offset);
+#endif
+ return tok;
+ } else {
+#ifdef TVBPARSE_DEBUG
+ if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_FIND) ws_warning("tvbparse_get: NOT FOUND");
+#endif
+ return NULL;
+ }
+}
+
+struct _elem_tree_stack_frame {
+ proto_tree* tree;
+ tvbparse_elem_t* elem;
+};
+
+void tvbparse_tree_add_elem(proto_tree* tree, tvbparse_elem_t* curr) {
+ wmem_stack_t *stack = wmem_stack_new(curr->parser->scope);
+ struct _elem_tree_stack_frame* frame = wmem_new(curr->parser->scope, struct _elem_tree_stack_frame);
+ proto_item* pi;
+ frame->tree = tree;
+ frame->elem = curr;
+
+ while (curr) {
+ pi = proto_tree_add_format_text(frame->tree,curr->parser->tvb,curr->offset,curr->len);
+
+ if(curr->sub) {
+ frame->elem = curr;
+ wmem_stack_push(stack, frame);
+ frame = wmem_new(curr->parser->scope, struct _elem_tree_stack_frame);
+ frame->tree = proto_item_add_subtree(pi,0);
+ curr = curr->sub;
+ continue;
+ }
+
+ curr = curr->next;
+
+ while( !curr && wmem_stack_count(stack) > 0 ) {
+ frame = (struct _elem_tree_stack_frame *)wmem_stack_pop(stack);
+ curr = frame->elem->next;
+ }
+
+ }
+}
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */