为什么要自己实现呢,因为脚本这东西总要加密,lua似乎没有直接从内存读取脚本这东西,似乎dostring可以,不过因为听说效率较低所以pass,而且dostring也不能读取编译后的文件。
其实纯C的函数指针和C++等高级语言的抽象接口差不多,不过灵活度还是要高很多。现在发现面向对象有些东西的确是太死板了,以前觉得模板这东西很强大,现在发现这个不过是来弥补先天的不足,那还不如C的函数指针来得直接方面和明了。
不过习惯了面向对象,要转到函数式编程还有点绕不开,去看了关于lua自己的lua_Reader的实现,分别是dostring和dofile的实现,大概只是这个东西只是解析相应的资源,最终给lua_load用来加载block。如果只是简单的字符串就简单了,直接传进去就好了,dostring就是这么干的,而dofile就复杂很多,仔细分析,最需要的区别还是对于有无BOM和编译后的lua文件的解析,对于一般的需求,那个判断BOM我就不弄了,但是还是要判断是否编译了。
最初自己卡在一个地方,后来发现原来是lua5.1编译好的文件lua5.2根本不认,好吧,手头没有5.2的编译器,只好拿源码去编个,然后就搞定了。总结来说,最大的区别就是文件头是不是LUA_SIGNATURE。lua_load会先读取第一个字符,发现是编译文件就用编译文件策略,然后进行读后面的字符。
另一个其实不太明白的地方是关于buffer的大小,看起来dostring似乎并没有考虑这个问题,可能也并不需要处理这个问题,但是dofile里面却是用了LUAL_BUFFERSIZE(512)这个值,每次只读512个字节,虽然不知道为什么要这样不过我还是模仿了他。
贴一下代码,这里的从文件读取其实可以换成从内存,反正只是buffer的不同而已。而且我也自己去判断是否是编译文件了。
struct LoadFile
{
bool hasHead;
int n;
char* buffer;
char* bufferToRead;
};
static const char *getFile(lua_State *L, void *ud, size_t *size)
{
LoadFile *lf = (LoadFile *)ud;
(void)L; /* not used */
if(lf->hasHead)
{
*size = 1;
lf->hasHead = false;
return LUA_SIGNATURE;
}
if(lf->n==0)return NULL;
if (lf->n > LUAL_BUFFERSIZE)
{
*size = LUAL_BUFFERSIZE;
lf->bufferToRead = lf->buffer;
lf->buffer += LUAL_BUFFERSIZE;
lf->n -= LUAL_BUFFERSIZE;
}
else
{
*size = lf->n;
lf->bufferToRead = lf->buffer;
lf->n = 0;
}
return lf->bufferToRead;
}
int LoadLuaFile(lua_State* L, const char* fileName, bool isLuac = false)
{
int ret = 0;
lua_pushfstring(L, "@%s", fileName);
HANDLE hFile = NULL;
hFile = CreateFile(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL);
DWORD size = GetFileSize(hFile, NULL);
BYTE buffer[40960];
DWORD flag;
ReadFile(hFile,buffer,size,&flag,0);
CloseHandle(hFile);
LoadFile file;
file.n = 0;
if (isLuac)
{
file.hasHead = true;
file.n = size-1;
file.buffer = (char*)(buffer+1);
}
else
{
file.hasHead = false;
file.n = size;
file.buffer = (char*)(buffer);
}
ret = lua_load(L, getFile, &file, lua_tostring(L, -1), NULL);
return ret;
}
想要吐槽的是,lua_load之前都还好,之后简直不知道该怎么阅读,实在太绕了,果然水平还不够啊。我找了半天,最终没有找到lua_Reader被调用的地方,后来想到其实可以单步调试进去看流程,原来面向过程还要这点好处,就是过程非常明了。。。不过C风格的命名真的很蛋疼!怎么剩怎么来