Change tvbparse's engine to use callbacks instead of a big switch.
authorLuis Ontanon <luis.ontanon@gmail.com>
Wed, 28 Dec 2005 23:57:43 +0000 (23:57 -0000)
committerLuis Ontanon <luis.ontanon@gmail.com>
Wed, 28 Dec 2005 23:57:43 +0000 (23:57 -0000)
add some primitives.

svn path=/trunk/; revision=16916

epan/tvbparse.c
epan/tvbparse.h

index 8a66bc903ec9c199ef112f55039ed7096b0abc67..06b3f094f6bfcb673011079a18d8edb2d11c3295 100644 (file)
 #include <epan/packet_info.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_WANTED_HANDLE  /* a handle to another one */
-    
-} 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;
-       
-       union {
-        const gchar* str;
-        guint val;
-        struct _tvbparse_wanted_t** handle;
-    } control;
+#define TVBPARSE_DEBUG_ALL 0xffffffff
+
+/*#define TVBPARSE_DEBUG_ 0x80000000
+#define TVBPARSE_DEBUG_ 0x40000000
+#define TVBPARSE_DEBUG_ 0x20000000
+#define TVBPARSE_DEBUG_ 0x10000000*/
+
+#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
+/*#define TVBPARSE_DEBUG_ 0x00010000
+#define TVBPARSE_DEBUG_ 0x00008000
+#define TVBPARSE_DEBUG_ 0x00004000
+#define TVBPARSE_DEBUG_ 0x00002000
+#define TVBPARSE_DEBUG_ 0x00001000*/
+
+#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_ 0x00000020
+#define TVBPARSE_DEBUG_ 0x00000010
+#define TVBPARSE_DEBUG_ 0x00000008
+#define TVBPARSE_DEBUG_ 0x00000004
+#define TVBPARSE_DEBUG_ 0x00000002
+#define TVBPARSE_DEBUG_ 0x00000001*/
+
+/*
+#define TVBPARSE_DEBUG (TVBPARSE_DEBUG_SOME)
+*/
+
+static tvbparse_elem_t* new_tok(tvbparse_t* tt,
+                                int id,
+                                int offset,
+                                int len,
+                                const tvbparse_wanted_t* wanted) {
+       tvbparse_elem_t* tok;
     
-       int len;
-       
-       guint min;
-       guint max;
-       
-       const void* data;
-       tvbparse_action_t before;
-       tvbparse_action_t after;
+#ifdef TVBPARSE_DEBUG
+    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_NEWTOK) g_warning("new_tok: id=%i offset=%u len=%u",id,offset,len);
+#endif
+
+    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;
        
-       GPtrArray* elems;
-};
+       return tok;
+}
+
+static int ignore(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) g_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) g_warning("ignore: consumed=%i",consumed);
+#endif
+        
+    }
 
+#ifdef TVBPARSE_DEBUG
+    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_IGNORE) g_warning("ignore: len=%i",len);
+#endif
+    
+    return len;
+}
+
+
+static int cond_char (tvbparse_t* tt, 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) g_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) g_warning("cond_char: GOT: '%c'",c);
+#endif
+            return 1;
+        }
+    }
+    
+    return -1;
+}
 
 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;
+                                 const gchar* chr,
+                                 const void* data,
+                                 tvbparse_action_t before_cb,
+                                 tvbparse_action_t after_cb) {
+       tvbparse_wanted_t* w = g_malloc0(sizeof(tvbparse_wanted_t));
+       
+    w->condition = cond_char;
+    w->id = id;
        w->control.str = 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;
 }
 
+static int cond_chars (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) g_warning("cond_chars: 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 ) {
+        gchar t = (gchar) tvb_get_guint8(tt->tvb,offset++);
+        gchar c;
+        guint i = 0;
+        
+        while ( (c = wanted->control.str[i++]) ) {
+            if (c == t) goto next_char;
+        }
+        
+        break;
+        
+next_char:
+        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) g_warning("cond_chars: GOT len=%i",length);
+#endif
+        return length;                 
+    }
+}
+
 tvbparse_wanted_t* tvbparse_chars(int id,
                                                                  guint min_len,
                                                                  guint max_len,
@@ -116,43 +224,113 @@ tvbparse_wanted_t* tvbparse_chars(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* w = g_malloc0(sizeof(tvbparse_wanted_t));
        
-       w->id = id;
-       w->type = TVBPARSE_WANTED_SIMPLE_CHARS;
+    w->condition = cond_chars;
+    w->id = id;
        w->control.str = chr;
-       w->len = 0;
        w->min = min_len ? min_len : 1;
-       w->max = max_len ? max_len : G_MAXINT;
+       w->max = max_len ? max_len : G_MAXINT/2;
        w->data = data;
        w->before = before_cb;
        w->after = after_cb;
-       w->elems = g_ptr_array_new();
        
        return w;
 }
 
+
+static int cond_not_char(tvbparse_t* tt, 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) g_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) g_warning("cond_not_char: GOT='%c'",t);
+#endif        
+        return 1;
+    }
+}
+
 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;
+                                     const gchar* chr,
+                                     const void* data,
+                                     tvbparse_action_t before_cb,
+                                     tvbparse_action_t after_cb) {
+       tvbparse_wanted_t* w = g_malloc0(sizeof(tvbparse_wanted_t));
+       
+    w->condition = cond_not_char;
+    w->id = id;
        w->control.str = 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;
 }
 
+static int cond_not_chars(tvbparse_t* tt, int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
+    guint length = 0;
+    int left = tt->end_offset - offset;
+    int start = offset;
+
+#ifdef TVBPARSE_DEBUG
+    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_NOT_CHARS) g_warning("cond_not_chars: control='%s'",wanted->control.str);
+#endif
+    
+    if ( offset + (int)wanted->min > tt->end_offset )
+        return -1;
+
+    if (left < (int)wanted->min)
+        return -1;
+
+    left = left <= (int)wanted->max ? left :  (int)wanted->max;
+
+    while( left > 0 ) {
+        gchar c;
+        gchar t = (gchar) tvb_get_guint8(tt->tvb,offset);
+        guint i = 0;
+        
+        while ( (c = wanted->control.str[i++]) ) {
+            if (c == t) goto end_not_chars;
+        }
+        
+        offset++;
+        length++;
+        left--;
+    }
+end_not_chars:
+    
+    if ( length < wanted->min ) {
+        return -1;
+    } else {
+        *tok = new_tok(tt,wanted->id,start,length,wanted);
+#ifdef TVBPARSE_DEBUG
+        if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_NOT_CHARS) g_warning("cond_not_chars: GOT len=%i",length);
+#endif        
+        return length;
+    }
+}
+
 tvbparse_wanted_t* tvbparse_not_chars(int id,
                                                                          guint min_len,
                                                                          guint max_len,
@@ -160,90 +338,151 @@ tvbparse_wanted_t* tvbparse_not_chars(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* w = g_malloc0(sizeof(tvbparse_wanted_t));
        
-       w->id = id;
-       w->type = TVBPARSE_WANTED_SIMPLE_NOT_CHARS;
+    w->condition = cond_not_chars;
+    w->id = id;
        w->control.str = chr;
        w->len = 0;
        w->min = min_len ? min_len : 1;
-       w->max = max_len ? max_len : G_MAXINT;
+       w->max = max_len ? max_len : G_MAXINT/2;
        w->data = data;
        w->before = before_cb;
        w->after = after_cb;
-       w->elems = g_ptr_array_new();
        
        return w;
 }
 
 
+static int cond_string(tvbparse_t* tt, int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
+    int len = wanted->len;
+#ifdef TVBPARSE_DEBUG
+    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_STRING) g_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) g_warning("cond_string: GOT len=%i",len);
+#endif        
+        return len;
+    } else {
+        return -1;
+    }
+}
+
 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));
+       tvbparse_wanted_t* w = g_malloc0(sizeof(tvbparse_wanted_t));
        
-       w->id = id;
-       w->type = TVBPARSE_WANTED_SIMPLE_STRING;
+    w->condition = cond_string;
+    w->id = id;
        w->control.str = 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;
 }
 
+static int cond_casestring(tvbparse_t* tt, int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
+    int len = wanted->len;
+#ifdef TVBPARSE_DEBUG
+    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CASESTRING) g_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) g_warning("cond_casestring: GOT len=%i",len);
+#endif                
+        return len;
+    } else {
+        *tok = NULL;
+        return -1;
+    }
+}
+
 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));
+                                       const gchar* str,
+                                       const void* data,
+                                       tvbparse_action_t before_cb,
+                                       tvbparse_action_t after_cb) {
+       tvbparse_wanted_t* w = g_malloc0(sizeof(tvbparse_wanted_t));
        
-       w->id = id;
-       w->type = TVBPARSE_WANTED_SIMPLE_CASESTRING;
+    w->condition = cond_casestring;
+    w->id = id;
        w->control.str = 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;
 }
 
+static int cond_one_of(tvbparse_t* tt, int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
+    guint i;
+#ifdef TVBPARSE_DEBUG
+    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_ONEOF) g_warning("cond_one_of: START");
+#endif
+    
+    if ( offset > tt->end_offset )
+        return -1;
+
+    for(i=0; i < wanted->control.elems->len; i++) {
+        tvbparse_wanted_t* w = g_ptr_array_index(wanted->control.elems,i);
+        tvbparse_elem_t* new = NULL;
+        int curr_len;
+        
+        if ( offset + w->len > tt->end_offset )
+            return -1;
+        
+        curr_len = w->condition(tt, offset, w,  &new);
+
+        if (curr_len >= 0) {
+            *tok = new_tok(tt, wanted->id, new->offset, new->len, wanted);
+            (*tok)->sub = new;
+#ifdef TVBPARSE_DEBUG
+            if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_ONEOF) g_warning("cond_one_of: GOT len=%i",curr_len);
+#endif
+            return curr_len;                   
+        }
+    }
+
+    return -1;
+}
 
 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));
+                                      const void* data, 
+                                      tvbparse_action_t before_cb,
+                                      tvbparse_action_t after_cb,
+                                      ...) {
+       tvbparse_wanted_t* w = g_malloc0(sizeof(tvbparse_wanted_t));
        tvbparse_t* el;
        va_list ap;
        
-       w->id = id;
-       w->type = TVBPARSE_WANTED_SET_ONEOF;
-       w->control.val = 0;
-       w->len = 0;
-       w->min = 0;
-       w->max = 0;
+    w->condition = cond_one_of;
+    w->id = id;
        w->data = data;
        w->before = before_cb;
        w->after = after_cb;
-       w->elems = g_ptr_array_new();
+       w->control.elems = g_ptr_array_new();
        
        va_start(ap,after_cb);
        
        while(( el = va_arg(ap,tvbparse_t*) )) {
-               g_ptr_array_add(w->elems,el);
+               g_ptr_array_add(w->control.elems,el);
        };
        
        va_end(ap);
@@ -251,36 +490,241 @@ tvbparse_wanted_t* tvbparse_set_oneof(int id,
        return w;
 }
 
+static int cond_hash(tvbparse_t* tt, 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;
+    
+#ifdef TVBPARSE_DEBUG
+    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_HASH) g_warning("cond_hash: START");
+#endif
+    
+    tvbparse_elem_t* ret_tok;
+    if ( offset > tt->end_offset )
+        return -1;
+    
+    key_len = wanted->control.hash.key->condition(tt, offset, wanted->control.hash.key,  &key_elem);
+
+    if (key_len < 0) 
+        return -1;
+    
+    key = tvb_get_ephemeral_string(key_elem->tvb,key_elem->offset,key_elem->len);
+#ifdef TVBPARSE_DEBUG
+    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_HASH) g_warning("cond_hash: got key='%s'",key);
+#endif
+    
+    if ((value_wanted = g_hash_table_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) 
+            return -1;
+    } else {
+        return -1;
+    }
+
+    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) g_warning("cond_hash: GOT len=%i",tot_len);
+#endif
+    
+    return tot_len;
+}
+
+tvbparse_wanted_t* tvbparse_hashed(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 = g_malloc0(sizeof(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 = g_hash_table_new(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*);
+               g_hash_table_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*);
+               g_hash_table_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;
+    
+    if ( offset > tt->end_offset )
+        return -1;
+#ifdef TVBPARSE_DEBUG
+    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_SEQ) g_warning("cond_seq: START");
+#endif
+    
+    for(i=0; i < wanted->control.elems->len; i++) {
+        tvbparse_wanted_t* w = g_ptr_array_index(wanted->control.elems,i);
+        tvbparse_elem_t* new = NULL;
+
+        if ( offset + w->len > tt->end_offset )
+            return -1;
+        
+        
+        len = w->condition(tt, offset, w, &new);
+        
+        if (len >= 0) {
+            if (ret_tok) {
+                ret_tok->len = (new->offset - ret_tok->offset) + new->len;
+                ret_tok->sub->last->next = new;
+                ret_tok->sub->last = new;
+            } else {
+                ret_tok = new_tok(tt, wanted->id, new->offset, new->len, wanted);
+                ret_tok->sub = new;
+                new->last = new;
+            }
+        } else {
+            return -1;
+        }
+        
+        offset += len;
+        offset += ignore(tt,offset);
+    }
+
+    *tok = ret_tok;
+    
+#ifdef TVBPARSE_DEBUG
+    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_SEQ) g_warning("cond_seq: GOT len=%i",offset - start);
+#endif
+    
+    return offset - start;                     
+}
+
+
 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));
+                                    const void* data,
+                                    tvbparse_action_t before_cb,
+                                    tvbparse_action_t after_cb,
+                                    ...) {
+       tvbparse_wanted_t* w = g_malloc0(sizeof(tvbparse_wanted_t));
        tvbparse_wanted_t*  el = NULL;
        va_list ap;
        
-       w->id = id;
-       w->type = TVBPARSE_WANTED_SET_SEQ;
-       w->control.val = 0;
-       w->len = 0;
-       w->min = 0;
-       w->max = 0;
+    w->condition = cond_seq;
+    w->id = id;
        w->data = data;
        w->before = before_cb;
        w->after = after_cb;
-       w->elems = g_ptr_array_new();
+       w->control.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);
+               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) g_warning("cond_some: START");
+#endif
+    
+    if ( offset > tt->end_offset )
+        return -1;
+    
+    if ( wanted->min == 0 ) {
+        ret_tok = new_tok(tt,wanted->id,tt->offset,0,wanted);
+    }
+    
+    while (got_so_far < wanted->max) {
+        tvbparse_elem_t* new = NULL;
+        int consumed;
+        
+        if ( offset > tt->end_offset )
+            return -1;
+        
+        consumed = wanted->control.subelem->condition(tt, offset, wanted->control.subelem, &new);
+        
+        if(consumed >= 0) {
+            if (ret_tok) {
+                ret_tok->len = (new->offset - ret_tok->offset) + new->len;
+                
+                if (ret_tok->sub) {
+                    ret_tok->sub->last->next = new;
+                    ret_tok->sub->last = new;
+                } else {
+                    ret_tok->sub = new;                            
+                }
+            } else {
+                ret_tok = new_tok(tt, wanted->id, new->offset, new->len, wanted);
+                ret_tok->sub = new;
+            }
+        } else {
+            break;
+        }
+        
+        offset += consumed;
+        got_so_far++;
+    }
+    
+#ifdef TVBPARSE_DEBUG
+    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_SOME) g_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) g_warning("cond_some: GOT len=%i",offset - start);
+#endif
+    return offset - start;
+}
 
 tvbparse_wanted_t* tvbparse_some(int id,
                                                                 guint from,
@@ -290,71 +734,427 @@ tvbparse_wanted_t* tvbparse_some(int id,
                                                                 tvbparse_action_t after_cb,
                                                                 const tvbparse_wanted_t* el) {
        
-       tvbparse_wanted_t* w = g_malloc(sizeof(tvbparse_wanted_t));
+       tvbparse_wanted_t* w = g_malloc0(sizeof(tvbparse_wanted_t));
        
        g_assert(from <= to);
        
-       w->id = id;
-       w->type = TVBPARSE_WANTED_CARDINALITY;
-       w->control.val = 0;
-       w->len = 0;
+    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->elems = g_ptr_array_new();
-       
-       g_ptr_array_add(w->elems,(gpointer)el);
+       w->control.subelem = el;
        
        return w;
 }
 
+
+static int cond_until(tvbparse_t* tt, int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
+    tvbparse_elem_t* new = NULL;
+    int len = 0;
+    int target_offset = offset;
+#ifdef TVBPARSE_DEBUG
+    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_UNTIL) g_warning("cond_until: START");
+#endif
+    
+    if ( offset + wanted->control.until.subelem->len > tt->end_offset )
+        return -1;
+    
+    do {
+        len = wanted->control.until.subelem->condition(tt, target_offset++, wanted->control.until.subelem,  &new);
+    } while(len < 0  && target_offset+1 < tt->end_offset);
+    
+    if (len >= 0) {
+        
+        new->id = wanted->id;
+        new->next = NULL;
+        new->last = NULL;
+        new->wanted = wanted;
+        new->offset = offset;
+        
+        (*tok) = new;        
+        
+        switch (wanted->control.until.mode) {
+            case TP_UNTIL_INCLUDE:
+                new->len = target_offset - offset - 1 + len;
+#ifdef TVBPARSE_DEBUG
+                if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_UNTIL) g_warning("cond_until: GOT len=%i",target_offset - offset -1 + len);
+#endif
+                return target_offset - offset -1 + len;
+            case TP_UNTIL_SPEND:
+                new->len = target_offset - offset - 1;
+#ifdef TVBPARSE_DEBUG
+                if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_UNTIL) g_warning("cond_until: GOT len=%i",target_offset - offset -1 + len);
+#endif
+                return target_offset - offset - 1 + len;
+            case TP_UNTIL_LEAVE:
+                new->len = target_offset - offset - 1;
+#ifdef TVBPARSE_DEBUG
+                if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_UNTIL) g_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(int id,
-                                                  const void* data,
-                                                  tvbparse_action_t before_cb,
-                                                  tvbparse_action_t after_cb,
-                                                  const tvbparse_wanted_t* el,
-                                                  int op_mode) {
-       tvbparse_wanted_t* w = g_malloc(sizeof(tvbparse_wanted_t));
-       
-       w->id = id;
-       w->type = TVBPARSE_WANTED_UNTIL;
-       
-       w->control.val = op_mode;
+                                  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 = g_malloc0(sizeof(tvbparse_wanted_t));
        
-       w->len = 0;
-       w->min = 0;
-       w->max = 0;
+    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;
-       w->elems = g_ptr_array_new();
-       
-       g_ptr_array_add(w->elems,(gpointer)el);
        
        return w;
 }
 
+static int cond_handle(tvbparse_t* tt, int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
+    tvbparse_wanted_t* w = *(wanted->control.handle);
+    int len = w->condition(tt, offset, w,  tok);
+
+    if (len >= 0) {
+        return len;
+    } else {
+        return -1;
+    }
+}
+
 tvbparse_wanted_t* tvbparse_handle(tvbparse_wanted_t** handle) {
-       tvbparse_wanted_t* w = g_malloc(sizeof(tvbparse_wanted_t));
-       
-       w->id = 0;
-       w->type = TVBPARSE_WANTED_HANDLE;
+       tvbparse_wanted_t* w = g_malloc0(sizeof(tvbparse_wanted_t));
        
+    w->condition = cond_handle;
        w->control.handle = handle;
        
-       w->len = 0;
-       w->min = 0;
-       w->max = 0;
-       w->data = NULL;
-       w->before = NULL;
-       w->after = NULL;
-       w->elems = NULL;
+       return w;
+}
+
+static int cond_end(tvbparse_t* tt, int offset, const tvbparse_wanted_t * wanted _U_, tvbparse_elem_t** tok) {
+    if (offset == tt->end_offset) {
+        *tok = new_tok(tt,wanted->id,offset,0,wanted);
+        return 0;
+    } else {
+        return -1;
+    }
+}
+
+tvbparse_wanted_t* tvbparse_end_of_buffer(int id,
+                               const void* data,
+                               tvbparse_action_t before_cb,
+                               tvbparse_action_t after_cb) {
+    tvbparse_wanted_t* w = g_malloc0(sizeof(tvbparse_wanted_t));
        
+    w->id = id;
+    w->condition = cond_end;
+       w->after = after_cb;
+    w->before = before_cb;
+    w->data = data;
        return w;
+    
+}
+
+
+#if 0
+/* these extract binary values */
+
+static int cond_ft(tvbparse_t* tt, int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) {
+    guint len = 0;
+
+    if ( offset + wanted->len > tt->end_offset )
+        return -1;
+
+    if (wanted->len) {
+        return wanted->len;
+    } else if (wanted->control.ftenum == FT_STRINGZ) {
+            if (( len = tvb_find_guint8(tt->tvb,offset,tt->end_offset - offset,'\0') >= 0 )) {
+                *tok = new_tok(tt,wanted->id,offset,len,wanted);
+                return len;
+            } else {
+                return -1;
+            }
+    } else {
+        return -2;
+    }
+}
+
+gint ft_lens[] = {-1,-1,-1, 1, 2, 3, 4, 8, 1, 2, 3, 4, 8, 4, 8,-1,-1,-1, 0, -1, 6, -1, -1, 4, sizeof(struct e_in6_addr), -1, -1, -1, -1 };
+
+tvbparse_wanted_t* tvbparse_ft(int id,
+                               const void* data,
+                               tvbparse_action_t before_cb,
+                               tvbparse_action_t after_cb,
+                               enum ftenum ftenum) {
+    gint len = ft_lens[ftenum];
+    
+    if (len >= 0) {
+        tvbparse_wanted_t* w = g_malloc0(sizeof(tvbparse_wanted_t));
+        
+        w->id = id;
+        w->condition = cond_ft;
+        w->len = len;
+        w->control.ftenum = ftenum;
+        w->after = after_cb;
+        w->before = before_cb;
+        w->data = data;
+        
+        return w;
+    } else {
+        g_assert(! "unsupported ftenum" );
+        return NULL;
+    }
+}    
+
+static int cond_ft_comp(tvbparse_t* tt, int offset, const tvbparse_wanted_t * wanted _U_, tvbparse_elem_t** tok) {
+    void* l = wanted->control.number.extract(tt->tvb,offset);
+    const void* r = &(wanted->control.number.value);
+    
+    if ( offset + wanted->len > tt->end_offset )
+        return -1;
+
+    if ( wanted->control.number.comp(&l,&r) ) {
+        *tok = new_tok(tt,wanted->id,offset,wanted->len,wanted);
+        return wanted->len;
+    } else {
+        return -1;
+    }
+}
+
+static gboolean comp_gt_i(void* lp, const void* rp) { return ( *((gint64*)lp) > *((gint64*)rp) ); }
+static gboolean comp_ge_i(void* lp, const void* rp) { return ( *((gint64*)lp) >= *((gint64*)rp) ); }
+static gboolean comp_eq_i(void* lp, const void* rp) { return ( *((gint64*)lp) == *((gint64*)rp) ); }
+static gboolean comp_ne_i(void* lp, const void* rp) { return ( *((gint64*)lp) != *((gint64*)rp) ); }
+static gboolean comp_le_i(void* lp, const void* rp) { return ( *((gint64*)lp) <= *((gint64*)rp) ); }
+static gboolean comp_lt_i(void* lp, const void* rp) { return ( *((gint64*)lp) < *((gint64*)rp) ); }
+
+static gboolean comp_gt_u(void* lp, const void* rp) { return ( *((guint64*)lp) > *((guint64*)rp) ); }
+static gboolean comp_ge_u(void* lp, const void* rp) { return ( *((guint64*)lp) >= *((guint64*)rp) ); }
+static gboolean comp_eq_u(void* lp, const void* rp) { return ( *((guint64*)lp) == *((guint64*)rp) ); }
+static gboolean comp_ne_u(void* lp, const void* rp) { return ( *((guint64*)lp) != *((guint64*)rp) ); }
+static gboolean comp_le_u(void* lp, const void* rp) { return ( *((guint64*)lp) <= *((guint64*)rp) ); }
+static gboolean comp_lt_u(void* lp, const void* rp) { return ( *((guint64*)lp) < *((guint64*)rp) ); }
+
+static gboolean comp_gt_f(void* lp, const void* rp) { return ( *((gdouble*)lp) > *((gdouble*)rp) ); }
+static gboolean comp_ge_f(void* lp, const void* rp) { return ( *((gdouble*)lp) >= *((gdouble*)rp) ); }
+static gboolean comp_eq_f(void* lp, const void* rp) { return ( *((gdouble*)lp) == *((gdouble*)rp) ); }
+static gboolean comp_ne_f(void* lp, const void* rp) { return ( *((gdouble*)lp) != *((gdouble*)rp) ); }
+static gboolean comp_le_f(void* lp, const void* rp) { return ( *((gdouble*)lp) <= *((gdouble*)rp) ); }
+static gboolean comp_lt_f(void* lp, const void* rp) { return ( *((gdouble*)lp) < *((gdouble*)rp) ); }
+
+static void* extract_u8(tvbuff_t* tvb, guint offset) {
+    guint64* p = ep_new(guint64);
+    *p = tvb_get_guint8(tvb,offset);
+    return p;
 }
 
+static void* extract_uns(tvbuff_t* tvb, guint offset) {
+    guint64* p = ep_new(guint64);
+    *p = tvb_get_ntohs(tvb,offset);
+    return p;
+}
+
+static void* extract_un24(tvbuff_t* tvb, guint offset) {
+    guint64* p = ep_new(guint64);
+    *p = tvb_get_ntoh24(tvb,offset);
+    return p;
+}
+
+static void* extract_unl(tvbuff_t* tvb, guint offset) {
+    guint64* p = ep_new(guint64);
+    *p = tvb_get_ntohl(tvb,offset);
+    return p;
+}
+
+static void* extract_un64(tvbuff_t* tvb, guint offset) {
+    guint64* p = ep_new(guint64);
+    *p = tvb_get_ntoh64(tvb,offset);
+    return p;
+}
+
+static void* extract_ules(tvbuff_t* tvb, guint offset) {
+    guint64* p = ep_new(guint64);
+    *p = tvb_get_letohs(tvb,offset);
+    return p;
+}
+
+static void* extract_ule24(tvbuff_t* tvb, guint offset) {
+    guint64* p = ep_new(guint64);
+    *p = tvb_get_letoh24(tvb,offset);
+    return p;
+}
+
+static void* extract_ulel(tvbuff_t* tvb, guint offset) {
+    guint64* p = ep_new(guint64);
+    *p = tvb_get_letohl(tvb,offset);
+    return p;
+}
+
+static void* extract_ule64(tvbuff_t* tvb, guint offset) {
+    guint64* p = ep_new(guint64);
+    *p = tvb_get_letoh64(tvb,offset);
+    return p;
+}
+
+static void* extract_ins(tvbuff_t* tvb, guint offset) {
+    guint64* p = ep_new(guint64);
+    *p = tvb_get_ntohs(tvb,offset);
+    return p;
+}
+
+static void* extract_in24(tvbuff_t* tvb, guint offset) {
+    guint64* p = ep_new(guint64);
+    *p = tvb_get_ntoh24(tvb,offset);
+    return p;
+}
+
+static void* extract_inl(tvbuff_t* tvb, guint offset) {
+    guint64* p = ep_new(guint64);
+    *p = tvb_get_ntohl(tvb,offset);
+    return p;
+}
+
+static void* extract_in64(tvbuff_t* tvb, guint offset) {
+    guint64* p = ep_new(guint64);
+    *p = tvb_get_ntoh64(tvb,offset);
+    return p;
+}
+
+static void* extract_iles(tvbuff_t* tvb, guint offset) {
+    guint64* p = ep_new(guint64);
+    *p = tvb_get_letohs(tvb,offset);
+    return p;
+}
+
+static void* extract_ile24(tvbuff_t* tvb, guint offset) {
+    guint64* p = ep_new(guint64);
+    *p = tvb_get_letoh24(tvb,offset);
+    return p;
+}
+
+static void* extract_ilel(tvbuff_t* tvb, guint offset) {
+    guint64* p = ep_new(guint64);
+    *p = tvb_get_letohl(tvb,offset);
+    return p;
+}
+
+static void* extract_ile64(tvbuff_t* tvb, guint offset) {
+    guint64* p = ep_new(guint64);
+    *p = tvb_get_letoh64(tvb,offset);
+    return p;
+}
+
+static void* extract_inf(tvbuff_t* tvb, guint offset) {
+    gdouble* p = ep_new(gdouble);
+    *p = tvb_get_ntohieee_float(tvb,offset);
+    return p;
+}
+
+static void* extract_ind(tvbuff_t* tvb, guint offset) {
+    gdouble* p = ep_new(gdouble);
+    *p = tvb_get_ntohieee_double(tvb,offset);
+    return p;
+}
+
+static void* extract_ilef(tvbuff_t* tvb, guint offset) {
+    gdouble* p = ep_new(gdouble);
+    *p = tvb_get_letohieee_float(tvb,offset);
+    return p;
+}
+
+static void* extract_iled(tvbuff_t* tvb, guint offset) {
+    gdouble* p = ep_new(gdouble);
+    *p = tvb_get_letohieee_double(tvb,offset);
+    return p;
+}
+
+
+
+static gboolean (*comps_u[])(void*, const void*) = {comp_gt_u,comp_ge_u,comp_eq_u,comp_ne_u,comp_le_u,comp_lt_u};
+static gboolean (*comps_i[])(void*, const void*) = {comp_gt_i,comp_ge_i,comp_eq_i,comp_ne_i,comp_le_i,comp_lt_i};
+static gboolean (*comps_f[])(void*, const void*) = {comp_gt_f,comp_ge_f,comp_eq_f,comp_ne_f,comp_le_f,comp_lt_f};
+
+static gboolean (**comps[])(void*, const void*) = {comps_u,comps_i,comps_f};
+
+static void* (*extract_n[])(tvbuff_t* tvb, guint offset)  =  { NULL, NULL, NULL, extract_u8, extract_uns, extract_un24, extract_unl, extract_un64, extract_u8, extract_ins, extract_in24, extract_inl, extract_in64, extract_inf, extract_ind, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,NULL, NULL };
+static void* (*extract_le[])(tvbuff_t* tvb, guint offset)  =  {        NULL, NULL, NULL, extract_u8, extract_ules, extract_ule24, extract_ulel, extract_ule64, extract_u8, extract_iles, extract_ile24, extract_ilel, extract_ile64, extract_ilef, extract_iled, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,NULL, NULL };
+
+static void* (**extracts[])(tvbuff_t* tvb, guint offset) = { extract_n, extract_le};
+
+
+tvbparse_wanted_t* tvbparse_ft_numcmp(int id,
+                                     const void* data,
+                                     tvbparse_action_t before_cb,
+                                     tvbparse_action_t after_cb,
+                                     enum ftenum ftenum,
+                                     int little_endian,
+                                     enum ft_cmp_op ft_cmp_op,
+                                     ... ) {
+       tvbparse_wanted_t* w = g_malloc0(sizeof(tvbparse_wanted_t));
+    va_list ap;
+    
+    va_start(ap,ft_cmp_op);
+    
+    switch (ftenum) {
+        case FT_UINT8:
+        case FT_UINT16:
+        case FT_UINT24:
+        case FT_UINT32:
+            w->control.number.comp = comps[0][ft_cmp_op];
+            w->control.number.value.u = va_arg(ap,guint32);
+            break;
+        case FT_UINT64:
+            w->control.number.comp = comps[0][ft_cmp_op];
+            w->control.number.value.u = va_arg(ap,guint64);
+            break;
+        case FT_INT8:
+        case FT_INT16:
+        case FT_INT24:
+        case FT_INT32:
+            w->control.number.comp = comps[1][ft_cmp_op];
+            w->control.number.value.i = va_arg(ap,gint32);
+            break;            
+        case FT_INT64:
+            w->control.number.comp = comps[1][ft_cmp_op];
+            w->control.number.value.i = va_arg(ap,gint64);
+            break;            
+        case FT_FLOAT:
+        case FT_DOUBLE:
+            w->control.number.comp = comps[1][ft_cmp_op];
+            w->control.number.value.i = va_arg(ap,gdouble);
+            break;
+        default:
+            g_assert(! "comparision unsupported");
+    }
+
+    w->control.number.extract = extracts[little_endian][ftenum];
+
+    g_assert(w->control.number.extract && "extraction unsupported");
+    
+    w->id = id;
+    w->condition = cond_ft_comp;
+    w->after = after_cb;
+    w->before = before_cb;
+    w->data = data;
+
+    return w;
+}
+
+#endif
+
 
 tvbparse_wanted_t* tvbparse_quoted(int id,
                                                                   const void* data,
@@ -368,22 +1168,21 @@ tvbparse_wanted_t* tvbparse_quoted(int id,
        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);
-       
+                              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_,
@@ -400,12 +1199,17 @@ tvbparse_t* tvbparse_init(tvbuff_t* tvb,
                                                  const tvbparse_wanted_t* ignore) {
        tvbparse_t* tt = ep_alloc(sizeof(tvbparse_t));
        
+#ifdef TVBPARSE_DEBUG
+    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_TT) g_warning("tvbparse_init: offset=%i len=%i",offset,len);
+#endif                
+    
+    
        tt->tvb = tvb;
        tt->offset = offset;
-       tt->max_len = (len == -1) ? (int) tvb_length(tvb) : len;
+       len = (len == -1) ? (int) tvb_length(tvb) : len;
+    tt->end_offset = offset + len;
        tt->data = data;
        tt->ignore = ignore;
-       tt->depth = 0;
        return tt;
 }
 
@@ -413,400 +1217,127 @@ gboolean tvbparse_reset(tvbparse_t* tt,
                                                int offset,
                                                int len) {
        
+#ifdef TVBPARSE_DEBUG
+    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_TT) g_warning("tvbparse_init: offset=%i len=%i",offset,len);
+#endif                
+    
        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;
+               tt->end_offset = offset + len;
                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;
-}
-
 guint tvbparse_curr_offset(tvbparse_t* tt) {
     return tt->offset;
 }
-guint tvbparse_len_left(tvbparse_t* tt) {
-    return tt->max_len;
+
+static void execute_callbacks(tvbparse_t* tt, tvbparse_elem_t* curr) {
+    ep_stack_t stack = ep_stack_new();
+    
+    while (curr) {
+        if(curr->wanted->before) {
+#ifdef TVBPARSE_DEBUG
+            if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CB) g_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) {
+            ep_stack_push(stack,curr);
+            curr = curr->sub;
+            continue;
+        } else {
+#ifdef TVBPARSE_DEBUG
+            if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CB) g_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 && ep_stack_peek(stack) ) {
+            curr = ep_stack_pop(stack);
+#ifdef TVBPARSE_DEBUG
+            if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CB) g_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;
+        }
+    }
+
 }
 
 tvbparse_elem_t* tvbparse_get(tvbparse_t* tt,
-                                                                 const tvbparse_wanted_t* wanted) {
+                              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->control.str[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->control.str[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->control.str[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->control.str[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->control.str, 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->control.str, 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);
-                       
-            if ( wanted->min == 0 ) {
-                tok = new_tok(tt,wanted->id,tt->offset,0,wanted);
-            }
+       int consumed;
+    int offset = tt->offset;
+    
+#ifdef TVBPARSE_DEBUG
+    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_GET) g_warning("tvbparse_get: ENTER offset=%i",offset);
+#endif                            
+    
+    offset += ignore(tt,offset);
+
+#ifdef TVBPARSE_DEBUG
+    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_GET) g_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) g_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) g_warning("tvbparse_get: DONE offset=%i", tt->offset);
+#endif                            
+        return tok; 
+    } else {
+        return NULL;
+    }
             
-                       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;
-                        if (tok->sub) {
-                            tok->sub->last->next = new;
-                            tok->sub->last = new;
-                        } else {
-                            tok->sub = 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;
-                               
-                               switch (wanted->control.val) {
-                    case TP_UNTIL_INCLUDE:
-                        tok->len = (tok->offset - offset) + tok->len;
-                        break;
-                    case TP_UNTIL_LEAVE:
-                        tt->offset -= tok->len;
-                        tt->max_len += tok->len;
-                        /* fall through */
-                    case TP_UNTIL_SPEND:
-                        tok->len = (tok->offset - offset);
-                        break;
-                    default:
-                        DISSECTOR_ASSERT_NOT_REACHED();
-                               }
-                               
-                               tok->offset = offset;
-                               tok->id = wanted->id;
-                               tok->next = NULL;
-                               tok->last = tok;
-                               tok->wanted = wanted;
-                               
-                               goto accept;
-                       } else {
-                               goto reject;
-                       }
-               }
-        case TVBPARSE_WANTED_HANDLE:
-        {
-            tok = tvbparse_get(tt, *(wanted->control.handle));
-            if (tok) {
-                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,TRUE);
-                       }
-                       
-                       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;
+    int len = 0;
+    int offset = tt->offset;
+    int target_offset = offset -1;
+
+#ifdef TVBPARSE_DEBUG
+    if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_FIND) g_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) g_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) g_warning("tvbparse_get: DONE offset=%i", tt->offset);
+#endif                            
+        return tok;
+    } else {
+#ifdef TVBPARSE_DEBUG
+        if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_FIND) g_warning("tvbparse_get: NOT FOUND");
+#endif                            
+        return NULL;
+    }
 }
 
 struct _elem_tree_stack_frame {
@@ -815,7 +1346,7 @@ struct _elem_tree_stack_frame {
 };
 
 void tvbparse_tree_add_elem(proto_tree* tree, tvbparse_elem_t* curr) {
-    GPtrArray* stack = g_ptr_array_new();
+    ep_stack_t stack = ep_stack_new();
     struct _elem_tree_stack_frame* frame = ep_alloc(sizeof(struct _elem_tree_stack_frame));
     proto_item* pi;
     frame->tree = tree;
@@ -826,7 +1357,7 @@ void tvbparse_tree_add_elem(proto_tree* tree, tvbparse_elem_t* curr) {
         
         if(curr->sub) {
             frame->elem = curr;
-            g_ptr_array_add(stack,frame);
+            ep_stack_push(stack,frame);
             frame = ep_alloc(sizeof(struct _elem_tree_stack_frame));
             frame->tree = proto_item_add_subtree(pi,0);
             curr = curr->sub;
@@ -835,13 +1366,11 @@ void tvbparse_tree_add_elem(proto_tree* tree, tvbparse_elem_t* curr) {
         
         curr = curr->next;
         
-        while( !curr && stack->len ) {
-            frame = g_ptr_array_remove_index_fast(stack,stack->len - 1);
+        while( !curr && ep_stack_peek(stack) ) {
+            frame = ep_stack_pop(stack);
             curr = frame->elem->next;
         }
         
     }
-    
-    g_ptr_array_free(stack,TRUE);
 }
 
index ac67f7ddb74da0a8baa899872b7cc944205e6a25..742363a0aa28b73632992d61f990a256da2087d6 100644 (file)
 #include <epan/tvbuff.h>
 #include <glib.h>
 
-/* a definition of something we want to look for */
+typedef struct _tvbparse_elem_t tvbparse_elem_t;
 typedef struct _tvbparse_wanted_t tvbparse_wanted_t;
+typedef struct _tvbparse_t tvbparse_t;
+
+
+/*
+ * a callback function to be called before or after an element has been
+ * successfuly extracted.
+ *
+ * Note that if the token belongs to a composed token the callbacks of the
+ * components won't be called unless the composed token is successfully
+ * extracted.
+ *
+ * tvbparse_data: the private data of the parser
+ * wanted_data: the private data of the wanted element
+ * elem: the extracted element
+ */
+typedef void (*tvbparse_action_t)(void* tvbparse_data, const void* wanted_data, struct _tvbparse_elem_t* elem);
+
+typedef int (*tvbparse_condition_t)
+(tvbparse_t*, int,
+ const tvbparse_wanted_t*, 
+ tvbparse_elem_t**);
+
+
+typedef enum  {
+    TP_UNTIL_INCLUDE, /* last elem is included, its span is spent by the parser */
+    TP_UNTIL_SPEND, /* last elem is not included, but its span is spent by the parser */
+    TP_UNTIL_LEAVE /* last elem is not included, neither its span is spent by the parser */
+} until_mode_t;
+
+
+struct _tvbparse_wanted_t {
+       int id;
+    tvbparse_condition_t condition;
+    
+       union {
+        const gchar* str;
+        struct _tvbparse_wanted_t** handle;
+        struct {
+            union {
+                gint64 i;
+                guint64 u;
+                gdouble f;
+            } value;            
+            gboolean (*comp)(void*,const void*);
+            void* (*extract)(tvbuff_t*,guint);
+        } number;
+        enum ftenum ftenum;
+        struct {
+            until_mode_t mode;
+            const tvbparse_wanted_t* subelem;
+        } until;
+        struct {
+            GHashTable* table;
+            struct _tvbparse_wanted_t* key;
+            struct _tvbparse_wanted_t* other;
+        } hash;
+        GPtrArray* elems;
+        const tvbparse_wanted_t* subelem;
+        void* p;
+    } control;
+    
+       int len;
+       
+       guint min;
+       guint max;
+       
+       const void* data;
+    
+       tvbparse_action_t before;
+       tvbparse_action_t after;
+       
+};
 
 /* an instance of a per packet parser */
-typedef struct _tvbparse_t tvbparse_t;
+struct _tvbparse_t {
+       tvbuff_t* tvb;
+       int offset;
+    int end_offset;
+       void* data;
+       const tvbparse_wanted_t* ignore;
+};
+
 
 /* a matching token returned by either tvbparser_get or tvb_parser_find */
-typedef struct _tvbparse_elem_t {
+struct _tvbparse_elem_t {
        int id;
        
        tvbuff_t* tvb;
@@ -91,21 +170,7 @@ typedef struct _tvbparse_elem_t {
        struct _tvbparse_elem_t* last;
        
        const tvbparse_wanted_t* wanted;
-} tvbparse_elem_t;
-
-/*
- * a callback function to be called before or after an element has been
- * successfuly extracted.
- *
- * Note that if the token belongs to a composed token the callbacks of the
- * components won't be called unless the composed token is successfully
- * extracted.
- *
- * tvbparse_data: the private data of the parser
- * wanted_data: the private data of the wanted element
- * elem: the extracted element
- */
-typedef void (*tvbparse_action_t)(void* tvbparse_data, const void* wanted_data, struct _tvbparse_elem_t* elem);
+};
 
 
 /*
@@ -213,21 +278,17 @@ tvbparse_wanted_t* tvbparse_casestring(int id,
  *
  * It won't have a subelement, the ending's callbacks won't get called.
  */
-tvbparse_wanted_t* tvbparse_until(int id,
-                                                                 const void* private_data,
-                                                                 tvbparse_action_t before_cb,
-                                                                 tvbparse_action_t after_cb,
-                                                                 const tvbparse_wanted_t* ending,
-                                                                 int op_mode);
 
 /*
  * op_mode values determine how the terminating element and the current offset
  * of the parser are handled 
  */
-        
-#define TP_UNTIL_INCLUDE 0 /* elem is included, its span is spent by the parser */
-#define TP_UNTIL_SPEND 1 /* elem is not included, but its span is spent by the parser */
-#define TP_UNTIL_LEAVE 2 /* elem is not included, neither its span is spent by the parser */
+tvbparse_wanted_t* tvbparse_until(int id,
+                                                                 const void* private_data,
+                                                                 tvbparse_action_t before_cb,
+                                                                 tvbparse_action_t after_cb,
+                                                                 const tvbparse_wanted_t* ending,
+                                                                 until_mode_t until_mode);
 
 /*
  * one_of
@@ -244,6 +305,20 @@ tvbparse_wanted_t* tvbparse_set_oneof(int id,
                                                                          tvbparse_action_t after_cb,
                                                                          ...);
 
+/* 
+ * hashed
+ */
+
+tvbparse_wanted_t* tvbparse_hashed(int id,
+                                   const void* data, 
+                                   tvbparse_action_t before_cb,
+                                   tvbparse_action_t after_cb,
+                                   tvbparse_wanted_t* key,
+                                   tvbparse_wanted_t* other,
+                                   ...);
+
+void tvbparse_hashed_add(tvbparse_wanted_t* w, ...);
+
 /*
  * sequence
  *
@@ -287,6 +362,41 @@ tvbparse_wanted_t* tvbparse_some(int id,
  */
 tvbparse_wanted_t* tvbparse_handle(tvbparse_wanted_t** handle);
 
+#if 0
+
+enum ft_cmp_op {
+    TVBPARSE_CMP_GT,
+    TVBPARSE_CMP_GE,
+    TVBPARSE_CMP_EQ,
+    TVBPARSE_CMP_NE,
+    TVBPARSE_CMP_LE,
+    TVBPARSE_CMP_LT
+};
+
+/* not yet tested */
+tvbparse_wanted_t* tvbparse_ft(int id,
+                               const void* data,
+                               tvbparse_action_t before_cb,
+                               tvbparse_action_t after_cb,
+                               enum ftenum ftenum);
+
+/* not yet tested */
+tvbparse_wanted_t* tvbparse_end_of_buffer(int id,
+                                          const void* data,
+                                          tvbparse_action_t before_cb,
+                                          tvbparse_action_t after_cb);
+/* not yet tested */
+tvbparse_wanted_t* tvbparse_ft_numcmp(int id,
+                                      const void* data,
+                                      tvbparse_action_t before_cb,
+                                      tvbparse_action_t after_cb,
+                                      enum ftenum ftenum,
+                                      int little_endian,
+                                      enum ft_cmp_op ft_cmp_op,
+                                      ... );
+
+#endif
+
 /*  quoted
  *  this is a composed candidate, that will try to match a quoted string
  *  (included the quotes) including into it every escaped quote.