luat_lib_pack.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. /*
  2. @module pack
  3. @summary 打包和解包格式串
  4. @version 1.0
  5. @date 2021.12.20
  6. @video https://www.bilibili.com/video/BV1Sr4y1n7bP
  7. @tag LUAT_USE_PACK
  8. @usage
  9. --[[
  10. '<' 设为小端编码
  11. '>' 设为大端编码
  12. '=' 大小端遵循本地设置
  13. 'z' 空字符串,0字节
  14. 'a' size_t字符串,前4字节表达长度,然后接着是N字节的数据
  15. 'A' 指定长度字符串, 例如A8, 代表8字节的数据
  16. 'f' float, 4字节
  17. 'd' double , 8字节
  18. 'n' Lua number , 32bit固件4字节, 64bit固件8字节
  19. 'c' char , 1字节
  20. 'b' byte = unsigned char , 1字节
  21. 'h' short , 2字节
  22. 'H' unsigned short , 2字节
  23. 'i' int , 4字节
  24. 'I' unsigned int , 4字节
  25. 'l' long , 8字节, 仅64bit固件能正确获取
  26. 'L' unsigned long , 8字节, 仅64bit固件能正确获取
  27. ]]
  28. -- 详细用法请查看demo
  29. */
  30. #define OP_ZSTRING 'z' /* zero-terminated string */
  31. #define OP_BSTRING 'p' /* string preceded by length byte */
  32. #define OP_WSTRING 'P' /* string preceded by length word */
  33. #define OP_SSTRING 'a' /* string preceded by length size_t */
  34. #define OP_STRING 'A' /* string */
  35. #define OP_FLOAT 'f' /* float */
  36. #define OP_DOUBLE 'd' /* double */
  37. #define OP_NUMBER 'n' /* Lua number */
  38. #define OP_CHAR 'c' /* char */
  39. #define OP_BYTE 'b' /* byte = unsigned char */
  40. #define OP_SHORT 'h' /* short */
  41. #define OP_USHORT 'H' /* unsigned short */
  42. #define OP_INT 'i' /* int */
  43. #define OP_UINT 'I' /* unsigned int */
  44. #define OP_LONG 'l' /* long */
  45. #define OP_ULONG 'L' /* unsigned long */
  46. #define OP_LITTLEENDIAN '<' /* little endian */
  47. #define OP_BIGENDIAN '>' /* big endian */
  48. #define OP_NATIVE '=' /* native endian */
  49. #include <ctype.h>
  50. #include <string.h>
  51. #include "lua.h"
  52. #include "lualib.h"
  53. #include "lauxlib.h"
  54. #define LUAT_LOG_TAG "pack"
  55. #include "luat_log.h"
  56. static void badcode(lua_State *L, int c)
  57. {
  58. char s[]="bad code `?'";
  59. s[sizeof(s)-3]=c;
  60. luaL_argerror(L,1,s);
  61. }
  62. static int doendian(int c)
  63. {
  64. int x=1;
  65. int e=*(char*)&x;
  66. if (c==OP_LITTLEENDIAN) return !e;
  67. if (c==OP_BIGENDIAN) return e;
  68. if (c==OP_NATIVE) return 0;
  69. return 0;
  70. }
  71. static void doswap(int swap, void *p, size_t n)
  72. {
  73. if (swap)
  74. {
  75. char *a=p;
  76. int i,j;
  77. for (i=0, j=n-1, n=n/2; n--; i++, j--)
  78. {
  79. char t=a[i]; a[i]=a[j]; a[j]=t;
  80. }
  81. }
  82. }
  83. #define UNPACKNUMBER(OP,T) \
  84. case OP: \
  85. { \
  86. T a; \
  87. int m=sizeof(a); \
  88. if (i+m>len) goto done; \
  89. memcpy(&a,s+i,m); \
  90. i+=m; \
  91. doswap(swap,&a,m); \
  92. lua_pushnumber(L,(lua_Number)a); \
  93. ++n; \
  94. break; \
  95. }
  96. #define UNPACKINT(OP,T) \
  97. case OP: \
  98. { \
  99. T a; \
  100. int m=sizeof(a); \
  101. if (i+m>len) goto done; \
  102. memcpy(&a,s+i,m); \
  103. i+=m; \
  104. doswap(swap,&a,m); \
  105. lua_pushinteger(L,(lua_Integer)a); \
  106. ++n; \
  107. break; \
  108. }
  109. #define UNPACKINT8(OP,T) \
  110. case OP: \
  111. { \
  112. T a; \
  113. int m=sizeof(a); \
  114. if (i+m>len) goto done; \
  115. memcpy(&a,s+i,m); \
  116. i+=m; \
  117. doswap(swap,&a,m); \
  118. int t = (a & 0x80)?(0xffffff00+a):a;\
  119. lua_pushinteger(L,(lua_Integer)t); \
  120. ++n; \
  121. break; \
  122. }
  123. #define UNPACKSTRING(OP,T) \
  124. case OP: \
  125. { \
  126. T l; \
  127. int m=sizeof(l); \
  128. if (i+m>len) goto done; \
  129. memcpy(&l,s+i,m); \
  130. doswap(swap,&l,m); \
  131. if (i+m+l>len) goto done; \
  132. i+=m; \
  133. lua_pushlstring(L,s+i,l); \
  134. i+=l; \
  135. ++n; \
  136. break; \
  137. }
  138. /*
  139. 解包字符串
  140. @api pack.unpack( string, format, init)
  141. @string 需解包的字符串
  142. @string 格式化符号
  143. @int 默认值为1,标记解包开始的位置
  144. @return int 字符串标记的位置
  145. @return any 第一个解包的值, 根据format值,可能有N个返回值
  146. @usage
  147. local _,a = pack.unpack(x,">h") --解包成short (2字节)
  148. */
  149. static int l_unpack(lua_State *L)
  150. {
  151. size_t len;
  152. const char *s=luaL_checklstring(L,1,&len);
  153. const unsigned char *f= (const unsigned char*)luaL_checkstring(L,2);
  154. int i=luaL_optnumber(L,3,1)-1;
  155. int n=0;
  156. int swap=0;
  157. lua_pushnil(L);
  158. while (*f)
  159. {
  160. int c=*f++;
  161. int N=1;
  162. if (isdigit(*f))
  163. {
  164. N=0;
  165. while (isdigit(*f)) N=10*N+(*f++)-'0';
  166. if (N==0 && c==OP_STRING) { lua_pushliteral(L,""); ++n; }
  167. }
  168. while (N--) {
  169. if (!lua_checkstack(L, n))
  170. return luaL_error(L, "too many results to unpack");
  171. switch (c)
  172. {
  173. case OP_LITTLEENDIAN:
  174. case OP_BIGENDIAN:
  175. case OP_NATIVE:
  176. {
  177. swap=doendian(c);
  178. N=0;
  179. break;
  180. }
  181. case OP_STRING:
  182. {
  183. ++N;
  184. if (i+N>len) goto done;
  185. lua_pushlstring(L,s+i,N);
  186. i+=N;
  187. ++n;
  188. N=0;
  189. break;
  190. }
  191. case OP_ZSTRING:
  192. {
  193. size_t l;
  194. if (i>=len) goto done;
  195. l=strlen(s+i);
  196. lua_pushlstring(L,s+i,l);
  197. i+=l+1;
  198. ++n;
  199. break;
  200. }
  201. UNPACKSTRING(OP_BSTRING, unsigned char)
  202. UNPACKSTRING(OP_WSTRING, unsigned short)
  203. UNPACKSTRING(OP_SSTRING, size_t)
  204. UNPACKNUMBER(OP_NUMBER, lua_Number)
  205. #ifndef LUA_NUMBER_INTEGRAL
  206. UNPACKNUMBER(OP_DOUBLE, double)
  207. UNPACKNUMBER(OP_FLOAT, float)
  208. #endif
  209. UNPACKINT8(OP_CHAR, int8_t)
  210. UNPACKINT(OP_BYTE, uint8_t)
  211. UNPACKINT(OP_SHORT, int16_t)
  212. UNPACKINT(OP_USHORT, uint16_t)
  213. UNPACKINT(OP_INT, int32_t)
  214. UNPACKINT(OP_UINT, uint32_t)
  215. UNPACKINT(OP_LONG, int64_t)
  216. UNPACKINT(OP_ULONG, uint64_t)
  217. case ' ': case ',':
  218. break;
  219. default:
  220. badcode(L,c);
  221. break;
  222. }
  223. }
  224. }
  225. done:
  226. lua_pushinteger(L,i+1);
  227. lua_replace(L,-n-2);
  228. return n+1;
  229. }
  230. #define PACKNUMBER(OP,T) \
  231. case OP: \
  232. { \
  233. T a=(T)luaL_checknumber(L,i++); \
  234. doswap(swap,&a,sizeof(a)); \
  235. luaL_addlstring(&b,(void*)&a,sizeof(a)); \
  236. break; \
  237. }
  238. #define PACKINT(OP,T) \
  239. case OP: \
  240. { \
  241. T a=(T)luaL_checkinteger(L,i++); \
  242. doswap(swap,&a,sizeof(a)); \
  243. luaL_addlstring(&b,(void*)&a,sizeof(a)); \
  244. break; \
  245. }
  246. #define PACKSTRING(OP,T) \
  247. case OP: \
  248. { \
  249. size_t l; \
  250. const char *a=luaL_checklstring(L,i++,&l); \
  251. T ll=(T)l; \
  252. doswap(swap,&ll,sizeof(ll)); \
  253. luaL_addlstring(&b,(void*)&ll,sizeof(ll)); \
  254. luaL_addlstring(&b,a,l); \
  255. break; \
  256. }
  257. /*
  258. 打包字符串的值
  259. @api pack.pack( format, val1, val2, val3, valn )
  260. @string format 格式化符号
  261. @any 第一个需打包的值
  262. @any 第二个需打包的值
  263. @any 第二个需打包的值
  264. @any 第n个需打包的值
  265. @return string 一个包含所有格式化变量的字符串
  266. @usage
  267. local data = pack.pack('<h', crypto.crc16("MODBUS", val))
  268. log.info("data", data, data:toHex())
  269. */
  270. static int l_pack(lua_State *L)
  271. {
  272. int i=2;
  273. const unsigned char *f=(const unsigned char*)luaL_checkstring(L,1);
  274. int swap=0;
  275. luaL_Buffer b;
  276. luaL_buffinit(L,&b);
  277. while (*f)
  278. {
  279. int c=*f++;
  280. int N=1;
  281. if (isdigit(*f))
  282. {
  283. N=0;
  284. while (isdigit(*f)) N=10*N+(*f++)-'0';
  285. }
  286. while (N--) switch (c)
  287. {
  288. case OP_LITTLEENDIAN:
  289. case OP_BIGENDIAN:
  290. case OP_NATIVE:
  291. {
  292. swap=doendian(c);
  293. N=0;
  294. break;
  295. }
  296. case OP_STRING:
  297. case OP_ZSTRING:
  298. {
  299. size_t l;
  300. const char *a=luaL_checklstring(L,i++,&l);
  301. luaL_addlstring(&b,a,l+(c==OP_ZSTRING));
  302. break;
  303. }
  304. PACKSTRING(OP_BSTRING, unsigned char)
  305. PACKSTRING(OP_WSTRING, unsigned short)
  306. PACKSTRING(OP_SSTRING, size_t)
  307. PACKNUMBER(OP_NUMBER, lua_Number)
  308. #ifndef LUA_NUMBER_INTEGRAL
  309. PACKNUMBER(OP_DOUBLE, double)
  310. PACKNUMBER(OP_FLOAT, float)
  311. #endif
  312. PACKINT(OP_CHAR, char)
  313. PACKINT(OP_BYTE, uint8_t)
  314. PACKINT(OP_SHORT, int16_t)
  315. PACKINT(OP_USHORT, uint16_t)
  316. PACKINT(OP_INT, int32_t)
  317. PACKINT(OP_UINT, uint32_t)
  318. PACKINT(OP_LONG, int64_t)
  319. PACKINT(OP_ULONG, uint64_t)
  320. case ' ': case ',':
  321. break;
  322. default:
  323. badcode(L,c);
  324. break;
  325. }
  326. }
  327. luaL_pushresult(&b);
  328. return 1;
  329. }
  330. int luat_pack(lua_State *L) {
  331. return l_pack(L);
  332. }
  333. int luat_unpack(lua_State *L) {
  334. return l_unpack(L);
  335. }
  336. #include "rotable2.h"
  337. static const rotable_Reg_t reg_pack[] =
  338. {
  339. {"pack", ROREG_FUNC(l_pack)},
  340. {"unpack", ROREG_FUNC(l_unpack)},
  341. {NULL, ROREG_INT(0) }
  342. };
  343. LUAMOD_API int luaopen_pack( lua_State *L ) {
  344. luat_newlib2(L, reg_pack);
  345. return 1;
  346. }