luat_lib_pack.c 7.8 KB

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