diff options
Diffstat (limited to 'epan/wslua/wslua_struct.c')
-rw-r--r-- | epan/wslua/wslua_struct.c | 176 |
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 */ } |