| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345 |
- /*
- * lpack.c
- * a Lua library for packing and unpacking binary data
- * Luiz Henrique de Figueiredo <[email protected]>
- * 29 Jun 2007 19:27:20
- * This code is hereby placed in the public domain.
- * with contributions from Ignacio Castaño <[email protected]> and
- * Roberto Ierusalimschy <[email protected]>.
- *
- * Ported to SquiLu by Domingo Alvarez Duarte [email protected] on 21/09/2016
- */
- #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_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 "squirrel.h"
- #include "sqstdblobimpl.h"
- SQ_OPT_STRING_STRLEN();
- static SQRESULT badcode(HSQUIRRELVM v, int c)
- {
- SQChar s[]=_SC("bad code '?'");
- s[sizeof(s)-(3*sizeof(SQChar))]=c;
- return sq_throwerror(v,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=(char*)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_T(OP,T, SQ_P, SQ_T) \
- case OP: \
- { \
- T a; \
- int m=sizeof(a); \
- if (i+m>s_size) goto done; \
- memcpy(&a,s+i,m); \
- i+=m; \
- doswap(swap,&a,m); \
- SQ_P(v,(SQ_T)a); \
- ++n; \
- break; \
- }
- #define UNPACKFLOAT(OP, T) UNPACKNUMBER_T(OP, T, sq_pushfloat, SQFloat)
- #define UNPACKINTEGER(OP, T) UNPACKNUMBER_T(OP, T, sq_pushinteger, SQInteger)
- #define UNPACKSTRING(OP,T) \
- case OP: \
- { \
- T l; \
- int m=sizeof(l); \
- if (i+m>s_size) goto done; \
- memcpy(&l,s+i,m); \
- doswap(swap,&l,m); \
- if (i+m+l>s_size) goto done; \
- i+=m; \
- sq_pushstring(v,s+i,l); \
- i+=l; \
- ++n; \
- break; \
- }
- static SQRESULT sq_unpack(HSQUIRRELVM v) /** unpack(s,f,[init]) */
- {
- SQ_FUNC_VARS(v);
- const SQChar *s;
- SQInteger s_size;
- SQObjectType ot = sq_gettype(v, 2);
- switch(ot)
- {
- case OT_STRING: sq_getstr_and_size(v, 2, &s, &s_size); break;
- case OT_USERDATA:
- sq_getuserdata(v, 2, (SQUserPointer*)&s, NULL);
- s_size = sq_getsize(v, 2);
- break;
- default:
- return sq_throwerror(v, _SC("unexpected type %d for parameter 1"), ot);
- }
- SQ_GET_STRING(v, 3, f);
- SQ_OPT_INTEGER(v,4, i, 0);
- SQInteger n=0;
- int swap=0;
- sq_pushnull(v);
- 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) { sq_pushliteral(v,_SC("")); ++n; }
- }
- while (N--) switch (c)
- {
- case OP_LITTLEENDIAN:
- case OP_BIGENDIAN:
- case OP_NATIVE:
- {
- swap=doendian(c);
- N=0;
- break;
- }
- case OP_STRING:
- {
- ++N;
- if (i+N>s_size) goto done;
- sq_pushstring(v,s+i,N);
- i+=N;
- ++n;
- N=0;
- break;
- }
- case OP_ZSTRING:
- {
- size_t l;
- if (i>=s_size) goto done;
- l=strlen(s+i);
- sq_pushstring(v,s+i,l);
- i+=l+1;
- ++n;
- break;
- }
- UNPACKSTRING(OP_BSTRING, unsigned char)
- UNPACKSTRING(OP_WSTRING, unsigned short)
- UNPACKSTRING(OP_SSTRING, size_t)
- UNPACKFLOAT(OP_DOUBLE, double)
- UNPACKFLOAT(OP_FLOAT, float)
- UNPACKINTEGER(OP_CHAR, char)
- UNPACKINTEGER(OP_BYTE, unsigned char)
- UNPACKINTEGER(OP_SHORT, short)
- UNPACKINTEGER(OP_USHORT, unsigned short)
- UNPACKINTEGER(OP_INT, int)
- UNPACKINTEGER(OP_UINT, unsigned int)
- UNPACKINTEGER(OP_LONG, long)
- UNPACKINTEGER(OP_ULONG, unsigned long)
- case ' ': case ',':
- break;
- default:
- return badcode(v,c);
- break;
- }
- }
- done:
- SQInteger nelm = sq_gettop(v) - _top_ - 1; //-1 because first sq_pushnull
- if(nelm > 0)
- {
- SQInteger arraypos = _top_ +1;
- sq_newarray(v, nelm);
- sq_replace(v, arraypos);
- for(SQInteger i=nelm-1; i >= 0; --i)
- {
- sq_arrayset(v, arraypos, i);
- }
- }
- return 1;
- }
- #define PACKINTEGER(OP,T) \
- case OP: \
- { \
- SQ_GET_INTEGER(v, i++, inum); \
- T a=(T)inum; \
- doswap(swap,&a,sizeof(a)); \
- b.Write((void*)&a,sizeof(a)); \
- break; \
- }
- #define PACKFLOAT(OP,T) \
- case OP: \
- { \
- SQ_GET_FLOAT(v, i++, fnum); \
- T a=(T)fnum; \
- doswap(swap,&a,sizeof(a)); \
- b.Write((void*)&a,sizeof(a)); \
- break; \
- }
- #define PACKSTRING(OP,T) \
- case OP: \
- { \
- SQ_GET_STRING(v, i++, str); \
- T ll=(T)str_size; \
- doswap(swap,&ll,sizeof(ll)); \
- b.Write((void*)&ll,sizeof(ll)); \
- b.Write(str, str_size); \
- break; \
- }
- static SQRESULT sq_pack_base(HSQUIRRELVM v, int toUserdata) /** pack(f,...) */
- {
- SQ_FUNC_VARS_NO_TOP(v);
- SQ_GET_STRING(v, 2, f);
- int i=3;
- int swap=0;
- SQBlob b(0, 8192);
- 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:
- {
- SQ_GET_STRING(v, i++, str);
- b.Write(str, str_size+(c==OP_ZSTRING));
- break;
- }
- PACKSTRING(OP_BSTRING, unsigned char)
- PACKSTRING(OP_WSTRING, unsigned short)
- PACKSTRING(OP_SSTRING, size_t)
- PACKFLOAT(OP_DOUBLE, double)
- PACKFLOAT(OP_FLOAT, float)
- PACKINTEGER(OP_CHAR, char)
- PACKINTEGER(OP_BYTE, unsigned char)
- PACKINTEGER(OP_SHORT, short)
- PACKINTEGER(OP_USHORT, unsigned short)
- PACKINTEGER(OP_INT, int)
- PACKINTEGER(OP_UINT, unsigned int)
- PACKINTEGER(OP_LONG, long)
- PACKINTEGER(OP_ULONG, unsigned long)
- case ' ': case ',':
- break;
- default:
- return badcode(v,c);
- break;
- }
- }
- if(toUserdata)
- {
- SQUserPointer ptr = sq_newuserdata(v, b.Len());
- memcpy(ptr, b.GetBuf(), b.Len());
- }
- else sq_pushstring(v, (SQChar*)b.GetBuf(), b.Len());
- return 1;
- }
- static SQRESULT sq_pack(HSQUIRRELVM v) /** pack(f,...) */
- {
- return sq_pack_base(v, 0);
- }
- static SQRESULT sq_pack_to_userdata(HSQUIRRELVM v) /** pack(f,...) */
- {
- return sq_pack_base(v, 1);
- }
- static SQRESULT sq_pushmem(HSQUIRRELVM v) /** pushmem(size) */
- {
- SQ_FUNC_VARS_NO_TOP(v);
- SQ_GET_INTEGER(v, 2, mem_size);
- sq_newuserdata(v, mem_size);
- return 1;
- }
- static SQRESULT sq_getaddress(HSQUIRRELVM v) /** getaddress(udata) */
- {
- SQUserPointer ptr = 0;
- sq_getuserdata(v, -1, &ptr, NULL);
- sq_pushinteger(v, (SQInteger)ptr);
- return 1;
- }
- #define _DECL_FUNC(name,nparams,tycheck) {_SC(#name),sq_##name,nparams,tycheck}
- static SQRegFunction sq_pack_methods[] =
- {
- _DECL_FUNC(pack,-3,_SC(".s.")),
- _DECL_FUNC(pack_to_userdata,-3,_SC(".s.")),
- _DECL_FUNC(unpack,-3,_SC(".s|usi")),
- _DECL_FUNC(pushmem,2,_SC(".i")),
- _DECL_FUNC(getaddress,2,_SC(".u")),
- {0,0}
- };
- #undef _DECL_FUNC
- #ifdef __cplusplus
- extern "C" {
- #endif
- SQRESULT sqext_register_pack(HSQUIRRELVM v)
- {
- sq_pushstring(v,_SC("sqpack"),-1);
- sq_newtable(v);
- sq_insert_reg_funcs(v, sq_pack_methods);
- sq_newslot(v,-3,SQTrue);
- return 0;
- }
- #ifdef __cplusplus
- }
- #endif
|