Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
lua/lundump.c
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
318 lines (261 sloc)
6.93 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| ** $Id: lundump.c $ | |
| ** load precompiled Lua chunks | |
| ** See Copyright Notice in lua.h | |
| */ | |
| #define lundump_c | |
| #define LUA_CORE | |
| #include "lprefix.h" | |
| #include <limits.h> | |
| #include <string.h> | |
| #include "lua.h" | |
| #include "ldebug.h" | |
| #include "ldo.h" | |
| #include "lfunc.h" | |
| #include "lmem.h" | |
| #include "lobject.h" | |
| #include "lstring.h" | |
| #include "lundump.h" | |
| #include "lzio.h" | |
| #if !defined(luai_verifycode) | |
| #define luai_verifycode(L,b,f) /* empty */ | |
| #endif | |
| typedef struct { | |
| lua_State *L; | |
| ZIO *Z; | |
| const char *name; | |
| } LoadState; | |
| static l_noret error (LoadState *S, const char *why) { | |
| luaO_pushfstring(S->L, "%s: bad binary format (%s)", S->name, why); | |
| luaD_throw(S->L, LUA_ERRSYNTAX); | |
| } | |
| /* | |
| ** All high-level loads go through loadVector; you can change it to | |
| ** adapt to the endianness of the input | |
| */ | |
| #define loadVector(S,b,n) loadBlock(S,b,(n)*sizeof((b)[0])) | |
| static void loadBlock (LoadState *S, void *b, size_t size) { | |
| if (luaZ_read(S->Z, b, size) != 0) | |
| error(S, "truncated chunk"); | |
| } | |
| #define loadVar(S,x) loadVector(S,&x,1) | |
| static lu_byte loadByte (LoadState *S) { | |
| int b = zgetc(S->Z); | |
| if (b == EOZ) | |
| error(S, "truncated chunk"); | |
| return cast_byte(b); | |
| } | |
| static size_t loadUnsigned (LoadState *S, size_t limit) { | |
| size_t x = 0; | |
| int b; | |
| limit >>= 7; | |
| do { | |
| b = loadByte(S); | |
| if (x >= limit) | |
| error(S, "integer overflow"); | |
| x = (x << 7) | (b & 0x7f); | |
| } while ((b & 0x80) == 0); | |
| return x; | |
| } | |
| static size_t loadSize (LoadState *S) { | |
| return loadUnsigned(S, ~(size_t)0); | |
| } | |
| static int loadInt (LoadState *S) { | |
| return cast_int(loadUnsigned(S, INT_MAX)); | |
| } | |
| static lua_Number loadNumber (LoadState *S) { | |
| lua_Number x; | |
| loadVar(S, x); | |
| return x; | |
| } | |
| static lua_Integer loadInteger (LoadState *S) { | |
| lua_Integer x; | |
| loadVar(S, x); | |
| return x; | |
| } | |
| /* | |
| ** Load a nullable string. | |
| */ | |
| static TString *loadStringN (LoadState *S) { | |
| size_t size = loadSize(S); | |
| if (size == 0) | |
| return NULL; | |
| else if (--size <= LUAI_MAXSHORTLEN) { /* short string? */ | |
| char buff[LUAI_MAXSHORTLEN]; | |
| loadVector(S, buff, size); | |
| return luaS_newlstr(S->L, buff, size); | |
| } | |
| else { /* long string */ | |
| TString *ts = luaS_createlngstrobj(S->L, size); | |
| loadVector(S, getstr(ts), size); /* load directly in final place */ | |
| return ts; | |
| } | |
| } | |
| /* | |
| ** Load a non-nullable string. | |
| */ | |
| static TString *loadString (LoadState *S) { | |
| TString *st = loadStringN(S); | |
| if (st == NULL) | |
| error(S, "bad format for constant string"); | |
| return st; | |
| } | |
| static void loadCode (LoadState *S, Proto *f) { | |
| int n = loadInt(S); | |
| f->code = luaM_newvectorchecked(S->L, n, Instruction); | |
| f->sizecode = n; | |
| loadVector(S, f->code, n); | |
| } | |
| static void loadFunction(LoadState *S, Proto *f, TString *psource); | |
| static void loadConstants (LoadState *S, Proto *f) { | |
| int i; | |
| int n = loadInt(S); | |
| f->k = luaM_newvectorchecked(S->L, n, TValue); | |
| f->sizek = n; | |
| for (i = 0; i < n; i++) | |
| setnilvalue(&f->k[i]); | |
| for (i = 0; i < n; i++) { | |
| TValue *o = &f->k[i]; | |
| int t = loadByte(S); | |
| switch (t) { | |
| case LUA_VNIL: | |
| setnilvalue(o); | |
| break; | |
| case LUA_VFALSE: | |
| setbfvalue(o); | |
| break; | |
| case LUA_VTRUE: | |
| setbtvalue(o); | |
| break; | |
| case LUA_VNUMFLT: | |
| setfltvalue(o, loadNumber(S)); | |
| break; | |
| case LUA_VNUMINT: | |
| setivalue(o, loadInteger(S)); | |
| break; | |
| case LUA_VSHRSTR: | |
| case LUA_VLNGSTR: | |
| setsvalue2n(S->L, o, loadString(S)); | |
| break; | |
| default: lua_assert(0); | |
| } | |
| } | |
| } | |
| static void loadProtos (LoadState *S, Proto *f) { | |
| int i; | |
| int n = loadInt(S); | |
| f->p = luaM_newvectorchecked(S->L, n, Proto *); | |
| f->sizep = n; | |
| for (i = 0; i < n; i++) | |
| f->p[i] = NULL; | |
| for (i = 0; i < n; i++) { | |
| f->p[i] = luaF_newproto(S->L); | |
| loadFunction(S, f->p[i], f->source); | |
| } | |
| } | |
| static void loadUpvalues (LoadState *S, Proto *f) { | |
| int i, n; | |
| n = loadInt(S); | |
| f->upvalues = luaM_newvectorchecked(S->L, n, Upvaldesc); | |
| f->sizeupvalues = n; | |
| for (i = 0; i < n; i++) { | |
| f->upvalues[i].name = NULL; | |
| f->upvalues[i].instack = loadByte(S); | |
| f->upvalues[i].idx = loadByte(S); | |
| f->upvalues[i].kind = loadByte(S); | |
| } | |
| } | |
| static void loadDebug (LoadState *S, Proto *f) { | |
| int i, n; | |
| n = loadInt(S); | |
| f->lineinfo = luaM_newvectorchecked(S->L, n, ls_byte); | |
| f->sizelineinfo = n; | |
| loadVector(S, f->lineinfo, n); | |
| n = loadInt(S); | |
| f->abslineinfo = luaM_newvectorchecked(S->L, n, AbsLineInfo); | |
| f->sizeabslineinfo = n; | |
| for (i = 0; i < n; i++) { | |
| f->abslineinfo[i].pc = loadInt(S); | |
| f->abslineinfo[i].line = loadInt(S); | |
| } | |
| n = loadInt(S); | |
| f->locvars = luaM_newvectorchecked(S->L, n, LocVar); | |
| f->sizelocvars = n; | |
| for (i = 0; i < n; i++) | |
| f->locvars[i].varname = NULL; | |
| for (i = 0; i < n; i++) { | |
| f->locvars[i].varname = loadStringN(S); | |
| f->locvars[i].startpc = loadInt(S); | |
| f->locvars[i].endpc = loadInt(S); | |
| } | |
| n = loadInt(S); | |
| for (i = 0; i < n; i++) | |
| f->upvalues[i].name = loadStringN(S); | |
| } | |
| static void loadFunction (LoadState *S, Proto *f, TString *psource) { | |
| f->source = loadStringN(S); | |
| if (f->source == NULL) /* no source in dump? */ | |
| f->source = psource; /* reuse parent's source */ | |
| f->linedefined = loadInt(S); | |
| f->lastlinedefined = loadInt(S); | |
| f->numparams = loadByte(S); | |
| f->is_vararg = loadByte(S); | |
| f->maxstacksize = loadByte(S); | |
| loadCode(S, f); | |
| loadConstants(S, f); | |
| loadUpvalues(S, f); | |
| loadProtos(S, f); | |
| loadDebug(S, f); | |
| } | |
| static void checkliteral (LoadState *S, const char *s, const char *msg) { | |
| char buff[sizeof(LUA_SIGNATURE) + sizeof(LUAC_DATA)]; /* larger than both */ | |
| size_t len = strlen(s); | |
| loadVector(S, buff, len); | |
| if (memcmp(s, buff, len) != 0) | |
| error(S, msg); | |
| } | |
| static void fchecksize (LoadState *S, size_t size, const char *tname) { | |
| if (loadByte(S) != size) | |
| error(S, luaO_pushfstring(S->L, "%s size mismatch", tname)); | |
| } | |
| #define checksize(S,t) fchecksize(S,sizeof(t),#t) | |
| static void checkHeader (LoadState *S) { | |
| /* skip 1st char (already read and checked) */ | |
| checkliteral(S, &LUA_SIGNATURE[1], "not a binary chunk"); | |
| if (loadByte(S) != LUAC_VERSION) | |
| error(S, "version mismatch"); | |
| if (loadByte(S) != LUAC_FORMAT) | |
| error(S, "format mismatch"); | |
| checkliteral(S, LUAC_DATA, "corrupted chunk"); | |
| checksize(S, Instruction); | |
| checksize(S, lua_Integer); | |
| checksize(S, lua_Number); | |
| if (loadInteger(S) != LUAC_INT) | |
| error(S, "integer format mismatch"); | |
| if (loadNumber(S) != LUAC_NUM) | |
| error(S, "float format mismatch"); | |
| } | |
| /* | |
| ** Load precompiled chunk. | |
| */ | |
| LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) { | |
| LoadState S; | |
| LClosure *cl; | |
| if (*name == '@' || *name == '=') | |
| S.name = name + 1; | |
| else if (*name == LUA_SIGNATURE[0]) | |
| S.name = "binary string"; | |
| else | |
| S.name = name; | |
| S.L = L; | |
| S.Z = Z; | |
| checkHeader(&S); | |
| cl = luaF_newLclosure(L, loadByte(&S)); | |
| setclLvalue2s(L, L->top, cl); | |
| luaD_inctop(L); | |
| cl->p = luaF_newproto(L); | |
| loadFunction(&S, cl->p, NULL); | |
| lua_assert(cl->nupvalues == cl->p->sizeupvalues); | |
| luai_verifycode(L, buff, cl->p); | |
| return cl; | |
| } | |