]>
git.saurik.com Git - redis.git/blob - deps/lua/src/lua_struct.c
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 ** =======================================================
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
39 /* is 'x' a power of 2? */
40 #define isp2(x) ((x) > 0 && ((x) & ((x) - 1)) == 0)
42 /* dummy structure to get alignment requirements */
49 #define PADDING (sizeof(struct cD) - sizeof(double))
50 #define MAXALIGN (PADDING > sizeof(int) ? PADDING : sizeof(int))
64 typedef struct Header
{
70 static size_t getnum (const char **fmt
, size_t df
) {
71 if (!isdigit(**fmt
)) /* no number? */
72 return df
; /* return default value */
76 a
= a
*10 + *((*fmt
)++) - '0';
77 } while (isdigit(**fmt
));
83 #define defaultoptions(h) ((h)->endian = native.endian, (h)->align = 1)
87 static size_t optsize (lua_State
*L
, char opt
, const char **fmt
) {
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);
95 case 'c': return getnum(fmt
, 1);
96 case 's': case ' ': case '<': case '>': case '!': return 0;
98 int sz
= getnum(fmt
, sizeof(int));
100 luaL_error(L
, "integral size %d is not a power of 2", sz
);
104 const char *msg
= lua_pushfstring(L
, "invalid format option [%c]", opt
);
105 return luaL_argerror(L
, 1, msg
);
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);
118 static void commoncases (lua_State
*L
, int opt
, const char **fmt
, Header
*h
) {
120 case ' ': return; /* ignore white spaces */
121 case '>': h
->endian
= BIG
; return;
122 case '<': h
->endian
= LITTLE
; return;
124 int a
= getnum(fmt
, MAXALIGN
);
126 luaL_error(L
, "alignment %d is not a power of 2", a
);
135 static void putinteger (lua_State
*L
, luaL_Buffer
*b
, int arg
, int endian
,
137 lua_Number n
= luaL_checknumber(L
, arg
);
139 if (n
< (lua_Number
)LONG_MAX
)
142 value
= (unsigned long)n
;
143 if (endian
== LITTLE
) {
145 for (i
= 0; i
< size
; i
++)
146 luaL_addchar(b
, (value
>> 8*i
) & 0xff);
150 for (i
= size
- 1; i
>= 0; i
--)
151 luaL_addchar(b
, (value
>> 8*i
) & 0xff);
156 static void correctbytes (char *b
, int size
, int endian
) {
157 if (endian
!= native
.endian
) {
168 static int b_pack (lua_State
*L
) {
170 const char *fmt
= luaL_checkstring(L
, 1);
173 size_t totalsize
= 0;
175 lua_pushnil(L
); /* mark to separate arguments from string buffer */
176 luaL_buffinit(L
, &b
);
177 while (*fmt
!= '\0') {
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');
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
);
190 luaL_putchar(&b
, '\0');
194 float f
= (float)luaL_checknumber(L
, arg
++);
195 correctbytes((char *)&f
, size
, h
.endian
);
196 luaL_addlstring(&b
, (char *)&f
, size
);
200 double d
= luaL_checknumber(L
, arg
++);
201 correctbytes((char *)&d
, size
, h
.endian
);
202 luaL_addlstring(&b
, (char *)&d
, size
);
205 case 'c': case 's': {
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
);
212 luaL_putchar(&b
, '\0'); /* add zero at the end */
217 default: commoncases(L
, opt
, &fmt
, &h
);
226 static lua_Number
getinteger (const char *buff
, int endian
,
227 int issigned
, int size
) {
231 for (i
= 0; i
< size
; i
++)
232 l
|= (unsigned long)(unsigned char)buff
[size
- i
- 1] << (i
*8);
236 for (i
= 0; i
< size
; i
++)
237 l
|= (unsigned long)(unsigned char)buff
[i
] << (i
*8);
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
;
250 static int b_unpack (lua_State
*L
) {
252 const char *fmt
= luaL_checkstring(L
, 1);
254 const char *data
= luaL_checklstring(L
, 2, &ld
);
255 size_t pos
= luaL_optinteger(L
, 3, 1) - 1;
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");
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
);
276 memcpy(&f
, data
+pos
, size
);
277 correctbytes((char *)&f
, sizeof(f
), h
.endian
);
278 lua_pushnumber(L
, f
);
283 memcpy(&d
, data
+pos
, size
);
284 correctbytes((char *)&d
, sizeof(d
), h
.endian
);
285 lua_pushnumber(L
, d
);
290 if (!lua_isnumber(L
, -1))
291 luaL_error(L
, "format `c0' needs a previous size");
292 size
= lua_tonumber(L
, -1);
294 luaL_argcheck(L
, pos
+size
<= ld
, 2, "data string too short");
296 lua_pushlstring(L
, data
+pos
, size
);
300 const char *e
= (const char *)memchr(data
+pos
, '\0', ld
- pos
);
302 luaL_error(L
, "unfinished string in data");
303 size
= (e
- (data
+pos
)) + 1;
304 lua_pushlstring(L
, data
+pos
, size
- 1);
307 default: commoncases(L
, opt
, &fmt
, &h
);
311 lua_pushinteger(L
, pos
+ 1);
312 return lua_gettop(L
) - 2;
315 /* }====================================================== */
319 static const struct luaL_reg thislib
[] = {
321 {"unpack", b_unpack
},
326 LUALIB_API
int luaopen_struct (lua_State
*L
) {
327 luaL_register(L
, "struct", thislib
);
333 /******************************************************************************
334 * Copyright (C) 2010 Lua.org, PUC-Rio. All rights reserved.
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:
344 * The above copyright notice and this permission notice shall be
345 * included in all copies or substantial portions of the Software.
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 ******************************************************************************/