lua_struct.c 11 KB

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