struct.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. /*
  2. ** {======================================================
  3. ** Library for packing/unpacking structures.
  4. ** $Id: struct.c,v 1.4 2012/07/04 18:54:29 roberto Exp $
  5. ** See Copyright Notice at the end of this file
  6. ** =======================================================
  7. */
  8. // Original: http://www.inf.puc-rio.br/~roberto/struct/
  9. // This was ported to NodeMCU by Philip Gladstone, N1DQ
  10. /*
  11. ** Valid formats:
  12. ** > - big endian
  13. ** < - little endian
  14. ** ![num] - alignment
  15. ** x - pading
  16. ** b/B - signed/unsigned byte
  17. ** h/H - signed/unsigned short
  18. ** l/L - signed/unsigned long
  19. ** T - size_t
  20. ** i/In - signed/unsigned integer with size `n' (default is size of int)
  21. ** cn - sequence of `n' chars (from/to a string); when packing, n==0 means
  22. the whole string; when unpacking, n==0 means use the previous
  23. read number as the string length
  24. ** s - zero-terminated string
  25. ** f - float
  26. ** d - double
  27. ** ' ' - ignored
  28. */
  29. #include <assert.h>
  30. #include <ctype.h>
  31. #include <limits.h>
  32. #include <stddef.h>
  33. #include <string.h>
  34. #include "module.h"
  35. #include "lauxlib.h"
  36. /* basic integer type */
  37. #if !defined(STRUCT_INT)
  38. #define STRUCT_INT long
  39. #endif
  40. typedef STRUCT_INT Inttype;
  41. /* corresponding unsigned version */
  42. typedef unsigned STRUCT_INT Uinttype;
  43. /* maximum size (in bytes) for integral types */
  44. #ifdef LUA_NUMBER_INTEGRAL
  45. #ifdef LUA_INTEGRAL_LONGLONG
  46. #define MAXINTSIZE 8
  47. #else
  48. #define MAXINTSIZE 4
  49. #endif
  50. #else
  51. #define MAXINTSIZE 32
  52. #endif
  53. #ifndef LUA_MININTEGER
  54. #define LUA_MININTEGER INT_MIN
  55. #endif
  56. #ifndef LUA_MAXINTEGER
  57. #define LUA_MAXINTEGER INT_MAX
  58. #endif
  59. /* is 'x' a power of 2? */
  60. #define isp2(x) ((x) > 0 && ((x) & ((x) - 1)) == 0)
  61. /* dummy structure to get alignment requirements */
  62. struct cD {
  63. char c;
  64. double d;
  65. };
  66. #define PADDING (sizeof(struct cD) - sizeof(double))
  67. #define MAXALIGN (PADDING > sizeof(int) ? PADDING : sizeof(int))
  68. /* endian options */
  69. #define BIG 0
  70. #define LITTLE 1
  71. static union {
  72. int dummy;
  73. char endian;
  74. } const native = {1};
  75. typedef struct Header {
  76. int endian;
  77. int align;
  78. } Header;
  79. static int getnum (const char **fmt, int df) {
  80. if (!isdigit(**fmt)) /* no number? */
  81. return df; /* return default value */
  82. else {
  83. int a = 0;
  84. do {
  85. a = a*10 + *((*fmt)++) - '0';
  86. } while (isdigit(**fmt));
  87. return a;
  88. }
  89. }
  90. #define defaultoptions(h) ((h)->endian = native.endian, (h)->align = 1)
  91. static size_t optsize (lua_State *L, char opt, const char **fmt) {
  92. switch (opt) {
  93. case 'B': case 'b': return sizeof(char);
  94. case 'H': case 'h': return sizeof(short);
  95. case 'L': case 'l': return sizeof(long);
  96. case 'T': return sizeof(size_t);
  97. #ifndef LUA_NUMBER_INTEGRAL
  98. case 'f': return sizeof(float);
  99. case 'd': return sizeof(double);
  100. #endif
  101. case 'x': return 1;
  102. case 'c': return getnum(fmt, 1);
  103. case 'i': case 'I': {
  104. int sz = getnum(fmt, sizeof(int));
  105. if (sz > MAXINTSIZE)
  106. luaL_error(L, "integral size %d is larger than limit of %d",
  107. sz, MAXINTSIZE);
  108. return sz;
  109. }
  110. default: return 0; /* other cases do not need alignment */
  111. }
  112. }
  113. /*
  114. ** return number of bytes needed to align an element of size 'size'
  115. ** at current position 'len'
  116. */
  117. static int gettoalign (size_t len, Header *h, int opt, size_t size) {
  118. if (size == 0 || opt == 'c') return 0;
  119. if (size > (size_t)h->align)
  120. size = h->align; /* respect max. alignment */
  121. return (size - (len & (size - 1))) & (size - 1);
  122. }
  123. /*
  124. ** options to control endianess and alignment
  125. */
  126. static void controloptions (lua_State *L, int opt, const char **fmt,
  127. Header *h) {
  128. switch (opt) {
  129. case ' ': return; /* ignore white spaces */
  130. case '>': h->endian = BIG; return;
  131. case '<': h->endian = LITTLE; return;
  132. case '!': {
  133. int a = getnum(fmt, MAXALIGN);
  134. if (!isp2(a))
  135. luaL_error(L, "alignment %d is not a power of 2", a);
  136. h->align = a;
  137. return;
  138. }
  139. default: {
  140. const char *msg = lua_pushfstring(L, "invalid format option '%c'", opt);
  141. luaL_argerror(L, 1, msg);
  142. }
  143. }
  144. }
  145. static void putinteger (lua_State *L, luaL_Buffer *b, int arg, int endian,
  146. int size) {
  147. int32_t n = luaL_checkinteger(L, arg);
  148. Uinttype value;
  149. char buff[MAXINTSIZE];
  150. if (n < 0)
  151. value = (Uinttype)(Inttype)n;
  152. else
  153. value = (Uinttype)n;
  154. if (endian == LITTLE) {
  155. int i;
  156. for (i = 0; i < size; i++) {
  157. buff[i] = (value & 0xff);
  158. value >>= 8;
  159. }
  160. }
  161. else {
  162. int i;
  163. for (i = size - 1; i >= 0; i--) {
  164. buff[i] = (value & 0xff);
  165. value >>= 8;
  166. }
  167. }
  168. luaL_addlstring(b, buff, size);
  169. }
  170. static void correctbytes (char *b, int size, int endian) {
  171. if (endian != native.endian) {
  172. int i = 0;
  173. while (i < --size) {
  174. char temp = b[i];
  175. b[i++] = b[size];
  176. b[size] = temp;
  177. }
  178. }
  179. }
  180. static int b_pack (lua_State *L) {
  181. luaL_Buffer b;
  182. const char *fmt = luaL_checkstring(L, 1);
  183. Header h;
  184. int arg = 2;
  185. size_t totalsize = 0;
  186. defaultoptions(&h);
  187. lua_pushnil(L); /* mark to separate arguments from string buffer */
  188. luaL_buffinit(L, &b);
  189. while (*fmt != '\0') {
  190. int opt = *fmt++;
  191. size_t size = optsize(L, opt, &fmt);
  192. int toalign = gettoalign(totalsize, &h, opt, size);
  193. totalsize += toalign;
  194. while (toalign-- > 0) luaL_addchar(&b, '\0');
  195. switch (opt) {
  196. case 'b': case 'B': case 'h': case 'H':
  197. case 'l': case 'L': case 'T': case 'i': case 'I': { /* integer types */
  198. putinteger(L, &b, arg++, h.endian, size);
  199. break;
  200. }
  201. case 'x': {
  202. luaL_addchar(&b, '\0');
  203. break;
  204. }
  205. #ifndef LUA_NUMBER_INTEGRAL
  206. case 'f': {
  207. float f = (float)luaL_checknumber(L, arg++);
  208. correctbytes((char *)&f, size, h.endian);
  209. luaL_addlstring(&b, (char *)&f, size);
  210. break;
  211. }
  212. case 'd': {
  213. double d = luaL_checknumber(L, arg++);
  214. correctbytes((char *)&d, size, h.endian);
  215. luaL_addlstring(&b, (char *)&d, size);
  216. break;
  217. }
  218. #endif
  219. case 'c': case 's': {
  220. size_t l;
  221. const char *s = luaL_checklstring(L, arg++, &l);
  222. if (size == 0) size = l;
  223. luaL_argcheck(L, l >= (size_t)size, arg, "string too short");
  224. luaL_addlstring(&b, s, size);
  225. if (opt == 's') {
  226. luaL_addchar(&b, '\0'); /* add zero at the end */
  227. size++;
  228. }
  229. break;
  230. }
  231. default: controloptions(L, opt, &fmt, &h);
  232. }
  233. totalsize += size;
  234. }
  235. luaL_pushresult(&b);
  236. return 1;
  237. }
  238. static int64_t getinteger (const char *buff, int endian,
  239. int issigned, int size) {
  240. uint64_t l = 0;
  241. int i;
  242. if (endian == BIG) {
  243. for (i = 0; i < size; i++) {
  244. l <<= 8;
  245. l |= (unsigned char)buff[i];
  246. }
  247. }
  248. else {
  249. for (i = size - 1; i >= 0; i--) {
  250. l <<= 8;
  251. l |= (unsigned char)buff[i];
  252. }
  253. }
  254. if (!issigned)
  255. return (int64_t)l;
  256. else { /* signed format */
  257. uint64_t mask = (uint64_t)(~((uint64_t)0)) << (size*8 - 1);
  258. if (l & mask) /* negative value? */
  259. l |= mask; /* signal extension */
  260. return (int64_t)l;
  261. }
  262. }
  263. static int b_unpack (lua_State *L) {
  264. Header h;
  265. const char *fmt = luaL_checkstring(L, 1);
  266. size_t ld;
  267. const char *data = luaL_checklstring(L, 2, &ld);
  268. size_t pos = luaL_optinteger(L, 3, 1) - 1;
  269. defaultoptions(&h);
  270. lua_settop(L, 2);
  271. while (*fmt) {
  272. int opt = *fmt++;
  273. size_t size = optsize(L, opt, &fmt);
  274. pos += gettoalign(pos, &h, opt, size);
  275. luaL_argcheck(L, pos+size <= ld, 2, "data string too short");
  276. luaL_checkstack(L, 2, "too many results");
  277. switch (opt) {
  278. case 'b': case 'B': case 'h': case 'H':
  279. case 'l': case 'L': case 'T': case 'i': case 'I': { /* integer types */
  280. int issigned = islower(opt);
  281. int64_t res = getinteger(data+pos, h.endian, issigned, size);
  282. if (res >= LUA_MININTEGER && res <= LUA_MAXINTEGER) {
  283. lua_pushinteger(L, res);
  284. } else {
  285. lua_pushnumber(L, res);
  286. }
  287. break;
  288. }
  289. case 'x': {
  290. break;
  291. }
  292. #ifndef LUA_NUMBER_INTEGRAL
  293. case 'f': {
  294. float f;
  295. memcpy(&f, data+pos, size);
  296. correctbytes((char *)&f, sizeof(f), h.endian);
  297. lua_pushnumber(L, f);
  298. break;
  299. }
  300. case 'd': {
  301. double d;
  302. memcpy(&d, data+pos, size);
  303. correctbytes((char *)&d, sizeof(d), h.endian);
  304. lua_pushnumber(L, d);
  305. break;
  306. }
  307. #endif
  308. case 'c': {
  309. if (size == 0) {
  310. if (!lua_isnumber(L, -1))
  311. luaL_error(L, "format `c0' needs a previous size");
  312. size = lua_tointeger(L, -1);
  313. lua_pop(L, 1);
  314. luaL_argcheck(L, pos+size <= ld, 2, "data string too short");
  315. }
  316. lua_pushlstring(L, data+pos, size);
  317. break;
  318. }
  319. case 's': {
  320. const char *e = (const char *)memchr(data+pos, '\0', ld - pos);
  321. if (e == NULL)
  322. luaL_error(L, "unfinished string in data");
  323. size = (e - (data+pos)) + 1;
  324. lua_pushlstring(L, data+pos, size - 1);
  325. break;
  326. }
  327. default: controloptions(L, opt, &fmt, &h);
  328. }
  329. pos += size;
  330. }
  331. lua_pushinteger(L, pos + 1);
  332. return lua_gettop(L) - 2;
  333. }
  334. static int b_size (lua_State *L) {
  335. Header h;
  336. const char *fmt = luaL_checkstring(L, 1);
  337. size_t pos = 0;
  338. defaultoptions(&h);
  339. while (*fmt) {
  340. int opt = *fmt++;
  341. size_t size = optsize(L, opt, &fmt);
  342. pos += gettoalign(pos, &h, opt, size);
  343. if (opt == 's')
  344. luaL_argerror(L, 1, "option 's' has no fixed size");
  345. else if (opt == 'c' && size == 0)
  346. luaL_argerror(L, 1, "option 'c0' has no fixed size");
  347. if (!isalnum(opt))
  348. controloptions(L, opt, &fmt, &h);
  349. pos += size;
  350. }
  351. lua_pushinteger(L, pos);
  352. return 1;
  353. }
  354. /* }====================================================== */
  355. LROT_BEGIN(thislib, NULL, 0)
  356. LROT_FUNCENTRY( pack, b_pack )
  357. LROT_FUNCENTRY( unpack, b_unpack )
  358. LROT_FUNCENTRY( size, b_size )
  359. LROT_END(thislib, NULL, 0)
  360. NODEMCU_MODULE(STRUCT, "struct", thislib, NULL);
  361. /******************************************************************************
  362. * Copyright (C) 2010-2012 Lua.org, PUC-Rio. All rights reserved.
  363. *
  364. * Permission is hereby granted, free of charge, to any person obtaining
  365. * a copy of this software and associated documentation files (the
  366. * "Software"), to deal in the Software without restriction, including
  367. * without limitation the rights to use, copy, modify, merge, publish,
  368. * distribute, sublicense, and/or sell copies of the Software, and to
  369. * permit persons to whom the Software is furnished to do so, subject to
  370. * the following conditions:
  371. *
  372. * The above copyright notice and this permission notice shall be
  373. * included in all copies or substantial portions of the Software.
  374. *
  375. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  376. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  377. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  378. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  379. * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  380. * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  381. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  382. ******************************************************************************/