summaryrefslogtreecommitdiff
path: root/epan/tvbparse.c
diff options
context:
space:
mode:
authorLuis Ontanon <luis.ontanon@gmail.com>2005-09-08 19:50:13 +0000
committerLuis Ontanon <luis.ontanon@gmail.com>2005-09-08 19:50:13 +0000
commit8a4fd5e3b0ae2a602b414d08675085f7ef1f8625 (patch)
treec6cb7b1f75fc907c34a8fd7392cf42ab9ecb5188 /epan/tvbparse.c
parente0331bbb1c23aad02e6b0264e959cac4d180b84c (diff)
downloadwireshark-8a4fd5e3b0ae2a602b414d08675085f7ef1f8625.tar.gz
an API for "bufferless" parsing of text tvbs
svn path=/trunk/; revision=15726
Diffstat (limited to 'epan/tvbparse.c')
-rw-r--r--epan/tvbparse.c756
1 files changed, 756 insertions, 0 deletions
diff --git a/epan/tvbparse.c b/epan/tvbparse.c
new file mode 100644
index 0000000000..3bbcc1a01d
--- /dev/null
+++ b/epan/tvbparse.c
@@ -0,0 +1,756 @@
+/* tvbparse.c
+*
+* Copyright 2005, Luis E. Garcia Ontanon <luis.ontanon@gmail.com>
+*
+* $Id: $
+*
+* Ethereal - Network traffic analyzer
+* By Gerald Combs <gerald@ethereal.com>
+* Copyright 1998 Gerald Combs
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+
+#include <epan/emem.h>
+#include <epan/proto.h>
+#include <epan/tvbparse.h>
+
+typedef enum _tvbparse_wanted_type_t {
+ TVBPARSE_WANTED_NONE, /* currently unused */
+
+ /* simple tokens */
+ TVBPARSE_WANTED_SIMPLE_CHAR, /* just one matching char */
+ TVBPARSE_WANTED_SIMPLE_CHARS, /* a sequence of matching chars */
+ TVBPARSE_WANTED_SIMPLE_NOT_CHAR, /* one non matching char */
+ TVBPARSE_WANTED_SIMPLE_NOT_CHARS, /* a sequence of non matching chars */
+ TVBPARSE_WANTED_SIMPLE_STRING, /* a string */
+ TVBPARSE_WANTED_SIMPLE_CASESTRING, /* a caseless string */
+ TVBPARSE_WANTED_UNTIL, /* all the characters until the first matching token */
+
+ /* composed tokens */
+ TVBPARSE_WANTED_SET_ONEOF, /* one of the given types */
+ TVBPARSE_WANTED_SET_SEQ, /* an exact sequence of tokens of the given types */
+ TVBPARSE_WANTED_CARDINALITY, /* one or more tokens of the given type */
+} tvbparse_type_t;
+
+struct _tvbparse_t {
+ tvbuff_t* tvb;
+ int offset;
+ int max_len;
+ void* data;
+ const tvbparse_wanted_t* ignore;
+ guint depth;
+};
+
+struct _tvbparse_wanted_t {
+ int id;
+ tvbparse_type_t type;
+
+ const gchar* ctl;
+ int len;
+
+ guint min;
+ guint max;
+
+ const void* data;
+ tvbparse_action_t before;
+ tvbparse_action_t after;
+
+ GPtrArray* elems;
+};
+
+
+tvbparse_wanted_t* tvbparse_char(int id,
+ const gchar* chr,
+ const void* data,
+ tvbparse_action_t before_cb,
+ tvbparse_action_t after_cb) {
+ tvbparse_wanted_t* w = g_malloc(sizeof(tvbparse_wanted_t));
+
+ w->id = id;
+ w->type = TVBPARSE_WANTED_SIMPLE_CHAR;
+ w->ctl = chr;
+ w->len = 1;
+ w->min = 0;
+ w->max = 0;
+ w->data = data;
+ w->before = before_cb;
+ w->after = after_cb;
+ w->elems = g_ptr_array_new();
+
+ return w;
+}
+
+tvbparse_wanted_t* tvbparse_chars(int id,
+ guint min_len,
+ guint max_len,
+ const gchar* chr,
+ const void* data,
+ tvbparse_action_t before_cb,
+ tvbparse_action_t after_cb) {
+ tvbparse_wanted_t* w = g_malloc(sizeof(tvbparse_wanted_t));
+
+ w->id = id;
+ w->type = TVBPARSE_WANTED_SIMPLE_CHARS;
+ w->ctl = chr;
+ w->len = 0;
+ w->min = min_len ? min_len : 1;
+ w->max = max_len ? max_len : G_MAXINT;
+ w->data = data;
+ w->before = before_cb;
+ w->after = after_cb;
+ w->elems = g_ptr_array_new();
+
+ return w;
+}
+
+tvbparse_wanted_t* tvbparse_not_char(int id,
+ const gchar* chr,
+ const void* data,
+ tvbparse_action_t before_cb,
+ tvbparse_action_t after_cb) {
+ tvbparse_wanted_t* w = g_malloc(sizeof(tvbparse_wanted_t));
+
+ w->id = id;
+ w->type = TVBPARSE_WANTED_SIMPLE_NOT_CHAR;
+ w->ctl = chr;
+ w->len = 0;
+ w->min = 0;
+ w->max = 0;
+ w->data = data;
+ w->before = before_cb;
+ w->after = after_cb;
+ w->elems = g_ptr_array_new();
+
+ return w;
+}
+
+tvbparse_wanted_t* tvbparse_not_chars(int id,
+ guint min_len,
+ guint max_len,
+ const gchar* chr,
+ const void* data,
+ tvbparse_action_t before_cb,
+ tvbparse_action_t after_cb){
+ tvbparse_wanted_t* w = g_malloc(sizeof(tvbparse_wanted_t));
+
+ w->id = id;
+ w->type = TVBPARSE_WANTED_SIMPLE_NOT_CHARS;
+ w->ctl = chr;
+ w->len = 0;
+ w->min = min_len ? min_len : 1;
+ w->max = max_len ? max_len : G_MAXINT;
+ w->data = data;
+ w->before = before_cb;
+ w->after = after_cb;
+ w->elems = g_ptr_array_new();
+
+ return w;
+}
+
+
+tvbparse_wanted_t* tvbparse_string(int id,
+ const gchar* str,
+ const void* data,
+ tvbparse_action_t before_cb,
+ tvbparse_action_t after_cb) {
+ tvbparse_wanted_t* w = g_malloc(sizeof(tvbparse_wanted_t));
+
+ w->id = id;
+ w->type = TVBPARSE_WANTED_SIMPLE_STRING;
+ w->ctl = str;
+ w->len = strlen(str);
+ w->min = 0;
+ w->max = 0;
+ w->data = data;
+ w->before = before_cb;
+ w->after = after_cb;
+ w->elems = g_ptr_array_new();
+
+ return w;
+}
+
+tvbparse_wanted_t* tvbparse_casestring(int id,
+ const gchar* str,
+ const void* data,
+ tvbparse_action_t before_cb,
+ tvbparse_action_t after_cb) {
+ tvbparse_wanted_t* w = g_malloc(sizeof(tvbparse_wanted_t));
+
+ w->id = id;
+ w->type = TVBPARSE_WANTED_SIMPLE_CASESTRING;
+ w->ctl = str;
+ w->len = strlen(str);
+ w->min = 0;
+ w->max = 0;
+ w->data = data;
+ w->before = before_cb;
+ w->after = after_cb;
+ w->elems = g_ptr_array_new();
+
+ return w;
+}
+
+
+tvbparse_wanted_t* tvbparse_set_oneof(int id,
+ const void* data,
+ tvbparse_action_t before_cb,
+ tvbparse_action_t after_cb,
+ ...) {
+ tvbparse_wanted_t* w = g_malloc(sizeof(tvbparse_wanted_t));
+ tvbparse_t* el;
+ va_list ap;
+
+ w->id = id;
+ w->type = TVBPARSE_WANTED_SET_ONEOF;
+ w->ctl = NULL;
+ w->len = 0;
+ w->min = 0;
+ w->max = 0;
+ w->data = data;
+ w->before = before_cb;
+ w->after = after_cb;
+ w->elems = g_ptr_array_new();
+
+ va_start(ap,after_cb);
+
+ while(( el = va_arg(ap,tvbparse_t*) )) {
+ g_ptr_array_add(w->elems,el);
+ };
+
+ va_end(ap);
+
+ return w;
+}
+
+tvbparse_wanted_t* tvbparse_set_seq(int id,
+ const void* data,
+ tvbparse_action_t before_cb,
+ tvbparse_action_t after_cb,
+ ...) {
+ tvbparse_wanted_t* w = g_malloc(sizeof(tvbparse_wanted_t));
+ tvbparse_wanted_t* el = NULL;
+ va_list ap;
+
+ w->id = id;
+ w->type = TVBPARSE_WANTED_SET_SEQ;
+ w->ctl = NULL;
+ w->len = 0;
+ w->min = 0;
+ w->max = 0;
+ w->data = data;
+ w->before = before_cb;
+ w->after = after_cb;
+ w->elems = g_ptr_array_new();
+
+ va_start(ap,after_cb);
+
+ while(( el = va_arg(ap,tvbparse_wanted_t*) )) {
+ g_ptr_array_add(w->elems,el);
+ };
+
+ va_end(ap);
+ return w;
+}
+
+
+tvbparse_wanted_t* tvbparse_some(int id,
+ guint from,
+ guint to,
+ const void* data,
+ tvbparse_action_t before_cb,
+ tvbparse_action_t after_cb,
+ const tvbparse_wanted_t* el) {
+
+ tvbparse_wanted_t* w = g_malloc(sizeof(tvbparse_wanted_t));
+
+ g_assert(from > 0 && from < to);
+
+ w->id = id;
+ w->type = TVBPARSE_WANTED_CARDINALITY;
+ w->ctl = NULL;
+ w->len = 0;
+ w->min = from;
+ w->max = to;
+ w->data = data;
+ w->before = before_cb;
+ w->after = after_cb;
+ w->elems = g_ptr_array_new();
+
+ g_ptr_array_add(w->elems,(gpointer)el);
+
+ return w;
+}
+
+tvbparse_wanted_t* tvbparse_until(int id,
+ const void* data,
+ tvbparse_action_t before_cb,
+ tvbparse_action_t after_cb,
+ const tvbparse_wanted_t* el,
+ gboolean include_term) {
+ tvbparse_wanted_t* w = g_malloc(sizeof(tvbparse_wanted_t));
+
+ w->id = id;
+ w->type = TVBPARSE_WANTED_UNTIL;
+
+ /* XXX this is ugly */
+ w->ctl = include_term ? "include" : "do not include";
+
+ w->len = 0;
+ w->min = 0;
+ w->max = 0;
+ w->data = data;
+ w->before = before_cb;
+ w->after = after_cb;
+ w->elems = g_ptr_array_new();
+
+ g_ptr_array_add(w->elems,(gpointer)el);
+
+ return w;
+}
+
+
+tvbparse_wanted_t* tvbparse_quoted(int id,
+ const void* data,
+ tvbparse_action_t before_cb,
+ tvbparse_action_t after_cb,
+ char quote,
+ char esc) {
+
+ gchar* esc_quot = g_strdup_printf("%c%c",esc,quote);
+ gchar* quot = g_strdup_printf("%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(tvbuff_t* tvb,
+ int offset,
+ int len,
+ void* data,
+ const tvbparse_wanted_t* ignore) {
+ tvbparse_t* tt = ep_alloc(sizeof(tvbparse_t));
+
+ tt->tvb = tvb;
+ tt->offset = offset;
+ tt->max_len = (len == -1) ? (int) tvb_length(tvb) : len;
+ tt->data = data;
+ tt->ignore = ignore;
+ tt->depth = 0;
+ return tt;
+}
+
+gboolean tvbparse_reset(tvbparse_t* tt,
+ int offset,
+ int len) {
+
+ len = (len == -1) ? (int) tvb_length(tt->tvb) : len;
+
+ if( tvb_length_remaining(tt->tvb, offset) >= len) {
+ tt->offset = offset;
+ tt->max_len = len;
+ tt->depth = 0;
+ return TRUE;
+ } else {
+ tt->depth = 0;
+ return FALSE;
+ }
+}
+
+static tvbparse_elem_t* new_tok(tvbparse_t* tt,
+ int id,
+ int offset,
+ int len,
+ const tvbparse_wanted_t* wanted) {
+ tvbparse_elem_t* tok = ep_alloc(sizeof(tvbparse_elem_t));
+
+ 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;
+}
+
+tvbparse_elem_t* tvbparse_get(tvbparse_t* tt,
+ const tvbparse_wanted_t* wanted) {
+ tvbparse_elem_t* tok = NULL;
+ int save_offset = tt->offset;
+ int save_len = tt->max_len;
+
+ tt->depth++;
+
+ if (tt->ignore && tt->ignore != wanted) {
+ tvbparse_wanted_t* save = (void*)tt->ignore;
+ tt->ignore = NULL;
+ while ( tvbparse_get(tt,save) ) {
+ ;
+ }
+ tt->ignore = save;
+ }
+
+ switch(wanted->type) {
+ case TVBPARSE_WANTED_NONE:
+ goto reject;
+ case TVBPARSE_WANTED_SIMPLE_NOT_CHAR:
+ {
+ gchar c, t;
+ guint i;
+ gboolean not_matched = FALSE;
+
+ if (! tt->max_len )
+ goto reject;
+
+ t = (gchar) tvb_get_guint8(tt->tvb,tt->offset);
+
+ for(i = 0; (c = wanted->ctl[i]) && tt->max_len; i++) {
+ if ( c == t ) {
+ not_matched = TRUE;
+ }
+ }
+
+ if (not_matched) {
+ goto reject;
+ } else {
+ tt->offset++;
+ tt->max_len--;
+ tok = new_tok(tt,wanted->id,tt->offset-1,1,wanted);
+ goto accept;
+ }
+ }
+ case TVBPARSE_WANTED_SIMPLE_CHAR:
+ {
+ gchar c,t;
+ guint i;
+
+ if (! tt->max_len )
+ goto reject;
+
+ t = (gchar) tvb_get_guint8(tt->tvb,tt->offset);
+
+ for(i = 0; (c = wanted->ctl[i]) && tt->max_len; i++) {
+ if ( c == t ) {
+ tt->offset++;
+ tt->max_len--;
+ tok = new_tok(tt,wanted->id,tt->offset-1,1,wanted);
+ goto accept;
+ }
+ }
+ goto reject;
+ }
+ case TVBPARSE_WANTED_SIMPLE_NOT_CHARS:
+ {
+ gchar c, t;
+ guint i;
+ guint offset = tt->offset;
+ guint length = 0;
+
+ while( tt->max_len && length < wanted->max) {
+ gboolean not_matched = FALSE;
+ t = (gchar) tvb_get_guint8(tt->tvb,tt->offset);
+ i = 0;
+
+ while ( (c = wanted->ctl[i]) && tt->max_len ) {
+
+ if (c == t) {
+ not_matched = TRUE;
+ }
+
+ i++;
+ }
+
+ if ( not_matched )
+ break;
+
+ length++;
+ tt->offset++;
+ tt->max_len--;
+ };
+
+ if ( length < wanted->min ) {
+ goto reject;
+ } else {
+ tok = new_tok(tt,wanted->id,offset,length,wanted);
+ goto accept;
+ }
+ }
+ case TVBPARSE_WANTED_SIMPLE_CHARS:
+ {
+ gchar c, t;
+ guint i;
+ guint offset = tt->offset;
+ guint length = 0;
+
+ while( tt->max_len && length < wanted->max) {
+ gboolean matched = FALSE;
+ t = (gchar) tvb_get_guint8(tt->tvb,tt->offset);
+ i = 0;
+
+ while ( (c = wanted->ctl[i]) && tt->max_len ) {
+
+ if (c == t) {
+ matched = TRUE;
+ break;
+ }
+
+ i++;
+ }
+
+ if (! matched )
+ break;
+
+ length++;
+ tt->offset++;
+ tt->max_len--;
+ };
+
+ if (length < wanted->min) {
+ goto reject;
+ } else {
+ tok = new_tok(tt,wanted->id,offset,length,wanted);
+ goto accept;
+ }
+ }
+ case TVBPARSE_WANTED_SIMPLE_STRING:
+ {
+ if ( tvb_strneql(tt->tvb, tt->offset, wanted->ctl, wanted->len) == 0 ) {
+ int offset = tt->offset;
+ tt->offset += wanted->len;
+ tt->max_len -= wanted->len;
+ tok = new_tok(tt,wanted->id,offset,wanted->len,wanted);
+ goto accept;
+ } else {
+ goto reject;
+ }
+ }
+ case TVBPARSE_WANTED_SIMPLE_CASESTRING:
+ {
+ if ( tvb_strncaseeql(tt->tvb, tt->offset, wanted->ctl, wanted->len) == 0 ) {
+ int offset = tt->offset;
+ tt->offset += wanted->len;
+ tt->max_len -= wanted->len;
+ tok = new_tok(tt,wanted->id,offset,wanted->len,wanted);
+ goto accept;
+ } else {
+ goto reject;
+ }
+ }
+ case TVBPARSE_WANTED_SET_ONEOF:
+ {
+ guint i;
+
+ for(i=0; i < wanted->elems->len; i++) {
+ tvbparse_wanted_t* w = g_ptr_array_index(wanted->elems,i);
+ tvbparse_elem_t* new = tvbparse_get(tt, w);
+
+ if (new) {
+ tok = new_tok(tt, wanted->id, new->offset, new->len, wanted);
+ tok->sub = new;
+ goto accept;
+ }
+ }
+ goto reject;
+ }
+ case TVBPARSE_WANTED_SET_SEQ:
+ {
+ guint i;
+
+ for(i=0; i < wanted->elems->len; i++) {
+ tvbparse_wanted_t* w = g_ptr_array_index(wanted->elems,i);
+ tvbparse_elem_t* new = tvbparse_get(tt, w);
+
+ if (new) {
+ if (tok) {
+ tok->len = (new->offset - tok->offset) + new->len;
+ tok->sub->last->next = new;
+ tok->sub->last = new;
+ } else {
+ tok = new_tok(tt, wanted->id, new->offset, new->len, wanted);
+ tok->sub = new;
+ }
+ } else {
+ goto reject;
+ }
+
+ }
+
+ goto accept;
+ }
+ case TVBPARSE_WANTED_CARDINALITY:
+ {
+ guint got_so_far = 0;
+ tvbparse_wanted_t* w = g_ptr_array_index(wanted->elems,0);
+
+ while (got_so_far < wanted->max) {
+ tvbparse_elem_t* new = tvbparse_get(tt, w);
+
+ if(new) {
+ if (tok) {
+ tok->len = (new->offset - tok->offset) + new->len;
+ tok->sub->last->next = new;
+ tok->sub->last = new;
+ } else {
+ tok = new_tok(tt, wanted->id, new->offset, new->len, wanted);
+ tok->sub = new;
+ }
+ } else {
+ break;
+ }
+
+ got_so_far++;
+ }
+
+ if(got_so_far < wanted->min) {
+ goto reject;
+ }
+
+ goto accept;
+ }
+ case TVBPARSE_WANTED_UNTIL:
+ {
+ int offset = tt->offset;
+ tvbparse_wanted_t* w = g_ptr_array_index(wanted->elems,0);
+ tvbparse_elem_t* new = tvbparse_find(tt, w);
+
+ if (new) {
+ tok = new;
+
+ /* XXX this is ugly */
+ if (*(wanted->ctl) == 'i' ) {
+ tok->len = (tok->offset - offset) + tok->len;
+ } else {
+ tok->len = (tok->offset - offset);
+
+ tt->offset = save_offset + tok->len;
+ tt->max_len = save_len - tok->len;
+ }
+
+ tok->offset = offset;
+ tok->id = wanted->id;
+ tok->next = NULL;
+ tok->last = tok;
+ tok->wanted = wanted;
+
+ goto accept;
+ } else {
+ goto reject;
+ }
+ }
+ }
+
+ DISSECTOR_ASSERT_NOT_REACHED();
+ return NULL;
+
+accept:
+ if (tok) {
+ if( tt->depth == 1 ) {
+ GPtrArray* stack = g_ptr_array_new();
+ tvbparse_elem_t* curr = tok;
+
+ while (curr) {
+
+ if(curr->wanted->before) {
+ curr->wanted->before(tt->data, curr->wanted->data, curr);
+ }
+
+ if(curr->sub) {
+ g_ptr_array_add(stack,curr);
+ curr = curr->sub;
+ continue;
+ } else {
+ if(curr->wanted->after) curr->wanted->after(tt->data, curr->wanted->data, curr);
+ }
+
+ curr = curr->next;
+
+ while( !curr && stack->len ) {
+ curr = g_ptr_array_remove_index_fast(stack,stack->len - 1);
+ if( curr->wanted->after ) curr->wanted->after(tt->data, curr->wanted->data, curr);
+ curr = curr->next;
+ }
+
+ }
+
+ g_ptr_array_free(stack,FALSE);
+ }
+
+ tt->depth--;
+ return tok;
+ }
+
+reject:
+ tt->offset = save_offset;
+ tt->max_len = save_len;
+ tt->depth--;
+ return NULL;
+
+}
+
+
+tvbparse_elem_t* tvbparse_find(tvbparse_t* tt, const tvbparse_wanted_t* wanted) {
+ int save_offset = tt->offset;
+ int save_len = tt->max_len;
+ tvbparse_elem_t* tok = NULL;
+
+ while ( tvb_length_remaining(tt->tvb,tt->offset) >= wanted->len ) {
+ if (( tok = tvbparse_get(tt, wanted) )) {
+ return tok;
+ }
+ tt->offset++;
+ tt->max_len--;
+ }
+
+ tt->offset = save_offset;
+ tt->max_len = save_len;
+
+ return NULL;
+}
+