File: | builds/wireshark/wireshark/epan/wslua/wslua_struct.c |
Warning: | line 453, column 48 The result of left shift is undefined because the right operand is negative |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /****************************************************************************** | |||
2 | * Copyright (C) 2010-2012 Lua.org, PUC-Rio. All rights reserved. | |||
3 | * | |||
4 | * SPDX-License-Identifier: MIT | |||
5 | * | |||
6 | ******************************************************************************/ | |||
7 | /* | |||
8 | ** {====================================================== | |||
9 | ** Library for packing/unpacking structures. | |||
10 | ** See Copyright Notice above. | |||
11 | ** | |||
12 | ** Small changes were made by Hadriel Kaplan - those changes | |||
13 | ** are in the Public Domain. | |||
14 | ** | |||
15 | ** Some changes are based on a patch to struct.h from | |||
16 | ** Flemming Madsen, from here: | |||
17 | ** http://lua-users.org/lists/lua-l/2009-10/msg00572.html | |||
18 | ** In particular, these changes from him: | |||
19 | ** -Can handle 'long long' integers (i8 / I8); though they're converted to doubles | |||
20 | ** -Can insert/specify padding anywhere in a struct. ('X' eg. when a string is following a union) | |||
21 | ** -Can report current offset in both pack and unpack ('=') | |||
22 | ** -Can mask out return values when you only want to calculate sizes or unmarshal pascal-style strings. '(' & ')' | |||
23 | ** | |||
24 | ** Changes I made: | |||
25 | ** -Added support for Int64/UInt64 being packed/unpacked, using 'e'/'E' | |||
26 | ** -Made it follow Wireshark's conventions so we could get API docs | |||
27 | ** ======================================================= | |||
28 | */ | |||
29 | /* | |||
30 | ** Valid formats: | |||
31 | ** > - big endian | |||
32 | ** < - little endian | |||
33 | ** ![num] - alignment | |||
34 | ** x[num] - pad num bytes, default 1 | |||
35 | ** X[num] - pad to num align, default MAXALIGN | |||
36 | ** | |||
37 | ** Following are system-dependent sizes: | |||
38 | ** i/I - signed/unsigned int | |||
39 | ** l/L - signed/unsigned long | |||
40 | ** f - float | |||
41 | ** T - size_t | |||
42 | ** | |||
43 | ** Following are system-independent sizes: | |||
44 | ** b/B - signed/unsigned byte | |||
45 | ** h/H - signed/unsigned short | |||
46 | ** in/In - signed/unsigned integer of size `n' bytes | |||
47 | Note: Unpack of i/I is done to a Lua_number, typically a double, | |||
48 | so unpacking a 64-bit field (i8/I8) will lose precision. | |||
49 | Use e/E to unpack into a Wireshark Int64/UInt64 object/userdata instead. | |||
50 | ** e/E - signed/unsigned eight-byte Integer (64bits, long long), to/from Int64/UInt64 object | |||
51 | ** d - double | |||
52 | ** cn - sequence of `n' chars (from/to a string); when packing, n==0 means | |||
53 | the whole string; when unpacking, n==0 means use the previous | |||
54 | read number as the string length | |||
55 | ** s - zero-terminated string | |||
56 | ** ' ' - ignored | |||
57 | ** '(' ')' - stop assigning items. ')' start assigning (padding when packing) | |||
58 | ** '=' - return current position / offset | |||
59 | */ | |||
60 | ||||
61 | #include "config.h" | |||
62 | ||||
63 | #include <limits.h> | |||
64 | #include <wsutil/array.h> | |||
65 | #include "wslua.h" | |||
66 | ||||
67 | /* WSLUA_MODULE Struct Binary encode/decode support | |||
68 | ||||
69 | The Struct class offers basic facilities to convert Lua values to and from C-style structs | |||
70 | in binary Lua strings. This is based on Roberto Ierusalimschy's Lua struct library found | |||
71 | in http://www.inf.puc-rio.br/~roberto/struct/, with some minor modifications as follows: | |||
72 | * Added support for `Int64`/`UInt64` being packed/unpacked, using 'e'/'E'. | |||
73 | * Can handle 'long long' integers (i8 / I8); though they're converted to doubles. | |||
74 | * Can insert/specify padding anywhere in a struct. ('X' eg. when a string is following a union). | |||
75 | * Can report current offset in both `pack` and `unpack` ('`=`'). | |||
76 | * Can mask out return values when you only want to calculate sizes or unmarshal | |||
77 | pascal-style strings using '`(`' & '`)`'. | |||
78 | ||||
79 | All but the first of those changes are based on an email from Flemming Madsen, on the lua-users | |||
80 | mailing list, which can be found http://lua-users.org/lists/lua-l/2009-10/msg00572.html[here]. | |||
81 | ||||
82 | The main functions are `Struct.pack`, which packs multiple Lua values into a struct-like | |||
83 | Lua binary string; and `Struct.unpack`, which unpacks multiple Lua values from a given | |||
84 | struct-like Lua binary string. There are some additional helper functions available as well. | |||
85 | ||||
86 | All functions in the Struct library are called as static member functions, not object methods, | |||
87 | so they are invoked as "Struct.pack(...)" instead of "object:pack(...)". | |||
88 | ||||
89 | The fist argument to several of the `Struct` functions is a format string, which describes | |||
90 | the layout of the structure. The format string is a sequence of conversion elements, which | |||
91 | respect the current endianness and the current alignment requirements. Initially, the | |||
92 | current endianness is the machine's native endianness and the current alignment requirement | |||
93 | is 1 (meaning no alignment at all). You can change these settings with appropriate directives | |||
94 | in the format string. | |||
95 | ||||
96 | The supported elements in the format string are as follows: | |||
97 | ||||
98 | * `$$ $$' (empty space) ignored. | |||
99 | * `++!++__n__' flag to set the current alignment requirement to 'n' (necessarily a power of 2); | |||
100 | an absent 'n' means the machine's native alignment. | |||
101 | * `++>++' flag to set mode to big endian (i.e., network-order). | |||
102 | * `++<++' flag to set mode to little endian. | |||
103 | * `++x++' a padding zero byte with no corresponding Lua value. | |||
104 | * `++b++' a signed char. | |||
105 | * `++B++' an unsigned char. | |||
106 | * `++h++' a signed short (native size). | |||
107 | * `++H++' an unsigned short (native size). | |||
108 | * `++l++' a signed long (native size). | |||
109 | * `++L++' an unsigned long (native size). | |||
110 | * `++T++' a size_t (native size). | |||
111 | * `++i++__n__' a signed integer with 'n' bytes. An absent 'n' means the native size of an int. | |||
112 | * `++I++__n__' like `++i++__n__' but unsigned. | |||
113 | * `++e++' signed 8-byte Integer (64-bits, long long), to/from a +Int64+ object. | |||
114 | * `++E++' unsigned 8-byte Integer (64-bits, long long), to/from a +UInt64+ object. | |||
115 | * `++f++' a float (native size). | |||
116 | * `++d++' a double (native size). | |||
117 | * `++s++' a zero-terminated string. | |||
118 | * `++c++__n__' a sequence of exactly 'n' chars corresponding to a single Lua string. An absent 'n' | |||
119 | means 1. When packing, the given string must have at least 'n' characters (extra | |||
120 | characters are discarded). | |||
121 | * `++c0++' this is like `++c++__n__', except that the 'n' is given by other means: When packing, 'n' is | |||
122 | the length of the given string; when unpacking, 'n' is the value of the previous unpacked | |||
123 | value (which must be a number). In that case, this previous value is not returned. | |||
124 | * `++x++__n__' pad to 'n' number of bytes, default 1. | |||
125 | * `++X++__n__' pad to 'n' alignment, default MAXALIGN. | |||
126 | * `++(++' to stop assigning items, and `++)++' start assigning (padding when packing). | |||
127 | * `++=++' to return the current position / offset. | |||
128 | ||||
129 | [IMPORTANT] | |||
130 | ==== | |||
131 | Using `i`, `I`, `h`, `H`, `l`, `L`, `f`, and `T` is strongly discouraged, as those sizes | |||
132 | are system-dependent. Use the explicitly sized variants instead, such as `i4` or `E`. | |||
133 | ||||
134 | Unpacking of `i`/`I` is done to a Lua number, a double-precision floating point, | |||
135 | so unpacking a 64-bit field (`i8`/`I8`) will lose precision. | |||
136 | Use `e`/`E` to unpack into a Wireshark `Int64`/`UInt64` object instead. | |||
137 | ==== | |||
138 | ||||
139 | [NOTE] | |||
140 | ==== | |||
141 | Lua 5.3 and later provides several built-in functions for struct unpacking and packing: | |||
142 | https://www.lua.org/manual/5.4/manual.html#pdf-string.pack[string.pack], | |||
143 | https://www.lua.org/manual/5.4/manual.html#pdf-string.packsize[string.packsize], and | |||
144 | https://www.lua.org/manual/5.4/manual.html#pdf-string.unpack[string.unpack]. | |||
145 | You can use those as well, but note that the | |||
146 | https://www.lua.org/manual/5.4/manual.html#6.4.2[format string] conversion elements | |||
147 | are slightly different, and they do not support the Wireshark `Int64`/`UInt64` objects. | |||
148 | ==== | |||
149 | */ | |||
150 | ||||
151 | ||||
152 | /* The following line is here so that make-reg.py does the right thing. This 'Struct' class | |||
153 | isn't really a class, so it doesn't have the checkStruct/pushStruct/etc. functions | |||
154 | the following macro would generate; but it does need to be registered and such, so... | |||
155 | WSLUA_CLASS_DEFINE_BASE(Struct,NOP,0); | |||
156 | */ | |||
157 | ||||
158 | /* basic integer type - yes this is system-specific size - it's meant to be */ | |||
159 | #if !defined(STRUCT_INTlong) | |||
160 | #define STRUCT_INTlong long | |||
161 | #endif | |||
162 | ||||
163 | typedef STRUCT_INTlong Inttype; | |||
164 | ||||
165 | /* corresponding unsigned version */ | |||
166 | typedef unsigned STRUCT_INTlong Uinttype; | |||
167 | ||||
168 | /* maximum size (in bytes) for integral types */ | |||
169 | #define MAXINTSIZE32 32 | |||
170 | ||||
171 | /* is 'x' a power of 2? */ | |||
172 | #define isp2(x)((x) > 0 && ((x) & ((x) - 1)) == 0) ((x) > 0 && ((x) & ((x) - 1)) == 0) | |||
173 | ||||
174 | /* dummy structure to get padding/alignment requirements */ | |||
175 | struct cD { | |||
176 | char c; | |||
177 | double d; | |||
178 | }; | |||
179 | ||||
180 | ||||
181 | #define PADDING(sizeof(struct cD) - sizeof(double)) (sizeof(struct cD) - sizeof(double)) | |||
182 | #define MAXALIGN((sizeof(struct cD) - sizeof(double)) > sizeof(int) ? (sizeof (struct cD) - sizeof(double)) : sizeof(int)) (PADDING(sizeof(struct cD) - sizeof(double)) > sizeof(int) ? PADDING(sizeof(struct cD) - sizeof(double)) : sizeof(int)) | |||
183 | ||||
184 | ||||
185 | /* endian options */ | |||
186 | #define BIG0 0 | |||
187 | #define LITTLE1 1 | |||
188 | ||||
189 | /* trick to determine native endianness of system */ | |||
190 | static union { | |||
191 | int dummy; | |||
192 | char endian; | |||
193 | } const native = {1}; | |||
194 | ||||
195 | /* settings info */ | |||
196 | typedef struct Header { | |||
197 | int endian; | |||
198 | int align; | |||
199 | bool_Bool noassign; | |||
200 | } Header; | |||
201 | ||||
202 | /* For options that take a number argument, gets the number */ | |||
203 | static int getnum (lua_State *L, const char **fmt, int df) { | |||
204 | if (!g_ascii_isdigit(**fmt)((g_ascii_table[(guchar) (**fmt)] & G_ASCII_DIGIT) != 0)) /* no number? */ | |||
205 | return df; /* return default value */ | |||
206 | else { | |||
207 | int a = 0; | |||
208 | do { | |||
209 | if (a > (INT_MAX2147483647 / 10) || a * 10 > (INT_MAX2147483647 - (**fmt - '0'))) | |||
210 | luaL_error(L, "integral size overflow"); | |||
211 | a = a*10 + *((*fmt)++) - '0'; | |||
212 | } while (g_ascii_isdigit(**fmt)((g_ascii_table[(guchar) (**fmt)] & G_ASCII_DIGIT) != 0)); | |||
213 | return a; | |||
214 | } | |||
215 | } | |||
216 | ||||
217 | ||||
218 | #define defaultoptions(h)((h)->endian = native.endian, (h)->align = 1, (h)->noassign = 0) ((h)->endian = native.endian, (h)->align = 1, (h)->noassign = false0) | |||
219 | ||||
220 | ||||
221 | /* gets size (number of bytes) for a given type */ | |||
222 | static size_t optsize (lua_State *L, char opt, const char **fmt) { | |||
223 | switch (opt) { | |||
224 | case 'B': case 'b': return sizeof(char); | |||
225 | case 'H': case 'h': return sizeof(short); | |||
226 | case 'L': case 'l': return sizeof(long); | |||
227 | case 'E': case 'e': return sizeof(int64_t); | |||
228 | case 'T': return sizeof(size_t); | |||
229 | case 'f': return sizeof(float); | |||
230 | case 'd': return sizeof(double); | |||
231 | case 'x': return getnum(L, fmt, 1); | |||
232 | case 'X': return getnum(L, fmt, MAXALIGN((sizeof(struct cD) - sizeof(double)) > sizeof(int) ? (sizeof (struct cD) - sizeof(double)) : sizeof(int))); | |||
233 | case 'c': return getnum(L, fmt, 1); | |||
234 | case 'i': case 'I': { | |||
235 | int sz = getnum(L, fmt, sizeof(int)); | |||
236 | if (sz > MAXINTSIZE32) | |||
237 | luaL_error(L, "integral size %d is larger than limit of %d", | |||
238 | sz, MAXINTSIZE32); | |||
239 | return sz; | |||
240 | } | |||
241 | case 's': case ' ': | |||
242 | case '<': case '>': | |||
243 | case '(': case ')': | |||
244 | case '!': case '=': | |||
245 | return 0; /* these cases do not have a size */ | |||
246 | default: { | |||
247 | const char *msg = lua_pushfstring(L, "invalid format option [%c]", opt); | |||
248 | return luaL_argerror(L, 1, msg); | |||
249 | } | |||
250 | } | |||
251 | } | |||
252 | ||||
253 | ||||
254 | /* | |||
255 | ** return number of bytes needed to align an element of size 'size' | |||
256 | ** at current position 'len' | |||
257 | */ | |||
258 | static int gettoalign (size_t len, Header *h, int opt, size_t size) { | |||
259 | if (size == 0 || opt == 'c' || opt == 's') return 0; | |||
260 | if (size > (size_t)h->align) | |||
261 | size = h->align; /* respect max. alignment */ | |||
262 | return (int)((size - (len & (size - 1))) & (size - 1)); | |||
263 | } | |||
264 | ||||
265 | ||||
266 | /* | |||
267 | ** options to control endianness and alignment settings | |||
268 | */ | |||
269 | static void controloptions (lua_State *L, int opt, const char **fmt, | |||
270 | Header *h) { | |||
271 | switch (opt) { | |||
272 | case ' ': return; /* ignore white spaces */ | |||
273 | case '>': h->endian = BIG0; return; | |||
274 | case '<': h->endian = LITTLE1; return; | |||
275 | case '(': h->noassign = true1; return; | |||
276 | case ')': h->noassign = false0; return; | |||
277 | case '!': { | |||
278 | int a = getnum(L, fmt, MAXALIGN((sizeof(struct cD) - sizeof(double)) > sizeof(int) ? (sizeof (struct cD) - sizeof(double)) : sizeof(int))); | |||
279 | if (!isp2(a)((a) > 0 && ((a) & ((a) - 1)) == 0)) | |||
280 | luaL_error(L, "alignment %d is not a power of 2", a); | |||
281 | h->align = a; | |||
282 | return; | |||
283 | } | |||
284 | default: { | |||
285 | const char *msg = lua_pushfstring(L, "invalid format option '%c'", opt); | |||
286 | luaL_argerror(L, 1, msg); | |||
287 | } | |||
288 | } | |||
289 | } | |||
290 | ||||
291 | /* Encodes a Lua number as an integer of given size and endianness into a string struct */ | |||
292 | static void putinteger (lua_State *L, luaL_Buffer *b, int arg, int endian, | |||
293 | int size) { | |||
294 | lua_Number n = luaL_checknumber(L, arg); | |||
295 | /* this one's not system dependent size - it's a long long */ | |||
296 | int64_t value; | |||
297 | char buff[MAXINTSIZE32]; | |||
298 | if (n < 0) | |||
299 | value = (uint64_t)(int64_t)n; | |||
300 | else | |||
301 | value = (uint64_t)n; | |||
302 | if (endian == LITTLE1) { | |||
303 | int i; | |||
304 | for (i = 0; i < size; i++) { | |||
305 | buff[i] = (value & 0xff); | |||
306 | value >>= 8; | |||
307 | } | |||
308 | } | |||
309 | else { | |||
310 | int i; | |||
311 | for (i = size - 1; i >= 0; i--) { | |||
312 | buff[i] = (value & 0xff); | |||
313 | value >>= 8; | |||
314 | } | |||
315 | } | |||
316 | luaL_addlstring(b, buff, size); | |||
317 | } | |||
318 | ||||
319 | /* corrects endianness - usually done by other functions themselves, but is | |||
320 | * used for float/doubles, since on some platforms they're endian'ed as well | |||
321 | */ | |||
322 | static void correctbytes (char *b, int size, int endian) { | |||
323 | if (endian != native.endian) { | |||
324 | int i = 0; | |||
325 | while (i < --size) { | |||
326 | char temp = b[i]; | |||
327 | b[i++] = b[size]; | |||
328 | b[size] = temp; | |||
329 | } | |||
330 | } | |||
331 | } | |||
332 | ||||
333 | ||||
334 | WSLUA_CONSTRUCTORstatic int Struct_pack (lua_State *L) { | |||
335 | /* Returns a string containing the values arg1, arg2, etc. packed/encoded according to the format string. */ | |||
336 | #define WSLUA_ARG_Struct_pack_FORMAT1 1 /* The format string */ | |||
337 | #define WSLUA_ARG_Struct_pack_VALUE2 2 /* One or more Lua value(s) to encode, based on the given format. */ | |||
338 | luaL_Buffer b; | |||
339 | const char *fmt = wslua_checkstring_only(L, WSLUA_ARG_Struct_pack_FORMAT1); | |||
340 | Header h; | |||
341 | int poscnt = 0; | |||
342 | int posBuf[10]; | |||
343 | int arg = 2; | |||
344 | size_t totalsize = 0; | |||
345 | defaultoptions(&h)((&h)->endian = native.endian, (&h)->align = 1, (&h)->noassign = 0); | |||
346 | lua_pushnil(L); /* mark to separate arguments from string buffer */ | |||
347 | luaL_buffinit(L, &b); | |||
348 | while (*fmt != '\0') { | |||
349 | int opt = *fmt++; | |||
350 | size_t size = optsize(L, opt, &fmt); | |||
351 | int toalign = gettoalign(totalsize, &h, opt, size); | |||
352 | totalsize += toalign; | |||
353 | while (toalign-- > 0) luaL_addchar(&b, '\0')((void)((&b)->n < (&b)->size || luaL_prepbuffsize ((&b), 1)), ((&b)->b[(&b)->n++] = ('\0'))); | |||
354 | if (opt == 'X') size = 0; /* 'X' is about alignment, not size */ | |||
355 | if (h.noassign && size) opt = 'x'; /* for pack, "(i4)" is the same as "x4" */ | |||
356 | switch (opt) { | |||
357 | case 'b': case 'B': case 'h': case 'H': | |||
358 | case 'l': case 'L': case 'T': case 'i': case 'I': { /* integer types */ | |||
359 | putinteger(L, &b, arg++, h.endian, (int)size); | |||
360 | break; | |||
361 | } | |||
362 | case 'e': { | |||
363 | Int64_pack(L, &b, arg++, h.endian == LITTLE1); | |||
364 | break; | |||
365 | } | |||
366 | case 'E': { | |||
367 | UInt64_pack(L, &b, arg++, h.endian == LITTLE1); | |||
368 | break; | |||
369 | } | |||
370 | case 'x': case 'X': { | |||
371 | size_t len = size; | |||
372 | while (len-- > 0) | |||
373 | luaL_addchar(&b, '\0')((void)((&b)->n < (&b)->size || luaL_prepbuffsize ((&b), 1)), ((&b)->b[(&b)->n++] = ('\0'))); | |||
374 | break; | |||
375 | } | |||
376 | case 'f': { | |||
377 | float f = (float)luaL_checknumber(L, arg++); | |||
378 | correctbytes((char *)&f, (int)size, h.endian); | |||
379 | luaL_addlstring(&b, (char *)&f, size); | |||
380 | break; | |||
381 | } | |||
382 | case 'd': { | |||
383 | double d = luaL_checknumber(L, arg++); | |||
384 | correctbytes((char *)&d, (int)size, h.endian); | |||
385 | luaL_addlstring(&b, (char *)&d, size); | |||
386 | break; | |||
387 | } | |||
388 | case 'c': case 's': { | |||
389 | size_t l; | |||
390 | const char *s = luaL_checklstring(L, arg++, &l); | |||
391 | if (size == 0) size = l; | |||
392 | luaL_argcheck(L, l >= (size_t)size, arg, "string too short")((void)((__builtin_expect(((l >= (size_t)size) != 0), 1)) || luaL_argerror(L, (arg), ("string too short")))); | |||
393 | luaL_addlstring(&b, s, size); | |||
394 | if (opt == 's') { | |||
395 | luaL_addchar(&b, '\0')((void)((&b)->n < (&b)->size || luaL_prepbuffsize ((&b), 1)), ((&b)->b[(&b)->n++] = ('\0'))); /* add zero at the end */ | |||
396 | size++; | |||
397 | } | |||
398 | break; | |||
399 | } | |||
400 | case '=': { | |||
401 | if (poscnt < (int)array_length(posBuf)(sizeof (posBuf) / sizeof (posBuf)[0])) | |||
402 | posBuf[poscnt++] = (int)totalsize + 1; | |||
403 | break; | |||
404 | } | |||
405 | default: controloptions(L, opt, &fmt, &h); | |||
406 | } | |||
407 | totalsize += size; | |||
408 | } | |||
409 | luaL_pushresult(&b); | |||
410 | for (arg = 0; arg < poscnt; arg++) | |||
411 | lua_pushinteger(L, posBuf[arg]); | |||
412 | WSLUA_RETURN(poscnt + 1)return (poscnt + 1); /* The packed binary Lua string, plus any positions due to '=' being used in format. */ | |||
413 | } | |||
414 | ||||
415 | static Uinttype decodeinteger (const char *buff, int endian, int size) | |||
416 | { | |||
417 | Uinttype l = 0; | |||
418 | int i; | |||
419 | if (endian == BIG0) { | |||
420 | for (i = 0; i < size; i++) { | |||
421 | l <<= 8; | |||
422 | l |= (Uinttype)(unsigned char)buff[i]; | |||
423 | } | |||
424 | } | |||
425 | else { | |||
426 | for (i = size - 1; i >= 0; i--) { | |||
427 | l <<= 8; | |||
428 | l |= (Uinttype)(unsigned char)buff[i]; | |||
429 | } | |||
430 | } | |||
431 | return l; | |||
432 | } | |||
433 | ||||
434 | /* Decodes an integer from a string struct into a lua_Integer, if it fits | |||
435 | * without truncation, or a lua_Number, based on given endianness and size. | |||
436 | * If the integer type is signed, that is handled correctly as well. | |||
437 | * Note for large values of size there can be a loss of precision. | |||
438 | */ | |||
439 | static void getinteger (lua_State *L, const char *buff, int endian, | |||
440 | int issigned, int size) { | |||
441 | Uinttype l = decodeinteger(buff, endian, size); | |||
442 | if (!issigned
| |||
443 | if (size < LUA_INTEGER_SIZE8) { | |||
444 | /* Fits in a lua_Integer (we need a larger size as lua_Integer | |||
445 | * is signed.) */ | |||
446 | lua_pushinteger(L, (lua_Integer)l); | |||
447 | } else { | |||
448 | /* Does not fit in a lua_Integer */ | |||
449 | lua_pushnumber(L, (lua_Number)l); | |||
450 | } | |||
451 | } | |||
452 | else { /* signed format */ | |||
453 | Uinttype mask = (Uinttype)(~((Uinttype)0)) << (size*8 - 1); | |||
| ||||
454 | if (l & mask) /* negative value? */ | |||
455 | l |= mask; /* sign extension */ | |||
456 | if (size <= LUA_INTEGER_SIZE8) { | |||
457 | /* Fits in a lua_Integer */ | |||
458 | lua_pushinteger(L, (lua_Integer)(Inttype)l); | |||
459 | } else { | |||
460 | /* Does not fit in a lua_Integer */ | |||
461 | lua_pushnumber(L, (lua_Number)(Inttype)l); | |||
462 | } | |||
463 | } | |||
464 | } | |||
465 | ||||
466 | #define b_pushnumber(n){ if (!h.noassign) lua_pushnumber(L, (lua_Number)(n)); } { if (!h.noassign) lua_pushnumber(L, (lua_Number)(n)); } | |||
467 | ||||
468 | WSLUA_CONSTRUCTORstatic int Struct_unpack (lua_State *L) { | |||
469 | /* Unpacks/decodes multiple Lua values from a given struct-like binary Lua string. | |||
470 | The number of returned values depends on the format given, plus an additional value of the position where it stopped reading is returned. */ | |||
471 | #define WSLUA_ARG_Struct_unpack_FORMAT1 1 /* The format string */ | |||
472 | #define WSLUA_ARG_Struct_unpack_STRUCT2 2 /* The binary Lua string to unpack */ | |||
473 | #define WSLUA_OPTARG_Struct_unpack_BEGIN3 3 /* The position to begin reading from (default=1) */ | |||
474 | Header h; | |||
475 | const char *fmt = wslua_checkstring_only(L, WSLUA_ARG_Struct_unpack_FORMAT1); | |||
476 | size_t ld; | |||
477 | const char *data = wslua_checklstring_only(L, WSLUA_ARG_Struct_unpack_STRUCT2, &ld); | |||
478 | size_t pos = luaL_optinteger(L, WSLUA_OPTARG_Struct_unpack_BEGIN3, 1) - 1; | |||
479 | defaultoptions(&h)((&h)->endian = native.endian, (&h)->align = 1, (&h)->noassign = 0); | |||
480 | lua_settop(L, 2); | |||
481 | while (*fmt) { | |||
| ||||
482 | int opt = *fmt++; | |||
483 | size_t size = optsize(L, opt, &fmt); | |||
484 | pos += gettoalign(pos, &h, opt, size); | |||
485 | luaL_argcheck(L, pos+size <= ld, 2, "data string too short")((void)((__builtin_expect(((pos+size <= ld) != 0), 1)) || luaL_argerror (L, (2), ("data string too short")))); | |||
486 | ||||
487 | if (opt == 'X') size = 0; | |||
488 | if (h.noassign
| |||
489 | /* if we're not assigning, and the opt type has a size, then loop again */ | |||
490 | /* this will not be the case for control options, 'c0', 's', and '=' */ | |||
491 | pos += size; | |||
492 | continue; | |||
493 | } | |||
494 | ||||
495 | luaL_checkstack(L, 1, "too many results"); | |||
496 | switch (opt) { | |||
497 | case 'b': case 'B': case 'h': case 'H': | |||
498 | case 'l': case 'L': case 'T': case 'i': case 'I': { /* integer types */ | |||
499 | int issigned = g_ascii_islower(opt)((g_ascii_table[(guchar) (opt)] & G_ASCII_LOWER) != 0); | |||
500 | getinteger(L, data+pos, h.endian, issigned, (int)size); | |||
501 | break; | |||
502 | } | |||
503 | case 'e': { | |||
504 | Int64_unpack(L, data+pos, h.endian == LITTLE1); | |||
505 | break; | |||
506 | } | |||
507 | case 'E': { | |||
508 | UInt64_unpack(L, data+pos, h.endian == LITTLE1); | |||
509 | break; | |||
510 | } | |||
511 | case 'x': case 'X': { | |||
512 | break; | |||
513 | } | |||
514 | case 'f': { | |||
515 | float f; | |||
516 | memcpy(&f, data+pos, size); | |||
517 | correctbytes((char *)&f, sizeof(f), h.endian); | |||
518 | lua_pushnumber(L, f); | |||
519 | break; | |||
520 | } | |||
521 | case 'd': { | |||
522 | double d; | |||
523 | memcpy(&d, data+pos, size); | |||
524 | correctbytes((char *)&d, sizeof(d), h.endian); | |||
525 | lua_pushnumber(L, d); | |||
526 | break; | |||
527 | } | |||
528 | case 'c': { | |||
529 | if (size == 0) { | |||
530 | if (!lua_isnumber(L, -1)) | |||
531 | luaL_error(L, "format `c0' needs a previous size"); | |||
532 | size = wslua_touint32(L, -1)(uint32_t) ( lua_tointegerx(L,(-1),((void*)0)) ); | |||
533 | lua_pop(L, 1)lua_settop(L, -(1)-1); | |||
534 | luaL_argcheck(L, pos+size <= ld, 2, "data string too short")((void)((__builtin_expect(((pos+size <= ld) != 0), 1)) || luaL_argerror (L, (2), ("data string too short")))); | |||
535 | } | |||
536 | if (!h.noassign) | |||
537 | lua_pushlstring(L, data+pos, size); | |||
538 | break; | |||
539 | } | |||
540 | case 's': { | |||
541 | const char *e = (const char *)memchr(data+pos, '\0', ld - pos); | |||
542 | if (e == NULL((void*)0)) | |||
543 | luaL_error(L, "unfinished string in data"); | |||
544 | size = (e - (data+pos)) + 1; | |||
545 | if (!h.noassign) | |||
546 | lua_pushlstring(L, data+pos, size - 1); | |||
547 | break; | |||
548 | } | |||
549 | case '=': { | |||
550 | lua_pushinteger(L, pos + 1); | |||
551 | break; | |||
552 | } | |||
553 | default: controloptions(L, opt, &fmt, &h); | |||
554 | } | |||
555 | pos += size; | |||
556 | } | |||
557 | lua_pushinteger(L, pos + 1); | |||
558 | WSLUA_RETURN(lua_gettop(L) - 2)return (lua_gettop(L) - 2); /* One or more values based on format, plus the position it stopped unpacking. */ | |||
559 | } | |||
560 | ||||
561 | ||||
562 | WSLUA_CONSTRUCTORstatic int Struct_size (lua_State *L) { | |||
563 | /* Returns the length of a binary string that would be consumed/handled by the given format string. */ | |||
564 | #define WSLUA_ARG_Struct_size_FORMAT1 1 /* The format string */ | |||
565 | Header h; | |||
566 | const char *fmt = wslua_checkstring_only(L, WSLUA_ARG_Struct_size_FORMAT1); | |||
567 | size_t pos = 0; | |||
568 | defaultoptions(&h)((&h)->endian = native.endian, (&h)->align = 1, (&h)->noassign = 0); | |||
569 | while (*fmt) { | |||
570 | int opt = *fmt++; | |||
571 | size_t size = optsize(L, opt, &fmt); | |||
572 | pos += gettoalign(pos, &h, opt, size); | |||
573 | if (opt == 's') | |||
574 | luaL_argerror(L, 1, "option 's' has no fixed size"); | |||
575 | else if (opt == 'c' && size == 0) | |||
576 | luaL_argerror(L, 1, "option 'c0' has no fixed size"); | |||
577 | if (!g_ascii_isalnum(opt)((g_ascii_table[(guchar) (opt)] & G_ASCII_ALNUM) != 0)) | |||
578 | controloptions(L, opt, &fmt, &h); | |||
579 | pos += size; | |||
580 | } | |||
581 | lua_pushinteger(L, pos); | |||
582 | WSLUA_RETURN(1)return (1); /* The size number */ | |||
583 | } | |||
584 | ||||
585 | WSLUA_CONSTRUCTORstatic int Struct_values (lua_State *L) { | |||
586 | /* Returns the number of Lua values contained in the given format string. | |||
587 | This will be the number of returned values from a call to Struct.unpack() | |||
588 | not including the extra return value of offset position. (i.e., Struct.values() | |||
589 | does not count that extra return value) This will also be the number of | |||
590 | arguments Struct.pack() expects, not including the format string argument. */ | |||
591 | #define WSLUA_ARG_Struct_values_FORMAT1 1 /* The format string */ | |||
592 | Header h; | |||
593 | const char *fmt = wslua_checkstring_only(L, WSLUA_ARG_Struct_values_FORMAT1); | |||
594 | size_t vals = 0; | |||
595 | defaultoptions(&h)((&h)->endian = native.endian, (&h)->align = 1, (&h)->noassign = 0); | |||
596 | while (*fmt) { | |||
597 | int opt = *fmt++; | |||
598 | /* we use a size != 0 to mean it is a value */ | |||
599 | size_t size = optsize(L, opt, &fmt); | |||
600 | /* but some will be zero and not be a value, or vice-versa */ | |||
601 | switch (opt) { | |||
602 | case 's': case 'c': | |||
603 | /* these are values */ | |||
604 | size = 1; | |||
605 | break; | |||
606 | case 'x': case 'X': | |||
607 | /* these are not */ | |||
608 | size = 0; | |||
609 | break; | |||
610 | default: | |||
611 | break; | |||
612 | } | |||
613 | if (!g_ascii_isalnum(opt)((g_ascii_table[(guchar) (opt)] & G_ASCII_ALNUM) != 0)) | |||
614 | controloptions(L, opt, &fmt, &h); | |||
615 | else if (size && !h.noassign) | |||
616 | vals++; | |||
617 | } | |||
618 | lua_pushinteger(L, vals); | |||
619 | WSLUA_RETURN(1)return (1); /* The number of values */ | |||
620 | } | |||
621 | ||||
622 | WSLUA_CONSTRUCTORstatic int Struct_tohex (lua_State *L) { | |||
623 | /* Converts the passed-in binary string to a hex-ascii string. */ | |||
624 | #define WSLUA_ARG_Struct_tohex_BYTESTRING1 1 /* A Lua string consisting of binary bytes */ | |||
625 | #define WSLUA_OPTARG_Struct_tohex_LOWERCASE2 2 /* True to use lower-case hex characters (default=false). */ | |||
626 | #define WSLUA_OPTARG_Struct_tohex_SEPARATOR3 3 /* A string separator to insert between hex bytes (default=nil). */ | |||
627 | const char* s = NULL((void*)0); | |||
628 | size_t len = 0; | |||
629 | bool_Bool lowercase = false0; | |||
630 | const char* sep = NULL((void*)0); | |||
631 | ||||
632 | /* luaL_checklstring coerces the argument to a string, and that's ok for tohex, | |||
633 | just not fromhex. In fact, we should accept/coerce a Int64/UInt64 here too someday. */ | |||
634 | s = luaL_checklstring(L, WSLUA_ARG_Struct_tohex_BYTESTRING1, &len); | |||
635 | ||||
636 | lowercase = wslua_optbool(L,WSLUA_OPTARG_Struct_tohex_LOWERCASE2,false0); | |||
637 | sep = luaL_optstring(L,WSLUA_OPTARG_Struct_tohex_SEPARATOR,NULL)(luaL_optlstring(L, (3), (((void*)0)), ((void*)0))); | |||
638 | ||||
639 | wslua_bin2hex(L, s, (unsigned)len, lowercase, sep); | |||
640 | WSLUA_RETURN(1)return (1); /* The Lua hex-ascii string */ | |||
641 | } | |||
642 | ||||
643 | WSLUA_CONSTRUCTORstatic int Struct_fromhex (lua_State *L) { | |||
644 | /* Converts the passed-in hex-ascii string to a binary string. */ | |||
645 | #define WSLUA_ARG_Struct_fromhex_HEXBYTES1 1 /* A string consisting of hexadecimal bytes like "00 B1 A2" or "1a2b3c4d" */ | |||
646 | #define WSLUA_OPTARG_Struct_fromhex_SEPARATOR2 2 /* A string separator between hex bytes/words (default none). */ | |||
647 | const char* s = NULL((void*)0); | |||
648 | size_t len = 0; | |||
649 | const char* sep = NULL((void*)0); | |||
650 | ||||
651 | /* luaL_checklstring coerces the argument to a string, and we don't want to do that */ | |||
652 | s = wslua_checklstring_only(L, WSLUA_ARG_Struct_fromhex_HEXBYTES1, &len); | |||
653 | ||||
654 | sep = luaL_optstring(L,WSLUA_OPTARG_Struct_fromhex_SEPARATOR,NULL)(luaL_optlstring(L, (2), (((void*)0)), ((void*)0))); | |||
655 | ||||
656 | wslua_hex2bin(L, s, (unsigned)len, sep); | |||
657 | WSLUA_RETURN(1)return (1); /* The Lua binary string */ | |||
658 | } | |||
659 | ||||
660 | /* }====================================================== */ | |||
661 | ||||
662 | /* Gets registered as metamethod automatically by WSLUA_REGISTER_CLASS/META */ | |||
663 | static int Struct__gc(lua_State* L _U___attribute__((unused))) { | |||
664 | return 0; | |||
665 | } | |||
666 | ||||
667 | WSLUA_METHODSstatic const luaL_Reg Struct_methods[] = { | |||
668 | WSLUA_CLASS_FNREG(Struct,pack){ "pack", Struct_pack }, | |||
669 | WSLUA_CLASS_FNREG(Struct,unpack){ "unpack", Struct_unpack }, | |||
670 | WSLUA_CLASS_FNREG(Struct,size){ "size", Struct_size }, | |||
671 | WSLUA_CLASS_FNREG(Struct,values){ "values", Struct_values }, | |||
672 | WSLUA_CLASS_FNREG(Struct,tohex){ "tohex", Struct_tohex }, | |||
673 | WSLUA_CLASS_FNREG(Struct,fromhex){ "fromhex", Struct_fromhex }, | |||
674 | { NULL((void*)0), NULL((void*)0) } | |||
675 | }; | |||
676 | ||||
677 | WSLUA_METAstatic const luaL_Reg Struct_meta[] = { | |||
678 | { NULL((void*)0), NULL((void*)0) } | |||
679 | }; | |||
680 | ||||
681 | LUALIB_APIextern int Struct_register(lua_State* L) { | |||
682 | WSLUA_REGISTER_CLASS(Struct){ const wslua_class Struct_class = { .name = "Struct", .class_methods = Struct_methods, .class_meta = Struct_meta, .instance_methods = Struct_methods, .instance_meta = Struct_meta, .attrs = ((void *)0) }; wslua_register_class(L, &Struct_class); (lua_getfield (L, (-1000000 - 1000), ("Struct"))); lua_pushcclosure(L, (Struct__gc ), 0); lua_setfield(L, -2, "__gc"); lua_settop(L, -(1)-1); }; | |||
683 | return 0; | |||
684 | } | |||
685 | ||||
686 | /* | |||
687 | * Editor modelines - https://www.wireshark.org/tools/modelines.html | |||
688 | * | |||
689 | * Local Variables: | |||
690 | * c-basic-offset: 2 | |||
691 | * tab-width: 8 | |||
692 | * indent-tabs-mode: nil | |||
693 | * End: | |||
694 | * | |||
695 | * vi: set shiftwidth=2 tabstop=8 expandtab: | |||
696 | * :indentSize=2:tabSize=8:noTabs=true: | |||
697 | */ |