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