update: 更新aliyun库及其demo
[LuatOS.git] / luat / modules / luat_lib_pack.c
blob19af3e027e7852b4eb7e95ee31b51d0fa4c84231
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固件能正确获取
29 -- 详细用法请查看demo
32 #define OP_ZSTRING 'z' /* zero-terminated string */
33 #define OP_BSTRING 'p' /* string preceded by length byte */
34 #define OP_WSTRING 'P' /* string preceded by length word */
35 #define OP_SSTRING 'a' /* string preceded by length size_t */
36 #define OP_STRING 'A' /* string */
37 #define OP_FLOAT 'f' /* float */
38 #define OP_DOUBLE 'd' /* double */
39 #define OP_NUMBER 'n' /* Lua number */
40 #define OP_CHAR 'c' /* char */
41 #define OP_BYTE 'b' /* byte = unsigned char */
42 #define OP_SHORT 'h' /* short */
43 #define OP_USHORT 'H' /* unsigned short */
44 #define OP_INT 'i' /* int */
45 #define OP_UINT 'I' /* unsigned int */
46 #define OP_LONG 'l' /* long */
47 #define OP_ULONG 'L' /* unsigned long */
48 #define OP_LITTLEENDIAN '<' /* little endian */
49 #define OP_BIGENDIAN '>' /* big endian */
50 #define OP_NATIVE '=' /* native endian */
52 #include <ctype.h>
53 #include <string.h>
55 #include "lua.h"
56 #include "lualib.h"
57 #include "lauxlib.h"
59 #define LUAT_LOG_TAG "pack"
60 #include "luat_log.h"
62 static void badcode(lua_State *L, int c)
64 char s[]="bad code `?'";
65 s[sizeof(s)-3]=c;
66 luaL_argerror(L,1,s);
69 static int doendian(int c)
71 int x=1;
72 int e=*(char*)&x;
73 if (c==OP_LITTLEENDIAN) return !e;
74 if (c==OP_BIGENDIAN) return e;
75 if (c==OP_NATIVE) return 0;
76 return 0;
79 static void doswap(int swap, void *p, size_t n)
81 if (swap)
83 char *a=p;
84 int i,j;
85 for (i=0, j=n-1, n=n/2; n--; i++, j--)
87 char t=a[i]; a[i]=a[j]; a[j]=t;
92 #define UNPACKNUMBER(OP,T) \
93 case OP: \
94 { \
95 T a; \
96 int m=sizeof(a); \
97 if (i+m>len) goto done; \
98 memcpy(&a,s+i,m); \
99 i+=m; \
100 doswap(swap,&a,m); \
101 lua_pushnumber(L,(lua_Number)a); \
102 ++n; \
103 break; \
106 #define UNPACKINT(OP,T) \
107 case OP: \
109 T a; \
110 int m=sizeof(a); \
111 if (i+m>len) goto done; \
112 memcpy(&a,s+i,m); \
113 i+=m; \
114 doswap(swap,&a,m); \
115 lua_pushinteger(L,(lua_Integer)a); \
116 ++n; \
117 break; \
120 #define UNPACKINT8(OP,T) \
121 case OP: \
123 T a; \
124 int m=sizeof(a); \
125 if (i+m>len) goto done; \
126 memcpy(&a,s+i,m); \
127 i+=m; \
128 doswap(swap,&a,m); \
129 int t = (a & 0x80)?(0xffffff00+a):a;\
130 lua_pushinteger(L,(lua_Integer)t); \
131 ++n; \
132 break; \
135 #define UNPACKSTRING(OP,T) \
136 case OP: \
138 T l; \
139 int m=sizeof(l); \
140 if (i+m>len) goto done; \
141 memcpy(&l,s+i,m); \
142 doswap(swap,&l,m); \
143 if (i+m+l>len) goto done; \
144 i+=m; \
145 lua_pushlstring(L,s+i,l); \
146 i+=l; \
147 ++n; \
148 break; \
152 解包字符串
153 @api pack.unpack( string, format, init)
154 @string 需解包的字符串
155 @string 格式化符号
156 @int 默认值为1,标记解包开始的位置
157 @return int 字符串标记的位置
158 @return any 第一个解包的值, 根据format值,可能有N个返回值
159 @usage
160 local _,a = pack.unpack(x,">h") --解包成short (2字节)
162 static int l_unpack(lua_State *L)
164 size_t len;
165 const char *s=luaL_checklstring(L,1,&len);
166 const unsigned char *f= (const unsigned char*)luaL_checkstring(L,2);
167 int i=luaL_optnumber(L,3,1)-1;
168 int n=0;
169 int swap=0;
170 lua_pushnil(L);
171 while (*f)
173 int c=*f++;
174 int N=1;
175 if (isdigit(*f))
177 N=0;
178 while (isdigit(*f)) N=10*N+(*f++)-'0';
179 if (N==0 && c==OP_STRING) { lua_pushliteral(L,""); ++n; }
181 while (N--) {
182 if (!lua_checkstack(L, n))
183 return luaL_error(L, "too many results to unpack");
184 switch (c)
187 case OP_LITTLEENDIAN:
188 case OP_BIGENDIAN:
189 case OP_NATIVE:
191 swap=doendian(c);
192 N=0;
193 break;
195 case OP_STRING:
197 ++N;
198 if (i+N>len) goto done;
199 lua_pushlstring(L,s+i,N);
200 i+=N;
201 ++n;
202 N=0;
203 break;
205 case OP_ZSTRING:
207 size_t l;
208 if (i>=len) goto done;
209 l=strlen(s+i);
210 lua_pushlstring(L,s+i,l);
211 i+=l+1;
212 ++n;
213 break;
215 UNPACKSTRING(OP_BSTRING, unsigned char)
216 UNPACKSTRING(OP_WSTRING, unsigned short)
217 UNPACKSTRING(OP_SSTRING, size_t)
218 UNPACKNUMBER(OP_NUMBER, lua_Number)
219 #ifndef LUA_NUMBER_INTEGRAL
220 UNPACKNUMBER(OP_DOUBLE, double)
221 UNPACKNUMBER(OP_FLOAT, float)
222 #endif
223 UNPACKINT8(OP_CHAR, char)
224 UNPACKINT(OP_BYTE, unsigned char)
225 UNPACKINT(OP_SHORT, short)
226 UNPACKINT(OP_USHORT, unsigned short)
227 UNPACKINT(OP_INT, int)
228 UNPACKINT(OP_UINT, unsigned int)
229 UNPACKINT(OP_LONG, long)
230 UNPACKINT(OP_ULONG, unsigned long)
231 case ' ': case ',':
232 break;
233 default:
234 badcode(L,c);
235 break;
239 done:
240 lua_pushnumber(L,i+1);
241 lua_replace(L,-n-2);
242 return n+1;
245 #define PACKNUMBER(OP,T) \
246 case OP: \
248 T a=(T)luaL_checknumber(L,i++); \
249 doswap(swap,&a,sizeof(a)); \
250 luaL_addlstring(&b,(void*)&a,sizeof(a)); \
251 break; \
254 #define PACKINT(OP,T) \
255 case OP: \
257 T a=(T)luaL_checkinteger(L,i++); \
258 doswap(swap,&a,sizeof(a)); \
259 luaL_addlstring(&b,(void*)&a,sizeof(a)); \
260 break; \
263 #define PACKSTRING(OP,T) \
264 case OP: \
266 size_t l; \
267 const char *a=luaL_checklstring(L,i++,&l); \
268 T ll=(T)l; \
269 doswap(swap,&ll,sizeof(ll)); \
270 luaL_addlstring(&b,(void*)&ll,sizeof(ll)); \
271 luaL_addlstring(&b,a,l); \
272 break; \
276 打包字符串的值
277 @api pack.pack( format, val1, val2, val3, valn )
278 @string format 格式化符号
279 @any 第一个需打包的值
280 @any 第二个需打包的值
281 @any 第二个需打包的值
282 @any 第n个需打包的值
283 @return string 一个包含所有格式化变量的字符串
284 @usage
285 local data = pack.pack('<h', crypto.crc16("MODBUS", val))
286 log.info("data", data, data:toHex())
288 static int l_pack(lua_State *L)
290 int i=2;
291 const unsigned char *f=(const unsigned char*)luaL_checkstring(L,1);
292 int swap=0;
293 luaL_Buffer b;
294 luaL_buffinit(L,&b);
295 while (*f)
297 int c=*f++;
298 int N=1;
299 if (isdigit(*f))
301 N=0;
302 while (isdigit(*f)) N=10*N+(*f++)-'0';
304 while (N--) switch (c)
306 case OP_LITTLEENDIAN:
307 case OP_BIGENDIAN:
308 case OP_NATIVE:
310 swap=doendian(c);
311 N=0;
312 break;
314 case OP_STRING:
315 case OP_ZSTRING:
317 size_t l;
318 const char *a=luaL_checklstring(L,i++,&l);
319 luaL_addlstring(&b,a,l+(c==OP_ZSTRING));
320 break;
322 PACKSTRING(OP_BSTRING, unsigned char)
323 PACKSTRING(OP_WSTRING, unsigned short)
324 PACKSTRING(OP_SSTRING, size_t)
325 PACKNUMBER(OP_NUMBER, lua_Number)
326 #ifndef LUA_NUMBER_INTEGRAL
327 PACKNUMBER(OP_DOUBLE, double)
328 PACKNUMBER(OP_FLOAT, float)
329 #endif
330 PACKINT(OP_CHAR, char)
331 PACKINT(OP_BYTE, unsigned char)
332 PACKINT(OP_SHORT, short)
333 PACKINT(OP_USHORT, unsigned short)
334 PACKINT(OP_INT, int)
335 PACKINT(OP_UINT, unsigned int)
336 PACKINT(OP_LONG, long)
337 PACKINT(OP_ULONG, unsigned long)
338 case ' ': case ',':
339 break;
340 default:
341 badcode(L,c);
342 break;
345 luaL_pushresult(&b);
346 return 1;
349 int luat_pack(lua_State *L) {
350 return l_pack(L);
353 int luat_unpack(lua_State *L) {
354 return l_unpack(L);
357 #include "rotable2.h"
358 static const rotable_Reg_t reg_pack[] =
360 {"pack", ROREG_FUNC(l_pack)},
361 {"unpack", ROREG_FUNC(l_unpack)},
362 {NULL, ROREG_INT(0) }
365 LUAMOD_API int luaopen_pack( lua_State *L ) {
366 luat_newlib2(L, reg_pack);
367 return 1;