3 * a Lua library for packing and unpacking binary data
4 * Luiz Henrique de Figueiredo <lhf@tecgraf.puc-rio.br>
6 * This code is hereby placed in the public domain.
7 * with contributions from Ignacio Castao <castanyo@yahoo.es> and
8 * Roberto Ierusalimschy <roberto@inf.puc-rio.br>.
11 #define OP_ZSTRING 'z' /* zero-terminated string */
12 #define OP_BSTRING 'p' /* string preceded by length byte */
13 #define OP_WSTRING 'P' /* string preceded by length word */
14 #define OP_SSTRING 'a' /* string preceded by length size_t */
15 #define OP_STRING 'A' /* string */
16 #define OP_FLOAT 'f' /* float */
17 #define OP_DOUBLE 'd' /* double */
18 #define OP_NUMBER 'n' /* Lua number */
19 #define OP_CHAR 'c' /* char (1-byte int) */
20 #define OP_BYTE 'C' /* byte = unsigned char (1-byte unsigned int) */
21 #define OP_SHORT 's' /* short (2-byte int) */
22 #define OP_USHORT 'S' /* unsigned short (2-byte unsigned int) */
23 #define OP_INT 'i' /* int (4-byte int) */
24 #define OP_UINT 'I' /* unsigned int (4-byte unsigned int) */
25 #define OP_LONG 'l' /* long (8-byte int) */
26 #define OP_ULONG 'L' /* unsigned long (8-byte unsigned int) */
27 #define OP_LITTLEENDIAN '<' /* little endian */
28 #define OP_BIGENDIAN '>' /* big endian */
29 #define OP_NATIVE '=' /* native endian */
39 #include "pm3_binlib.h"
42 static void badcode(lua_State
*L
, int c
)
44 char s
[]="bad code `?'";
49 static int doendian(int c
)
53 if (c
==OP_LITTLEENDIAN
) return !e
;
54 if (c
==OP_BIGENDIAN
) return e
;
55 if (c
==OP_NATIVE
) return 0;
59 static void doswap(int swap
, void *p
, size_t n
)
65 for (i
=0, j
=n
-1, n
=n
/2; n
--; i
++, j
--)
67 char t
=a
[i
]; a
[i
]=a
[j
]; a
[j
]=t
;
72 #define UNPACKNUMBER(OP,T) \
77 if (i+m>len) { done = 1; break;} \
81 lua_pushnumber(L,(lua_Number)a); \
86 #define UNPACKSTRING(OP,T) \
91 if (i+m>len) { done = 1; break; } \
94 if (i+m+l>len) { done = 1; break;} \
96 lua_pushlstring(L,s+i,l); \
102 #define HEXDIGITS(DIG) \
103 "0123456789ABCDEF"[DIG]
105 static int l_unpack(lua_State
*L
) /** unpack(f,s, [init]) */
108 const char *s
=luaL_checklstring(L
,2,&len
); /* switched s and f */
109 const char *f
=luaL_checkstring(L
,1);
110 int i_read
= luaL_optint(L
,3,1)-1;
121 while (*f
&& done
== 0)
125 if (isdigit((int) (unsigned char) *f
))
128 while (isdigit((int) (unsigned char) *f
)) N
=10*N
+(*f
++)-'0';
129 if (N
==0 && c
==OP_STRING
) { lua_pushliteral(L
,""); ++n
; }
131 while (N
-- && done
== 0) switch (c
)
133 case OP_LITTLEENDIAN
:
144 if (i
+N
>len
) {done
= 1; break; }
145 lua_pushlstring(L
,s
+i
,N
);
154 if (i
>=len
) {done
= 1; break; }
156 lua_pushlstring(L
,s
+i
,l
);
162 UNPACKSTRING(OP_BSTRING
, uint8_t)
163 UNPACKSTRING(OP_WSTRING
, uint16_t)
164 UNPACKSTRING(OP_SSTRING
, uint32_t)
165 UNPACKNUMBER(OP_NUMBER
, lua_Number
)
166 UNPACKNUMBER(OP_DOUBLE
, double)
167 UNPACKNUMBER(OP_FLOAT
, float)
168 UNPACKNUMBER(OP_CHAR
, int8_t)
169 UNPACKNUMBER(OP_BYTE
, uint8_t)
170 UNPACKNUMBER(OP_SHORT
, int16_t)
171 UNPACKNUMBER(OP_USHORT
, uint16_t)
172 UNPACKNUMBER(OP_INT
, int32_t)
173 UNPACKNUMBER(OP_UINT
, uint32_t)
174 UNPACKNUMBER(OP_LONG
, int64_t)
175 UNPACKNUMBER(OP_ULONG
, uint64_t)
181 luaL_buffinit(L
,&buf
);
183 if (i
+N
> len
) {done
= 1; break;}
184 for (unsigned int ii
= i
; ii
< i
+N
; ii
++) {
187 hdigit
= HEXDIGITS(val
);
188 luaL_addlstring(&buf
, &hdigit
, 1);
191 hdigit
= HEXDIGITS(val
);
192 luaL_addlstring(&buf
, &hdigit
, 1);
194 luaL_pushresult(&buf
);
208 lua_pushnumber(L
,i
+1);
213 #define PACKNUMBER(OP,T) \
216 T a=(T)luaL_checknumber(L,i++); \
217 doswap(swap,&a,sizeof(a)); \
218 luaL_addlstring(&b,(char*)&a,sizeof(a)); \
222 #define PACKSTRING(OP,T) \
226 const char *a=luaL_checklstring(L,i++,&l); \
228 doswap(swap,&ll,sizeof(ll)); \
229 luaL_addlstring(&b,(char*)&ll,sizeof(ll)); \
230 luaL_addlstring(&b,a,l); \
234 static int l_pack(lua_State
*L
) /** pack(f,...) */
237 const char *f
=luaL_checkstring(L
,1);
245 if (isdigit((int) (unsigned char) *f
))
248 while (isdigit((int) (unsigned char) *f
)) N
=10*N
+(*f
++)-'0';
250 while (N
--) switch (c
)
252 case OP_LITTLEENDIAN
:
264 const char *a
=luaL_checklstring(L
,i
++,&l
);
265 luaL_addlstring(&b
,a
,l
+(c
==OP_ZSTRING
));
268 PACKSTRING(OP_BSTRING
, uint8_t)
269 PACKSTRING(OP_WSTRING
, uint16_t)
270 PACKSTRING(OP_SSTRING
, uint32_t)
271 PACKNUMBER(OP_NUMBER
, lua_Number
)
272 PACKNUMBER(OP_DOUBLE
, double)
273 PACKNUMBER(OP_FLOAT
, float)
274 PACKNUMBER(OP_CHAR
, int8_t)
275 PACKNUMBER(OP_BYTE
, uint8_t)
276 PACKNUMBER(OP_SHORT
, int16_t)
277 PACKNUMBER(OP_USHORT
, uint16_t)
278 PACKNUMBER(OP_INT
, int32_t)
279 PACKNUMBER(OP_UINT
, uint32_t)
280 PACKNUMBER(OP_LONG
, int64_t)
281 PACKNUMBER(OP_ULONG
, uint64_t)
283 { // doing digit parsing the lpack way
284 unsigned char sbyte
= 0;
288 const char *a
= luaL_checklstring(L
, i
++, &l
);
289 for (ii
= 0; ii
< l
; ii
++) {
290 if (isxdigit((int) (unsigned char) a
[ii
])) {
291 if (isdigit((int) (unsigned char) a
[ii
])) {
292 sbyte
+= a
[ii
] - '0';
294 } else if (a
[ii
] >= 'A' && a
[ii
] <= 'F') {
295 sbyte
+= a
[ii
] - 'A' + 10;
297 } else if (a
[ii
] >= 'a' && a
[ii
] <= 'f') {
298 sbyte
+= a
[ii
] - 'a' + 10;
303 } else if (odd
== 2) {
304 luaL_addlstring(&b
, (char *) &sbyte
, 1);
308 } else if (isspace(a
[ii
])) {
311 /* err ... ignore too*/
315 luaL_addlstring(&b
, (char *) &sbyte
, 1);
330 static const luaL_Reg binlib
[] =
333 {"unpack", l_unpack
},
337 LUALIB_API
int luaopen_binlib (lua_State
*L
) {
338 luaL_newlib(L
, binlib
);
344 int set_bin_library (lua_State
*L
) {
346 luaL_requiref(L
, "bin", luaopen_binlib
, 1);