luat_lib_pack.c 7.9 KB

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