style
[RRG-proxmark3.git] / client / src / pm3_binlib.c
blob8ca6c894383d7fd4bc3eb5916681b2a30096f565
1 //-----------------------------------------------------------------------------
2 // Borrowed initially from https://github.com/LuaDist/lpack/blob/master/lpack.c
3 // Copyright (C) 2007 Luiz Henrique de Figueiredo <lhf@tecgraf.puc-rio.br>
4 // Copyright (C) Ignacio Castao <castanyo@yahoo.es>
5 // Copyright (C) Roberto Ierusalimschy <roberto@inf.puc-rio.br>
6 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
7 //
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation, either version 3 of the License, or
11 // (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
18 // See LICENSE.txt for the text of the license.
19 //-----------------------------------------------------------------------------
20 // a Lua library for packing and unpacking binary data
21 //-----------------------------------------------------------------------------
23 #define OP_ZSTRING 'z' /* zero-terminated string */
24 #define OP_BSTRING 'p' /* string preceded by length byte */
25 #define OP_WSTRING 'P' /* string preceded by length word */
26 #define OP_SSTRING 'a' /* string preceded by length size_t */
27 #define OP_STRING 'A' /* string */
28 #define OP_FLOAT 'f' /* float */
29 #define OP_DOUBLE 'd' /* double */
30 #define OP_NUMBER 'n' /* Lua number */
31 #define OP_CHAR 'c' /* char (1-byte int) */
32 #define OP_BYTE 'C' /* byte = unsigned char (1-byte unsigned int) */
33 #define OP_SHORT 's' /* short (2-byte int) */
34 #define OP_USHORT 'S' /* unsigned short (2-byte unsigned int) */
35 #define OP_INT 'i' /* int (4-byte int) */
36 #define OP_UINT 'I' /* unsigned int (4-byte unsigned int) */
37 #define OP_LONG 'l' /* long (8-byte int) */
38 #define OP_ULONG 'L' /* unsigned long (8-byte unsigned int) */
39 #define OP_LITTLEENDIAN '<' /* little endian */
40 #define OP_BIGENDIAN '>' /* big endian */
41 #define OP_NATIVE '=' /* native endian */
43 #define OP_HEX 'H'
45 #include <ctype.h>
46 #include <string.h>
47 #include <lua.h>
48 #include <lualib.h>
49 #include <lauxlib.h>
50 #include <stdint.h>
51 #include "pm3_binlib.h"
54 static void badcode(lua_State *L, int c) {
55 char s[] = "bad code `?'";
56 s[sizeof(s) - 3] = c;
57 luaL_argerror(L, 1, s);
60 static int doendian(int c) {
61 int x = 1;
62 int e = *(char *)&x;
63 if (c == OP_LITTLEENDIAN) return !e;
64 if (c == OP_BIGENDIAN) return e;
65 if (c == OP_NATIVE) return 0;
66 return 0;
69 static void doswap(int swap, void *p, size_t n) {
70 if (swap) {
71 char *a = (char *)p;
72 int i, j;
73 for (i = 0, j = n - 1, n = n / 2; n--; i++, j--) {
74 char t = a[i];
75 a[i] = a[j];
76 a[j] = t;
81 #define UNPACKNUMBER(OP,T) \
82 case OP: \
83 { \
84 T a; \
85 int m=sizeof(a); \
86 if (i+m>len) { done = 1; break;} \
87 memcpy(&a,s+i,m); \
88 i+=m; \
89 doswap(swap,&a,m); \
90 lua_pushnumber(L,(lua_Number)a); \
91 ++n; \
92 break; \
95 #define UNPACKSTRING(OP,T) \
96 case OP: \
97 { \
98 T l; \
99 int m = sizeof(l); \
100 if (i + m > len) { done = 1; break; } \
101 memcpy(&l, s+i, m); \
102 doswap(swap,&l,m); \
103 if (i + m + l > len) { done = 1; break;} \
104 i += m; \
105 lua_pushlstring(L,s+i,l); \
106 i += l; \
107 ++n; \
108 break; \
111 #define HEXDIGITS(DIG) \
112 "0123456789ABCDEF"[DIG]
114 static int l_unpack(lua_State *L) { /** unpack(f,s, [init]) */
115 size_t len;
116 const char *s = luaL_checklstring(L, 2, &len); /* switched s and f */
117 const char *f = luaL_checkstring(L, 1);
118 int i_read = luaL_optinteger(L, 3, 1) - 1;
119 //int i_read = (int)luaL_optint(L,(3),(1))-1;
120 unsigned int i;
121 if (i_read >= 0) {
122 i = i_read;
123 } else {
124 i = 0;
126 int n = 0;
127 int swap = 0;
128 int done = 0;
129 lua_pushnil(L);
130 while (*f && done == 0) {
131 int c = *f++;
132 int N = 1;
133 if (isdigit((int)(unsigned char) *f)) {
134 N = 0;
135 while (isdigit((int)(unsigned char) *f)) N = 10 * N + (*f++) - '0';
136 if (N == 0 && c == OP_STRING) { lua_pushliteral(L, ""); ++n; }
138 while (N-- && done == 0) switch (c) {
139 case OP_LITTLEENDIAN:
140 case OP_BIGENDIAN:
141 case OP_NATIVE: {
142 swap = doendian(c);
143 N = 0;
144 break;
146 case OP_STRING: {
147 ++N;
148 if (i + N > len) {done = 1; break; }
149 lua_pushlstring(L, s + i, N);
150 i += N;
151 ++n;
152 N = 0;
153 break;
155 case OP_ZSTRING: {
156 size_t l;
157 if (i >= len) {done = 1; break; }
158 l = strlen(s + i);
159 lua_pushlstring(L, s + i, l);
160 i += l + 1;
161 ++n;
162 break;
165 UNPACKSTRING(OP_BSTRING, uint8_t)
166 UNPACKSTRING(OP_WSTRING, uint16_t)
167 UNPACKSTRING(OP_SSTRING, uint32_t)
168 UNPACKNUMBER(OP_NUMBER, lua_Number)
169 UNPACKNUMBER(OP_DOUBLE, double)
170 UNPACKNUMBER(OP_FLOAT, float)
171 UNPACKNUMBER(OP_CHAR, int8_t)
172 UNPACKNUMBER(OP_BYTE, uint8_t)
173 UNPACKNUMBER(OP_SHORT, int16_t)
174 UNPACKNUMBER(OP_USHORT, uint16_t)
175 UNPACKNUMBER(OP_INT, int32_t)
176 UNPACKNUMBER(OP_UINT, uint32_t)
177 UNPACKNUMBER(OP_LONG, int64_t)
178 UNPACKNUMBER(OP_ULONG, uint64_t)
179 case OP_HEX: {
180 luaL_Buffer buf;
181 char hdigit = '0';
182 luaL_buffinit(L, &buf);
183 N++;
184 if (i + N > len) {done = 1; break;}
185 for (unsigned int ii = i; ii < i + N; ii++) {
186 int val = s[ii] & 0xF0;
187 val = val >> 4;
188 hdigit = HEXDIGITS(val);
189 luaL_addlstring(&buf, &hdigit, 1);
191 val = s[ii] & 0x0F;
192 hdigit = HEXDIGITS(val);
193 luaL_addlstring(&buf, &hdigit, 1);
195 luaL_pushresult(&buf);
196 n++;
197 i += N;
198 N = 0;
199 break;
202 case ' ':
203 case ',':
204 break;
205 default:
206 badcode(L, c);
207 break;
210 lua_pushnumber(L, i + 1);
211 lua_replace(L, -n - 2);
212 return n + 1;
215 #define PACKNUMBER(OP,T) \
216 case OP: \
218 lua_Number n = luaL_checknumber(L,i++); \
219 T a=(T)n; \
220 doswap(swap,&a,sizeof(a)); \
221 luaL_addlstring(&b,(char*)&a,sizeof(a)); \
222 break; \
225 #define PACKSTRING(OP,T) \
226 case OP: \
228 size_t l; \
229 const char *a=luaL_checklstring(L,i++,&l); \
230 T ll=(T)l; \
231 doswap(swap,&ll,sizeof(ll)); \
232 luaL_addlstring(&b,(char*)&ll,sizeof(ll)); \
233 luaL_addlstring(&b,a,l); \
234 break; \
237 static int l_pack(lua_State *L) { /** pack(f,...) */
238 int i = 2;
239 const char *f = luaL_checkstring(L, 1);
240 int swap = 0;
241 luaL_Buffer b;
242 luaL_buffinit(L, &b);
243 while (*f) {
244 int c = *f++;
245 int N = 1;
246 if (isdigit((int)(unsigned char) *f)) {
247 N = 0;
248 while (isdigit((int)(unsigned char) *f)) N = 10 * N + (*f++) - '0';
250 while (N--) switch (c) {
251 case OP_LITTLEENDIAN:
252 case OP_BIGENDIAN:
253 case OP_NATIVE: {
254 swap = doendian(c);
255 N = 0;
256 break;
258 case OP_STRING:
259 case OP_ZSTRING: {
260 size_t l;
261 const char *a = luaL_checklstring(L, i++, &l);
262 luaL_addlstring(&b, a, l + (c == OP_ZSTRING));
263 break;
265 PACKSTRING(OP_BSTRING, uint8_t)
266 PACKSTRING(OP_WSTRING, uint16_t)
267 PACKSTRING(OP_SSTRING, uint32_t)
268 PACKNUMBER(OP_NUMBER, lua_Number)
269 PACKNUMBER(OP_DOUBLE, double)
270 PACKNUMBER(OP_FLOAT, float)
271 PACKNUMBER(OP_CHAR, int8_t)
272 PACKNUMBER(OP_BYTE, uint8_t)
273 PACKNUMBER(OP_SHORT, int16_t)
274 PACKNUMBER(OP_USHORT, uint16_t)
275 PACKNUMBER(OP_INT, int32_t)
276 PACKNUMBER(OP_UINT, uint32_t)
277 PACKNUMBER(OP_LONG, int64_t)
278 PACKNUMBER(OP_ULONG, uint64_t)
279 case OP_HEX: {
280 // doing digit parsing the lpack way
281 unsigned char sbyte = 0;
282 size_t l;
283 unsigned int ii = 0;
284 int odd = 0;
285 const char *a = luaL_checklstring(L, i++, &l);
286 for (ii = 0; ii < l; ii++) {
287 if (isxdigit((int)(unsigned char) a[ii])) {
288 if (isdigit((int)(unsigned char) a[ii])) {
289 sbyte += a[ii] - '0';
290 odd++;
291 } else if (a[ii] >= 'A' && a[ii] <= 'F') {
292 sbyte += a[ii] - 'A' + 10;
293 odd++;
294 } else if (a[ii] >= 'a' && a[ii] <= 'f') {
295 sbyte += a[ii] - 'a' + 10;
296 odd++;
298 if (odd == 1) {
299 sbyte = sbyte << 4;
300 } else if (odd == 2) {
301 luaL_addlstring(&b, (char *) &sbyte, 1);
302 sbyte = 0;
303 odd = 0;
305 } else if (isspace(a[ii])) {
306 /* ignore */
307 } else {
308 /* err ... ignore too*/
311 if (odd == 1) {
312 luaL_addlstring(&b, (char *) &sbyte, 1);
314 break;
316 case ' ':
317 case ',':
318 break;
319 default:
320 badcode(L, c);
321 break;
324 luaL_pushresult(&b);
325 return 1;
328 static const luaL_Reg binlib[] = {
329 {"pack", l_pack},
330 {"unpack", l_unpack},
331 {NULL, NULL}
334 LUALIB_API int luaopen_binlib(lua_State *L);
335 LUALIB_API int luaopen_binlib(lua_State *L) {
336 luaL_newlib(L, binlib);
337 return 1;
340 ** Open bin library
342 int set_bin_library(lua_State *L) {
344 luaL_requiref(L, "bin", luaopen_binlib, 1);
345 lua_pop(L, 1);
346 return 1;