Imported from ../lua-3.0.tar.gz.
[lua.git] / src / undump.c
blob1a00ef7f3d75f2b65382311afdc4792f53ae4dc0
1 /*
2 ** undump.c
3 ** load bytecodes from files
4 */
6 char* rcs_undump="$Id: undump.c,v 1.24 1997/06/17 18:19:17 roberto Exp $";
8 #include <stdio.h>
9 #include <string.h>
10 #include "auxlib.h"
11 #include "opcode.h"
12 #include "luamem.h"
13 #include "table.h"
14 #include "undump.h"
15 #include "zio.h"
17 static int swapword=0;
18 static int swapfloat=0;
19 static TFunc* Main=NULL; /* functions in a chunk */
20 static TFunc* lastF=NULL;
22 static void FixCode(Byte* code, Byte* end) /* swap words */
24 Byte* p;
25 for (p=code; p!=end;)
27 int op=*p;
28 switch (op)
30 case PUSHNIL:
31 case PUSH0:
32 case PUSH1:
33 case PUSH2:
34 case PUSHLOCAL0:
35 case PUSHLOCAL1:
36 case PUSHLOCAL2:
37 case PUSHLOCAL3:
38 case PUSHLOCAL4:
39 case PUSHLOCAL5:
40 case PUSHLOCAL6:
41 case PUSHLOCAL7:
42 case PUSHLOCAL8:
43 case PUSHLOCAL9:
44 case PUSHINDEXED:
45 case STORELOCAL0:
46 case STORELOCAL1:
47 case STORELOCAL2:
48 case STORELOCAL3:
49 case STORELOCAL4:
50 case STORELOCAL5:
51 case STORELOCAL6:
52 case STORELOCAL7:
53 case STORELOCAL8:
54 case STORELOCAL9:
55 case STOREINDEXED0:
56 case ADJUST0:
57 case EQOP:
58 case LTOP:
59 case LEOP:
60 case GTOP:
61 case GEOP:
62 case ADDOP:
63 case SUBOP:
64 case MULTOP:
65 case DIVOP:
66 case POWOP:
67 case CONCOP:
68 case MINUSOP:
69 case NOTOP:
70 case POP:
71 case RETCODE0:
72 p++;
73 break;
74 case PUSHBYTE:
75 case PUSHLOCAL:
76 case STORELOCAL:
77 case STOREINDEXED:
78 case STORELIST0:
79 case ADJUST:
80 case RETCODE:
81 case VARARGS:
82 case STOREMAP:
83 p+=2;
84 break;
85 case STORELIST:
86 case CALLFUNC:
87 p+=3;
88 break;
89 case PUSHFUNCTION:
90 p+=5; /* TODO: use sizeof(TFunc*) or old? */
91 break;
92 case PUSHWORD:
93 case PUSHSELF:
94 case CREATEARRAY:
95 case ONTJMP:
96 case ONFJMP:
97 case JMP:
98 case UPJMP:
99 case IFFJMP:
100 case IFFUPJMP:
101 case SETLINE:
102 case PUSHSTRING:
103 case PUSHGLOBAL:
104 case STOREGLOBAL:
106 Byte t;
107 t=p[1]; p[1]=p[2]; p[2]=t;
108 p+=3;
109 break;
111 case PUSHFLOAT: /* assumes sizeof(float)==4 */
113 Byte t;
114 t=p[1]; p[1]=p[4]; p[4]=t;
115 t=p[2]; p[2]=p[3]; p[3]=t;
116 p+=5;
117 break;
119 case STORERECORD:
121 int n=*++p;
122 p++;
123 while (n--)
125 Byte t;
126 t=p[0]; p[0]=p[1]; p[1]=t;
127 p+=2;
129 break;
131 default:
132 luaL_verror("corrupt binary file: bad opcode %d at %d\n",
133 op,(int)(p-code));
134 break;
139 static void Unthread(Byte* code, int i, int v)
141 while (i!=0)
143 Word w;
144 Byte* p=code+i;
145 memcpy(&w,p,sizeof(w));
146 i=w; w=v;
147 memcpy(p,&w,sizeof(w));
151 static int LoadWord(ZIO* Z)
153 Word w;
154 zread(Z,&w,sizeof(w));
155 if (swapword)
157 Byte* p=(Byte*)&w;
158 Byte t;
159 t=p[0]; p[0]=p[1]; p[1]=t;
161 return w;
164 static int LoadSize(ZIO* Z)
166 Word hi=LoadWord(Z);
167 Word lo=LoadWord(Z);
168 int s=(hi<<16)|lo;
169 if ((Word)s != s) lua_error("code too long");
170 return s;
173 static void* LoadBlock(int size, ZIO* Z)
175 void* b=luaI_malloc(size);
176 zread(Z,b,size);
177 return b;
180 static char* LoadString(ZIO* Z)
182 int size=LoadWord(Z);
183 char *b=luaI_buffer(size);
184 zread(Z,b,size);
185 return b;
188 static char* LoadNewString(ZIO* Z)
190 return LoadBlock(LoadWord(Z),Z);
193 static void LoadFunction(ZIO* Z)
195 TFunc* tf=new(TFunc);
196 tf->next=NULL;
197 tf->locvars=NULL;
198 tf->size=LoadSize(Z);
199 tf->lineDefined=LoadWord(Z);
200 if (IsMain(tf)) /* new main */
202 tf->fileName=LoadNewString(Z);
203 Main=lastF=tf;
205 else /* fix PUSHFUNCTION */
207 tf->marked=LoadWord(Z);
208 tf->fileName=Main->fileName;
209 memcpy(Main->code+tf->marked,&tf,sizeof(tf));
210 lastF=lastF->next=tf;
212 tf->code=LoadBlock(tf->size,Z);
213 if (swapword || swapfloat) FixCode(tf->code,tf->code+tf->size);
214 while (1) /* unthread */
216 int c=zgetc(Z);
217 if (c==ID_VAR) /* global var */
219 int i=LoadWord(Z);
220 char* s=LoadString(Z);
221 int v=luaI_findsymbolbyname(s);
222 Unthread(tf->code,i,v);
224 else if (c==ID_STR) /* constant string */
226 int i=LoadWord(Z);
227 char* s=LoadString(Z);
228 int v=luaI_findconstantbyname(s);
229 Unthread(tf->code,i,v);
231 else
233 zungetc(Z);
234 break;
239 static void LoadSignature(ZIO* Z)
241 char* s=SIGNATURE;
242 while (*s!=0 && zgetc(Z)==*s)
243 ++s;
244 if (*s!=0) lua_error("cannot load binary file: bad signature");
247 static void LoadHeader(ZIO* Z)
249 Word w,tw=TEST_WORD;
250 float f,tf=TEST_FLOAT;
251 int version;
252 LoadSignature(Z);
253 version=zgetc(Z);
254 if (version>0x23) /* after 2.5 */
256 int oldsizeofW=zgetc(Z);
257 int oldsizeofF=zgetc(Z);
258 int oldsizeofP=zgetc(Z);
259 if (oldsizeofW!=2)
260 luaL_verror(
261 "cannot load binary file created on machine with sizeof(Word)=%d; "
262 "expected 2",oldsizeofW);
263 if (oldsizeofF!=4)
264 luaL_verror(
265 "cannot load binary file created on machine with sizeof(float)=%d; "
266 "expected 4\nnot an IEEE machine?",oldsizeofF);
267 if (oldsizeofP!=sizeof(TFunc*)) /* TODO: pack? */
268 luaL_verror(
269 "cannot load binary file created on machine with sizeof(TFunc*)=%d; "
270 "expected %d",oldsizeofP,(int)sizeof(TFunc*));
272 zread(Z,&w,sizeof(w)); /* test word */
273 if (w!=tw)
275 swapword=1;
277 zread(Z,&f,sizeof(f)); /* test float */
278 if (f!=tf)
280 Byte* p=(Byte*)&f;
281 Byte t;
282 swapfloat=1;
283 t=p[0]; p[0]=p[3]; p[3]=t;
284 t=p[1]; p[1]=p[2]; p[2]=t;
285 if (f!=tf) /* TODO: try another perm? */
286 lua_error("cannot load binary file: unknown float representation");
290 static void LoadChunk(ZIO* Z)
292 LoadHeader(Z);
293 while (1)
295 int c=zgetc(Z);
296 if (c==ID_FUN) LoadFunction(Z); else { zungetc(Z); break; }
301 ** load one chunk from a file.
302 ** return list of functions found, headed by main, or NULL at EOF.
304 TFunc* luaI_undump1(ZIO* Z)
306 int c=zgetc(Z);
307 if (c==ID_CHUNK)
309 LoadChunk(Z);
310 return Main;
312 else if (c!=EOZ)
313 lua_error("not a lua binary file");
314 return NULL;
318 ** load and run all chunks in a file
320 int luaI_undump(ZIO* Z)
322 TFunc* m;
323 while ((m=luaI_undump1(Z)))
325 int status=luaI_dorun(m);
326 luaI_freefunc(m);
327 if (status!=0) return status;
329 return 0;