diff --git a/epan/wslua/init_wslua.c b/epan/wslua/init_wslua.c index 90b9e43d6a..fd42080ada 100644 --- a/epan/wslua/init_wslua.c +++ b/epan/wslua/init_wslua.c @@ -163,9 +163,6 @@ int dissect_lua(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* data lua_pinfo = pinfo; lua_tvb = tvb; - lua_tree = create_TreeItem(tree, proto_tree_add_item(tree, hf_wslua_fake, tvb, 0, 0, ENC_NA)); - PROTO_ITEM_SET_HIDDEN(lua_tree->item); - /* * almost equivalent to Lua: * dissectors[current_proto](tvb,pinfo,tree) @@ -185,7 +182,8 @@ int dissect_lua(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* data push_Tvb(L,tvb); push_Pinfo(L,pinfo); - push_TreeItem(L,lua_tree); + lua_tree = push_TreeItem(L, tree, proto_tree_add_item(tree, hf_wslua_fake, tvb, 0, 0, ENC_NA)); + PROTO_ITEM_SET_HIDDEN(lua_tree->item); if ( lua_pcall(L,3,1,0) ) { proto_tree_add_expert_format(tree, pinfo, &ei_lua_error, tvb, 0, 0, "Lua Error: %s", lua_tostring(L,-1)); @@ -278,12 +276,10 @@ gboolean heur_dissect_lua(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, v return FALSE; } - lua_tree = create_TreeItem(tree, proto_tree_add_item(tree, hf_wslua_fake, tvb, 0, 0, ENC_NA)); - PROTO_ITEM_SET_HIDDEN(lua_tree->item); - push_Tvb(L,tvb); push_Pinfo(L,pinfo); - push_TreeItem(L,lua_tree); + lua_tree = push_TreeItem(L, tree, proto_tree_add_item(tree, hf_wslua_fake, tvb, 0, 0, ENC_NA)); + PROTO_ITEM_SET_HIDDEN(lua_tree->item); if ( lua_pcall(L,3,1,0) ) { proto_tree_add_expert_format(tree, pinfo, &ei_lua_error, tvb, 0, 0, diff --git a/epan/wslua/lrexlib.h b/epan/wslua/lrexlib.h index eff305cecb..34e2ce9189 100644 --- a/epan/wslua/lrexlib.h +++ b/epan/wslua/lrexlib.h @@ -53,9 +53,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. /* public function declarations */ REX_API int REX_OPENLIB (lua_State *L); -int Gregex_get_compile_flags (lua_State *L); -int Gregex_get_match_flags (lua_State *L); -int Gregex_get_flags (lua_State *L); +extern int Gregex_get_compile_flags (lua_State *L); +extern int Gregex_get_match_flags (lua_State *L); +extern int Gregex_get_flags (lua_State *L); /* Special values for maxmatch in gsub. They all must be negative. */ #define GSUB_UNLIMITED -1 diff --git a/epan/wslua/lrexlib_glib.c b/epan/wslua/lrexlib_glib.c index fd24c28a5c..8a4c11a47c 100644 --- a/epan/wslua/lrexlib_glib.c +++ b/epan/wslua/lrexlib_glib.c @@ -54,9 +54,6 @@ THE SOFTWARE. #include "lauxlib.h" #include "lrexlib.h" -extern int Gregex_get_flags (lua_State *L); -extern int Gregex_get_compile_flags (lua_State *L); -extern int Gregex_get_match_flags (lua_State *L); extern flag_pair gregex_error_flags[]; /* These 2 settings may be redefined from the command-line or the makefile. diff --git a/epan/wslua/wslua.h b/epan/wslua/wslua.h index 8d41607ee3..18ea9d3019 100644 --- a/epan/wslua/wslua.h +++ b/epan/wslua/wslua.h @@ -118,7 +118,7 @@ typedef struct _wslua_field_t { int hfid; int ett; char* name; - char* abbr; + char* abbrev; char* blob; enum ftenum type; unsigned base; @@ -128,7 +128,7 @@ typedef struct _wslua_field_t { typedef struct _wslua_expert_field_t { expert_field ids; - const gchar *abbr; + const gchar *abbrev; const gchar *text; int group; int severity; @@ -707,9 +707,10 @@ extern void clear_outstanding_Columns(void); extern void clear_outstanding_PrivateTable(void); extern int get_hf_wslua_text(void); -extern TreeItem* push_TreeItem(lua_State* L, TreeItem ti); +extern TreeItem push_TreeItem(lua_State *L, proto_tree *tree, proto_item *item); extern void clear_outstanding_TreeItem(void); +extern FieldInfo* push_FieldInfo(lua_State *L, field_info* f); extern void clear_outstanding_FieldInfo(void); extern void wslua_print_stack(char* s, lua_State* L); @@ -720,7 +721,7 @@ extern int wslua_cleanup(void); extern tap_extractor_t wslua_get_tap_extractor(const gchar* name); extern int wslua_set_tap_enums(lua_State* L); -extern int wslua_is_field_available(lua_State* L, const char* field_abbr); +extern ProtoField wslua_is_field_available(lua_State* L, const char* field_abbr); extern char* wslua_get_actual_filename(const char* fname); diff --git a/epan/wslua/wslua_field.c b/epan/wslua/wslua_field.c index 3bbdde3a1e..39a66f0e93 100644 --- a/epan/wslua/wslua_field.c +++ b/epan/wslua/wslua_field.c @@ -45,7 +45,13 @@ WSLUA_CLASS_DEFINE(FieldInfo,FAIL_ON_NULL_OR_EXPIRED("FieldInfo"),NOP); static GPtrArray* outstanding_FieldInfo = NULL; -#define PUSH_FIELDINFO(L,fi) {g_ptr_array_add(outstanding_FieldInfo,fi);pushFieldInfo(L,fi);} +FieldInfo* push_FieldInfo(lua_State* L, field_info* f) { + FieldInfo fi = (FieldInfo) g_malloc(sizeof(struct _wslua_field_info)); + fi->ws_fi = f; + fi->expired = FALSE; + g_ptr_array_add(outstanding_FieldInfo,fi); + return pushFieldInfo(L,fi); +} CLEAR_OUTSTANDING(FieldInfo,expired,TRUE) @@ -210,7 +216,7 @@ WSLUA_METAMETHOD FieldInfo__call(lua_State* L) { } } -/* WSLUA_ATTRIBUTE FieldInfo_label RO The string representing this field */ +/* WSLUA_ATTRIBUTE FieldInfo_label RO The string representing this field. */ WSLUA_METAMETHOD FieldInfo__tostring(lua_State* L) { /* The string representation of the field. */ FieldInfo fi = checkFieldInfo(L,1); @@ -244,7 +250,7 @@ WSLUA_METAMETHOD FieldInfo__tostring(lua_State* L) { return 1; } -/* WSLUA_ATTRIBUTE FieldInfo_display RO The string display of this field as seen in GUI */ +/* WSLUA_ATTRIBUTE FieldInfo_display RO The string display of this field as seen in GUI. */ static int FieldInfo_get_display(lua_State* L) { /* The display string of this field as seen in GUI. */ FieldInfo fi = checkFieldInfo(L,1); @@ -272,7 +278,43 @@ static int FieldInfo_get_display(lua_State* L) { return 1; } -/* WSLUA_ATTRIBUTE FieldInfo_range RO The `TvbRange` covering this field */ +/* WSLUA_ATTRIBUTE FieldInfo_type RO The internal field type, a number which + matches one of the `ftype` values in `init.lua`. + + @since 1.99.9 + */ +static int FieldInfo_get_type(lua_State* L) { + FieldInfo fi = checkFieldInfo(L,1); + + if (fi->ws_fi->hfinfo) { + lua_pushnumber(L, fi->ws_fi->hfinfo->type); + } + else { + lua_pushnil(L); + } + + return 1; +} + +/* WSLUA_ATTRIBUTE FieldInfo_source RO The source `Tvb` object the `FieldInfo` is derived + from, or nil if there is none. + + @since 1.99.9 + */ +static int FieldInfo_get_source(lua_State* L) { + FieldInfo fi = checkFieldInfo(L,1); + + if (fi->ws_fi->ds_tvb) { + push_Tvb(L, fi->ws_fi->ds_tvb); + } + else { + lua_pushnil(L); + } + + return 1; +} + +/* WSLUA_ATTRIBUTE FieldInfo_range RO The `TvbRange` covering this field. */ static int FieldInfo_get_range(lua_State* L) { /* The `TvbRange` covering this field. */ FieldInfo fi = checkFieldInfo(L,1); @@ -284,7 +326,7 @@ static int FieldInfo_get_range(lua_State* L) { return 0; } -/* WSLUA_ATTRIBUTE FieldInfo_generated RO Whether this field was marked as generated (boolean) */ +/* WSLUA_ATTRIBUTE FieldInfo_generated RO Whether this field was marked as generated (boolean). */ static int FieldInfo_get_generated(lua_State* L) { /* Whether this field was marked as generated. */ FieldInfo fi = checkFieldInfo(L,1); @@ -293,7 +335,54 @@ static int FieldInfo_get_generated(lua_State* L) { return 1; } -/* WSLUA_ATTRIBUTE FieldInfo_name RO The name of this field */ +/* WSLUA_ATTRIBUTE FieldInfo_hidden RO Whether this field was marked as hidden (boolean). + + @since 1.99.9 + */ +static int FieldInfo_get_hidden(lua_State* L) { + FieldInfo fi = checkFieldInfo(L,1); + + lua_pushboolean(L,FI_GET_FLAG(fi->ws_fi, FI_HIDDEN)); + return 1; +} + +/* WSLUA_ATTRIBUTE FieldInfo_is_url RO Whether this field was marked as being a URL (boolean). + + @since 1.99.9 + */ +static int FieldInfo_get_is_url(lua_State* L) { + FieldInfo fi = checkFieldInfo(L,1); + + lua_pushboolean(L,FI_GET_FLAG(fi->ws_fi, FI_URL)); + return 1; +} + +/* WSLUA_ATTRIBUTE FieldInfo_little_endian RO Whether this field is little-endian encoded (boolean). + + @since 1.99.9 + */ +static int FieldInfo_get_little_endian(lua_State* L) { + FieldInfo fi = checkFieldInfo(L,1); + + lua_pushboolean(L,FI_GET_FLAG(fi->ws_fi, FI_LITTLE_ENDIAN)); + return 1; +} + +/* WSLUA_ATTRIBUTE FieldInfo_big_endian RO Whether this field is big-endian encoded (boolean). + + @since 1.99.9 + */ +static int FieldInfo_get_big_endian(lua_State* L) { + FieldInfo fi = checkFieldInfo(L,1); + + lua_pushboolean(L,FI_GET_FLAG(fi->ws_fi, FI_BIG_ENDIAN)); + return 1; +} + +/* WSLUA_ATTRIBUTE FieldInfo_name RO The filter name of this field. + + @since 1.99.9 + */ static int FieldInfo_get_name(lua_State* L) { /* The filter name of this field. */ FieldInfo fi = checkFieldInfo(L,1); @@ -374,8 +463,14 @@ static int FieldInfo__gc(lua_State* L _U_) { WSLUA_ATTRIBUTES FieldInfo_attributes[] = { WSLUA_ATTRIBUTE_ROREG(FieldInfo,range), WSLUA_ATTRIBUTE_ROREG(FieldInfo,generated), + WSLUA_ATTRIBUTE_ROREG(FieldInfo,hidden), + WSLUA_ATTRIBUTE_ROREG(FieldInfo,is_url), + WSLUA_ATTRIBUTE_ROREG(FieldInfo,little_endian), + WSLUA_ATTRIBUTE_ROREG(FieldInfo,big_endian), WSLUA_ATTRIBUTE_ROREG(FieldInfo,name), WSLUA_ATTRIBUTE_ROREG(FieldInfo,display), + WSLUA_ATTRIBUTE_ROREG(FieldInfo,type), + WSLUA_ATTRIBUTE_ROREG(FieldInfo,source), { "label", FieldInfo__tostring, NULL }, { "value", FieldInfo__call, NULL }, { "tvb", FieldInfo_get_range, NULL }, @@ -422,11 +517,7 @@ WSLUA_FUNCTION wslua_all_field_infos(lua_State* L) { if (found) { for (i=0; ilen; i++) { - FieldInfo fi = (FieldInfo)g_malloc(sizeof(struct _wslua_field_info)); - fi->ws_fi = (field_info *)g_ptr_array_index(found,i); - fi->expired = FALSE; - - PUSH_FIELDINFO(L,fi); + push_FieldInfo(L, (field_info *)g_ptr_array_index(found,i)); items_found++; } @@ -583,6 +674,74 @@ WSLUA_CONSTRUCTOR Field_list(lua_State *L) { WSLUA_RETURN(1); /* The array table of field filter names */ } +/* the following is used in Field_get_xxx functions later */ +#define GET_HFINFO_MEMBER(luafunc, member) \ + if (wanted_fields) { \ + /* before registration, so it's a gchar** of the abbrev */ \ + const gchar* name = (const gchar*) *fi; \ + if (name) { \ + hfinfo = proto_registrar_get_byname(name); \ + if (!hfinfo) { \ + /* could be a Lua-created field */ \ + ProtoField pf = wslua_is_field_available(L, name); \ + if (pf) { \ + luafunc(L, pf->member); \ + return 1; \ + } \ + } \ + } else { \ + luaL_error(L, "Field." #member ": unknown field"); \ + return 0; \ + } \ + } else { \ + hfinfo = *fi; \ + } \ + \ + if (hfinfo) { \ + luafunc(L,hfinfo->member); \ + } else \ + lua_pushnil(L) + + +/* WSLUA_ATTRIBUTE Field_name RO The filter name of this field, or nil. + + @since 1.99.9 + */ +static int Field_get_name(lua_State* L) { + Field fi = checkField(L,1); + header_field_info* hfinfo = NULL; + + GET_HFINFO_MEMBER(lua_pushstring, abbrev); + + return 1; +} + +/* WSLUA_ATTRIBUTE Field_display RO The full display name of this field, or nil. + + @since 1.99.9 + */ +static int Field_get_display(lua_State* L) { + Field fi = checkField(L,1); + header_field_info* hfinfo = NULL; + + GET_HFINFO_MEMBER(lua_pushstring, name); + + return 1; +} + +/* WSLUA_ATTRIBUTE Field_type RO The `ftype` of this field, or nil. + + @since 1.99.9 + */ +static int Field_get_type(lua_State* L) { + Field fi = checkField(L,1); + header_field_info* hfinfo = NULL; + + GET_HFINFO_MEMBER(lua_pushnumber, type); + + return 1; +} + WSLUA_METAMETHOD Field__call (lua_State* L) { /* Obtain all values (see `FieldInfo`) for this field. */ Field f = checkField(L,1); @@ -604,11 +763,7 @@ WSLUA_METAMETHOD Field__call (lua_State* L) { guint i; if (found) { for (i=0; ilen; i++) { - FieldInfo fi = (FieldInfo)g_malloc(sizeof(struct _wslua_field_info)); - fi->ws_fi = (field_info *)g_ptr_array_index(found,i); - fi->expired = FALSE; - - PUSH_FIELDINFO(L,fi); + push_FieldInfo(L, (field_info *) g_ptr_array_index(found,i)); items_found++; } } @@ -619,7 +774,7 @@ WSLUA_METAMETHOD Field__call (lua_State* L) { } WSLUA_METAMETHOD Field__tostring(lua_State* L) { - /* Obtain a string with the field name. */ + /* Obtain a string with the field filter name. */ Field f = checkField(L,1); if (wanted_fields) { @@ -636,6 +791,13 @@ static int Field__gc(lua_State* L _U_) { return 0; } +WSLUA_ATTRIBUTES Field_attributes[] = { + WSLUA_ATTRIBUTE_ROREG(Field,name), + WSLUA_ATTRIBUTE_ROREG(Field,display), + WSLUA_ATTRIBUTE_ROREG(Field,type), + { NULL, NULL, NULL } +}; + WSLUA_METHODS Field_methods[] = { WSLUA_CLASS_FNREG(Field,new), WSLUA_CLASS_FNREG(Field,list), @@ -653,6 +815,7 @@ int Field_register(lua_State* L) { wanted_fields = g_ptr_array_new(); WSLUA_REGISTER_CLASS(Field); + WSLUA_REGISTER_ATTRIBUTES(Field); outstanding_FieldInfo = g_ptr_array_new(); return 0; diff --git a/epan/wslua/wslua_proto.c b/epan/wslua/wslua_proto.c index 2a4197a7ba..8cd3907ad5 100644 --- a/epan/wslua/wslua_proto.c +++ b/epan/wslua/wslua_proto.c @@ -876,7 +876,7 @@ WSLUA_CONSTRUCTOR ProtoField_new(lua_State* L) { f->hfid = -2; f->ett = -1; f->name = g_strdup(name); - f->abbr = g_strdup(abbr); + f->abbrev = g_strdup(abbr); f->type = type; f->base = base; if (tfs) { @@ -940,7 +940,7 @@ static int ProtoField_integer(lua_State* L, enum ftenum type) { f->hfid = -2; f->ett = -1; f->name = g_strdup(name); - f->abbr = g_strdup(abbr); + f->abbrev = g_strdup(abbr); f->type = type; f->base = base; if (vs64) { @@ -1104,7 +1104,7 @@ static int ProtoField_boolean(lua_State* L, enum ftenum type) { f->hfid = -2; f->ett = -1; f->name = g_strdup(name); - f->abbr = g_strdup(abbr); + f->abbrev = g_strdup(abbr); f->type = type; f->vs = TFS(tfs); f->base = base; @@ -1157,7 +1157,7 @@ static int ProtoField_time(lua_State* L,enum ftenum type) { f->hfid = -2; f->ett = -1; f->name = g_strdup(name); - f->abbr = g_strdup(abbr); + f->abbrev = g_strdup(abbr); f->type = type; f->vs = NULL; f->base = base; @@ -1201,7 +1201,7 @@ static int ProtoField_other(lua_State* L,enum ftenum type) { f->hfid = -2; f->ett = -1; f->name = g_strdup(name); - f->abbr = g_strdup(abbr); + f->abbrev = g_strdup(abbr); f->type = type; f->vs = NULL; f->base = BASE_NONE; @@ -1330,7 +1330,7 @@ WSLUA_METAMETHOD ProtoField__tostring(lua_State* L) { /* Returns a string with info about a protofield (for debugging purposes). */ ProtoField f = checkProtoField(L,1); gchar* s = g_strdup_printf("ProtoField(%i): %s %s %s %s %p %.8x %s", - f->hfid,f->name,f->abbr, + f->hfid,f->name,f->abbrev, ftenum_to_string(f->type), base_to_string(f->base), f->vs,f->mask,f->blob); @@ -1355,7 +1355,7 @@ static int ProtoField__gc(lua_State* L) { /* g_assert() ?? */ } else if (f->hfid == -2) { g_free(f->name); - g_free(f->abbr); + g_free(f->abbrev); g_free(f->blob); g_free(f); } @@ -1443,7 +1443,7 @@ WSLUA_CONSTRUCTOR ProtoExpert_new(lua_State* L) { pe->ids.ei = EI_INIT_EI; pe->ids.hf = EI_INIT_HF; - pe->abbr = g_strdup(abbr); + pe->abbrev = g_strdup(abbr); pe->text = g_strdup(text); pe->group = group; pe->severity = severity; @@ -1464,7 +1464,7 @@ WSLUA_METAMETHOD ProtoExpert__tostring(lua_State* L) { lua_pushstring(L,"ProtoExpert pointer is NULL!"); } else { lua_pushfstring(L, "ProtoExpert: ei=%d, hf=%d, abbr=%s, text=%s, group=%d, severity=%d", - pe->ids.ei, pe->ids.hf, pe->abbr, pe->text, pe->group, pe->severity); + pe->ids.ei, pe->ids.hf, pe->abbrev, pe->text, pe->group, pe->severity); } return 1; } @@ -1953,7 +1953,7 @@ int Proto_register(lua_State* L) { * Query field abbr that is defined and bound to a Proto in lua. * They are not registered until the end of the initialization. */ -int wslua_is_field_available(lua_State* L, const char* field_abbr) { +ProtoField wslua_is_field_available(lua_State* L, const char* field_abbr) { lua_rawgeti(L, LUA_REGISTRYINDEX, protocols_table_ref); lua_pushnil(L); while (lua_next(L, -2)) { @@ -1965,10 +1965,10 @@ int wslua_is_field_available(lua_State* L, const char* field_abbr) { lua_pushnil(L); while (lua_next(L, -2)) { ProtoField f = checkProtoField(L, -1); - if (strcmp(field_abbr, f->abbr) == 0) { + if (strcmp(field_abbr, f->abbrev) == 0) { /* found! */ lua_pop(L, 6); - return 1; + return f; } lua_pop(L, 1); /* table value */ } @@ -1976,7 +1976,7 @@ int wslua_is_field_available(lua_State* L, const char* field_abbr) { } lua_pop(L, 1); /* protocols_table_ref */ - return 0; + return NULL; } int Proto_commit(lua_State* L) { @@ -2010,7 +2010,7 @@ int Proto_commit(lua_State* L) { hfri.p_id = &(f->hfid); hfri.hfinfo.name = f->name; - hfri.hfinfo.abbrev = f->abbr; + hfri.hfinfo.abbrev = f->abbrev; hfri.hfinfo.type = f->type; hfri.hfinfo.display = f->base; hfri.hfinfo.strings = VALS(f->vs); @@ -2043,7 +2043,7 @@ int Proto_commit(lua_State* L) { ei_register_info eiri = { NULL, { NULL, 0, 0, NULL, EXPFILL } }; eiri.ids = &(e->ids); - eiri.eiinfo.name = e->abbr; + eiri.eiinfo.name = e->abbrev; eiri.eiinfo.group = e->group; eiri.eiinfo.severity = e->severity; eiri.eiinfo.summary = e->text; @@ -2143,12 +2143,11 @@ wslua_dissect_tcp_dissector(tvbuff_t *tvb, packet_info *pinfo, lua_rawgeti(L, LUA_REGISTRYINDEX, fs->dissect_ref); if (lua_isfunction(L,1)) { - /* XXX: not sure if it's kosher to just use the tree as the item */ - TreeItem ti = create_TreeItem(tree, (proto_item*)tree); push_Tvb(L,tvb); push_Pinfo(L,pinfo); - push_TreeItem(L,ti); + /* XXX: not sure if it's kosher to just use the tree as the item */ + push_TreeItem(L, tree, (proto_item*)tree); if ( lua_pcall(L,3,1,0) ) { luaL_error(L, "Lua Error dissect_tcp_pdus dissect_func: %s", lua_tostring(L,-1)); diff --git a/epan/wslua/wslua_tree.c b/epan/wslua/wslua_tree.c index f65bed1ae1..fe251f1c83 100644 --- a/epan/wslua/wslua_tree.c +++ b/epan/wslua/wslua_tree.c @@ -37,13 +37,21 @@ static gint wslua_ett = -1; static GPtrArray* outstanding_TreeItem = NULL; -#define PUSH_TREEITEM(L,i) {g_ptr_array_add(outstanding_TreeItem,i);pushTreeItem(L,i);} -TreeItem* push_TreeItem(lua_State*L, TreeItem t) { - g_ptr_array_add(outstanding_TreeItem,t); - return pushTreeItem(L,t); +/* pushing a TreeItem with a NULL item or subtree is completely valid for this function */ +TreeItem push_TreeItem(lua_State *L, proto_tree *tree, proto_item *item) { + TreeItem ti = (struct _wslua_treeitem *)g_malloc(sizeof(struct _wslua_treeitem)); + + ti->tree = tree; + ti->item = item; + ti->expired = FALSE; + + g_ptr_array_add(outstanding_TreeItem, ti); + + return *(pushTreeItem(L,ti)); } +/* creates the TreeItem but does NOT push it into Lua */ TreeItem create_TreeItem(proto_tree* tree, proto_item* item) { TreeItem tree_item = (TreeItem)g_malloc(sizeof(struct _wslua_treeitem)); @@ -57,8 +65,25 @@ TreeItem create_TreeItem(proto_tree* tree, proto_item* item) CLEAR_OUTSTANDING(TreeItem, expired, TRUE) WSLUA_CLASS_DEFINE(TreeItem,FAIL_ON_NULL_OR_EXPIRED("TreeItem"),NOP); -/* ++TreeItem++s represent information in the packet-details pane. - A root +TreeItem+ is passed to dissectors as the third argument. */ +/* ++TreeItem++s represent information in the packet-details pane of + Wireshark, and the packet details view of Tshark. A `TreeItem` represents + a node in the tree, which might also be a subtree and have a list of + children. The children of a subtree have zero or more siblings: other children + of the same `TreeItem` subtree. + + During dissection, heuristic-dissection, and post-dissection, a root + +TreeItem+ is passed to dissectors as the third argument of the function + callback (e.g., `myproto.dissector(tvbuf,pktinfo,root)`). + + In some cases the tree is not truly added to, in order to improve performance. + For example for packets not currently displayed/selected in Wireshark's visible + window pane, or if Tshark isn't invoked with the `-V` switch. However the + "add" type `TreeItem` functions can still be called, and still return `TreeItem` + objects - but the info isn't really added to the tree. Therefore you do not + typically need to worry about whether there's a real tree or not. If, for some + reason, you need to know it, you can use the `tree.visible` attribute getter + to retrieve the state. + */ /* the following is used by TreeItem_add_packet_field() - this can THROW errors */ static proto_item * @@ -264,9 +289,7 @@ WSLUA_METHOD TreeItem_add_packet_field(lua_State *L) { nargs--; } - tree_item = create_TreeItem(proto_item_add_subtree(item,ett > 0 ? ett : wslua_ett), item); - - PUSH_TREEITEM(L,tree_item); + tree_item = push_TreeItem(L, proto_item_add_subtree(item,ett > 0 ? ett : wslua_ett), item); /* move the tree object before the field value */ lua_insert(L, 1); @@ -315,7 +338,11 @@ static int TreeItem_add_item_any(lua_State *L, gboolean little_endian) { } if (hfid > 0 ) { + /* hfid is > 0 when the first arg was a ProtoField or Proto */ + if (lua_gettop(L)) { + /* if we got here, the (L,1) index is the value to add, instead of decoding from the Tvb */ + switch(type) { case FT_PROTOCOL: item = proto_tree_add_item(tree_item->tree,hfid,tvbr->tvb->ws_tvb,tvbr->offset,tvbr->len,ENC_NA); @@ -388,17 +415,20 @@ static int TreeItem_add_item_any(lua_State *L, gboolean little_endian) { lua_remove(L,1); } else { + /* the Lua stack is empty - no value was given - so decode the value from the tvb */ if (type == FT_STRINGZ) tvbr->len = tvb_strsize (tvbr->tvb->ws_tvb, tvbr->offset); item = proto_tree_add_item(tree_item->tree, hfid, tvbr->tvb->ws_tvb, tvbr->offset, tvbr->len, little_endian ? ENC_LITTLE_ENDIAN : ENC_BIG_ENDIAN); } if ( lua_gettop(L) ) { + /* if there was a value, it was removed earlier, so what's left is the display string to set */ const gchar* s = lua_tostring(L,1); if (s) proto_item_set_text(item,"%s",s); lua_remove(L,1); } } else { + /* no ProtoField or Proto was given */ if (lua_gettop(L)) { const gchar* s = lua_tostring(L,1); const int hf = get_hf_wslua_text(); @@ -416,14 +446,13 @@ static int TreeItem_add_item_any(lua_State *L, gboolean little_endian) { } while(lua_gettop(L)) { + /* keep appending more text */ const gchar* s = lua_tostring(L,1); if (s) proto_item_append_text(item, " %s", s); lua_remove(L,1); } - tree_item = create_TreeItem(proto_item_add_subtree(item,ett > 0 ? ett : wslua_ett), item); - - PUSH_TREEITEM(L,tree_item); + tree_item = push_TreeItem(L, proto_item_add_subtree(item,ett > 0 ? ett : wslua_ett), item); return 1; } @@ -467,6 +496,38 @@ WSLUA_METHOD TreeItem_add_le(lua_State *L) { WSLUA_RETURN(TreeItem_add_item_any(L,TRUE)); /* The new child TreeItem. */ } +/* WSLUA_ATTRIBUTE TreeItem_text RW Set/get the `TreeItem`'s display string (string). + + For the getter, if the TreeItem has no display string, then nil is returned. + + @since 1.99.3 + */ +static int TreeItem_get_text(lua_State* L) { + TreeItem ti = checkTreeItem(L,1); + gchar label_str[ITEM_LABEL_LENGTH+1]; + gchar *label_ptr; + field_info *fi = PITEM_FINFO(ti->item); + + if(fi) { + if (!fi->rep) { + label_ptr = label_str; + proto_item_fill_label(fi, label_str); + } else + label_ptr = fi->rep->representation; + + if (label_ptr) { + lua_pushstring(L, label_ptr); + } else { + lua_pushnil(L); + } + } else { + lua_pushnil(L); + } + + return 1; +} + +/* the following is used as both a method and attribute */ WSLUA_METHOD TreeItem_set_text(lua_State *L) { /* Sets the text of the label. @@ -636,14 +697,55 @@ WSLUA_METHOD TreeItem_add_tvb_expert_info(lua_State *L) { WSLUA_RETURN(1); /* The same TreeItem. */ } + +/* WSLUA_ATTRIBUTE TreeItem_visible RO Get the `TreeItem`'s subtree visibility status (boolean). + + @since 1.99.9 + */ +static int TreeItem_get_visible(lua_State* L) { + TreeItem ti = checkTreeItem(L,1); + + if (ti->tree) { + lua_pushboolean(L, PTREE_DATA(ti->tree)->visible); + } + else { + lua_pushboolean(L, FALSE); + } + + return 1; +} + + +/* WSLUA_ATTRIBUTE TreeItem_generated RW Set/get the `TreeItem`'s generated state (boolean). + + @since 1.99.9 + */ +static int TreeItem_get_generated(lua_State* L) { + TreeItem ti = checkTreeItem(L,1); + + lua_pushboolean(L, PROTO_ITEM_IS_GENERATED(ti->item)); + + return 1; +} + +/* the following is used as both a method and attribute. As a method it defaults + to setting the value, because that's what it used to do before. */ WSLUA_METHOD TreeItem_set_generated(lua_State *L) { /* Marks the `TreeItem` as a generated field (with data inferred but not contained in the packet). This used to return nothing, but as of 1.11.3 it returns the same tree item to allow chained calls. */ +#define WSLUA_OPTARG_TreeItem_set_generated_BOOL 2 /* A Lua boolean, which if `true` sets the `TreeItem` + generated flag, else clears it (default=true) */ TreeItem ti = checkTreeItem(L,1); + gboolean set = wslua_optbool(L, WSLUA_OPTARG_TreeItem_set_generated_BOOL, TRUE); - PROTO_ITEM_SET_GENERATED(ti->item); + if (set) { + PROTO_ITEM_SET_GENERATED(ti->item); + } else { + if (ti->item) + FI_RESET_FLAG(PITEM_FINFO(ti->item), FI_GENERATED); + } /* copy the TreeItem userdata so we give it back */ lua_pushvalue(L, 1); @@ -651,12 +753,35 @@ WSLUA_METHOD TreeItem_set_generated(lua_State *L) { WSLUA_RETURN(1); /* The same TreeItem. */ } +/* WSLUA_ATTRIBUTE TreeItem_hidden RW Set/get `TreeItem`'s hidden state (boolean). -WSLUA_METHOD TreeItem_set_hidden(lua_State *L) { - /* This function should not be used, and is provided for backwards-compatibility only. */ + @since 1.99.9 + */ +static int TreeItem_get_hidden(lua_State* L) { TreeItem ti = checkTreeItem(L,1); - PROTO_ITEM_SET_HIDDEN(ti->item); + lua_pushboolean(L, PROTO_ITEM_IS_HIDDEN(ti->item)); + + return 1; +} + +/* the following is used as both a method and attribute. As a method it defaults + to setting the value, because that's what it used to do before. */ +WSLUA_METHOD TreeItem_set_hidden(lua_State *L) { + /* Marks the `TreeItem` as a hidden field (neither displayed nor used in filters). + + This used to return nothing, but as of 1.11.3 it returns the same tree item to allow chained calls. + */ +#define WSLUA_OPTARG_TreeItem_set_hidden_BOOL 2 /* A Lua boolean, which if `true` sets the `TreeItem` + hidden flag, else clears it (default=true) */ + TreeItem ti = checkTreeItem(L,1); + gboolean set = wslua_optbool(L, WSLUA_OPTARG_TreeItem_set_hidden_BOOL, TRUE); + + if (set) { + PROTO_ITEM_SET_HIDDEN(ti->item); + } else { + PROTO_ITEM_SET_VISIBLE(ti->item); + } /* copy the TreeItem userdata so we give it back */ lua_pushvalue(L, 1); @@ -664,6 +789,21 @@ WSLUA_METHOD TreeItem_set_hidden(lua_State *L) { WSLUA_RETURN(1); /* The same TreeItem. */ } +/* WSLUA_ATTRIBUTE TreeItem_len RW Set/get `TreeItem`'s length inside tvb, after it has already been created. + + @since 1.99.9 + */ +static int TreeItem_get_len(lua_State* L) { + TreeItem ti = checkTreeItem(L,1); + int len = 0; + + len = proto_item_get_len(ti->item); + + lua_pushinteger(L, len > 0 ? len : 0); + + return 1; +} + WSLUA_METHOD TreeItem_set_len(lua_State *L) { /* Set `TreeItem`'s length inside tvb, after it has already been created. @@ -681,6 +821,28 @@ WSLUA_METHOD TreeItem_set_len(lua_State *L) { WSLUA_RETURN(1); /* The same TreeItem. */ } +WSLUA_METAMETHOD TreeItem__tostring(lua_State* L) { + /* Returns string debug information about the `TreeItem`. + + @since 1.99.9 + */ + TreeItem ti = toTreeItem(L,1); + + if (ti) { + lua_pushfstring(L, + "TreeItem: expired=%s, has item=%s, has subtree=%s, they are %sthe same", + ti->expired ? "true" : "false", + ti->item ? "true" : "false", + ti->tree ? "true" : "false", + (ti->tree == ti->item) ? "" : "not "); + } + else { + lua_pushstring(L, "No TreeItem object!"); + } + + return 1; +} + /* Gets registered as metamethod automatically by WSLUA_REGISTER_CLASS/META */ static int TreeItem__gc(lua_State* L) { TreeItem ti = toTreeItem(L,1); @@ -692,6 +854,15 @@ static int TreeItem__gc(lua_State* L) { return 0; } +WSLUA_ATTRIBUTES TreeItem_attributes[] = { + WSLUA_ATTRIBUTE_RWREG(TreeItem,generated), + WSLUA_ATTRIBUTE_RWREG(TreeItem,hidden), + WSLUA_ATTRIBUTE_RWREG(TreeItem,len), + WSLUA_ATTRIBUTE_RWREG(TreeItem,text), + WSLUA_ATTRIBUTE_ROREG(TreeItem,visible), + { NULL, NULL, NULL } +}; + WSLUA_METHODS TreeItem_methods[] = { WSLUA_CLASS_FNREG(TreeItem,add_packet_field), WSLUA_CLASS_FNREG(TreeItem,add), @@ -709,12 +880,14 @@ WSLUA_METHODS TreeItem_methods[] = { }; WSLUA_META TreeItem_meta[] = { + WSLUA_CLASS_MTREG(TreeItem,tostring), { NULL, NULL } }; int TreeItem_register(lua_State *L) { gint* etts[] = { &wslua_ett }; WSLUA_REGISTER_CLASS(TreeItem); + WSLUA_REGISTER_ATTRIBUTES(TreeItem); outstanding_TreeItem = g_ptr_array_new(); proto_register_subtree_array(etts,1); return 0; diff --git a/epan/wslua/wslua_tvb.c b/epan/wslua/wslua_tvb.c index 8c8ed4e118..5fad6ddbf5 100644 --- a/epan/wslua/wslua_tvb.c +++ b/epan/wslua/wslua_tvb.c @@ -563,6 +563,42 @@ WSLUA_METHOD Tvb_reported_length_remaining(lua_State* L) { WSLUA_RETURN(1); /* The captured length of the `Tvb`. */ } +WSLUA_METHOD Tvb_bytes(lua_State* L) { + /* Obtain a `ByteArray` from a `Tvb`. + + @since 1.99.9 + */ +#define WSLUA_OPTARG_Tvb_bytes_OFFSET 2 /* The offset (in octets) from the beginning of the `Tvb`. Defaults to 0. */ +#define WSLUA_OPTARG_Tvb_bytes_LENGTH 3 /* The length (in octets) of the range. Defaults to until the end of the `Tvb`. */ + Tvb tvb = checkTvb(L,1); + GByteArray* ba; + int offset = luaL_optint(L, WSLUA_OPTARG_Tvb_bytes_OFFSET, 0); + int len = luaL_optint(L,WSLUA_OPTARG_Tvb_bytes_LENGTH,-1); + + if (tvb->expired) { + luaL_error(L,"expired tvb"); + return 0; + } + + ba = g_byte_array_new(); + + if (len < 0) { + len = tvb_captured_length_remaining(tvb->ws_tvb,offset); + if (len < 0) { + luaL_error(L,"out of bounds"); + return 0; + } + } else if ( (guint)(len + offset) > tvb_captured_length(tvb->ws_tvb)) { + luaL_error(L,"Range is out of bounds"); + return 0; + } + + g_byte_array_append(ba, tvb_get_ptr(tvb->ws_tvb, offset, len), len); + pushByteArray(L,ba); + + WSLUA_RETURN(1); /* The `ByteArray` object or nil. */ +} + WSLUA_METHOD Tvb_offset(lua_State* L) { /* Returns the raw offset (from the beginning of the source `Tvb`) of a sub `Tvb`. */ Tvb tvb = checkTvb(L,1); @@ -674,7 +710,40 @@ WSLUA_METHOD Tvb_raw(lua_State* L) { WSLUA_RETURN(1); /* A Lua string of the binary bytes in the `Tvb`. */ } +WSLUA_METAMETHOD Tvb__eq(lua_State* L) { + /* Checks whether the two `Tvb` contents are equal. + + @since 1.99.9 + */ + Tvb tvb_l = checkTvb(L,1); + Tvb tvb_r = checkTvb(L,2); + + int len_l = tvb_captured_length(tvb_l->ws_tvb); + int len_r = tvb_captured_length(tvb_r->ws_tvb); + + /* it is not an error if their ds_tvb are different... they're just not equal */ + if (len_l == len_r) + { + const gchar* lp = tvb_get_ptr(tvb_l->ws_tvb, 0, len_l); + const gchar* rp = tvb_get_ptr(tvb_r->ws_tvb, 0, len_r); + int i = 0; + + for (; i < len_l; ++i) { + if (lp[i] != rp[i]) { + lua_pushboolean(L,0); + return 1; + } + } + lua_pushboolean(L,1); + } else { + lua_pushboolean(L,0); + } + + return 1; +} + WSLUA_METHODS Tvb_methods[] = { + WSLUA_CLASS_FNREG(Tvb,bytes), WSLUA_CLASS_FNREG(Tvb,range), WSLUA_CLASS_FNREG(Tvb,len), WSLUA_CLASS_FNREG(Tvb,offset), @@ -685,6 +754,7 @@ WSLUA_METHODS Tvb_methods[] = { }; WSLUA_META Tvb_meta[] = { + WSLUA_CLASS_MTREG(Tvb,eq), WSLUA_CLASS_MTREG(Tvb,tostring), {"__call", Tvb_range}, { NULL, NULL } @@ -722,13 +792,6 @@ WSLUA_METHOD TvbRange_uint(lua_State* L) { case 4: lua_pushnumber(L,tvb_get_ntohl(tvbr->tvb->ws_tvb,tvbr->offset)); WSLUA_RETURN(1); /* The unsigned integer value. */ - /* - * XXX: - * lua uses double so we have 52 bits to play with - * we are missing 5 and 6 byte integers within lua's range - * and 64 bit integers are not supported (there's a lib for - * lua that does). - */ default: luaL_error(L,"TvbRange:uint() does not handle %d byte integers",tvbr->len); return 0; @@ -1576,6 +1639,36 @@ WSLUA_METHOD TvbRange_raw(lua_State* L) { WSLUA_RETURN(1); /* A Lua string of the binary bytes in the `TvbRange`. */ } +WSLUA_METAMETHOD TvbRange__eq(lua_State* L) { + /* Checks whether the two `TvbRange` contents are equal. + + @since 1.99.9 + */ + TvbRange tvb_l = checkTvbRange(L,1); + TvbRange tvb_r = checkTvbRange(L,2); + + /* it is not an error if their ds_tvb are different... they're just not equal */ + if (tvb_l->len == tvb_r->len && + tvb_l->len <= tvb_captured_length_remaining(tvb_l->tvb->ws_tvb, tvb_l->offset) && + tvb_r->len <= tvb_captured_length_remaining(tvb_r->tvb->ws_tvb, tvb_r->offset)) + { + const gchar* lp = tvb_get_ptr(tvb_l->tvb->ws_tvb, tvb_l->offset, tvb_l->len); + const gchar* rp = tvb_get_ptr(tvb_r->tvb->ws_tvb, tvb_r->offset, tvb_r->len); + int i = 0; + + for (; i < tvb_r->len; ++i) { + if (lp[i] != rp[i]) { + lua_pushboolean(L,0); + return 1; + } + } + lua_pushboolean(L,1); + } else { + lua_pushboolean(L,0); + } + + return 1; +} WSLUA_METAMETHOD TvbRange__tostring(lua_State* L) { /* Converts the `TvbRange` into a string. Since the string gets truncated, @@ -1635,6 +1728,7 @@ WSLUA_METHODS TvbRange_methods[] = { WSLUA_META TvbRange_meta[] = { WSLUA_CLASS_MTREG(TvbRange,tostring), WSLUA_CLASS_MTREG(wslua,concat), + WSLUA_CLASS_MTREG(TvbRange,eq), {"__call", TvbRange_range}, { NULL, NULL } }; diff --git a/test/lua/field.lua b/test/lua/field.lua index b77528729e..2e9d1c62bb 100644 --- a/test/lua/field.lua +++ b/test/lua/field.lua @@ -72,6 +72,18 @@ local f_bootp_opt = Field.new("bootp.option.type") test("Field__tostring-1", tostring(f_frame_proto) == "frame.protocols") +test("Field.name-1", f_frame_proto.name == "frame.protocols") +test("Field.name-2", f_eth_src.name == "eth.src") + +test("Field.display-1", f_frame_proto.display == "Protocols in frame") +test("Field.display-2", f_eth_src.display == "Source") + +test("Field.type-1", f_frame_proto.type == ftypes.STRING) +test("Field.type-2", f_eth_src.type == ftypes.ETHER) +test("Field.type-3", f_ip_src.type == ftypes.IPv4) +test("Field.type-4", f_udp_srcport.type == ftypes.UINT16) +test("Field.type-5", f_bootp_opt.type == ftypes.UINT8) + -- make sure can't create a FieldInfo outside tap test("Field__call-1",not pcall(makeFieldInfo,f_eth_src)) @@ -90,11 +102,33 @@ function tap.packet(pinfo,tvb) test("Field__call-2",pcall(makeFieldInfo,f_eth_src)) + test("Field.name-3", f_frame_proto.name == "frame.protocols") + test("Field.name-4", f_eth_src.name == "eth.src") + + test("Field.display-3", f_frame_proto.display == "Protocols in frame") + test("Field.display-4", f_eth_src.display == "Source") + + test("Field.type-6", f_frame_proto.type == ftypes.STRING) + test("Field.type-7", f_eth_src.type == ftypes.ETHER) + test("Field.type-8", f_ip_src.type == ftypes.IPv4) + test("Field.type-9", f_udp_srcport.type == ftypes.UINT16) + test("Field.type-10", f_bootp_opt.type == ftypes.UINT8) testing("FieldInfo") + local finfo_udp_srcport = f_udp_srcport() + test("FieldInfo.name-1", finfo_udp_srcport.name == "udp.srcport") + test("FieldInfo.type-1", finfo_udp_srcport.type == ftypes.UINT16) + test("FieldInfo.little_endian-1", finfo_udp_srcport.little_endian == false) + -- the following should be true, but UDP doesn't set it right? + -- test("FieldInfo.big_endian-1", finfo_udp_srcport.big_endian == true) + test("FieldInfo.is_url-1", finfo_udp_srcport.is_url == false) + test("FieldInfo.offset-1", finfo_udp_srcport.offset == 34) + test("FieldInfo.source-1", finfo_udp_srcport.source == tvb) + -- check ether addr local fi_eth_src = f_eth_src() + test("FieldInfo.type-2", fi_eth_src.type == ftypes.ETHER) test("FieldInfo.range-0",pcall(getFieldInfo,fi_eth_src,"range")) local eth_macs = { f_eth_mac() } local eth_src1 = tostring(f_eth_src().range)