自己尝试实现了一个lua_Reader

为什么要自己实现呢,因为脚本这东西总要加密,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风格的命名真的很蛋疼!怎么剩怎么来

你可能感兴趣的:(编程语言,脚本,lua)