/* ** $Id: lundump.c,v 1.4 1998/01/13 20:05:24 lhf Exp $ ** load bytecodes from files ** See Copyright Notice in lua.h */ #include #include "lauxlib.h" #include "lfunc.h" #include "lmem.h" #include "lstring.h" #include "lundump.h" typedef struct { ZIO* Z; int SwapNumber; int LoadFloat; } Sundump; static void unexpectedEOZ(ZIO* Z) { luaL_verror("unexpected end of binary file %s",Z->name); } static int ezgetc(ZIO* Z) { int c=zgetc(Z); if (c==EOZ) unexpectedEOZ(Z); return c; } static int ezread(ZIO* Z, void* b, int n) { int r=zread(Z,b,n); if (r!=0) unexpectedEOZ(Z); return r; } static int LoadWord(ZIO* Z) { int hi=ezgetc(Z); int lo=ezgetc(Z); return (hi<<8)|lo; } static void* LoadBlock(int size, ZIO* Z) { void* b=luaM_malloc(size); ezread(Z,b,size); return b; } static int LoadSize(ZIO* Z) { int hi=LoadWord(Z); int lo=LoadWord(Z); int s=(hi<<16)|lo; if (hi!=0 && s==lo) luaL_verror("code too long (%ld bytes)",(hi<<16)|(long)lo); return s; } static char* LoadString(ZIO* Z) { int size=LoadWord(Z); if (size==0) return NULL; else { char* b=luaL_openspace(size); ezread(Z,b,size); return b; } } static TaggedString* LoadTString(ZIO* Z) { char* s=LoadString(Z); return (s==NULL) ? NULL : luaS_new(s); } static void SwapFloat(float* f) { Byte* p=(Byte*)f; Byte* q=p+sizeof(float)-1; Byte t; t=*p; *p++=*q; *q--=t; t=*p; *p++=*q; *q--=t; } static void SwapDouble(double* f) { Byte* p=(Byte*)f; Byte* q=p+sizeof(double)-1; Byte t; t=*p; *p++=*q; *q--=t; t=*p; *p++=*q; *q--=t; t=*p; *p++=*q; *q--=t; t=*p; *p++=*q; *q--=t; } static real LoadNumber(Sundump* S) { if (S->LoadFloat) { float f; ezread(S->Z,&f,sizeof(f)); if (S->SwapNumber) SwapFloat(&f); return f; } else { double f; ezread(S->Z,&f,sizeof(f)); if (S->SwapNumber) SwapDouble(&f); return f; } } static void LoadLocals(TProtoFunc* tf, ZIO* Z) { int i,n=LoadWord(Z); if (n==0) return; tf->locvars=luaM_newvector(n+1,LocVar); for (i=0; ilocvars[i].line=LoadWord(Z); tf->locvars[i].varname=LoadTString(Z); } tf->locvars[i].line=-1; /* flag end of vector */ tf->locvars[i].varname=NULL; } static void LoadConstants(TProtoFunc* tf, Sundump* S) { int i,n=LoadWord(S->Z); tf->nconsts=n; if (n==0) return; tf->consts=luaM_newvector(n,TObject); for (i=0; iconsts+i; int c=ezgetc(S->Z); switch (c) { case ID_NUM: ttype(o)=LUA_T_NUMBER; nvalue(o)=LoadNumber(S); break; case ID_STR: ttype(o)=LUA_T_STRING; tsvalue(o)=LoadTString(S->Z); break; case ID_FUN: ttype(o)=LUA_T_PROTO; tfvalue(o)=NULL; break; #ifdef DEBUG default: /* cannot happen */ luaL_verror("internal error in LoadConstants: " "bad constant #%d type=%d ('%c')\n",i,c,c); break; #endif } } } static TProtoFunc* LoadFunction(Sundump* S); static void LoadFunctions(TProtoFunc* tf, Sundump* S) { while (zgetc(S->Z)==ID_FUNCTION) { int i=LoadWord(S->Z); TProtoFunc* t=LoadFunction(S); TObject* o=tf->consts+i; tfvalue(o)=t; } } static TProtoFunc* LoadFunction(Sundump* S) { ZIO* Z=S->Z; TProtoFunc* tf=luaF_newproto(); tf->lineDefined=LoadWord(Z); tf->fileName=LoadTString(Z); tf->code=LoadBlock(LoadSize(Z),Z); LoadConstants(tf,S); LoadLocals(tf,Z); LoadFunctions(tf,S); return tf; } static void LoadSignature(ZIO* Z) { char* s=SIGNATURE; while (*s!=0 && ezgetc(Z)==*s) ++s; if (*s!=0) luaL_verror("bad signature in binary file %s",Z->name); } static void LoadHeader(Sundump* S) { ZIO* Z=S->Z; int version,sizeofR; LoadSignature(Z); version=ezgetc(Z); if (version>VERSION) luaL_verror( "binary file %s too new: version=0x%02x; expected at most 0x%02x", Z->name,version,VERSION); if (version<0x31) /* major change in 3.1 */ luaL_verror( "binary file %s too old: version=0x%02x; expected at least 0x%02x", Z->name,version,0x31); sizeofR=ezgetc(Z); /* test float representation */ if (sizeofR==sizeof(float)) { float f,tf=TEST_FLOAT; ezread(Z,&f,sizeof(f)); if (f!=tf) { SwapFloat(&f); if (f!=tf) luaL_verror("unknown float representation in binary file %s",Z->name); S->SwapNumber=1; } S->LoadFloat=1; } else if (sizeofR==sizeof(double)) { double f,tf=TEST_FLOAT; ezread(Z,&f,sizeof(f)); if (f!=tf) { SwapDouble(&f); if (f!=tf) luaL_verror("unknown float representation in binary file %s",Z->name); S->SwapNumber=1; } S->LoadFloat=0; } else luaL_verror( "floats in binary file %s have %d bytes; " "expected %d (float) or %d (double)", Z->name,sizeofR,sizeof(float),sizeof(double)); } static TProtoFunc* LoadChunk(Sundump* S) { LoadHeader(S); return LoadFunction(S); } /* ** load one chunk from a file or buffer ** return main if ok and NULL at EOF */ TProtoFunc* luaU_undump1(ZIO* Z) { int c=zgetc(Z); Sundump S; S.Z=Z; S.SwapNumber=0; S.LoadFloat=1; if (c==ID_CHUNK) return LoadChunk(&S); else if (c!=EOZ) luaL_verror("%s is not a lua binary file",Z->name); return NULL; }