summaryrefslogtreecommitdiffstats
path: root/epan/wslua/wslua_struct.c
diff options
context:
space:
mode:
Diffstat (limited to 'epan/wslua/wslua_struct.c')
-rw-r--r--epan/wslua/wslua_struct.c176
1 files changed, 101 insertions, 75 deletions
diff --git a/epan/wslua/wslua_struct.c b/epan/wslua/wslua_struct.c
index 7d62dc09..c1f6dc1b 100644
--- a/epan/wslua/wslua_struct.c
+++ b/epan/wslua/wslua_struct.c
@@ -60,13 +60,8 @@
#include "config.h"
-#include <assert.h>
#include <limits.h>
-#include <stddef.h>
-#include <string.h>
-
-#include <stdio.h>
-
+#include <wsutil/array.h>
#include "wslua.h"
/* WSLUA_MODULE Struct Binary encode/decode support
@@ -131,7 +126,7 @@
* `++(++' to stop assigning items, and `++)++' start assigning (padding when packing).
* `++=++' to return the current position / offset.
- [NOTE]
+ [IMPORTANT]
====
Using `i`, `I`, `h`, `H`, `l`, `L`, `f`, and `T` is strongly discouraged, as those sizes
are system-dependent. Use the explicitly sized variants instead, such as `i4` or `E`.
@@ -141,7 +136,16 @@
Use `e`/`E` to unpack into a Wireshark `Int64`/`UInt64` object instead.
====
- @since 1.11.3
+ [NOTE]
+ ====
+ Lua 5.3 and later provides several built-in functions for struct unpacking and packing:
+ https://www.lua.org/manual/5.4/manual.html#pdf-string.pack[string.pack],
+ https://www.lua.org/manual/5.4/manual.html#pdf-string.packsize[string.packsize], and
+ https://www.lua.org/manual/5.4/manual.html#pdf-string.unpack[string.unpack].
+ You can use those as well, but note that the
+ https://www.lua.org/manual/5.4/manual.html#6.4.2[format string] conversion elements
+ are slightly different, and they do not support the Wireshark `Int64`/`UInt64` objects.
+ ====
*/
@@ -169,12 +173,12 @@ typedef unsigned STRUCT_INT Uinttype;
/* dummy structure to get padding/alignment requirements */
struct cD {
- gchar c;
- gdouble d;
+ char c;
+ double d;
};
-#define PADDING (sizeof(struct cD) - sizeof(gdouble))
+#define PADDING (sizeof(struct cD) - sizeof(double))
#define MAXALIGN (PADDING > sizeof(int) ? PADDING : sizeof(int))
@@ -185,23 +189,25 @@ struct cD {
/* trick to determine native endianness of system */
static union {
int dummy;
- gchar endian;
+ char endian;
} const native = {1};
/* settings info */
typedef struct Header {
int endian;
int align;
- gboolean noassign;
+ bool noassign;
} Header;
/* For options that take a number argument, gets the number */
-static int getnum (const gchar **fmt, int df) {
+static int getnum (lua_State *L, const char **fmt, int df) {
if (!g_ascii_isdigit(**fmt)) /* no number? */
return df; /* return default value */
else {
int a = 0;
do {
+ if (a > (INT_MAX / 10) || a * 10 > (INT_MAX - (**fmt - '0')))
+ luaL_error(L, "integral size overflow");
a = a*10 + *((*fmt)++) - '0';
} while (g_ascii_isdigit(**fmt));
return a;
@@ -209,24 +215,24 @@ static int getnum (const gchar **fmt, int df) {
}
-#define defaultoptions(h) ((h)->endian = native.endian, (h)->align = 1, (h)->noassign = FALSE)
+#define defaultoptions(h) ((h)->endian = native.endian, (h)->align = 1, (h)->noassign = false)
/* gets size (number of bytes) for a given type */
-static size_t optsize (lua_State *L, gchar opt, const gchar **fmt) {
+static size_t optsize (lua_State *L, char opt, const char **fmt) {
switch (opt) {
- case 'B': case 'b': return sizeof(gchar);
- case 'H': case 'h': return sizeof(gshort);
- case 'L': case 'l': return sizeof(glong);
- case 'E': case 'e': return sizeof(gint64);
+ case 'B': case 'b': return sizeof(char);
+ case 'H': case 'h': return sizeof(short);
+ case 'L': case 'l': return sizeof(long);
+ case 'E': case 'e': return sizeof(int64_t);
case 'T': return sizeof(size_t);
- case 'f': return sizeof(gfloat);
- case 'd': return sizeof(gdouble);
- case 'x': return getnum(fmt, 1);
- case 'X': return getnum(fmt, MAXALIGN);
- case 'c': return getnum(fmt, 1);
+ case 'f': return sizeof(float);
+ case 'd': return sizeof(double);
+ case 'x': return getnum(L, fmt, 1);
+ case 'X': return getnum(L, fmt, MAXALIGN);
+ case 'c': return getnum(L, fmt, 1);
case 'i': case 'I': {
- int sz = getnum(fmt, sizeof(int));
+ int sz = getnum(L, fmt, sizeof(int));
if (sz > MAXINTSIZE)
luaL_error(L, "integral size %d is larger than limit of %d",
sz, MAXINTSIZE);
@@ -238,7 +244,7 @@ static size_t optsize (lua_State *L, gchar opt, const gchar **fmt) {
case '!': case '=':
return 0; /* these cases do not have a size */
default: {
- const gchar *msg = lua_pushfstring(L, "invalid format option [%c]", opt);
+ const char *msg = lua_pushfstring(L, "invalid format option [%c]", opt);
return luaL_argerror(L, 1, msg);
}
}
@@ -260,16 +266,16 @@ static int gettoalign (size_t len, Header *h, int opt, size_t size) {
/*
** options to control endianness and alignment settings
*/
-static void controloptions (lua_State *L, int opt, const gchar **fmt,
+static void controloptions (lua_State *L, int opt, const char **fmt,
Header *h) {
switch (opt) {
case ' ': return; /* ignore white spaces */
case '>': h->endian = BIG; return;
case '<': h->endian = LITTLE; return;
- case '(': h->noassign = TRUE; return;
- case ')': h->noassign = FALSE; return;
+ case '(': h->noassign = true; return;
+ case ')': h->noassign = false; return;
case '!': {
- int a = getnum(fmt, MAXALIGN);
+ int a = getnum(L, fmt, MAXALIGN);
if (!isp2(a))
luaL_error(L, "alignment %d is not a power of 2", a);
h->align = a;
@@ -287,12 +293,12 @@ static void putinteger (lua_State *L, luaL_Buffer *b, int arg, int endian,
int size) {
lua_Number n = luaL_checknumber(L, arg);
/* this one's not system dependent size - it's a long long */
- gint64 value;
- gchar buff[MAXINTSIZE];
+ int64_t value;
+ char buff[MAXINTSIZE];
if (n < 0)
- value = (guint64)(gint64)n;
+ value = (uint64_t)(int64_t)n;
else
- value = (guint64)n;
+ value = (uint64_t)n;
if (endian == LITTLE) {
int i;
for (i = 0; i < size; i++) {
@@ -313,11 +319,11 @@ static void putinteger (lua_State *L, luaL_Buffer *b, int arg, int endian,
/* corrects endianness - usually done by other functions themselves, but is
* used for float/doubles, since on some platforms they're endian'ed as well
*/
-static void correctbytes (gchar *b, int size, int endian) {
+static void correctbytes (char *b, int size, int endian) {
if (endian != native.endian) {
int i = 0;
while (i < --size) {
- gchar temp = b[i];
+ char temp = b[i];
b[i++] = b[size];
b[size] = temp;
}
@@ -368,20 +374,20 @@ WSLUA_CONSTRUCTOR Struct_pack (lua_State *L) {
break;
}
case 'f': {
- gfloat f = (gfloat)luaL_checknumber(L, arg++);
- correctbytes((gchar *)&f, (int)size, h.endian);
- luaL_addlstring(&b, (gchar *)&f, size);
+ float f = (float)luaL_checknumber(L, arg++);
+ correctbytes((char *)&f, (int)size, h.endian);
+ luaL_addlstring(&b, (char *)&f, size);
break;
}
case 'd': {
- gdouble d = luaL_checknumber(L, arg++);
- correctbytes((gchar *)&d, (int)size, h.endian);
- luaL_addlstring(&b, (gchar *)&d, size);
+ double d = luaL_checknumber(L, arg++);
+ correctbytes((char *)&d, (int)size, h.endian);
+ luaL_addlstring(&b, (char *)&d, size);
break;
}
case 'c': case 's': {
size_t l;
- const gchar *s = luaL_checklstring(L, arg++, &l);
+ const char *s = luaL_checklstring(L, arg++, &l);
if (size == 0) size = l;
luaL_argcheck(L, l >= (size_t)size, arg, "string too short");
luaL_addlstring(&b, s, size);
@@ -392,7 +398,7 @@ WSLUA_CONSTRUCTOR Struct_pack (lua_State *L) {
break;
}
case '=': {
- if (poscnt < (int)(sizeof(posBuf)/sizeof(posBuf[0])))
+ if (poscnt < (int)array_length(posBuf))
posBuf[poscnt++] = (int)totalsize + 1;
break;
}
@@ -406,33 +412,54 @@ WSLUA_CONSTRUCTOR Struct_pack (lua_State *L) {
WSLUA_RETURN(poscnt + 1); /* The packed binary Lua string, plus any positions due to '=' being used in format. */
}
-/* Decodes an integer from a string struct into a Lua number, based on
- * given endianness and size. If the integer type is signed, this makes
- * the Lua number be +/- correctly as well.
- */
-static lua_Number getinteger (const gchar *buff, int endian,
- int issigned, int size) {
+static Uinttype decodeinteger (const char *buff, int endian, int size)
+{
Uinttype l = 0;
int i;
if (endian == BIG) {
for (i = 0; i < size; i++) {
l <<= 8;
- l |= (Uinttype)(guchar)buff[i];
+ l |= (Uinttype)(unsigned char)buff[i];
}
}
else {
for (i = size - 1; i >= 0; i--) {
l <<= 8;
- l |= (Uinttype)(guchar)buff[i];
+ l |= (Uinttype)(unsigned char)buff[i];
+ }
+ }
+ return l;
+}
+
+/* Decodes an integer from a string struct into a lua_Integer, if it fits
+ * without truncation, or a lua_Number, based on given endianness and size.
+ * If the integer type is signed, that is handled correctly as well.
+ * Note for large values of size there can be a loss of precision.
+ */
+static void getinteger (lua_State *L, const char *buff, int endian,
+ int issigned, int size) {
+ Uinttype l = decodeinteger(buff, endian, size);
+ if (!issigned) {
+ if (size < LUA_INTEGER_SIZE) {
+ /* Fits in a lua_Integer (we need a larger size as lua_Integer
+ * is signed.) */
+ lua_pushinteger(L, (lua_Integer)l);
+ } else {
+ /* Does not fit in a lua_Integer */
+ lua_pushnumber(L, (lua_Number)l);
}
}
- if (!issigned)
- return (lua_Number)l;
else { /* signed format */
Uinttype mask = (Uinttype)(~((Uinttype)0)) << (size*8 - 1);
if (l & mask) /* negative value? */
- l |= mask; /* signal extension */
- return (lua_Number)(Inttype)l;
+ l |= mask; /* sign extension */
+ if (size <= LUA_INTEGER_SIZE) {
+ /* Fits in a lua_Integer */
+ lua_pushinteger(L, (lua_Integer)(Inttype)l);
+ } else {
+ /* Does not fit in a lua_Integer */
+ lua_pushnumber(L, (lua_Number)(Inttype)l);
+ }
}
}
@@ -470,8 +497,7 @@ WSLUA_CONSTRUCTOR Struct_unpack (lua_State *L) {
case 'b': case 'B': case 'h': case 'H':
case 'l': case 'L': case 'T': case 'i': case 'I': { /* integer types */
int issigned = g_ascii_islower(opt);
- lua_Number res = getinteger(data+pos, h.endian, issigned, (int)size);
- lua_pushnumber(L, res);
+ getinteger(L, data+pos, h.endian, issigned, (int)size);
break;
}
case 'e': {
@@ -486,16 +512,16 @@ WSLUA_CONSTRUCTOR Struct_unpack (lua_State *L) {
break;
}
case 'f': {
- gfloat f;
+ float f;
memcpy(&f, data+pos, size);
- correctbytes((gchar *)&f, sizeof(f), h.endian);
+ correctbytes((char *)&f, sizeof(f), h.endian);
lua_pushnumber(L, f);
break;
}
case 'd': {
- gdouble d;
+ double d;
memcpy(&d, data+pos, size);
- correctbytes((gchar *)&d, sizeof(d), h.endian);
+ correctbytes((char *)&d, sizeof(d), h.endian);
lua_pushnumber(L, d);
break;
}
@@ -503,7 +529,7 @@ WSLUA_CONSTRUCTOR Struct_unpack (lua_State *L) {
if (size == 0) {
if (!lua_isnumber(L, -1))
luaL_error(L, "format `c0' needs a previous size");
- size = wslua_toguint32(L, -1);
+ size = wslua_touint32(L, -1);
lua_pop(L, 1);
luaL_argcheck(L, pos+size <= ld, 2, "data string too short");
}
@@ -512,7 +538,7 @@ WSLUA_CONSTRUCTOR Struct_unpack (lua_State *L) {
break;
}
case 's': {
- const gchar *e = (const char *)memchr(data+pos, '\0', ld - pos);
+ const char *e = (const char *)memchr(data+pos, '\0', ld - pos);
if (e == NULL)
luaL_error(L, "unfinished string in data");
size = (e - (data+pos)) + 1;
@@ -537,7 +563,7 @@ WSLUA_CONSTRUCTOR Struct_size (lua_State *L) {
/* Returns the length of a binary string that would be consumed/handled by the given format string. */
#define WSLUA_ARG_Struct_size_FORMAT 1 /* The format string */
Header h;
- const gchar *fmt = wslua_checkstring_only(L, WSLUA_ARG_Struct_size_FORMAT);
+ const char *fmt = wslua_checkstring_only(L, WSLUA_ARG_Struct_size_FORMAT);
size_t pos = 0;
defaultoptions(&h);
while (*fmt) {
@@ -564,7 +590,7 @@ WSLUA_CONSTRUCTOR Struct_values (lua_State *L) {
arguments Struct.pack() expects, not including the format string argument. */
#define WSLUA_ARG_Struct_values_FORMAT 1 /* The format string */
Header h;
- const gchar *fmt = wslua_checkstring_only(L, WSLUA_ARG_Struct_values_FORMAT);
+ const char *fmt = wslua_checkstring_only(L, WSLUA_ARG_Struct_values_FORMAT);
size_t vals = 0;
defaultoptions(&h);
while (*fmt) {
@@ -598,19 +624,19 @@ WSLUA_CONSTRUCTOR Struct_tohex (lua_State *L) {
#define WSLUA_ARG_Struct_tohex_BYTESTRING 1 /* A Lua string consisting of binary bytes */
#define WSLUA_OPTARG_Struct_tohex_LOWERCASE 2 /* True to use lower-case hex characters (default=false). */
#define WSLUA_OPTARG_Struct_tohex_SEPARATOR 3 /* A string separator to insert between hex bytes (default=nil). */
- const gchar* s = NULL;
+ const char* s = NULL;
size_t len = 0;
- gboolean lowercase = FALSE;
- const gchar* sep = NULL;
+ bool lowercase = false;
+ const char* sep = NULL;
/* luaL_checklstring coerces the argument to a string, and that's ok for tohex,
just not fromhex. In fact, we should accept/coerce a Int64/UInt64 here too someday. */
s = luaL_checklstring(L, WSLUA_ARG_Struct_tohex_BYTESTRING, &len);
- lowercase = wslua_optbool(L,WSLUA_OPTARG_Struct_tohex_LOWERCASE,FALSE);
+ lowercase = wslua_optbool(L,WSLUA_OPTARG_Struct_tohex_LOWERCASE,false);
sep = luaL_optstring(L,WSLUA_OPTARG_Struct_tohex_SEPARATOR,NULL);
- wslua_bin2hex(L, s, (guint)len, lowercase, sep);
+ wslua_bin2hex(L, s, (unsigned)len, lowercase, sep);
WSLUA_RETURN(1); /* The Lua hex-ascii string */
}
@@ -618,16 +644,16 @@ WSLUA_CONSTRUCTOR Struct_fromhex (lua_State *L) {
/* Converts the passed-in hex-ascii string to a binary string. */
#define WSLUA_ARG_Struct_fromhex_HEXBYTES 1 /* A string consisting of hexadecimal bytes like "00 B1 A2" or "1a2b3c4d" */
#define WSLUA_OPTARG_Struct_fromhex_SEPARATOR 2 /* A string separator between hex bytes/words (default none). */
- const gchar* s = NULL;
+ const char* s = NULL;
size_t len = 0;
- const gchar* sep = NULL;
+ const char* sep = NULL;
/* luaL_checklstring coerces the argument to a string, and we don't want to do that */
s = wslua_checklstring_only(L, WSLUA_ARG_Struct_fromhex_HEXBYTES, &len);
sep = luaL_optstring(L,WSLUA_OPTARG_Struct_fromhex_SEPARATOR,NULL);
- wslua_hex2bin(L, s, (guint)len, sep);
+ wslua_hex2bin(L, s, (unsigned)len, sep);
WSLUA_RETURN(1); /* The Lua binary string */
}