1 /*
2 ** {======================================================
3 ** Library for packing/unpacking structures.
4 ** $Id: struct.c,v 1.4 2012/07/04 18:54:29 roberto Exp $
5 ** See Copyright Notice at the end of this file
6 ** =======================================================
7 */
8 /*
9 ** Valid formats:
10 ** > - big endian
11 ** < - little endian
12 ** ![num] - alignment
13 ** x - pading
14 ** b/B - signed/unsigned byte
15 ** h/H - signed/unsigned short
16 ** l/L - signed/unsigned long
17 ** T - size_t
18 ** i/In - signed/unsigned integer with size `n' (default is size of int)
19 ** cn - sequence of `n' chars (from/to a string); when packing, n==0 means
20 the whole string; when unpacking, n==0 means use the previous
21 read number as the string length
22 ** s - zero-terminated string
23 ** f - float
24 ** d - double
25 ** ' ' - ignored
26 */
27
28
29 #include <assert.h>
30 #include <ctype.h>
31 #include <limits.h>
32 #include <stddef.h>
33 #include <string.h>
34
35
36 #include "lua.h"
37 #include "lauxlib.h"
38
39
40 #if (LUA_VERSION_NUM >= 502)
41
42 #define luaL_register(L,n,f) luaL_newlib(L,f)
43
44 #endif
45
46
47 /* basic integer type */
48 #if !defined(STRUCT_INT)
49 #define STRUCT_INT long
50 #endif
51
52 typedef STRUCT_INT Inttype;
53
54 /* corresponding unsigned version */
55 typedef unsigned STRUCT_INT Uinttype;
56
57
58 /* maximum size (in bytes) for integral types */
59 #define MAXINTSIZE 32
60
61 /* is 'x' a power of 2? */
62 #define isp2(x) ((x) > 0 && ((x) & ((x) - 1)) == 0)
63
64 /* dummy structure to get alignment requirements */
65 struct cD {
66 char c;
67 double d;
68 };
69
70
71 #define PADDING (sizeof(struct cD) - sizeof(double))
72 #define MAXALIGN (PADDING > sizeof(int) ? PADDING : sizeof(int))
73
74
75 /* endian options */
76 #define BIG 0
77 #define LITTLE 1
78
79
80 static union {
81 int dummy;
82 char endian;
83 } const native = {1};
84
85
86 typedef struct Header {
87 int endian;
88 int align;
89 } Header;
90
91
getnum(lua_State * L,const char ** fmt,int df)92 static int getnum (lua_State *L, const char **fmt, int df) {
93 if (!isdigit(**fmt)) /* no number? */
94 return df; /* return default value */
95 else {
96 int a = 0;
97 do {
98 if (a > (INT_MAX / 10) || a * 10 > (INT_MAX - (**fmt - '0')))
99 luaL_error(L, "integral size overflow");
100 a = a*10 + *((*fmt)++) - '0';
101 } while (isdigit(**fmt));
102 return a;
103 }
104 }
105
106
107 #define defaultoptions(h) ((h)->endian = native.endian, (h)->align = 1)
108
109
110
optsize(lua_State * L,char opt,const char ** fmt)111 static size_t optsize (lua_State *L, char opt, const char **fmt) {
112 switch (opt) {
113 case 'B': case 'b': return sizeof(char);
114 case 'H': case 'h': return sizeof(short);
115 case 'L': case 'l': return sizeof(long);
116 case 'T': return sizeof(size_t);
117 case 'f': return sizeof(float);
118 case 'd': return sizeof(double);
119 case 'x': return 1;
120 case 'c': return getnum(L, fmt, 1);
121 case 'i': case 'I': {
122 int sz = getnum(L, fmt, sizeof(int));
123 if (sz > MAXINTSIZE)
124 luaL_error(L, "integral size %d is larger than limit of %d",
125 sz, MAXINTSIZE);
126 return sz;
127 }
128 default: return 0; /* other cases do not need alignment */
129 }
130 }
131
132
133 /*
134 ** return number of bytes needed to align an element of size 'size'
135 ** at current position 'len'
136 */
gettoalign(size_t len,Header * h,int opt,size_t size)137 static int gettoalign (size_t len, Header *h, int opt, size_t size) {
138 if (size == 0 || opt == 'c') return 0;
139 if (size > (size_t)h->align)
140 size = h->align; /* respect max. alignment */
141 return (size - (len & (size - 1))) & (size - 1);
142 }
143
144
145 /*
146 ** options to control endianess and alignment
147 */
controloptions(lua_State * L,int opt,const char ** fmt,Header * h)148 static void controloptions (lua_State *L, int opt, const char **fmt,
149 Header *h) {
150 switch (opt) {
151 case ' ': return; /* ignore white spaces */
152 case '>': h->endian = BIG; return;
153 case '<': h->endian = LITTLE; return;
154 case '!': {
155 int a = getnum(L, fmt, MAXALIGN);
156 if (!isp2(a))
157 luaL_error(L, "alignment %d is not a power of 2", a);
158 h->align = a;
159 return;
160 }
161 default: {
162 const char *msg = lua_pushfstring(L, "invalid format option '%c'", opt);
163 luaL_argerror(L, 1, msg);
164 }
165 }
166 }
167
168
putinteger(lua_State * L,luaL_Buffer * b,int arg,int endian,int size)169 static void putinteger (lua_State *L, luaL_Buffer *b, int arg, int endian,
170 int size) {
171 lua_Number n = luaL_checknumber(L, arg);
172 Uinttype value;
173 char buff[MAXINTSIZE];
174 if (n < 0)
175 value = (Uinttype)(Inttype)n;
176 else
177 value = (Uinttype)n;
178 if (endian == LITTLE) {
179 int i;
180 for (i = 0; i < size; i++) {
181 buff[i] = (value & 0xff);
182 value >>= 8;
183 }
184 }
185 else {
186 int i;
187 for (i = size - 1; i >= 0; i--) {
188 buff[i] = (value & 0xff);
189 value >>= 8;
190 }
191 }
192 luaL_addlstring(b, buff, size);
193 }
194
195
correctbytes(char * b,int size,int endian)196 static void correctbytes (char *b, int size, int endian) {
197 if (endian != native.endian) {
198 int i = 0;
199 while (i < --size) {
200 char temp = b[i];
201 b[i++] = b[size];
202 b[size] = temp;
203 }
204 }
205 }
206
207
b_pack(lua_State * L)208 static int b_pack (lua_State *L) {
209 luaL_Buffer b;
210 const char *fmt = luaL_checkstring(L, 1);
211 Header h;
212 int arg = 2;
213 size_t totalsize = 0;
214 defaultoptions(&h);
215 lua_pushnil(L); /* mark to separate arguments from string buffer */
216 luaL_buffinit(L, &b);
217 while (*fmt != '\0') {
218 int opt = *fmt++;
219 size_t size = optsize(L, opt, &fmt);
220 int toalign = gettoalign(totalsize, &h, opt, size);
221 totalsize += toalign;
222 while (toalign-- > 0) luaL_addchar(&b, '\0');
223 switch (opt) {
224 case 'b': case 'B': case 'h': case 'H':
225 case 'l': case 'L': case 'T': case 'i': case 'I': { /* integer types */
226 putinteger(L, &b, arg++, h.endian, size);
227 break;
228 }
229 case 'x': {
230 luaL_addchar(&b, '\0');
231 break;
232 }
233 case 'f': {
234 float f = (float)luaL_checknumber(L, arg++);
235 correctbytes((char *)&f, size, h.endian);
236 luaL_addlstring(&b, (char *)&f, size);
237 break;
238 }
239 case 'd': {
240 double d = luaL_checknumber(L, arg++);
241 correctbytes((char *)&d, size, h.endian);
242 luaL_addlstring(&b, (char *)&d, size);
243 break;
244 }
245 case 'c': case 's': {
246 size_t l;
247 const char *s = luaL_checklstring(L, arg++, &l);
248 if (size == 0) size = l;
249 luaL_argcheck(L, l >= (size_t)size, arg, "string too short");
250 luaL_addlstring(&b, s, size);
251 if (opt == 's') {
252 luaL_addchar(&b, '\0'); /* add zero at the end */
253 size++;
254 }
255 break;
256 }
257 default: controloptions(L, opt, &fmt, &h);
258 }
259 totalsize += size;
260 }
261 luaL_pushresult(&b);
262 return 1;
263 }
264
265
getinteger(const char * buff,int endian,int issigned,int size)266 static lua_Number getinteger (const char *buff, int endian,
267 int issigned, int size) {
268 Uinttype l = 0;
269 int i;
270 if (endian == BIG) {
271 for (i = 0; i < size; i++) {
272 l <<= 8;
273 l |= (Uinttype)(unsigned char)buff[i];
274 }
275 }
276 else {
277 for (i = size - 1; i >= 0; i--) {
278 l <<= 8;
279 l |= (Uinttype)(unsigned char)buff[i];
280 }
281 }
282 if (!issigned)
283 return (lua_Number)l;
284 else { /* signed format */
285 Uinttype mask = (Uinttype)(~((Uinttype)0)) << (size*8 - 1);
286 if (l & mask) /* negative value? */
287 l |= mask; /* signal extension */
288 return (lua_Number)(Inttype)l;
289 }
290 }
291
292
b_unpack(lua_State * L)293 static int b_unpack (lua_State *L) {
294 Header h;
295 const char *fmt = luaL_checkstring(L, 1);
296 size_t ld;
297 const char *data = luaL_checklstring(L, 2, &ld);
298 size_t pos = luaL_optinteger(L, 3, 1) - 1;
299 defaultoptions(&h);
300 lua_settop(L, 2);
301 while (*fmt) {
302 int opt = *fmt++;
303 size_t size = optsize(L, opt, &fmt);
304 pos += gettoalign(pos, &h, opt, size);
305 luaL_argcheck(L, pos+size <= ld, 2, "data string too short");
306 luaL_checkstack(L, 1, "too many results");
307 switch (opt) {
308 case 'b': case 'B': case 'h': case 'H':
309 case 'l': case 'L': case 'T': case 'i': case 'I': { /* integer types */
310 int issigned = islower(opt);
311 lua_Number res = getinteger(data+pos, h.endian, issigned, size);
312 lua_pushnumber(L, res);
313 break;
314 }
315 case 'x': {
316 break;
317 }
318 case 'f': {
319 float f;
320 memcpy(&f, data+pos, size);
321 correctbytes((char *)&f, sizeof(f), h.endian);
322 lua_pushnumber(L, f);
323 break;
324 }
325 case 'd': {
326 double d;
327 memcpy(&d, data+pos, size);
328 correctbytes((char *)&d, sizeof(d), h.endian);
329 lua_pushnumber(L, d);
330 break;
331 }
332 case 'c': {
333 if (size == 0) {
334 if (!lua_isnumber(L, -1))
335 luaL_error(L, "format `c0' needs a previous size");
336 size = lua_tonumber(L, -1);
337 lua_pop(L, 1);
338 luaL_argcheck(L, pos+size <= ld, 2, "data string too short");
339 }
340 lua_pushlstring(L, data+pos, size);
341 break;
342 }
343 case 's': {
344 const char *e = (const char *)memchr(data+pos, '\0', ld - pos);
345 if (e == NULL)
346 luaL_error(L, "unfinished string in data");
347 size = (e - (data+pos)) + 1;
348 lua_pushlstring(L, data+pos, size - 1);
349 break;
350 }
351 default: controloptions(L, opt, &fmt, &h);
352 }
353 pos += size;
354 }
355 lua_pushinteger(L, pos + 1);
356 return lua_gettop(L) - 2;
357 }
358
359
b_size(lua_State * L)360 static int b_size (lua_State *L) {
361 Header h;
362 const char *fmt = luaL_checkstring(L, 1);
363 size_t pos = 0;
364 defaultoptions(&h);
365 while (*fmt) {
366 int opt = *fmt++;
367 size_t size = optsize(L, opt, &fmt);
368 pos += gettoalign(pos, &h, opt, size);
369 if (opt == 's')
370 luaL_argerror(L, 1, "option 's' has no fixed size");
371 else if (opt == 'c' && size == 0)
372 luaL_argerror(L, 1, "option 'c0' has no fixed size");
373 if (!isalnum(opt))
374 controloptions(L, opt, &fmt, &h);
375 pos += size;
376 }
377 lua_pushinteger(L, pos);
378 return 1;
379 }
380
381 /* }====================================================== */
382
383
384
385 static const struct luaL_Reg thislib[] = {
386 {"pack", b_pack},
387 {"unpack", b_unpack},
388 {"size", b_size},
389 {NULL, NULL}
390 };
391
392
393 LUALIB_API int luaopen_struct (lua_State *L);
394
luaopen_struct(lua_State * L)395 LUALIB_API int luaopen_struct (lua_State *L) {
396 luaL_register(L, "struct", thislib);
397 return 1;
398 }
399
400
401 /******************************************************************************
402 * Copyright (C) 2010-2012 Lua.org, PUC-Rio. All rights reserved.
403 *
404 * Permission is hereby granted, free of charge, to any person obtaining
405 * a copy of this software and associated documentation files (the
406 * "Software"), to deal in the Software without restriction, including
407 * without limitation the rights to use, copy, modify, merge, publish,
408 * distribute, sublicense, and/or sell copies of the Software, and to
409 * permit persons to whom the Software is furnished to do so, subject to
410 * the following conditions:
411 *
412 * The above copyright notice and this permission notice shall be
413 * included in all copies or substantial portions of the Software.
414 *
415 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
416 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
417 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
418 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
419 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
420 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
421 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
422 ******************************************************************************/
423
424