root/src/modules/lua_lpack.c

Revision e4877df78137b23c4f223a3c99234f053a384b77, 5.5 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 1 year ago)

port this up to lua 5.2

  • Property mode set to 100644
Line 
1 /*
2 * lpack.c
3 * a Lua library for packing and unpacking binary data
4 * Luiz Henrique de Figueiredo <lhf@tecgraf.puc-rio.br>
5 * 29 Jun 2007 19:27:20
6 * This code is hereby placed in the public domain.
7 * with contributions from Ignacio CastaÒo <castanyo@yahoo.es> and
8 * Roberto Ierusalimschy <roberto@inf.puc-rio.br>.
9 */
10
11 #define OP_ZSTRING      'z'             /* zero-terminated string */
12 #define OP_BSTRING      'p'             /* string preceded by length byte */
13 #define OP_WSTRING      'P'             /* string preceded by length word */
14 #define OP_SSTRING      'a'             /* string preceded by length size_t */
15 #define OP_STRING       'A'             /* string */
16 #define OP_FLOAT        'f'             /* float */
17 #define OP_DOUBLE       'd'             /* double */
18 #define OP_NUMBER       'n'             /* Lua number */
19 #define OP_CHAR         'c'             /* char */
20 #define OP_BYTE         'b'             /* byte = unsigned char */
21 #define OP_SHORT        'h'             /* short */
22 #define OP_USHORT       'H'             /* unsigned short */
23 #define OP_INT          'i'             /* int */
24 #define OP_UINT         'I'             /* unsigned int */
25 #define OP_LONG         'l'             /* long */
26 #define OP_ULONG        'L'             /* unsigned long */
27 #define OP_LITTLEENDIAN '<'             /* little endian */
28 #define OP_BIGENDIAN    '>'             /* big endian */
29 #define OP_NATIVE       '='             /* native endian */
30
31 #include <ctype.h>
32 #include <string.h>
33
34 #define LUA_COMPAT_MODULE
35 #include "lua_noit.h"
36
37 static void badcode(lua_State *L, int c)
38 {
39  char s[]="bad code `?'";
40  s[sizeof(s)-3]=c;
41  luaL_argerror(L,1,s);
42 }
43
44 static int doendian(int c)
45 {
46  int x=1;
47  int e=*(char*)&x;
48  if (c==OP_LITTLEENDIAN) return !e;
49  if (c==OP_BIGENDIAN) return e;
50  if (c==OP_NATIVE) return 0;
51  return 0;
52 }
53
54 static void doswap(int swap, void *p, size_t n)
55 {
56  if (swap)
57  {
58   char *a=p;
59   int i,j;
60   for (i=0, j=n-1, n=n/2; n--; i++, j--)
61   {
62    char t=a[i]; a[i]=a[j]; a[j]=t;
63   }
64  }
65 }
66
67 #define UNPACKNUMBER(OP,T)              \
68    case OP:                             \
69    {                                    \
70     T a;                                \
71     int m=sizeof(a);                    \
72     if (i+m>len) goto done;             \
73     memcpy(&a,s+i,m);                   \
74     i+=m;                               \
75     doswap(swap,&a,m);                  \
76     lua_pushnumber(L,(lua_Number)a);    \
77     ++n;                                \
78     break;                              \
79    }
80
81 #define UNPACKSTRING(OP,T)              \
82    case OP:                             \
83    {                                    \
84     T l;                                \
85     int m=sizeof(l);                    \
86     if (i+m>len) goto done;             \
87     memcpy(&l,s+i,m);                   \
88     doswap(swap,&l,m);                  \
89     if (i+m+l>len) goto done;           \
90     i+=m;                               \
91     lua_pushlstring(L,s+i,l);           \
92     i+=l;                               \
93     ++n;                                \
94     break;                              \
95    }
96
97 static int l_unpack(lua_State *L)               /** unpack(s,f,[init]) */
98 {
99  size_t len;
100  const char *s=luaL_checklstring(L,1,&len);
101  const char *f=luaL_checkstring(L,2);
102  int i=luaL_optnumber(L,3,1)-1;
103  int n=0;
104  int swap=0;
105  lua_pushnil(L);
106  while (*f)
107  {
108   int c=*f++;
109   int N=1;
110   if (isdigit(*f))
111   {
112    N=0;
113    while (isdigit(*f)) N=10*N+(*f++)-'0';
114    if (N==0 && c==OP_STRING) { lua_pushliteral(L,""); ++n; }
115   }
116   while (N--) switch (c)
117   {
118    case OP_LITTLEENDIAN:
119    case OP_BIGENDIAN:
120    case OP_NATIVE:
121    {
122     swap=doendian(c);
123     N=0;
124     break;
125    }
126    case OP_STRING:
127    {
128     ++N;
129     if (i+N>len) goto done;
130     lua_pushlstring(L,s+i,N);
131     i+=N;
132     ++n;
133     N=0;
134     break;
135    }
136    case OP_ZSTRING:
137    {
138     size_t l;
139     if (i>=len) goto done;
140     l=strlen(s+i);
141     lua_pushlstring(L,s+i,l);
142     i+=l+1;
143     ++n;
144     break;
145    }
146    UNPACKSTRING(OP_BSTRING, uint8_t)
147    UNPACKSTRING(OP_WSTRING, int16_t)
148    UNPACKSTRING(OP_SSTRING, size_t)
149    UNPACKNUMBER(OP_NUMBER, lua_Number)
150    UNPACKNUMBER(OP_DOUBLE, double)
151    UNPACKNUMBER(OP_FLOAT, float)
152    UNPACKNUMBER(OP_CHAR, char)
153    UNPACKNUMBER(OP_BYTE, uint8_t)
154    UNPACKNUMBER(OP_SHORT, int16_t)
155    UNPACKNUMBER(OP_USHORT, uint16_t)
156    UNPACKNUMBER(OP_INT, int32_t)
157    UNPACKNUMBER(OP_UINT, uint32_t)
158    UNPACKNUMBER(OP_LONG, int64_t)
159    UNPACKNUMBER(OP_ULONG, uint64_t)
160    case ' ': case ',':
161     break;
162    default:
163     badcode(L,c);
164     break;
165   }
166  }
167 done:
168  lua_pushnumber(L,i+1);
169  lua_replace(L,-n-2);
170  return n+1;
171 }
172
173 #define PACKNUMBER(OP,T)                        \
174    case OP:                                     \
175    {                                            \
176     T a=(T)luaL_checknumber(L,i++);             \
177     doswap(swap,&a,sizeof(a));                  \
178     luaL_addlstring(&b,(void*)&a,sizeof(a));    \
179     break;                                      \
180    }
181
182 #define PACKSTRING(OP,T)                        \
183    case OP:                                     \
184    {                                            \
185     size_t l;                                   \
186     const char *a=luaL_checklstring(L,i++,&l);  \
187     T ll=(T)l;                                  \
188     doswap(swap,&ll,sizeof(ll));                \
189     luaL_addlstring(&b,(void*)&ll,sizeof(ll));  \
190     luaL_addlstring(&b,a,l);                    \
191     break;                                      \
192    }
193
194 static int l_pack(lua_State *L)                 /** pack(f,...) */
195 {
196  int i=2;
197  const char *f=luaL_checkstring(L,1);
198  int swap=0;
199  luaL_Buffer b;
200  luaL_buffinit(L,&b);
201  while (*f)
202  {
203   int c=*f++;
204   int N=1;
205   if (isdigit(*f))
206   {
207    N=0;
208    while (isdigit(*f)) N=10*N+(*f++)-'0';
209   }
210   while (N--) switch (c)
211   {
212    case OP_LITTLEENDIAN:
213    case OP_BIGENDIAN:
214    case OP_NATIVE:
215    {
216     swap=doendian(c);
217     N=0;
218     break;
219    }
220    case OP_STRING:
221    case OP_ZSTRING:
222    {
223     size_t l;
224     const char *a=luaL_checklstring(L,i++,&l);
225     luaL_addlstring(&b,a,l+(c==OP_ZSTRING));
226     break;
227    }
228    PACKSTRING(OP_BSTRING, uint8_t)
229    PACKSTRING(OP_WSTRING, uint16_t)
230    PACKSTRING(OP_SSTRING, size_t)
231    PACKNUMBER(OP_NUMBER, lua_Number)
232    PACKNUMBER(OP_DOUBLE, double)
233    PACKNUMBER(OP_FLOAT, float)
234    PACKNUMBER(OP_CHAR, char)
235    PACKNUMBER(OP_BYTE, uint8_t)
236    PACKNUMBER(OP_SHORT, int16_t)
237    PACKNUMBER(OP_USHORT, uint16_t)
238    PACKNUMBER(OP_INT, int32_t)
239    PACKNUMBER(OP_UINT, uint32_t)
240    PACKNUMBER(OP_LONG, int64_t)
241    PACKNUMBER(OP_ULONG, uint64_t)
242    case ' ': case ',':
243     break;
244    default:
245     badcode(L,c);
246     break;
247   }
248  }
249  luaL_pushresult(&b);
250  return 1;
251 }
252
253 static const luaL_Reg R[] =
254 {
255         {"pack",        l_pack},
256         {"unpack",      l_unpack},
257         {NULL,  NULL}
258 };
259
260 int luaopen_pack(lua_State *L)
261 {
262   luaL_openlib(L, LUA_STRLIBNAME, R, 0);
263   return 0;
264 }
265
Note: See TracBrowser for help on using the browser.