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
) {
43 char s
[] = "bad code `?'";
45 luaL_argerror(L
, 1, s
);
48 static int doendian(int c
) {
51 if (c
== OP_LITTLEENDIAN
) return !e
;
52 if (c
== OP_BIGENDIAN
) return e
;
53 if (c
== OP_NATIVE
) return 0;
57 static void doswap(int swap
, void *p
, size_t n
) {
61 for (i
= 0, j
= n
- 1, n
= n
/ 2; n
--; i
++, j
--) {
69 #define UNPACKNUMBER(OP,T) \
74 if (i+m>len) { done = 1; break;} \
78 lua_pushnumber(L,(lua_Number)a); \
83 #define UNPACKSTRING(OP,T) \
88 if (i + m > len) { done = 1; break; } \
91 if (i + m + l > len) { done = 1; break;} \
93 lua_pushlstring(L,s+i,l); \
99 #define HEXDIGITS(DIG) \
100 "0123456789ABCDEF"[DIG]
102 static int l_unpack(lua_State
*L
) { /** unpack(f,s, [init]) */
104 const char *s
= luaL_checklstring(L
, 2, &len
); /* switched s and f */
105 const char *f
= luaL_checkstring(L
, 1);
106 int i_read
= luaL_optinteger(L
, 3, 1) - 1;
107 //int i_read = (int)luaL_optint(L,(3),(1))-1;
118 while (*f
&& done
== 0) {
121 if (isdigit((int)(unsigned char) *f
)) {
123 while (isdigit((int)(unsigned char) *f
)) N
= 10 * N
+ (*f
++) - '0';
124 if (N
== 0 && c
== OP_STRING
) { lua_pushliteral(L
, ""); ++n
; }
126 while (N
-- && done
== 0) switch (c
) {
127 case OP_LITTLEENDIAN
:
136 if (i
+ N
> len
) {done
= 1; break; }
137 lua_pushlstring(L
, s
+ i
, N
);
145 if (i
>= len
) {done
= 1; break; }
147 lua_pushlstring(L
, s
+ i
, l
);
153 UNPACKSTRING(OP_BSTRING
, uint8_t)
154 UNPACKSTRING(OP_WSTRING
, uint16_t)
155 UNPACKSTRING(OP_SSTRING
, uint32_t)
156 UNPACKNUMBER(OP_NUMBER
, lua_Number
)
157 UNPACKNUMBER(OP_DOUBLE
, double)
158 UNPACKNUMBER(OP_FLOAT
, float)
159 UNPACKNUMBER(OP_CHAR
, int8_t)
160 UNPACKNUMBER(OP_BYTE
, uint8_t)
161 UNPACKNUMBER(OP_SHORT
, int16_t)
162 UNPACKNUMBER(OP_USHORT
, uint16_t)
163 UNPACKNUMBER(OP_INT
, int32_t)
164 UNPACKNUMBER(OP_UINT
, uint32_t)
165 UNPACKNUMBER(OP_LONG
, int64_t)
166 UNPACKNUMBER(OP_ULONG
, uint64_t)
170 luaL_buffinit(L
, &buf
);
172 if (i
+ N
> len
) {done
= 1; break;}
173 for (unsigned int ii
= i
; ii
< i
+ N
; ii
++) {
174 int val
= s
[ii
] & 0xF0;
176 hdigit
= HEXDIGITS(val
);
177 luaL_addlstring(&buf
, &hdigit
, 1);
180 hdigit
= HEXDIGITS(val
);
181 luaL_addlstring(&buf
, &hdigit
, 1);
183 luaL_pushresult(&buf
);
198 lua_pushnumber(L
, i
+ 1);
199 lua_replace(L
, -n
- 2);
203 #define PACKNUMBER(OP,T) \
206 lua_Number n = luaL_checknumber(L,i++); \
208 doswap(swap,&a,sizeof(a)); \
209 luaL_addlstring(&b,(char*)&a,sizeof(a)); \
213 #define PACKSTRING(OP,T) \
217 const char *a=luaL_checklstring(L,i++,&l); \
219 doswap(swap,&ll,sizeof(ll)); \
220 luaL_addlstring(&b,(char*)&ll,sizeof(ll)); \
221 luaL_addlstring(&b,a,l); \
225 static int l_pack(lua_State
*L
) { /** pack(f,...) */
227 const char *f
= luaL_checkstring(L
, 1);
230 luaL_buffinit(L
, &b
);
234 if (isdigit((int)(unsigned char) *f
)) {
236 while (isdigit((int)(unsigned char) *f
)) N
= 10 * N
+ (*f
++) - '0';
238 while (N
--) switch (c
) {
239 case OP_LITTLEENDIAN
:
249 const char *a
= luaL_checklstring(L
, i
++, &l
);
250 luaL_addlstring(&b
, a
, l
+ (c
== OP_ZSTRING
));
253 PACKSTRING(OP_BSTRING
, uint8_t)
254 PACKSTRING(OP_WSTRING
, uint16_t)
255 PACKSTRING(OP_SSTRING
, uint32_t)
256 PACKNUMBER(OP_NUMBER
, lua_Number
)
257 PACKNUMBER(OP_DOUBLE
, double)
258 PACKNUMBER(OP_FLOAT
, float)
259 PACKNUMBER(OP_CHAR
, int8_t)
260 PACKNUMBER(OP_BYTE
, uint8_t)
261 PACKNUMBER(OP_SHORT
, int16_t)
262 PACKNUMBER(OP_USHORT
, uint16_t)
263 PACKNUMBER(OP_INT
, int32_t)
264 PACKNUMBER(OP_UINT
, uint32_t)
265 PACKNUMBER(OP_LONG
, int64_t)
266 PACKNUMBER(OP_ULONG
, uint64_t)
268 // doing digit parsing the lpack way
269 unsigned char sbyte
= 0;
273 const char *a
= luaL_checklstring(L
, i
++, &l
);
274 for (ii
= 0; ii
< l
; ii
++) {
275 if (isxdigit((int)(unsigned char) a
[ii
])) {
276 if (isdigit((int)(unsigned char) a
[ii
])) {
277 sbyte
+= a
[ii
] - '0';
279 } else if (a
[ii
] >= 'A' && a
[ii
] <= 'F') {
280 sbyte
+= a
[ii
] - 'A' + 10;
282 } else if (a
[ii
] >= 'a' && a
[ii
] <= 'f') {
283 sbyte
+= a
[ii
] - 'a' + 10;
288 } else if (odd
== 2) {
289 luaL_addlstring(&b
, (char *) &sbyte
, 1);
293 } else if (isspace(a
[ii
])) {
296 /* err ... ignore too*/
300 luaL_addlstring(&b
, (char *) &sbyte
, 1);
316 static const luaL_Reg binlib
[] = {
318 {"unpack", l_unpack
},
322 LUALIB_API
int luaopen_binlib(lua_State
*L
);
323 LUALIB_API
int luaopen_binlib(lua_State
*L
) {
324 luaL_newlib(L
, binlib
);
330 int set_bin_library(lua_State
*L
) {
332 luaL_requiref(L
, "bin", luaopen_binlib
, 1);