| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368 |
- /*
- @module pack
- @summary 打包和解包格式串
- @version 1.0
- @date 2021.12.20
- @video https://www.bilibili.com/video/BV1Sr4y1n7bP
- @tag LUAT_USE_PACK
- @usage
- --[[
- '<' 设为小端编码
- '>' 设为大端编码
- '=' 大小端遵循本地设置
- 'z' 空字符串,0字节
- 'a' size_t字符串,前4字节表达长度,然后接着是N字节的数据
- 'A' 指定长度字符串, 例如A8, 代表8字节的数据
- 'f' float, 4字节
- 'd' double , 8字节
- 'n' Lua number , 32bit固件4字节, 64bit固件8字节
- 'c' char , 1字节
- 'b' byte = unsigned char , 1字节
- 'h' short , 2字节
- 'H' unsigned short , 2字节
- 'i' int , 4字节
- 'I' unsigned int , 4字节
- 'l' long , 8字节, 仅64bit固件能正确获取
- 'L' unsigned long , 8字节, 仅64bit固件能正确获取
- ]]
- -- 详细用法请查看demo
- */
- #define OP_ZSTRING 'z' /* zero-terminated string */
- #define OP_BSTRING 'p' /* string preceded by length byte */
- #define OP_WSTRING 'P' /* string preceded by length word */
- #define OP_SSTRING 'a' /* string preceded by length size_t */
- #define OP_STRING 'A' /* string */
- #define OP_FLOAT 'f' /* float */
- #define OP_DOUBLE 'd' /* double */
- #define OP_NUMBER 'n' /* Lua number */
- #define OP_CHAR 'c' /* char */
- #define OP_BYTE 'b' /* byte = unsigned char */
- #define OP_SHORT 'h' /* short */
- #define OP_USHORT 'H' /* unsigned short */
- #define OP_INT 'i' /* int */
- #define OP_UINT 'I' /* unsigned int */
- #define OP_LONG 'l' /* long */
- #define OP_ULONG 'L' /* unsigned long */
- #define OP_LITTLEENDIAN '<' /* little endian */
- #define OP_BIGENDIAN '>' /* big endian */
- #define OP_NATIVE '=' /* native endian */
- #include <ctype.h>
- #include <string.h>
- #include "lua.h"
- #include "lualib.h"
- #include "lauxlib.h"
- #define LUAT_LOG_TAG "pack"
- #include "luat_log.h"
- static void badcode(lua_State *L, int c)
- {
- char s[]="bad code `?'";
- s[sizeof(s)-3]=c;
- luaL_argerror(L,1,s);
- }
- static int doendian(int c)
- {
- int x=1;
- int e=*(char*)&x;
- if (c==OP_LITTLEENDIAN) return !e;
- if (c==OP_BIGENDIAN) return e;
- if (c==OP_NATIVE) return 0;
- return 0;
- }
- static void doswap(int swap, void *p, size_t n)
- {
- if (swap)
- {
- char *a=p;
- int i,j;
- for (i=0, j=n-1, n=n/2; n--; i++, j--)
- {
- char t=a[i]; a[i]=a[j]; a[j]=t;
- }
- }
- }
- #define UNPACKNUMBER(OP,T) \
- case OP: \
- { \
- T a; \
- int m=sizeof(a); \
- if (i+m>len) goto done; \
- memcpy(&a,s+i,m); \
- i+=m; \
- doswap(swap,&a,m); \
- lua_pushnumber(L,(lua_Number)a); \
- ++n; \
- break; \
- }
- #define UNPACKINT(OP,T) \
- case OP: \
- { \
- T a; \
- int m=sizeof(a); \
- if (i+m>len) goto done; \
- memcpy(&a,s+i,m); \
- i+=m; \
- doswap(swap,&a,m); \
- lua_pushinteger(L,(lua_Integer)a); \
- ++n; \
- break; \
- }
- #define UNPACKINT8(OP,T) \
- case OP: \
- { \
- T a; \
- int m=sizeof(a); \
- if (i+m>len) goto done; \
- memcpy(&a,s+i,m); \
- i+=m; \
- doswap(swap,&a,m); \
- int t = (a & 0x80)?(0xffffff00+a):a;\
- lua_pushinteger(L,(lua_Integer)t); \
- ++n; \
- break; \
- }
- #define UNPACKSTRING(OP,T) \
- case OP: \
- { \
- T l; \
- int m=sizeof(l); \
- if (i+m>len) goto done; \
- memcpy(&l,s+i,m); \
- doswap(swap,&l,m); \
- if (i+m+l>len) goto done; \
- i+=m; \
- lua_pushlstring(L,s+i,l); \
- i+=l; \
- ++n; \
- break; \
- }
- /*
- 解包字符串
- @api pack.unpack( string, format, init)
- @string 需解包的字符串
- @string 格式化符号
- @int 默认值为1,标记解包开始的位置
- @return int 字符串标记的位置
- @return any 第一个解包的值, 根据format值,可能有N个返回值
- @usage
- local _,a = pack.unpack(x,">h") --解包成short (2字节)
- */
- static int l_unpack(lua_State *L)
- {
- size_t len;
- const char *s=luaL_checklstring(L,1,&len);
- const unsigned char *f= (const unsigned char*)luaL_checkstring(L,2);
- int i=luaL_optnumber(L,3,1)-1;
- int n=0;
- int swap=0;
- lua_pushnil(L);
- while (*f)
- {
- int c=*f++;
- int N=1;
- if (isdigit(*f))
- {
- N=0;
- while (isdigit(*f)) N=10*N+(*f++)-'0';
- if (N==0 && c==OP_STRING) { lua_pushliteral(L,""); ++n; }
- }
- while (N--) {
- if (!lua_checkstack(L, n))
- return luaL_error(L, "too many results to unpack");
- switch (c)
- {
-
- case OP_LITTLEENDIAN:
- case OP_BIGENDIAN:
- case OP_NATIVE:
- {
- swap=doendian(c);
- N=0;
- break;
- }
- case OP_STRING:
- {
- ++N;
- if (i+N>len) goto done;
- lua_pushlstring(L,s+i,N);
- i+=N;
- ++n;
- N=0;
- break;
- }
- case OP_ZSTRING:
- {
- size_t l;
- if (i>=len) goto done;
- l=strlen(s+i);
- lua_pushlstring(L,s+i,l);
- i+=l+1;
- ++n;
- break;
- }
- UNPACKSTRING(OP_BSTRING, unsigned char)
- UNPACKSTRING(OP_WSTRING, unsigned short)
- UNPACKSTRING(OP_SSTRING, size_t)
- UNPACKNUMBER(OP_NUMBER, lua_Number)
- #ifndef LUA_NUMBER_INTEGRAL
- UNPACKNUMBER(OP_DOUBLE, double)
- UNPACKNUMBER(OP_FLOAT, float)
- #endif
- UNPACKINT8(OP_CHAR, int8_t)
- UNPACKINT(OP_BYTE, uint8_t)
- UNPACKINT(OP_SHORT, int16_t)
- UNPACKINT(OP_USHORT, uint16_t)
- UNPACKINT(OP_INT, int32_t)
- UNPACKINT(OP_UINT, uint32_t)
- UNPACKINT(OP_LONG, int64_t)
- UNPACKINT(OP_ULONG, uint64_t)
- case ' ': case ',':
- break;
- default:
- badcode(L,c);
- break;
- }
- }
- }
- done:
- lua_pushinteger(L,i+1);
- lua_replace(L,-n-2);
- return n+1;
- }
- #define PACKNUMBER(OP,T) \
- case OP: \
- { \
- T a=(T)luaL_checknumber(L,i++); \
- doswap(swap,&a,sizeof(a)); \
- luaL_addlstring(&b,(void*)&a,sizeof(a)); \
- break; \
- }
- #define PACKINT(OP,T) \
- case OP: \
- { \
- T a=(T)luaL_checkinteger(L,i++); \
- doswap(swap,&a,sizeof(a)); \
- luaL_addlstring(&b,(void*)&a,sizeof(a)); \
- break; \
- }
- #define PACKSTRING(OP,T) \
- case OP: \
- { \
- size_t l; \
- const char *a=luaL_checklstring(L,i++,&l); \
- T ll=(T)l; \
- doswap(swap,&ll,sizeof(ll)); \
- luaL_addlstring(&b,(void*)&ll,sizeof(ll)); \
- luaL_addlstring(&b,a,l); \
- break; \
- }
- /*
- 打包字符串的值
- @api pack.pack( format, val1, val2, val3, valn )
- @string format 格式化符号
- @any 第一个需打包的值
- @any 第二个需打包的值
- @any 第二个需打包的值
- @any 第n个需打包的值
- @return string 一个包含所有格式化变量的字符串
- @usage
- local data = pack.pack('<h', crypto.crc16("MODBUS", val))
- log.info("data", data, data:toHex())
- */
- static int l_pack(lua_State *L)
- {
- int i=2;
- const unsigned char *f=(const unsigned char*)luaL_checkstring(L,1);
- int swap=0;
- luaL_Buffer b;
- luaL_buffinit(L,&b);
- while (*f)
- {
- int c=*f++;
- int N=1;
- if (isdigit(*f))
- {
- N=0;
- while (isdigit(*f)) N=10*N+(*f++)-'0';
- }
- while (N--) switch (c)
- {
- case OP_LITTLEENDIAN:
- case OP_BIGENDIAN:
- case OP_NATIVE:
- {
- swap=doendian(c);
- N=0;
- break;
- }
- case OP_STRING:
- case OP_ZSTRING:
- {
- size_t l;
- const char *a=luaL_checklstring(L,i++,&l);
- luaL_addlstring(&b,a,l+(c==OP_ZSTRING));
- break;
- }
- PACKSTRING(OP_BSTRING, unsigned char)
- PACKSTRING(OP_WSTRING, unsigned short)
- PACKSTRING(OP_SSTRING, size_t)
- PACKNUMBER(OP_NUMBER, lua_Number)
- #ifndef LUA_NUMBER_INTEGRAL
- PACKNUMBER(OP_DOUBLE, double)
- PACKNUMBER(OP_FLOAT, float)
- #endif
- PACKINT(OP_CHAR, char)
- PACKINT(OP_BYTE, uint8_t)
- PACKINT(OP_SHORT, int16_t)
- PACKINT(OP_USHORT, uint16_t)
- PACKINT(OP_INT, int32_t)
- PACKINT(OP_UINT, uint32_t)
- PACKINT(OP_LONG, int64_t)
- PACKINT(OP_ULONG, uint64_t)
- case ' ': case ',':
- break;
- default:
- badcode(L,c);
- break;
- }
- }
- luaL_pushresult(&b);
- return 1;
- }
- int luat_pack(lua_State *L) {
- return l_pack(L);
- }
- int luat_unpack(lua_State *L) {
- return l_unpack(L);
- }
- #include "rotable2.h"
- static const rotable_Reg_t reg_pack[] =
- {
- {"pack", ROREG_FUNC(l_pack)},
- {"unpack", ROREG_FUNC(l_unpack)},
- {NULL, ROREG_INT(0) }
- };
- LUAMOD_API int luaopen_pack( lua_State *L ) {
- luat_newlib2(L, reg_pack);
- return 1;
- }
|