sq_pack.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. /*
  2. * lpack.c
  3. * a Lua library for packing and unpacking binary data
  4. * Luiz Henrique de Figueiredo <[email protected]>
  5. * 29 Jun 2007 19:27:20
  6. * This code is hereby placed in the public domain.
  7. * with contributions from Ignacio Castaño <[email protected]> and
  8. * Roberto Ierusalimschy <[email protected]>.
  9. *
  10. * Ported to SquiLu by Domingo Alvarez Duarte [email protected] on 21/09/2016
  11. */
  12. #define OP_ZSTRING 'z' /* zero-terminated string */
  13. #define OP_BSTRING 'p' /* string preceded by length byte */
  14. #define OP_WSTRING 'P' /* string preceded by length word */
  15. #define OP_SSTRING 'a' /* string preceded by length size_t */
  16. #define OP_STRING 'A' /* string */
  17. #define OP_FLOAT 'f' /* float */
  18. #define OP_DOUBLE 'd' /* double */
  19. #define OP_CHAR 'c' /* char */
  20. #define OP_BYTE 'b' /* byte = unsigned char */
  21. #define OP_SHORT 'h' /* short */
  22. #define OP_USHORT 'H' /* unsigned short */
  23. #define OP_INT 'i' /* int */
  24. #define OP_UINT 'I' /* unsigned int */
  25. #define OP_LONG 'l' /* long */
  26. #define OP_ULONG 'L' /* unsigned long */
  27. #define OP_LITTLEENDIAN '<' /* little endian */
  28. #define OP_BIGENDIAN '>' /* big endian */
  29. #define OP_NATIVE '=' /* native endian */
  30. #include <ctype.h>
  31. #include <string.h>
  32. #include "squirrel.h"
  33. #include "sqstdblobimpl.h"
  34. SQ_OPT_STRING_STRLEN();
  35. static SQRESULT badcode(HSQUIRRELVM v, int c)
  36. {
  37. SQChar s[]=_SC("bad code '?'");
  38. s[sizeof(s)-(3*sizeof(SQChar))]=c;
  39. return sq_throwerror(v,s);
  40. }
  41. static int doendian(int c)
  42. {
  43. int x=1;
  44. int e=*(char*)&x;
  45. if (c==OP_LITTLEENDIAN) return !e;
  46. if (c==OP_BIGENDIAN) return e;
  47. if (c==OP_NATIVE) return 0;
  48. return 0;
  49. }
  50. static void doswap(int swap, void *p, size_t n)
  51. {
  52. if (swap)
  53. {
  54. char *a=(char*)p;
  55. int i,j;
  56. for (i=0, j=n-1, n=n/2; n--; i++, j--)
  57. {
  58. char t=a[i]; a[i]=a[j]; a[j]=t;
  59. }
  60. }
  61. }
  62. #define UNPACKNUMBER_T(OP,T, SQ_P, SQ_T) \
  63. case OP: \
  64. { \
  65. T a; \
  66. int m=sizeof(a); \
  67. if (i+m>s_size) goto done; \
  68. memcpy(&a,s+i,m); \
  69. i+=m; \
  70. doswap(swap,&a,m); \
  71. SQ_P(v,(SQ_T)a); \
  72. ++n; \
  73. break; \
  74. }
  75. #define UNPACKFLOAT(OP, T) UNPACKNUMBER_T(OP, T, sq_pushfloat, SQFloat)
  76. #define UNPACKINTEGER(OP, T) UNPACKNUMBER_T(OP, T, sq_pushinteger, SQInteger)
  77. #define UNPACKSTRING(OP,T) \
  78. case OP: \
  79. { \
  80. T l; \
  81. int m=sizeof(l); \
  82. if (i+m>s_size) goto done; \
  83. memcpy(&l,s+i,m); \
  84. doswap(swap,&l,m); \
  85. if (i+m+l>s_size) goto done; \
  86. i+=m; \
  87. sq_pushstring(v,s+i,l); \
  88. i+=l; \
  89. ++n; \
  90. break; \
  91. }
  92. static SQRESULT sq_unpack(HSQUIRRELVM v) /** unpack(s,f,[init]) */
  93. {
  94. SQ_FUNC_VARS(v);
  95. const SQChar *s;
  96. SQInteger s_size;
  97. SQObjectType ot = sq_gettype(v, 2);
  98. switch(ot)
  99. {
  100. case OT_STRING: sq_getstr_and_size(v, 2, &s, &s_size); break;
  101. case OT_USERDATA:
  102. sq_getuserdata(v, 2, (SQUserPointer*)&s, NULL);
  103. s_size = sq_getsize(v, 2);
  104. break;
  105. default:
  106. return sq_throwerror(v, _SC("unexpected type %d for parameter 1"), ot);
  107. }
  108. SQ_GET_STRING(v, 3, f);
  109. SQ_OPT_INTEGER(v,4, i, 0);
  110. SQInteger n=0;
  111. int swap=0;
  112. sq_pushnull(v);
  113. while (*f)
  114. {
  115. int c=*f++;
  116. int N=1;
  117. if (isdigit(*f))
  118. {
  119. N=0;
  120. while (isdigit(*f)) N=10*N+(*f++)-'0';
  121. if (N==0 && c==OP_STRING) { sq_pushliteral(v,_SC("")); ++n; }
  122. }
  123. while (N--) switch (c)
  124. {
  125. case OP_LITTLEENDIAN:
  126. case OP_BIGENDIAN:
  127. case OP_NATIVE:
  128. {
  129. swap=doendian(c);
  130. N=0;
  131. break;
  132. }
  133. case OP_STRING:
  134. {
  135. ++N;
  136. if (i+N>s_size) goto done;
  137. sq_pushstring(v,s+i,N);
  138. i+=N;
  139. ++n;
  140. N=0;
  141. break;
  142. }
  143. case OP_ZSTRING:
  144. {
  145. size_t l;
  146. if (i>=s_size) goto done;
  147. l=strlen(s+i);
  148. sq_pushstring(v,s+i,l);
  149. i+=l+1;
  150. ++n;
  151. break;
  152. }
  153. UNPACKSTRING(OP_BSTRING, unsigned char)
  154. UNPACKSTRING(OP_WSTRING, unsigned short)
  155. UNPACKSTRING(OP_SSTRING, size_t)
  156. UNPACKFLOAT(OP_DOUBLE, double)
  157. UNPACKFLOAT(OP_FLOAT, float)
  158. UNPACKINTEGER(OP_CHAR, char)
  159. UNPACKINTEGER(OP_BYTE, unsigned char)
  160. UNPACKINTEGER(OP_SHORT, short)
  161. UNPACKINTEGER(OP_USHORT, unsigned short)
  162. UNPACKINTEGER(OP_INT, int)
  163. UNPACKINTEGER(OP_UINT, unsigned int)
  164. UNPACKINTEGER(OP_LONG, long)
  165. UNPACKINTEGER(OP_ULONG, unsigned long)
  166. case ' ': case ',':
  167. break;
  168. default:
  169. return badcode(v,c);
  170. break;
  171. }
  172. }
  173. done:
  174. SQInteger nelm = sq_gettop(v) - _top_ - 1; //-1 because first sq_pushnull
  175. if(nelm > 0)
  176. {
  177. SQInteger arraypos = _top_ +1;
  178. sq_newarray(v, nelm);
  179. sq_replace(v, arraypos);
  180. for(SQInteger i=nelm-1; i >= 0; --i)
  181. {
  182. sq_arrayset(v, arraypos, i);
  183. }
  184. }
  185. return 1;
  186. }
  187. #define PACKINTEGER(OP,T) \
  188. case OP: \
  189. { \
  190. SQ_GET_INTEGER(v, i++, inum); \
  191. T a=(T)inum; \
  192. doswap(swap,&a,sizeof(a)); \
  193. b.Write((void*)&a,sizeof(a)); \
  194. break; \
  195. }
  196. #define PACKFLOAT(OP,T) \
  197. case OP: \
  198. { \
  199. SQ_GET_FLOAT(v, i++, fnum); \
  200. T a=(T)fnum; \
  201. doswap(swap,&a,sizeof(a)); \
  202. b.Write((void*)&a,sizeof(a)); \
  203. break; \
  204. }
  205. #define PACKSTRING(OP,T) \
  206. case OP: \
  207. { \
  208. SQ_GET_STRING(v, i++, str); \
  209. T ll=(T)str_size; \
  210. doswap(swap,&ll,sizeof(ll)); \
  211. b.Write((void*)&ll,sizeof(ll)); \
  212. b.Write(str, str_size); \
  213. break; \
  214. }
  215. static SQRESULT sq_pack_base(HSQUIRRELVM v, int toUserdata) /** pack(f,...) */
  216. {
  217. SQ_FUNC_VARS_NO_TOP(v);
  218. SQ_GET_STRING(v, 2, f);
  219. int i=3;
  220. int swap=0;
  221. SQBlob b(0, 8192);
  222. while (*f)
  223. {
  224. int c=*f++;
  225. int N=1;
  226. if (isdigit(*f))
  227. {
  228. N=0;
  229. while (isdigit(*f)) N=10*N+(*f++)-'0';
  230. }
  231. while (N--) switch (c)
  232. {
  233. case OP_LITTLEENDIAN:
  234. case OP_BIGENDIAN:
  235. case OP_NATIVE:
  236. {
  237. swap=doendian(c);
  238. N=0;
  239. break;
  240. }
  241. case OP_STRING:
  242. case OP_ZSTRING:
  243. {
  244. SQ_GET_STRING(v, i++, str);
  245. b.Write(str, str_size+(c==OP_ZSTRING));
  246. break;
  247. }
  248. PACKSTRING(OP_BSTRING, unsigned char)
  249. PACKSTRING(OP_WSTRING, unsigned short)
  250. PACKSTRING(OP_SSTRING, size_t)
  251. PACKFLOAT(OP_DOUBLE, double)
  252. PACKFLOAT(OP_FLOAT, float)
  253. PACKINTEGER(OP_CHAR, char)
  254. PACKINTEGER(OP_BYTE, unsigned char)
  255. PACKINTEGER(OP_SHORT, short)
  256. PACKINTEGER(OP_USHORT, unsigned short)
  257. PACKINTEGER(OP_INT, int)
  258. PACKINTEGER(OP_UINT, unsigned int)
  259. PACKINTEGER(OP_LONG, long)
  260. PACKINTEGER(OP_ULONG, unsigned long)
  261. case ' ': case ',':
  262. break;
  263. default:
  264. return badcode(v,c);
  265. break;
  266. }
  267. }
  268. if(toUserdata)
  269. {
  270. SQUserPointer ptr = sq_newuserdata(v, b.Len());
  271. memcpy(ptr, b.GetBuf(), b.Len());
  272. }
  273. else sq_pushstring(v, (SQChar*)b.GetBuf(), b.Len());
  274. return 1;
  275. }
  276. static SQRESULT sq_pack(HSQUIRRELVM v) /** pack(f,...) */
  277. {
  278. return sq_pack_base(v, 0);
  279. }
  280. static SQRESULT sq_pack_to_userdata(HSQUIRRELVM v) /** pack(f,...) */
  281. {
  282. return sq_pack_base(v, 1);
  283. }
  284. static SQRESULT sq_pushmem(HSQUIRRELVM v) /** pushmem(size) */
  285. {
  286. SQ_FUNC_VARS_NO_TOP(v);
  287. SQ_GET_INTEGER(v, 2, mem_size);
  288. sq_newuserdata(v, mem_size);
  289. return 1;
  290. }
  291. static SQRESULT sq_getaddress(HSQUIRRELVM v) /** getaddress(udata) */
  292. {
  293. SQUserPointer ptr = 0;
  294. sq_getuserdata(v, -1, &ptr, NULL);
  295. sq_pushinteger(v, (SQInteger)ptr);
  296. return 1;
  297. }
  298. #define _DECL_FUNC(name,nparams,tycheck) {_SC(#name),sq_##name,nparams,tycheck}
  299. static SQRegFunction sq_pack_methods[] =
  300. {
  301. _DECL_FUNC(pack,-3,_SC(".s.")),
  302. _DECL_FUNC(pack_to_userdata,-3,_SC(".s.")),
  303. _DECL_FUNC(unpack,-3,_SC(".s|usi")),
  304. _DECL_FUNC(pushmem,2,_SC(".i")),
  305. _DECL_FUNC(getaddress,2,_SC(".u")),
  306. {0,0}
  307. };
  308. #undef _DECL_FUNC
  309. #ifdef __cplusplus
  310. extern "C" {
  311. #endif
  312. SQRESULT sqext_register_pack(HSQUIRRELVM v)
  313. {
  314. sq_pushstring(v,_SC("sqpack"),-1);
  315. sq_newtable(v);
  316. sq_insert_reg_funcs(v, sq_pack_methods);
  317. sq_newslot(v,-3,SQTrue);
  318. return 0;
  319. }
  320. #ifdef __cplusplus
  321. }
  322. #endif