fix little endian vs big endian in the macros... again... but this time correct
[RRG-proxmark3.git] / client / src / pm3_binlib.c
blob56d281636d1a1e448b26ec1764aeb0ec48595be7
1 /*
2 * lpack.c
3 * a Lua library for packing and unpacking binary data
4 * Luiz Henrique de Figueiredo <lhf@tecgraf.puc-rio.br>
5 * 29 Jun 2007 19:27:20
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>.
9 */
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 */
31 #define OP_HEX 'H'
33 #include <ctype.h>
34 #include <string.h>
35 #include <lua.h>
36 #include <lualib.h>
37 #include <lauxlib.h>
38 #include <stdint.h>
39 #include "pm3_binlib.h"
42 static void badcode(lua_State *L, int c) {
43 char s[] = "bad code `?'";
44 s[sizeof(s) - 3] = c;
45 luaL_argerror(L, 1, s);
48 static int doendian(int c) {
49 int x = 1;
50 int e = *(char *)&x;
51 if (c == OP_LITTLEENDIAN) return !e;
52 if (c == OP_BIGENDIAN) return e;
53 if (c == OP_NATIVE) return 0;
54 return 0;
57 static void doswap(int swap, void *p, size_t n) {
58 if (swap) {
59 char *a = (char *)p;
60 int i, j;
61 for (i = 0, j = n - 1, n = n / 2; n--; i++, j--) {
62 char t = a[i];
63 a[i] = a[j];
64 a[j] = t;
69 #define UNPACKNUMBER(OP,T) \
70 case OP: \
71 { \
72 T a; \
73 int m=sizeof(a); \
74 if (i+m>len) { done = 1; break;} \
75 memcpy(&a,s+i,m); \
76 i+=m; \
77 doswap(swap,&a,m); \
78 lua_pushnumber(L,(lua_Number)a); \
79 ++n; \
80 break; \
83 #define UNPACKSTRING(OP,T) \
84 case OP: \
85 { \
86 T l; \
87 int m = sizeof(l); \
88 if (i + m > len) { done = 1; break; } \
89 memcpy(&l, s+i, m); \
90 doswap(swap,&l,m); \
91 if (i + m + l > len) { done = 1; break;} \
92 i += m; \
93 lua_pushlstring(L,s+i,l); \
94 i += l; \
95 ++n; \
96 break; \
99 #define HEXDIGITS(DIG) \
100 "0123456789ABCDEF"[DIG]
102 static int l_unpack(lua_State *L) { /** unpack(f,s, [init]) */
103 size_t len;
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;
108 unsigned int i;
109 if (i_read >= 0) {
110 i = i_read;
111 } else {
112 i = 0;
114 int n = 0;
115 int swap = 0;
116 int done = 0;
117 lua_pushnil(L);
118 while (*f && done == 0) {
119 int c = *f++;
120 int N = 1;
121 if (isdigit((int)(unsigned char) *f)) {
122 N = 0;
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:
128 case OP_BIGENDIAN:
129 case OP_NATIVE: {
130 swap = doendian(c);
131 N = 0;
132 break;
134 case OP_STRING: {
135 ++N;
136 if (i + N > len) {done = 1; break; }
137 lua_pushlstring(L, s + i, N);
138 i += N;
139 ++n;
140 N = 0;
141 break;
143 case OP_ZSTRING: {
144 size_t l;
145 if (i >= len) {done = 1; break; }
146 l = strlen(s + i);
147 lua_pushlstring(L, s + i, l);
148 i += l + 1;
149 ++n;
150 break;
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)
167 case OP_HEX: {
168 luaL_Buffer buf;
169 char hdigit = '0';
170 luaL_buffinit(L, &buf);
171 N++;
172 if (i + N > len) {done = 1; break;}
173 for (unsigned int ii = i; ii < i + N; ii++) {
174 int val = s[ii] & 0xF0;
175 val = val >> 4;
176 hdigit = HEXDIGITS(val);
177 luaL_addlstring(&buf, &hdigit, 1);
179 val = s[ii] & 0x0F;
180 hdigit = HEXDIGITS(val);
181 luaL_addlstring(&buf, &hdigit, 1);
183 luaL_pushresult(&buf);
184 n++;
185 i += N;
186 N = 0;
187 break;
190 case ' ':
191 case ',':
192 break;
193 default:
194 badcode(L, c);
195 break;
198 lua_pushnumber(L, i + 1);
199 lua_replace(L, -n - 2);
200 return n + 1;
203 #define PACKNUMBER(OP,T) \
204 case OP: \
206 lua_Number n = luaL_checknumber(L,i++); \
207 T a=(T)n; \
208 doswap(swap,&a,sizeof(a)); \
209 luaL_addlstring(&b,(char*)&a,sizeof(a)); \
210 break; \
213 #define PACKSTRING(OP,T) \
214 case OP: \
216 size_t l; \
217 const char *a=luaL_checklstring(L,i++,&l); \
218 T ll=(T)l; \
219 doswap(swap,&ll,sizeof(ll)); \
220 luaL_addlstring(&b,(char*)&ll,sizeof(ll)); \
221 luaL_addlstring(&b,a,l); \
222 break; \
225 static int l_pack(lua_State *L) { /** pack(f,...) */
226 int i = 2;
227 const char *f = luaL_checkstring(L, 1);
228 int swap = 0;
229 luaL_Buffer b;
230 luaL_buffinit(L, &b);
231 while (*f) {
232 int c = *f++;
233 int N = 1;
234 if (isdigit((int)(unsigned char) *f)) {
235 N = 0;
236 while (isdigit((int)(unsigned char) *f)) N = 10 * N + (*f++) - '0';
238 while (N--) switch (c) {
239 case OP_LITTLEENDIAN:
240 case OP_BIGENDIAN:
241 case OP_NATIVE: {
242 swap = doendian(c);
243 N = 0;
244 break;
246 case OP_STRING:
247 case OP_ZSTRING: {
248 size_t l;
249 const char *a = luaL_checklstring(L, i++, &l);
250 luaL_addlstring(&b, a, l + (c == OP_ZSTRING));
251 break;
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)
267 case OP_HEX: {
268 // doing digit parsing the lpack way
269 unsigned char sbyte = 0;
270 size_t l;
271 unsigned int ii = 0;
272 int odd = 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';
278 odd++;
279 } else if (a[ii] >= 'A' && a[ii] <= 'F') {
280 sbyte += a[ii] - 'A' + 10;
281 odd++;
282 } else if (a[ii] >= 'a' && a[ii] <= 'f') {
283 sbyte += a[ii] - 'a' + 10;
284 odd++;
286 if (odd == 1) {
287 sbyte = sbyte << 4;
288 } else if (odd == 2) {
289 luaL_addlstring(&b, (char *) &sbyte, 1);
290 sbyte = 0;
291 odd = 0;
293 } else if (isspace(a[ii])) {
294 /* ignore */
295 } else {
296 /* err ... ignore too*/
299 if (odd == 1) {
300 luaL_addlstring(&b, (char *) &sbyte, 1);
302 break;
304 case ' ':
305 case ',':
306 break;
307 default:
308 badcode(L, c);
309 break;
312 luaL_pushresult(&b);
313 return 1;
316 static const luaL_Reg binlib[] = {
317 {"pack", l_pack},
318 {"unpack", l_unpack},
319 {NULL, NULL}
322 LUALIB_API int luaopen_binlib(lua_State *L);
323 LUALIB_API int luaopen_binlib(lua_State *L) {
324 luaL_newlib(L, binlib);
325 return 1;
328 ** Open bin library
330 int set_bin_library(lua_State *L) {
332 luaL_requiref(L, "bin", luaopen_binlib, 1);
333 lua_pop(L, 1);
334 return 1;