Wireshark-dev: [Wireshark-dev] patch for wslua to support getting ranges from ranges
From: Sam Roberts <vieuxtech@xxxxxxxxx>
Date: Fri, 5 Jun 2009 14:08:16 -0700
Useful when you want to pull a buffer range out, and then parse that range.

For example, packets like:

uint16 count
uint8 flag
uint32 payload
-- ... flag and payload is repeated count times

It's nice to be able to pull each substructure out as a Tvbr, then
pass it to a function
that will parse it assuming offset zero is the flag, and bytes 1-5 are
the payload,
tracking the current position in the Tvb/buffer becomes easier.

Cheers,
Sam
Index: epan/wslua/wslua_tvb.c
===================================================================
--- epan/wslua/wslua_tvb.c	(revision 28639)
+++ epan/wslua/wslua_tvb.c	(working copy)
@@ -864,6 +865,46 @@
 	WSLUA_RETURN(1); /* The ByteArray */
 }
 
+WSLUA_METHOD TvbRange_bitfield(lua_State* L) {
+	/* Get a bitfield from a TvbRange. */
+#define WSLUA_OPTARG_TvbRange_bitfield_POSITION 2 /* The bit offset from the begining of the TvbRange. Defaults to 0. */
+#define WSLUA_OPTARG_TvbRange_bitfield_LENGTH 3 /* The length (in bits) of the field. Defaults to 1. */
+
+    TvbRange tvbr = checkTvbRange(L,1);
+    int pos = luaL_optint(L,WSLUA_OPTARG_TvbRange_bitfield_POSITION,0);
+    int len = luaL_optint(L,WSLUA_OPTARG_TvbRange_bitfield_LENGTH,1);
+
+    if (!(tvbr && tvbr->tvb)) return 0;
+    if (tvbr->tvb->expired) {
+        luaL_error(L,"expired tvb");
+        return 0;
+    }
+
+    if ((pos+len) > (tvbr->len<<3)) {
+        luaL_error(L, "Requested bitfield out of range");
+        return 0;
+    }
+
+    if (len <= 8) {
+        lua_pushnumber(L,(lua_Number)tvb_get_bits8(tvbr->tvb->ws_tvb,tvbr->offset*8 + pos, len));
+        return 1;
+    } else if (len <= 16) {
+        lua_pushnumber(L,tvb_get_bits16(tvbr->tvb->ws_tvb,tvbr->offset*8 + pos, len, FALSE));
+        return 1;
+    } else if (len <= 32) {
+        lua_pushnumber(L,tvb_get_bits32(tvbr->tvb->ws_tvb,tvbr->offset*8 + pos, len, FALSE));
+        return 1;
+    } else if (len <= 64) {
+        UInt64 num = g_malloc(sizeof(guint64));
+        *num = tvb_get_bits64(tvbr->tvb->ws_tvb,tvbr->offset*8 + pos, len, FALSE);
+        pushUInt64(L,num);
+        return 1;
+    } else {
+        luaL_error(L,"TvbRange:bitfield() does not handle %d bits",len);
+        return 0;
+    }
+}
+
 WSLUA_METHOD TvbRange_len(lua_State* L) {
 	/* Obtain the length of a TvbRange */
     TvbRange tvbr = checkTvbRange(L,1);
@@ -890,7 +931,33 @@
         return 1;
 }
 
+WSLUA_METHOD TvbRange_range(lua_State* L) {
+    /* Creates a sub-TbvRange from this TvbRange. This is used also as the TvbRange:__call() metamethod. */
+#define WSLUA_OPTARG_TvbRange_range_OFFSET 2 /* The offset (in octets) from the begining of the TvbRange. Defaults to 0. */
+#define WSLUA_OPTARG_TvbRange_range_LENGTH 3 /* The length (in octets) of the range. Defaults to until the end of the TvbRange. */
 
+    TvbRange tvbr = checkTvbRange(L,1);
+    int offset;
+    int len;
+
+    if (!tvbr) return 0;
+
+    offset = luaL_optint(L,WSLUA_OPTARG_TvbRange_range_OFFSET,0);
+    len = luaL_optint(L,WSLUA_OPTARG_TvbRange_range_LENGTH,tvbr->len-offset);
+
+    if (offset >= tvbr->len || (len + offset) > tvbr->len) {
+        luaL_error(L,"Range is out of bounds");
+        return 0;
+    }
+
+    if ((tvbr = new_TvbRange(L,tvbr->tvb->ws_tvb,tvbr->offset+offset,len))) {
+        PUSH_TVBRANGE(L,tvbr);
+	WSLUA_RETURN(1); /* The TvbRange */
+    }
+
+    return 0;
+}
+
 WSLUA_METAMETHOD TvbRange__tostring(lua_State* L) {
 	/* Converts the TvbRange into a string. As the string gets truncated
 	   you should use this only for debugging purposes
@@ -916,17 +983,20 @@
     {"le_float", TvbRange_le_float},
     {"ether", TvbRange_ether},
     {"ipv4", TvbRange_ipv4},
-	{"le_ipv4", TvbRange_le_ipv4},
+    {"le_ipv4", TvbRange_le_ipv4},
     {"string", TvbRange_string},
     {"bytes", TvbRange_bytes},
     {"len", TvbRange_len},
     {"offset", TvbRange_offset},
+    {"range", TvbRange_range},
     {"tvb", Tvb_tvb},
     { NULL, NULL }
 };
 
 static const luaL_reg TvbRange_meta[] = {
     {"__tostring", TvbRange__tostring},
+    {"__call", TvbRange_range},
     { NULL, NULL }
 };