这里贴上头文件说明以及实现
#ifndef __CC_LUA_STACK_H_
#define __CC_LUA_STACK_H_
extern "C" {
#include "lua.h"
}
#include "cocos2d.h"
#include "CCLuaValue.h"
#define LUASTACK_USED_FOR_QUICK_COCOS2DX
NS_CC_BEGIN
class LuaStack : public Ref
{
public:
static LuaStack *create(void);
static LuaStack *attach(lua_State *L);
virtual ~LuaStack();
/**
@brief Method used to get a pointer to the lua_State that the script module is attached to.
@return A pointer to the lua_State that the script module is attached to.
*/
//返回lua栈的指针
lua_State* getLuaState(void) {
return _state;
}
/**
@brief Add a path to find lua files in
@param path to be added to the Lua path
*/
//增加搜索路径
virtual void addSearchPath(const char* path);
/**
@brief Add lua loader, now it is used on android
*/
// 添加Lua加载器。
// 参数
// func 指向加载器的函数指针。
virtual void addLuaLoader(lua_CFunction func);
/**
@brief reload script code contained in the given string.
@param moduleFileName String object holding the filename of the script file that is to be executed
@return 0 if the string is excuted correctly.
@return other if the string is excuted wrongly.
*/
//重新加载给定字符串中包含的脚本代码。
//参数是要执行的脚本文件
//如果脚本文件被正确执行返回0。如果错误执行则返回其他数值
//重新加载对应moduleFileName指向的脚本文件。 如果package["loaded"][moduleFileName]值不为nil,它将先设置值为nil,然后,调用executeString函数。
virtual int reload(const char* moduleFileName);
/**
@brief Remove Object from lua state
@param object The object to be removed.
*/
//通过操作相关Lua table,移除Ref对象在Lua table中的引用。
//同时,设置相应的userdata为nullptr以及移除去该对象相关的Lua函数的引用。
//目前的机制下,开发者不调用这个函数,这个函数将会在LuaEngier的析构函数中自动被调用。
virtual void removeScriptObjectByObject(Ref* object);
/**
@brief Remove Lua function reference
*/
//通过设置toluafix_refid_function_mapping[nHandle]=nil,移除Lua函数引用。
virtual void removeScriptHandler(int nHandler);
/**
@brief Remove Lua function reference
*/
//重新分配Lua函数的引用id。
virtual int reallocateScriptHandler(int nHandler);
/**
@brief Execute script code contained in the given string.
@param codes holding the valid script code that should be executed.
@return 0 if the string is excuted correctly.
@return other if the string is excuted wrongly.
*/
//执行给定字符串中包含的脚本代码。
//codes 需被执行的脚本代码字符串。
//执行成功返回0,否则返回其它值。
virtual int executeString(const char* codes);
/**
@brief Execute a script file.
@param filename String object holding the filename of the script file that is to be executed
*/
// 执行一个脚本文件。
// 参数
// filename 脚本文件的文件名。
// 返回
// 如果碰到错误或者执行结果没有返回值返回0,否则返回1。
virtual int executeScriptFile(const char* filename);
/**
@brief Execute a scripted global function.
@brief The function should not take any parameters and should return an integer.
@param functionName String object holding the name of the function, in the global script environment, that is to be executed.
@return The integer value returned from the script function.
*/
// 执行全局的脚本函数。 该全局函数不应该有任何参数,同时返回一个整数。
// 参数
// functionName 全局脚本函数的字符串名称。
// 返回
// 从脚本函数返回的整数值。
virtual int executeGlobalFunction(const char* functionName);
virtual void clean(void);//清空栈
virtual void pushInt(int intValue);//压入整数
virtual void pushFloat(float floatValue);//压入浮点数
virtual void pushLong(long longValue);
virtual void pushBoolean(bool boolValue);
virtual void pushString(const char* stringValue);//将一个以'\0'结束的字符串指针压入Lua栈。
virtual void pushString(const char* stringValue, int length);//调用lua_pushlstring压入长度为len的字符串
virtual void pushNil(void);//压入nil
virtual void pushObject(Ref* objectValue, const char* typeName);//将一个Ref对象压入到Lua栈,详细信息请查阅toluafix_pushusertype_ccobject
virtual void pushLuaValue(const LuaValue& value);//根据不同类型的LuaValue,它将会在函数内部调用其它相关的push函数
virtual void pushLuaValueDict(const LuaValueDict& dict);//将一个Lua table压入Lua栈。 这个Lua table的key值为字符串,value值依赖LuaValue的类型通过调用pushLuaValue获得,
virtual void pushLuaValueArray(const LuaValueArray& array);//将一个Lua数组table压入Lua栈。 数组table的索引从1开始。 这个Lua数组table中的值通过调用pushLuaValue获得,
virtual bool pushFunctionByHandler(int nHandler);//通过给定的nHandler查找toluafix_refid_function_mapping table获取对应的Lua函数指针,并将它压入Lua栈。
//如果无法找到nHanlder对应的Lua函数指针, 它会把压入一个nil值到栈顶,并且在在调试模式,它还会输出错误日志。
virtual int executeFunction(int numArgs);//通过numArgs值,获取Lua栈上-(numArgs + 1)索引处的Lua函数并执行
virtual int executeFunctionByHandler(int nHandler, int numArgs);//查找并执行nHandler对应的Lua函数,这个函数有numArgs个参数。
virtual int executeFunctionReturnArray(int handler,int numArgs,int numResults,__Array& resultArray);//查找并执行handler对应的Lua函数,这个函数有numArgs个参数。
//调用这个函数将会返回numResults个返回值(可能大于1)。 所有的返回值将存在resultArray中。
virtual int executeFunction(int handler, int numArgs, int numResults, const std::function<void(lua_State*,int)>& func);//查找并执行handler对应的Lua函数,这个函数有numArgs个参数。
//调用这个函数将会返回numResults个返回值(可能大于1)。 所有的返回值将被用在回调函数func中。
// 处理assert信息。
// 参数
// msg assert信息字符串。
// 返回
// 如果当前_callFromLua不为0返回true,否则返回false。
virtual bool handleAssert(const char *msg, const char *cond, const char *file, int line);
//设置的xxtea加密算法的key和sign。
// 参数
// key key字符串指针
// sign sign字符串指针
virtual void setXXTEAKeyAndSign(const char *key, const char *sign);
virtual void cleanupXXTEAKeyAndSign();
virtual const char *getXXTEAKey(int *len);
virtual const char *getXXTEASign(int *len);
// 加载一个Lua程序块。该函数使用lua_load通过一个指向程序块的指针加载一块大小为chunkSize的Lua程序块。 如果当前支持xxtea算法,并且chunk的头部有sing签名,那么加载的程序块还需要进行解密操作。
// 参数
// L 当前lua_State。
// chunk 程序块指针。
// chunkSize 程序块大小。
// chunkName 程序块的名称。
// 返回
// 0,LUA_ERRSYNTAX或LUA_ERRMEM:。
int luaLoadBuffer(lua_State *L, const char *chunk, int chunkSize, const char *chunkName);
//从zip文件加载Lua程序块
// 参数
// zipFilePath zip文件的文件路径。
// 返回
// 加载成功返回1,否则返回0。
int loadChunksFromZIP(const char *zipFilePath);
//从当前的lua_State中加载Lua程序块。
// 参数
// L 当前的lua_State。
// 返回
// 加载成功返回1,否则返回0。
int luaLoadChunksFromZIP(lua_State *L);
protected:
LuaStack(void)
: _state(nullptr)
, _callFromLua(0)
, _xxteaEnabled(false)
, _xxteaKey(nullptr)
, _xxteaKeyLen(0)
, _xxteaSign(nullptr)
, _xxteaSignLen(0)
{
}
bool init(void);
bool initWithLuaState(lua_State *L);
lua_State *_state;
int _callFromLua;
bool _xxteaEnabled;
char* _xxteaKey;
int _xxteaKeyLen;
char* _xxteaSign;
int _xxteaSignLen;
};
NS_CC_END
#endif // __CC_LUA_STACK_H_
下面是实现
#include "CCLuaStack.h"
#include "tolua_fix.h"
#include "external/xxtea/xxtea.h"
extern "C" {
#include "lua.h"
#include "tolua++.h"
#include "lualib.h"
#include "lauxlib.h"
}
#include "Cocos2dxLuaLoader.h"
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_MAC)
#include "platform/ios/CCLuaObjcBridge.h"
#endif
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
#include "platform/android/CCLuaJavaBridge.h"
#endif
#include "LuaOpengl.h"
#include "LuaScriptHandlerMgr.h"
#include "lua_cocos2dx_auto.hpp"
#include "lua_cocos2dx_manual.hpp"
#include "LuaBasicConversions.h"
#include "lua_cocos2dx_deprecated.h"
#include "lua_cocos2dx_physics_auto.hpp"
#include "lua_cocos2dx_physics_manual.hpp"
#include "lua_cocos2dx_experimental_auto.hpp"
#include "lua_cocos2dx_experimental_manual.hpp"
namespace {
int lua_print(lua_State * luastate)//打印当前lua栈的里面值的类型
{
int nargs = lua_gettop(luastate);
std::string t;
for (int i=1; i <= nargs; i++)
{
if (lua_istable(luastate, i))
t += "table";
else if (lua_isnone(luastate, i))
t += "none";
else if (lua_isnil(luastate, i))
t += "nil";
else if (lua_isboolean(luastate, i))
{
if (lua_toboolean(luastate, i) != 0)
t += "true";
else
t += "false";
}
else if (lua_isfunction(luastate, i))
t += "function";
else if (lua_islightuserdata(luastate, i))
t += "lightuserdata";
else if (lua_isthread(luastate, i))
t += "thread";
else
{
const char * str = lua_tostring(luastate, i);
if (str)
t += lua_tostring(luastate, i);
else
t += lua_typename(luastate, lua_type(luastate, i));
}
if (i!=nargs)
t += "\t";
}
CCLOG("[LUA-print] %s", t.c_str());
return 0;
}
int lua_release_print(lua_State * L)
{
int nargs = lua_gettop(L);
std::string t;
for (int i=1; i <= nargs; i++)
{
if (lua_istable(L, i))
t += "table";
else if (lua_isnone(L, i))
t += "none";
else if (lua_isnil(L, i))
t += "nil";
else if (lua_isboolean(L, i))
{
if (lua_toboolean(L, i) != 0)
t += "true";
else
t += "false";
}
else if (lua_isfunction(L, i))
t += "function";
else if (lua_islightuserdata(L, i))
t += "lightuserdata";
else if (lua_isthread(L, i))
t += "thread";
else
{
const char * str = lua_tostring(L, i);
if (str)
t += lua_tostring(L, i);
else
t += lua_typename(L, lua_type(L, i));
}
if (i!=nargs)
t += "\t";
}
log("[LUA-print] %s", t.c_str());
return 0;
}
}
NS_CC_BEGIN
LuaStack::~LuaStack()
{
if (nullptr != _state)
{
lua_close(_state);//关闭lua栈
}
}
LuaStack *LuaStack::create(void)
{
LuaStack *stack = new (std::nothrow) LuaStack();//以不抛出异常的方式创建lua栈
stack->init();
stack->autorelease();//加入到自动释放池
return stack;
}
LuaStack *LuaStack::attach(lua_State *L)
{
LuaStack *stack = new (std::nothrow) LuaStack();
stack->initWithLuaState(L);
stack->autorelease();
return stack;
}
//这个函数很多看不懂,先记录这里
bool LuaStack::init(void)
{
_state = lua_open();//通过lua_open打开很多lua的标准库,供lua栈的使用
luaL_openlibs(_state);
toluafix_open(_state);
// Register our version of the global "print" function
const luaL_reg global_functions [] = {
{"print", lua_print},
{"release_print",lua_release_print},
{nullptr, nullptr}
};
luaL_register(_state, "_G", global_functions);//将上面的两个函数注册进lua的全局table里面
g_luaType.clear();
register_all_cocos2dx(_state);
tolua_opengl_open(_state);
register_all_cocos2dx_manual(_state);
register_all_cocos2dx_module_manual(_state);
register_all_cocos2dx_math_manual(_state);
register_all_cocos2dx_experimental(_state);
register_all_cocos2dx_experimental_manual(_state);
register_glnode_manual(_state);
#if CC_USE_PHYSICS
register_all_cocos2dx_physics(_state);
register_all_cocos2dx_physics_manual(_state);
#endif
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_MAC)
LuaObjcBridge::luaopen_luaoc(_state);
#endif
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
LuaJavaBridge::luaopen_luaj(_state);
#endif
register_all_cocos2dx_deprecated(_state);
register_all_cocos2dx_manual_deprecated(_state);
tolua_script_handler_mgr_open(_state);
// add cocos2dx loader
addLuaLoader(cocos2dx_lua_loader);
return true;
}
bool LuaStack::initWithLuaState(lua_State *L)
{
_state = L;
return true;
}
// lua_getglobal将全局变量avg的值入栈
//lua_getfield把 t[k] 值压入堆栈,这里的 t 是指有效索引 index 指向的值。
//llua_pop(_state, 2);从堆栈中弹出两个元素
void LuaStack::addSearchPath(const char* path)
{
lua_getglobal(_state, "package"); /* L: package */
lua_getfield(_state, -1, "path"); /* get package.path, L: package path */
const char* cur_path = lua_tostring(_state, -1);
lua_pushfstring(_state, "%s;%s/?.lua", cur_path, path); /* L: package path newpath */
lua_setfield(_state, -3, "path"); /* package.path = newpath, L: package path */
lua_pop(_state, 2); /* L: - */
}
//这个里面涉及到的元方法看不太懂
void LuaStack::addLuaLoader(lua_CFunction func)
{
if (!func) return;
// stack content after the invoking of the function
// get loader table
lua_getglobal(_state, "package"); /* L: package */
lua_getfield(_state, -1, "loaders"); /* L: package, loaders */
// insert loader into index 2
lua_pushcfunction(_state, func); /* L: package, loaders, func */
for (int i = (int)(lua_objlen(_state, -2) + 1); i > 2; --i)
{
lua_rawgeti(_state, -2, i - 1); /* L: package, loaders, func, function */
// we call lua_rawgeti, so the loader table now is at -3
lua_rawseti(_state, -3, i); /* L: package, loaders, func */
}
lua_rawseti(_state, -2, 2); /* L: package, loaders */
// set loaders into package
lua_setfield(_state, -2, "loaders"); /* L: package */
lua_pop(_state, 1);
}
void LuaStack::removeScriptObjectByObject(Ref* pObj)
{
toluafix_remove_ccobject_by_refid(_state, pObj->_luaID);
}
void LuaStack::removeScriptHandler(int nHandler)
{
toluafix_remove_function_by_refid(_state, nHandler);
}
//调用辅助库里面的luaL_loadstring执行一段字符串代码
int LuaStack::executeString(const char *codes)
{
luaL_loadstring(_state, codes);
return executeFunction(0);
}
//调用辅助库里面的luaLoadBuffer执行lua脚本文件
int LuaStack::executeScriptFile(const char* filename)
{
CCAssert(filename, "CCLuaStack::executeScriptFile() - invalid filename");
FileUtils *utils = FileUtils::getInstance();
std::string fullPath = utils->fullPathForFilename(filename);
Data data = utils->getDataFromFile(fullPath);
int rn = 0;
if (!data.isNull()) {
if (luaLoadBuffer(_state, (const char*)data.getBytes(), (int)data.getSize(), fullPath.c_str()) == 0) {
rn = executeFunction(0);
}
}
return rn;
}
//用这个lua_getglobal直接执行这个函数
int LuaStack::executeGlobalFunction(const char* functionName)
{
lua_getglobal(_state, functionName); /* query function by name, stack: function */
if (!lua_isfunction(_state, -1))
{
CCLOG("[LUA ERROR] name '%s' does not represent a Lua function", functionName);
lua_pop(_state, 1);
return 0;
}
return executeFunction(0);
}
//栈清零
void LuaStack::clean(void)
{
lua_settop(_state, 0);
}
void LuaStack::pushInt(int intValue)
{
lua_pushinteger(_state, intValue);
}
void LuaStack::pushFloat(float floatValue)
{
lua_pushnumber(_state, floatValue);
}
void LuaStack::pushLong(long longValue)
{
lua_pushnumber(_state, longValue);
}
void LuaStack::pushBoolean(bool boolValue)
{
lua_pushboolean(_state, boolValue);
}
void LuaStack::pushString(const char* stringValue)
{
lua_pushstring(_state, stringValue);
}
void LuaStack::pushString(const char* stringValue, int length)
{
lua_pushlstring(_state, stringValue, length);
}
void LuaStack::pushNil(void)
{
lua_pushnil(_state);
}
//压入一个Ref对象
void LuaStack::pushObject(Ref* objectValue, const char* typeName)
{
toluafix_pushusertype_ccobject(_state, objectValue->_ID, &objectValue->_luaID, objectValue, typeName);
}
//压入一个lua类型的值,根据什么值调用对应的逻辑代码
void LuaStack::pushLuaValue(const LuaValue& value)
{
const LuaValueType type = value.getType();
if (type == LuaValueTypeInt)
{
return pushInt(value.intValue());
}
else if (type == LuaValueTypeFloat)
{
return pushFloat(value.floatValue());
}
else if (type == LuaValueTypeBoolean)
{
return pushBoolean(value.booleanValue());
}
else if (type == LuaValueTypeString)
{
return pushString(value.stringValue().c_str());
}
else if (type == LuaValueTypeDict)
{
pushLuaValueDict(value.dictValue());
}
else if (type == LuaValueTypeArray)
{
pushLuaValueArray(value.arrayValue());
}
else if (type == LuaValueTypeObject)
{
pushObject(value.ccobjectValue(), value.getObjectTypename().c_str());
}
}
//将一个table压入栈
//lua_newtable创建一个空table并压入栈中
//随后循环这个table,将value压入栈
//lua_rawset(_state, -3);直接在table里面赋值,不触发元方法
void LuaStack::pushLuaValueDict(const LuaValueDict& dict)
{
lua_newtable(_state); /* L: table */
for (LuaValueDictIterator it = dict.begin(); it != dict.end(); ++it)
{
lua_pushstring(_state, it->first.c_str()); /* L: table key */
pushLuaValue(it->second); /* L: table key value */
lua_rawset(_state, -3); /* table.key = value, L: table */
}
}
void LuaStack::pushLuaValueArray(const LuaValueArray& array)
{
lua_newtable(_state); /* L: table */
int index = 1;
for (LuaValueArrayIterator it = array.begin(); it != array.end(); ++it)
{
pushLuaValue(*it); /* L: table value */
lua_rawseti(_state, -2, index); /* table[index] = value, L: table */
++index;
}
}
bool LuaStack::pushFunctionByHandler(int nHandler)
{
toluafix_get_function_by_refid(_state, nHandler); /* L: ... func */
if (!lua_isfunction(_state, -1))
{
CCLOG("[LUA ERROR] function refid '%d' does not reference a Lua function", nHandler);
lua_pop(_state, 1);
return false;
}
return true;
}
int LuaStack::executeFunction(int numArgs)
{
int functionIndex = -(numArgs + 1);
if (!lua_isfunction(_state, functionIndex))
{
CCLOG("value at stack [%d] is not function", functionIndex);
lua_pop(_state, numArgs + 1); // remove function and arguments
return 0;
}
int traceback = 0;
lua_getglobal(_state, "__G__TRACKBACK__"); /* L: ... func arg1 arg2 ... G */
if (!lua_isfunction(_state, -1))
{
lua_pop(_state, 1); /* L: ... func arg1 arg2 ... */
}
else
{
lua_insert(_state, functionIndex - 1); /* L: ... G func arg1 arg2 ... */
traceback = functionIndex - 1;
}
int error = 0;
++_callFromLua;
error = lua_pcall(_state, numArgs, 1, traceback); /* L: ... [G] ret */
--_callFromLua;
if (error)
{
if (traceback == 0)
{
CCLOG("[LUA ERROR] %s", lua_tostring(_state, - 1)); /* L: ... error */
lua_pop(_state, 1); // remove error message from stack
}
else /* L: ... G error */
{
lua_pop(_state, 2); // remove __G__TRACKBACK__ and error message from stack
}
return 0;
}
// get return value
int ret = 0;
if (lua_isnumber(_state, -1))
{
ret = (int)lua_tointeger(_state, -1);
}
else if (lua_isboolean(_state, -1))
{
ret = (int)lua_toboolean(_state, -1);
}
// remove return value from stack
lua_pop(_state, 1); /* L: ... [G] */
if (traceback)
{
lua_pop(_state, 1); // remove __G__TRACKBACK__ from stack /* L: ... */
}
return ret;
}
int LuaStack::executeFunctionByHandler(int nHandler, int numArgs)
{
int ret = 0;
if (pushFunctionByHandler(nHandler)) /* L: ... arg1 arg2 ... func */
{
if (numArgs > 0)
{
lua_insert(_state, -(numArgs + 1)); /* L: ... func arg1 arg2 ... */
}
ret = executeFunction(numArgs);
}
lua_settop(_state, 0);
return ret;
}
bool LuaStack::handleAssert(const char *msg, const char *cond, const char *file, int line)
{
if (_callFromLua == 0) return false;
const char *msgErr = msg ? msg : "unknown";
lua_pushstring(_state, "__G__TRACKBACK__");
lua_rawget(_state, LUA_GLOBALSINDEX);
lua_pushstring(_state, msgErr);
lua_call(_state, 1, 0);
if (cond && file)
{
lua_pushfstring(_state, "\n==============\nASSERT FAILED ON LUA EXECUTE:\n File: %s\n Line: %d\n\n Expression: %s\n==============", file, line, cond);
}
else
{
lua_pushfstring(_state, "\n==============\nASSERT FAILED ON LUA EXECUTE: %s\n==============", msgErr);
}
lua_error(_state);
return true;
}
int LuaStack::reallocateScriptHandler(int nHandler)
{
LUA_FUNCTION nNewHandle = -1;
if (pushFunctionByHandler(nHandler))
{
nNewHandle = toluafix_ref_function(_state,lua_gettop(_state),0);
}
/*
toluafix_get_function_by_refid(_state,nNewHandle);
if (!lua_isfunction(_state, -1))
{
CCLOG("Error!");
}
lua_settop(_state, 0);
*/
return nNewHandle;
}
int LuaStack::executeFunctionReturnArray(int handler,int numArgs,int numResults,__Array& resultArray)
{
int top = lua_gettop(_state);
if (pushFunctionByHandler(handler)) /* L: ... arg1 arg2 ... func */
{
if (numArgs > 0)
{
lua_insert(_state, -(numArgs + 1)); /* L: ... func arg1 arg2 ... */
}
int functionIndex = -(numArgs + 1);
if (!lua_isfunction(_state, functionIndex))
{
CCLOG("value at stack [%d] is not function", functionIndex);
lua_pop(_state, numArgs + 1); // remove function and arguments
lua_settop(_state,top);
return 0;
}
int traceback = 0;
lua_getglobal(_state, "__G__TRACKBACK__"); /* L: ... func arg1 arg2 ... G */
if (!lua_isfunction(_state, -1))
{
lua_pop(_state, 1); /* L: ... func arg1 arg2 ... */
}
else
{
lua_insert(_state, functionIndex - 1); /* L: ... G func arg1 arg2 ... */
traceback = functionIndex - 1;
}
int error = 0;
++_callFromLua;
error = lua_pcall(_state, numArgs, numResults, traceback); /* L: ... [G] ret1 ret2 ... retResults*/
--_callFromLua;
if (error)
{
if (traceback == 0)
{
CCLOG("[LUA ERROR] %s", lua_tostring(_state, - 1)); /* L: ... error */
lua_pop(_state, 1); // remove error message from stack
}
else /* L: ... G error */
{
lua_pop(_state, 2); // remove __G__TRACKBACK__ and error message from stack
}
lua_settop(_state,top);
return 0;
}
// get return value,don't pass LUA_MULTRET to numResults,
if (numResults <= 0)
{
lua_settop(_state,top);
return 0;
}
for (int i = 0 ; i < numResults; i++)
{
if (lua_type(_state, -1) == LUA_TBOOLEAN) {
bool value = lua_toboolean(_state, -1);
resultArray.addObject(Bool::create(value)) ;
}else if (lua_type(_state, -1) == LUA_TNUMBER) {
double value = lua_tonumber(_state, -1);
resultArray.addObject(Double::create(value));
}else if (lua_type(_state, -1) == LUA_TSTRING) {
const char* value = lua_tostring(_state, -1);
resultArray.addObject(String::create(value));
}else{
resultArray.addObject(static_cast<Ref*>(tolua_tousertype(_state, -1, nullptr)));
}
// remove return value from stack
lua_pop(_state, 1); /* L: ... [G] ret1 ret2 ... ret*/
}
/* L: ... [G]*/
if (traceback)
{
lua_pop(_state, 1); // remove __G__TRACKBACK__ from stack /* L: ... */
}
}
lua_settop(_state,top);
return 1;
}
int LuaStack::executeFunction(int handler, int numArgs, int numResults, const std::function<void(lua_State*,int)>& func)
{
if (pushFunctionByHandler(handler)) /* L: ... arg1 arg2 ... func */
{
if (numArgs > 0)
{
lua_insert(_state, -(numArgs + 1)); /* L: ... func arg1 arg2 ... */
}
int functionIndex = -(numArgs + 1);
if (!lua_isfunction(_state, functionIndex))
{
CCLOG("value at stack [%d] is not function", functionIndex);
lua_pop(_state, numArgs + 1); // remove function and arguments
return 0;
}
int traceCallback = 0;
lua_getglobal(_state, "__G__TRACKBACK__"); /* L: ... func arg1 arg2 ... G */
if (!lua_isfunction(_state, -1))
{
lua_pop(_state, 1); /* L: ... func arg1 arg2 ... */
}
else
{
lua_insert(_state, functionIndex - 1); /* L: ... G func arg1 arg2 ... */
traceCallback = functionIndex - 1;
}
int error = 0;
++_callFromLua;
error = lua_pcall(_state, numArgs, numResults, traceCallback); /* L: ... [G] ret1 ret2 ... retResults*/
--_callFromLua;
if (error)
{
if (traceCallback == 0)
{
CCLOG("[LUA ERROR] %s", lua_tostring(_state, - 1)); /* L: ... error */
lua_pop(_state, 1); // remove error message from stack
}
else /* L: ... G error */
{
lua_pop(_state, 2); // remove __G__TRACKBACK__ and error message from stack
}
return 0;
}
// get return value,don't pass LUA_MULTRET to numResults,
do {
if (numResults <= 0 || nullptr == func)
break;
func(_state, numResults);
} while (0);
if (traceCallback)
{
lua_pop(_state, 1); // remove __G__TRACKBACK__ from stack /* L: ... */
}
}
return 1;
}
int LuaStack::reload(const char* moduleFileName)
{
if (nullptr == moduleFileName || strlen(moduleFileName) == 0)
{
CCLOG("moudulFileName is null");
return 1;
}
lua_getglobal(_state, "package"); /* L: package */
lua_getfield(_state, -1, "loaded"); /* L: package loaded */
lua_pushstring(_state, moduleFileName);
lua_gettable(_state, -2); /* L:package loaded module */
if (!lua_isnil(_state, -1))
{
lua_pushstring(_state, moduleFileName); /* L:package loaded module name */
lua_pushnil(_state); /* L:package loaded module name nil*/
lua_settable(_state, -4); /* L:package loaded module */
}
lua_pop(_state, 3);
std::string name = moduleFileName;
std::string require = "require \'" + name + "\'";
return executeString(require.c_str());
}
void LuaStack::setXXTEAKeyAndSign(const char *key, const char *sign)
{
int keyLen = (int)strlen(key);
int signLen = (int)strlen(sign);
cleanupXXTEAKeyAndSign();
if (key && keyLen && sign && signLen)
{
_xxteaKey = (char*)malloc(keyLen);
memcpy(_xxteaKey, key, keyLen);
_xxteaKeyLen = keyLen;
_xxteaSign = (char*)malloc(signLen);
memcpy(_xxteaSign, sign, signLen);
_xxteaSignLen = signLen;
_xxteaEnabled = true;
}
else
{
_xxteaEnabled = false;
}
}
void LuaStack::cleanupXXTEAKeyAndSign()
{
if (_xxteaKey)
{
free(_xxteaKey);
_xxteaKey = nullptr;
_xxteaKeyLen = 0;
}
if (_xxteaSign)
{
free(_xxteaSign);
_xxteaSign = nullptr;
_xxteaSignLen = 0;
}
}
const char* LuaStack::getXXTEAKey(int *len)
{
if (_xxteaEnabled && _xxteaKey) {
if (len) {
*len = _xxteaKeyLen;
}
return _xxteaKey;
}
return nullptr;
}
const char* LuaStack::getXXTEASign(int *len)
{
if (_xxteaEnabled && _xxteaSign) {
if (len) {
*len = _xxteaSignLen;
}
return _xxteaSign;
}
return nullptr;
}
int LuaStack::loadChunksFromZIP(const char *zipFilePath)
{
pushString(zipFilePath);
luaLoadChunksFromZIP(_state);
int ret = lua_toboolean(_state, -1);
lua_pop(_state, 1);
return ret;
}
int LuaStack::luaLoadChunksFromZIP(lua_State *L)
{
if (lua_gettop(L) < 1) {
CCLOG("luaLoadChunksFromZIP() - invalid arguments");
return 0;
}
const char *zipFilename = lua_tostring(L, -1);
lua_settop(L, 0);
FileUtils *utils = FileUtils::getInstance();
std::string zipFilePath = utils->fullPathForFilename(zipFilename);
LuaStack *stack = this;
do {
ssize_t size = 0;
void *buffer = nullptr;
unsigned char *zipFileData = utils->getFileData(zipFilePath.c_str(), "rb", &size);
ZipFile *zip = nullptr;
bool isXXTEA = stack && stack->_xxteaEnabled && zipFileData;
for (int i = 0; isXXTEA && i < stack->_xxteaSignLen && i < size; ++i) {
isXXTEA = zipFileData[i] == stack->_xxteaSign[i];
}
if (isXXTEA) { // decrypt XXTEA
xxtea_long len = 0;
buffer = xxtea_decrypt(zipFileData + stack->_xxteaSignLen,
(xxtea_long)size - (xxtea_long)stack->_xxteaSignLen,
(unsigned char*)stack->_xxteaKey,
(xxtea_long)stack->_xxteaKeyLen,
&len);
free(zipFileData);
zipFileData = nullptr;
zip = ZipFile::createWithBuffer(buffer, len);
} else {
if (zipFileData) {
zip = ZipFile::createWithBuffer(zipFileData, size);
}
}
if (zip) {
CCLOG("lua_loadChunksFromZIP() - load zip file: %s%s", zipFilePath.c_str(), isXXTEA ? "*" : "");
lua_getglobal(L, "package");
lua_getfield(L, -1, "preload");
int count = 0;
std::string filename = zip->getFirstFilename();
while (filename.length()) {
ssize_t bufferSize = 0;
unsigned char *zbuffer = zip->getFileData(filename.c_str(), &bufferSize);
if (bufferSize) {
if (stack->luaLoadBuffer(L, (char*)zbuffer, (int)bufferSize, filename.c_str()) == 0) {
lua_setfield(L, -2, filename.c_str());
++count;
}
free(zbuffer);
}
filename = zip->getNextFilename();
}
CCLOG("lua_loadChunksFromZIP() - loaded chunks count: %d", count);
lua_pop(L, 2);
lua_pushboolean(L, 1);
delete zip;
} else {
CCLOG("lua_loadChunksFromZIP() - not found or invalid zip file: %s", zipFilePath.c_str());
lua_pushboolean(L, 0);
}
if (zipFileData) {
free(zipFileData);
}
if (buffer) {
free(buffer);
}
} while (0);
return 1;
}
int LuaStack::luaLoadBuffer(lua_State *L, const char *chunk, int chunkSize, const char *chunkName)
{
int r = 0;
if (_xxteaEnabled && strncmp(chunk, _xxteaSign, _xxteaSignLen) == 0)
{
// decrypt XXTEA
xxtea_long len = 0;
unsigned char* result = xxtea_decrypt((unsigned char*)chunk + _xxteaSignLen,
(xxtea_long)chunkSize - _xxteaSignLen,
(unsigned char*)_xxteaKey,
(xxtea_long)_xxteaKeyLen,
&len);
r = luaL_loadbuffer(L, (char*)result, len, chunkName);
free(result);
}
else
{
r = luaL_loadbuffer(L, chunk, chunkSize, chunkName);
}
#if defined(COCOS2D_DEBUG) && COCOS2D_DEBUG > 0
if (r)
{
switch (r)
{
case LUA_ERRSYNTAX:
CCLOG("[LUA ERROR] load \"%s\", error: syntax error during pre-compilation.", chunkName);
break;
case LUA_ERRMEM:
CCLOG("[LUA ERROR] load \"%s\", error: memory allocation error.", chunkName);
break;
case LUA_ERRFILE:
CCLOG("[LUA ERROR] load \"%s\", error: cannot open/read file.", chunkName);
break;
default:
CCLOG("[LUA ERROR] load \"%s\", error: unknown.", chunkName);
}
}
#endif
return r;
}
NS_CC_END