gateway: simplify stopping the cleanup timer
[olsrd.git] / lib / tas / src / lua / lundump.c
1
2 /*
3 ** $Id: lundump.c,v 1.49 2003/04/07 20:34:20 lhf Exp $
4 ** load pre-compiled Lua chunks
5 ** See Copyright Notice in lua.h
6 */
7
8 #define lundump_c
9
10 #include "lua.h"
11
12 #include "ldebug.h"
13 #include "lfunc.h"
14 #include "lmem.h"
15 #include "lopcodes.h"
16 #include "lstring.h"
17 #include "lundump.h"
18 #include "lzio.h"
19
20 #define LoadByte        (lu_byte) ezgetc
21
22 typedef struct {
23   lua_State *L;
24   ZIO *Z;
25   Mbuffer *b;
26   int swap;
27   const char *name;
28 } LoadState;
29
30 static void unexpectedEOZ(LoadState * S) __attribute__ ((noreturn));
31
32 static void
33 unexpectedEOZ(LoadState * S)
34 {
35   luaG_runerror(S->L, "unexpected end of file in %s", S->name);
36 }
37
38 static int
39 ezgetc(LoadState * S)
40 {
41   int c = zgetc(S->Z);
42   if (c == EOZ)
43     unexpectedEOZ(S);
44   return c;
45 }
46
47 static void
48 ezread(LoadState * S, void *b, int n)
49 {
50   int r = luaZ_read(S->Z, b, n);
51   if (r != 0)
52     unexpectedEOZ(S);
53 }
54
55 static void
56 LoadBlock(LoadState * S, void *b, size_t size)
57 {
58   if (S->swap) {
59     char *p = (char *)b + size - 1;
60     int n = size;
61     while (n--)
62       *p-- = (char)ezgetc(S);
63   } else
64     ezread(S, b, size);
65 }
66
67 static void
68 LoadVector(LoadState * S, void *b, int m, size_t size)
69 {
70   if (S->swap) {
71     char *q = (char *)b;
72     while (m--) {
73       char *p = q + size - 1;
74       int n = size;
75       while (n--)
76         *p-- = (char)ezgetc(S);
77       q += size;
78     }
79   } else
80     ezread(S, b, m * size);
81 }
82
83 static int
84 LoadInt(LoadState * S)
85 {
86   int x;
87   LoadBlock(S, &x, sizeof(x));
88   if (x < 0)
89     luaG_runerror(S->L, "bad integer in %s", S->name);
90   return x;
91 }
92
93 static size_t
94 LoadSize(LoadState * S)
95 {
96   size_t x;
97   LoadBlock(S, &x, sizeof(x));
98   return x;
99 }
100
101 static lua_Number
102 LoadNumber(LoadState * S)
103 {
104   lua_Number x;
105   LoadBlock(S, &x, sizeof(x));
106   return x;
107 }
108
109 static TString *
110 LoadString(LoadState * S)
111 {
112   size_t size = LoadSize(S);
113   if (size == 0)
114     return NULL;
115   else {
116     char *s = luaZ_openspace(S->L, S->b, size);
117     ezread(S, s, size);
118     return luaS_newlstr(S->L, s, size - 1);     /* remove trailing '\0' */
119   }
120 }
121
122 static void
123 LoadCode(LoadState * S, Proto * f)
124 {
125   int size = LoadInt(S);
126   f->code = luaM_newvector(S->L, size, Instruction);
127   f->sizecode = size;
128   LoadVector(S, f->code, size, sizeof(*f->code));
129 }
130
131 static void
132 LoadLocals(LoadState * S, Proto * f)
133 {
134   int i, n;
135   n = LoadInt(S);
136   f->locvars = luaM_newvector(S->L, n, LocVar);
137   f->sizelocvars = n;
138   for (i = 0; i < n; i++) {
139     f->locvars[i].varname = LoadString(S);
140     f->locvars[i].startpc = LoadInt(S);
141     f->locvars[i].endpc = LoadInt(S);
142   }
143 }
144
145 static void
146 LoadLines(LoadState * S, Proto * f)
147 {
148   int size = LoadInt(S);
149   f->lineinfo = luaM_newvector(S->L, size, int);
150   f->sizelineinfo = size;
151   LoadVector(S, f->lineinfo, size, sizeof(*f->lineinfo));
152 }
153
154 static void
155 LoadUpvalues(LoadState * S, Proto * f)
156 {
157   int i, n;
158   n = LoadInt(S);
159   if (n != 0 && n != f->nups)
160     luaG_runerror(S->L, "bad nupvalues in %s: read %d; expected %d", S->name, n, f->nups);
161   f->upvalues = luaM_newvector(S->L, n, TString *);
162   f->sizeupvalues = n;
163   for (i = 0; i < n; i++)
164     f->upvalues[i] = LoadString(S);
165 }
166
167 static Proto *LoadFunction(LoadState * S, TString * p);
168
169 static void
170 LoadConstants(LoadState * S, Proto * f)
171 {
172   int i, n;
173   n = LoadInt(S);
174   f->k = luaM_newvector(S->L, n, TObject);
175   f->sizek = n;
176   for (i = 0; i < n; i++) {
177     TObject *o = &f->k[i];
178     int t = LoadByte(S);
179     switch (t) {
180     case LUA_TNUMBER:
181       setnvalue(o, LoadNumber(S));
182       break;
183     case LUA_TSTRING:
184       setsvalue2n(o, LoadString(S));
185       break;
186     case LUA_TNIL:
187       setnilvalue(o);
188       break;
189     default:
190       luaG_runerror(S->L, "bad constant type (%d) in %s", t, S->name);
191       break;
192     }
193   }
194   n = LoadInt(S);
195   f->p = luaM_newvector(S->L, n, Proto *);
196   f->sizep = n;
197   for (i = 0; i < n; i++)
198     f->p[i] = LoadFunction(S, f->source);
199 }
200
201 static Proto *
202 LoadFunction(LoadState * S, TString * p)
203 {
204   Proto *f = luaF_newproto(S->L);
205   f->source = LoadString(S);
206   if (f->source == NULL)
207     f->source = p;
208   f->lineDefined = LoadInt(S);
209   f->nups = LoadByte(S);
210   f->numparams = LoadByte(S);
211   f->is_vararg = LoadByte(S);
212   f->maxstacksize = LoadByte(S);
213   LoadLines(S, f);
214   LoadLocals(S, f);
215   LoadUpvalues(S, f);
216   LoadConstants(S, f);
217   LoadCode(S, f);
218 #ifndef TRUST_BINARIES
219   if (!luaG_checkcode(f))
220     luaG_runerror(S->L, "bad code in %s", S->name);
221 #endif
222   return f;
223 }
224
225 static void
226 LoadSignature(LoadState * S)
227 {
228   const char *s = LUA_SIGNATURE;
229   while (*s != 0 && ezgetc(S) == *s)
230     ++s;
231   if (*s != 0)
232     luaG_runerror(S->L, "bad signature in %s", S->name);
233 }
234
235 static void
236 TestSize(LoadState * S, int s, const char *what)
237 {
238   int r = LoadByte(S);
239   if (r != s)
240     luaG_runerror(S->L, "virtual machine mismatch in %s: " "size of %s is %d but read %d", S->name, what, s, r);
241 }
242
243 #define TESTSIZE(s,w)   TestSize(S,s,w)
244 #define V(v)            v/16,v%16
245
246 static void
247 LoadHeader(LoadState * S)
248 {
249   int version;
250   lua_Number x, tx = TEST_NUMBER;
251   LoadSignature(S);
252   version = LoadByte(S);
253   if (version > VERSION)
254     luaG_runerror(S->L, "%s too new: " "read version %d.%d; expected at most %d.%d", S->name, V(version), V(VERSION));
255   if (version < VERSION0)       /* check last major change */
256     luaG_runerror(S->L, "%s too old: " "read version %d.%d; expected at least %d.%d", S->name, V(version), V(VERSION0));
257   S->swap = (luaU_endianness() != LoadByte(S)); /* need to swap bytes? */
258   TESTSIZE(sizeof(int), "int");
259   TESTSIZE(sizeof(size_t), "size_t");
260   TESTSIZE(sizeof(Instruction), "Instruction");
261   TESTSIZE(SIZE_OP, "OP");
262   TESTSIZE(SIZE_A, "A");
263   TESTSIZE(SIZE_B, "B");
264   TESTSIZE(SIZE_C, "C");
265   TESTSIZE(sizeof(lua_Number), "number");
266   x = LoadNumber(S);
267   if ((long)x != (long)tx)      /* disregard errors in last bits of fraction */
268     luaG_runerror(S->L, "unknown number format in %s", S->name);
269 }
270
271 static Proto *
272 LoadChunk(LoadState * S)
273 {
274   LoadHeader(S);
275   return LoadFunction(S, NULL);
276 }
277
278 /*
279 ** load precompiled chunk
280 */
281 Proto *
282 luaU_undump(lua_State * L, ZIO * Z, Mbuffer * buff)
283 {
284   LoadState S;
285   const char *s = zname(Z);
286   if (*s == '@' || *s == '=')
287     S.name = s + 1;
288   else if (*s == LUA_SIGNATURE[0])
289     S.name = "binary string";
290   else
291     S.name = s;
292   S.L = L;
293   S.Z = Z;
294   S.b = buff;
295   return LoadChunk(&S);
296 }
297
298 /*
299 ** find byte order
300 */
301 int
302 luaU_endianness(void)
303 {
304   int x = 1;
305   return *(char *)&x;
306 }