diff --git a/Client/mods/deathmatch/logic/lua/CLuaMain.cpp b/Client/mods/deathmatch/logic/lua/CLuaMain.cpp index 4f97dc44ba4..03412bd808b 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaMain.cpp +++ b/Client/mods/deathmatch/logic/lua/CLuaMain.cpp @@ -38,6 +38,8 @@ CLuaMain::CLuaMain(CLuaManager* pLuaManager, CResource* pResourceOwner, bool bEn m_pResource = pResourceOwner; + m_iPackageLoadedRef = -1; + m_bEnableOOP = bEnableOOP; CClientPerfStatLuaMemory::GetSingleton()->OnLuaMainCreate(this); @@ -158,6 +160,9 @@ void CLuaMain::InitVM() luaopen_utf8(m_luaVM); luaopen_os(m_luaVM); + // Initialize packages system + InitPackageStorage(m_luaVM); + // Initialize security restrictions. Very important to prevent lua trojans and viruses! InitSecurity(); @@ -212,7 +217,8 @@ void CLuaMain::InstructionCountHook(lua_State* luaVM, lua_Debug* pDebug) } } -bool CLuaMain::LoadScriptFromBuffer(const char* cpInBuffer, unsigned int uiInSize, const char* szFileName) + +bool CLuaMain::LoadScriptFromBuffer(const char* cpInBuffer, unsigned int uiInSize, const char* szFileName, bool bClearReturnValues) { SString strNiceFilename = ConformResourcePath(szFileName); @@ -276,7 +282,7 @@ bool CLuaMain::LoadScriptFromBuffer(const char* cpInBuffer, unsigned int uiInSiz g_pClientGame->GetScriptDebugging()->LogPCallError(m_luaVM, strRes, true); } // Cleanup any return values - if (lua_gettop(m_luaVM) > luaSavedTop) + if (bClearReturnValues && lua_gettop(m_luaVM) > luaSavedTop) lua_settop(m_luaVM, luaSavedTop); return true; } diff --git a/Client/mods/deathmatch/logic/lua/CLuaMain.h b/Client/mods/deathmatch/logic/lua/CLuaMain.h index 778564ddbeb..09d3b887437 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaMain.h +++ b/Client/mods/deathmatch/logic/lua/CLuaMain.h @@ -40,7 +40,7 @@ class CLuaMain //: public CClient CLuaMain(class CLuaManager* pLuaManager, CResource* pResourceOwner, bool bEnableOOP); ~CLuaMain(); - bool LoadScriptFromBuffer(const char* cpBuffer, unsigned int uiSize, const char* szFileName); + bool LoadScriptFromBuffer(const char* cpBuffer, unsigned int uiSize, const char* szFileName, bool bClearReturnValues = true); bool LoadScript(const char* szLUAScript); void UnloadScript(); @@ -79,6 +79,11 @@ class CLuaMain //: public CClient bool IsOOPEnabled() { return m_bEnableOOP; } + void InitPackageStorage(lua_State* L); // Create a psuedo package.loaded table + void GetPackage(lua_State* L, SString& strName); // Push the package value to the top of the stack + void SetPackage(lua_State* L, SString& strName); // Set the package to the value at the top of the stack + bool LoadLuaLib(lua_State* L, SString strName, SString& strError, bool& bEmpty); // Load a lua library of a given name + private: void InitSecurity(); @@ -88,6 +93,7 @@ class CLuaMain //: public CClient lua_State* m_luaVM; CLuaTimerManager* m_pLuaTimerManager; + int m_iPackageLoadedRef; bool m_bBeingDeleted; // prevent it being deleted twice diff --git a/Server/mods/deathmatch/logic/CAccessControlListManager.cpp b/Server/mods/deathmatch/logic/CAccessControlListManager.cpp index c5b89d43bb8..07ebaeca690 100644 --- a/Server/mods/deathmatch/logic/CAccessControlListManager.cpp +++ b/Server/mods/deathmatch/logic/CAccessControlListManager.cpp @@ -141,6 +141,10 @@ bool CAccessControlListManager::Load() { pRight = pACL->AddRight(&szRightName[8], CAccessControlListRight::RIGHT_TYPE_GENERAL, bAccess); } + else if (StringBeginsWith(szRightName, "module.")) + { + pRight = pACL->AddRight(&szRightName[7], CAccessControlListRight::RIGHT_TYPE_MODULE, bAccess); + } else continue; @@ -536,6 +540,11 @@ const char* CAccessControlListManager::ExtractRightName(const char* szRightName, eType = CAccessControlListRight::RIGHT_TYPE_GENERAL; return szRightName + 8; } + else if ( StringBeginsWith( szRightName, "module." ) ) + { + eType = CAccessControlListRight::RIGHT_TYPE_MODULE; + return szRightName + 7; + } // Failed return NULL; diff --git a/Server/mods/deathmatch/logic/CAccessControlListRight.h b/Server/mods/deathmatch/logic/CAccessControlListRight.h index 77754eef201..d74186a1046 100644 --- a/Server/mods/deathmatch/logic/CAccessControlListRight.h +++ b/Server/mods/deathmatch/logic/CAccessControlListRight.h @@ -23,7 +23,8 @@ class CAccessControlListRight RIGHT_TYPE_COMMAND, RIGHT_TYPE_FUNCTION, RIGHT_TYPE_RESOURCE, - RIGHT_TYPE_GENERAL + RIGHT_TYPE_GENERAL, + RIGHT_TYPE_MODULE }; public: diff --git a/Server/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp b/Server/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp index 5080411940a..e14a24ba62a 100644 --- a/Server/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp +++ b/Server/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp @@ -239,6 +239,7 @@ ADD_ENUM(CAccessControlListRight::RIGHT_TYPE_COMMAND, "command") ADD_ENUM(CAccessControlListRight::RIGHT_TYPE_FUNCTION, "function") ADD_ENUM(CAccessControlListRight::RIGHT_TYPE_RESOURCE, "resource") ADD_ENUM(CAccessControlListRight::RIGHT_TYPE_GENERAL, "general") +ADD_ENUM(CAccessControlListRight::RIGHT_TYPE_MODULE, "module") IMPLEMENT_ENUM_END("right-type") IMPLEMENT_ENUM_BEGIN(CElement::EElementType) diff --git a/Server/mods/deathmatch/logic/lua/CLuaMain.cpp b/Server/mods/deathmatch/logic/lua/CLuaMain.cpp index fa83d6b46d8..68c4cbddcf9 100644 --- a/Server/mods/deathmatch/logic/lua/CLuaMain.cpp +++ b/Server/mods/deathmatch/logic/lua/CLuaMain.cpp @@ -123,7 +123,6 @@ void CLuaMain::InitSecurity() lua_register(m_luaVM, "dofile", CLuaUtilDefs::DisabledFunction); lua_register(m_luaVM, "loadfile", CLuaUtilDefs::DisabledFunction); - lua_register(m_luaVM, "require", CLuaUtilDefs::DisabledFunction); lua_register(m_luaVM, "loadlib", CLuaUtilDefs::DisabledFunction); lua_register(m_luaVM, "getfenv", CLuaUtilDefs::DisabledFunction); lua_register(m_luaVM, "newproxy", CLuaUtilDefs::DisabledFunction); @@ -187,6 +186,9 @@ void CLuaMain::InitVM() luaopen_utf8(m_luaVM); luaopen_os(m_luaVM); + // Initialize packages system + InitPackageStorage(m_luaVM); + // Initialize security restrictions. Very important to prevent lua trojans and viruses! InitSecurity(); @@ -241,7 +243,7 @@ void CLuaMain::InstructionCountHook(lua_State* luaVM, lua_Debug* pDebug) } } -bool CLuaMain::LoadScriptFromBuffer(const char* cpInBuffer, unsigned int uiInSize, const char* szFileName) +bool CLuaMain::LoadScriptFromBuffer(const char* cpInBuffer, unsigned int uiInSize, const char* szFileName, bool bClearReturnValues) { SString strNiceFilename = ConformResourcePath(szFileName); @@ -311,7 +313,7 @@ bool CLuaMain::LoadScriptFromBuffer(const char* cpInBuffer, unsigned int uiInSiz g_pGame->GetScriptDebugging()->LogPCallError(m_luaVM, strRes, true); } // Cleanup any return values - if (lua_gettop(m_luaVM) > luaSavedTop) + if (bClearReturnValues && lua_gettop(m_luaVM) > luaSavedTop) lua_settop(m_luaVM, luaSavedTop); return true; } @@ -661,3 +663,53 @@ int CLuaMain::OnUndump(const char* p, size_t n) } return 1; } + +/////////////////////////////////////////////////////////////// +// +// CLuaMain::LoadClib +// +// Load a C lib of a given name +// +/////////////////////////////////////////////////////////////// +bool CLuaMain::LoadClib(lua_State* L, SString strName, SString& strError) +{ + SString strPath = strName; + // Name format shouldn't include slashes. Subdirs are dots. + ReplaceOccurrencesInString(strPath, "\\", ""); + ReplaceOccurrencesInString(strPath, "/", ""); + ReplaceOccurrencesInString(strPath, ".", "/"); + + strPath = PathJoin(g_pServerInterface->GetModManager()->GetServerPath(), SERVER_BIN_PATH_MOD, "modules", strPath); + +#ifdef WIN32 + strPath += ".dll"; +#else + strPath += ".so"; +#endif + + if (!FileExists(strPath)) + { + strError += "#3: " + ConformPath(strPath, "modules/"); + return false; + } + + // Check ACL permissions + if (!g_pGame->GetACLManager()->CanObjectUseRight(m_pResource->GetName().c_str(), CAccessControlListGroupObject::OBJECT_TYPE_RESOURCE, "*", + CAccessControlListRight::RIGHT_TYPE_MODULE, false) && + !g_pGame->GetACLManager()->CanObjectUseRight(m_pResource->GetName().c_str(), CAccessControlListGroupObject::OBJECT_TYPE_RESOURCE, strName.c_str(), + CAccessControlListRight::RIGHT_TYPE_MODULE, false)) + { + strError = "could not load module '" + strName + "' from file " + ConformPath(strPath, "modules/") + ":\n\t ACL access denied. Grant \"module." + + strName + "\" right to resource " + m_pResource->GetName(); + return false; + } + + if (!luaL_loader_C(L, strName.c_str(), strPath.c_str()) || lua_type(L, -1) == LUA_TNIL) + { + strError = "failed to load module '" + strName + "' from file " + ConformPath(strPath, "modules/"); + return false; + } + + SetPackage(L, strName); + return true; +} diff --git a/Server/mods/deathmatch/logic/lua/CLuaMain.h b/Server/mods/deathmatch/logic/lua/CLuaMain.h index d8b4dcc3d72..79666ad840a 100644 --- a/Server/mods/deathmatch/logic/lua/CLuaMain.h +++ b/Server/mods/deathmatch/logic/lua/CLuaMain.h @@ -46,7 +46,7 @@ class CLuaMain //: public CClient ~CLuaMain(); - bool LoadScriptFromBuffer(const char* cpBuffer, unsigned int uiSize, const char* szFileName); + bool LoadScriptFromBuffer(const char* cpBuffer, unsigned int uiSize, const char* szFileName, bool bClearReturnValues = true); bool LoadScript(const char* szLUAScript); void UnloadScript(); @@ -109,6 +109,12 @@ class CLuaMain //: public CClient static int LuaLoadBuffer(lua_State* L, const char* buff, size_t sz, const char* name); static int OnUndump(const char* p, size_t n); + void InitPackageStorage(lua_State* L); // Create a psuedo package.loaded table + void GetPackage(lua_State* L, SString& strName); // Push the package value to the top of the stack + void SetPackage(lua_State* L, SString& strName); // Set the package to the value at the top of the stack + bool LoadLuaLib(lua_State* L, SString strName, SString& strError, bool& bEmpty); // Load a lua library of a given name + bool LoadClib(lua_State* L, SString strName, SString& strError); // Load a C Lib of a given name + private: void InitSecurity(); void InitClasses(lua_State* luaVM); @@ -123,6 +129,7 @@ class CLuaMain //: public CClient lua_State* m_luaVM; CLuaTimerManager* m_pLuaTimerManager; + int m_iPackageLoadedRef; class CResource* m_pResource; class CResourceFile* m_pResourceFile; diff --git a/Server/mods/deathmatch/mtaserver.conf b/Server/mods/deathmatch/mtaserver.conf index 2d8cc2ad260..abf0831f5c4 100644 --- a/Server/mods/deathmatch/mtaserver.conf +++ b/Server/mods/deathmatch/mtaserver.conf @@ -1,294 +1,294 @@ - - - - Default MTA Server - - - - - - - auto - - - - 22003 - - - 32 - - - 22005 - - - - - - 5 - - - 20 - - - - - - none - - - - - - - - - - - - - - - - 1 - - - - - - 1 - - - 0 - - - - - - medium - - - - 100 - - 1500 - - 500 - - 400 - - 400 - - 100 - - 100 - - - 1 - - - 0 - - - 150 - - - 0 - - - server-id.keys - - - logs/server.log - - - logs/server_auth.log - - - logs/db.log - - - - - - acl.xml - - - logs/scripts.log - - - 0 - - - 0 - - - 1 - - - 36 - - - 0 - - - 1 - - - 4 - - - - - - backups - - - 3 - - - 5 - - - 1 - - - 1 - - - Admin - - - 1 - - - 127.0.0.1 - - - 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + Default MTA Server + + + + + + + auto + + + + 22003 + + + 32 + + + 22005 + + + + + + 5 + + + 20 + + + + + + none + + + + + + + + + + + + + + + + 1 + + + + + + 1 + + + 0 + + + + + + medium + + + + 100 + + 1500 + + 500 + + 400 + + 400 + + 100 + + 100 + + + 1 + + + 0 + + + 150 + + + 0 + + + server-id.keys + + + logs/server.log + + + logs/server_auth.log + + + logs/db.log + + + + + + acl.xml + + + logs/scripts.log + + + 0 + + + 0 + + + 1 + + + 36 + + + 0 + + + 1 + + + 4 + + + + + + backups + + + 3 + + + 5 + + + 1 + + + 1 + + + Admin + + + 1 + + + 127.0.0.1 + + + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Shared/mods/deathmatch/logic/lua/CLuaMain.Shared.cpp b/Shared/mods/deathmatch/logic/lua/CLuaMain.Shared.cpp new file mode 100644 index 00000000000..455d2a624ec --- /dev/null +++ b/Shared/mods/deathmatch/logic/lua/CLuaMain.Shared.cpp @@ -0,0 +1,155 @@ +/***************************************************************************** + * + * PROJECT: Multi Theft Auto + * LICENSE: See LICENSE in the top level directory + * FILE: Shared/mods/logic/lua/CLuaMain.Shared.cpp + * + *****************************************************************************/ + +#include "StdInc.h" + +/////////////////////////////////////////////////////////////// +// +// CLuaMain::InitPackageStorage +// +// Create a table for storage of Lua packages - stored in the Lua VM +// +/////////////////////////////////////////////////////////////// +void CLuaMain::InitPackageStorage(lua_State* L) +{ + lua_newtable(L); // stack: [tbl_new] + lua_pushstring(L, "loaded"); // stack: [tbl_new,"loaded"] + lua_newtable(L); // stack: [tbl_new,"loaded",tbl_new2] + + // We push our default Lua libs are loaded packages + std::vector szDefaultLibs = {"math", "string", "table", "debug", "utf8"}; + for (auto it : szDefaultLibs) + { + lua_pushstring(L, it); // stack: [tbl_new,"loaded",tbl_new2,"math"] + lua_getglobal(L, it); // stack: [tbl_new,"loaded",tbl_new2,"math",_G.math] + lua_settable(L, -3); // stack: [tbl_new,"loaded",tbl_new2] + } + + // Keep our package.loaded table safely in registry + m_iPackageLoadedRef = luaL_ref(L, LUA_REGISTRYINDEX); // stack: [tbl_new,"loaded"] + lua_rawgeti(L, LUA_REGISTRYINDEX, m_iPackageLoadedRef); // stack: [tbl_new,"loaded",tbl_new2] + + // Finally, store our original table as global package.loaded + lua_settable(L, -3); // stack: [tbl_new] + lua_setglobal(L, "package"); // stack: [] +} + +/////////////////////////////////////////////////////////////// +// +// CLuaMain::SetPackage +// +// Set the top most value as a package (No pop) +// +/////////////////////////////////////////////////////////////// +void CLuaMain::SetPackage(lua_State* L, SString& strName) +{ + if (m_iPackageLoadedRef < 0) + return; + // We set varPkg, which is already on the stack, into package.loaded.moduleName = varPkg. + // stack: [varPkg] + int iPkg = luaL_ref(L, LUA_REGISTRYINDEX); // stack: [] + lua_rawgeti(L, LUA_REGISTRYINDEX, m_iPackageLoadedRef); // [tbl_loaded] + + lua_pushstring(L, strName.c_str()); // stack: [tbl_loaded,"moduleName"] + lua_rawgeti(L, LUA_REGISTRYINDEX, iPkg); // stack: [tbl_loaded,"moduleName",varPkg] + lua_rawset(L, -3); // stack: [tbl_loaded] + lua_pop(L, 2); // stack: [] + lua_rawgeti(L, LUA_REGISTRYINDEX, iPkg); // stack: [varPkg] + + // Cleanup our used registry entry, i.e. REGISTRY[i] = nil. + lua_pushnil(L); // stack: [varPkg,nil] + lua_rawseti(L, LUA_REGISTRYINDEX, iPkg); // stack: [varPkg] +} + +/////////////////////////////////////////////////////////////// +// +// CLuaMain::GetPackage +// +// Push the value of a package of name to the stack +// +/////////////////////////////////////////////////////////////// +void CLuaMain::GetPackage(lua_State* L, SString& strName) +{ + if (m_iPackageLoadedRef < 0) + return; + + lua_rawgeti(L, LUA_REGISTRYINDEX, m_iPackageLoadedRef); // stack: [tbl_loaded] + lua_pushstring(L, strName.c_str()); // stack: [tbl_loaded,"moduleName"] + lua_rawget(L, -2); // stack: [tbl_loaded,varPkg] + lua_remove(L, -2); // stack: [varPkg] +} + +/////////////////////////////////////////////////////////////// +// +// CLuaMain::LoadLuaLib +// +// Load a Lua lib of a given name +// +/////////////////////////////////////////////////////////////// +bool CLuaMain::LoadLuaLib(lua_State* L, SString strName, SString& strError, bool& bEmpty) +{ + SString strPath = strName; + // Name format shouldn't include slashes. Subdirs are dots. + ReplaceOccurrencesInString(strPath, "\\", ""); + ReplaceOccurrencesInString(strPath, "/", ""); + ReplaceOccurrencesInString(strPath, ".", "/"); + +#ifdef MTA_CLIENT + SString strResPath = m_pResource->GetResourceDirectoryPath(ACCESS_PUBLIC, ""); +#else + SString strResPath = m_pResource->IsResourceZip() ? m_pResource->GetResourceCacheDirectoryPath() : m_pResource->GetResourceDirectoryPath(); +#endif + + std::vector buffer; + strError = "error loading module '" + strName + "' from locations:\n\t"; + // Try /?.lua + SString strFilePath = PathJoin(strResPath, strPath + ".lua"); + if (FileExists(strFilePath)) + FileLoad(strFilePath, buffer); + else + { + // Don't use a format string for safety, so we construct the error by hand + strError += "#1: " + ConformPath(strFilePath, "resources/") + "\n\t"; + + // Try /?/init.lua + strFilePath = PathJoin(strResPath, strPath, "init.lua"); + if (FileExists(strFilePath)) + FileLoad(strFilePath, buffer); + else + { + strError += "#2: " + ConformPath(strFilePath, "resources/") + "\n\t"; + return false; + } + } + + if (buffer.size() > 0) + { + int luaSavedTop = lua_gettop(L); + LoadScriptFromBuffer(&buffer.at(0), buffer.size(), strFilePath.c_str(), false); + // Only keep the first return value + if (lua_gettop(L) > luaSavedTop) + lua_settop(L, luaSavedTop + 1); + + if (lua_type(L, -1) == LUA_TNIL) + { + strError = "module '" + strName + "' in location " + ConformPath(strFilePath, "resources/") + " didn't return a value."; + bEmpty = true; + return false; + } + + SetPackage(L, strName); // Store our package into package.loaded + return true; + } + else + { + strError = "could not load module '" + strName + "' from file " + ConformPath(strFilePath, "resources/") + ": File is empty."; + bEmpty = true; + } + + return false; +} diff --git a/Shared/mods/deathmatch/logic/luadefs/CLuaUtilDefs.cpp b/Shared/mods/deathmatch/logic/luadefs/CLuaUtilDefs.cpp index bc1b90618f9..b63da616bcc 100644 --- a/Shared/mods/deathmatch/logic/luadefs/CLuaUtilDefs.cpp +++ b/Shared/mods/deathmatch/logic/luadefs/CLuaUtilDefs.cpp @@ -46,6 +46,9 @@ void CLuaUtilDefs::LoadFunctions() // Utility functions {"gettok", GetTok}, {"tocolor", tocolor}, + + // Package functions + {"require", Require}, }; // Add functions @@ -711,3 +714,47 @@ int CLuaUtilDefs::tocolor(lua_State* luaVM) lua_pushnumber(luaVM, static_cast(ulColor)); return 1; } + +int CLuaUtilDefs::Require(lua_State* luaVM) +{ + // table require ( string name ) + SString strMod; + + CLuaMain* pLuaMain = m_pLuaManager->GetVirtualMachine(luaVM); + CScriptArgReader argStream(luaVM); + argStream.ReadString(strMod); + + if (!argStream.HasErrors()) + { + SString strError = ""; + bool bEmpty = false; + // Check if package exists already, if so load it + // stack: ["moduleName"] + pLuaMain->GetPackage(luaVM, strMod); // stack: ["moduleName",pkgModule/nil] + if (lua_type(luaVM, -1) != LUA_TNIL) + return 1; + lua_pop(luaVM, 1); // stack: ["moduleName"] + + // Check whether the appropriate pure lua module exists + if (pLuaMain->LoadLuaLib(luaVM, strMod, strError, bEmpty)) // stack: ["moduleName",pkgLuaMod/nil] + return 1; + + if (bEmpty) + { + m_pScriptDebugging->LogCustom(luaVM, strError); + lua_pushboolean(luaVM, false); + return 1; + } +#ifndef MTA_CLIENT + // Check if a C library exists + if (pLuaMain->LoadClib(luaVM, strMod, strError)) // stack: ["moduleName",fncModule/nil] + return 1; +#endif + m_pScriptDebugging->LogCustom(luaVM, strError); + } + else + m_pScriptDebugging->LogCustom(luaVM, argStream.GetFullErrorMessage()); + + lua_pushboolean(luaVM, false); + return 1; +} diff --git a/Shared/mods/deathmatch/logic/luadefs/CLuaUtilDefs.h b/Shared/mods/deathmatch/logic/luadefs/CLuaUtilDefs.h index 849011a94d4..a9c785394a4 100644 --- a/Shared/mods/deathmatch/logic/luadefs/CLuaUtilDefs.h +++ b/Shared/mods/deathmatch/logic/luadefs/CLuaUtilDefs.h @@ -52,4 +52,7 @@ class CLuaUtilDefs : public CLuaDefs // Utility functions LUA_DECLARE(GetTok); LUA_DECLARE(tocolor); + + // Package functions + LUA_DECLARE(Require); }; diff --git a/Shared/sdk/SharedUtil.Misc.h b/Shared/sdk/SharedUtil.Misc.h index 6ec7c42bdc0..f1d1df55953 100644 --- a/Shared/sdk/SharedUtil.Misc.h +++ b/Shared/sdk/SharedUtil.Misc.h @@ -219,6 +219,8 @@ namespace SharedUtil // SString ConformResourcePath(const char* szRes, bool bConvertToUnixPathSep = false); + SString ConformPath(const char* szRes, SString szPath, bool bConvertToUnixPathSep = false); + // // string stuff // diff --git a/Shared/sdk/SharedUtil.Misc.hpp b/Shared/sdk/SharedUtil.Misc.hpp index 6b67f65cfab..cd11a4f7b27 100644 --- a/Shared/sdk/SharedUtil.Misc.hpp +++ b/Shared/sdk/SharedUtil.Misc.hpp @@ -1607,6 +1607,43 @@ SString SharedUtil::ConformResourcePath(const char* szRes, bool bConvertToUnixPa return strText; } +SString SharedUtil::ConformPath(const char* szRes, SString szPath, bool bConvertToUnixPathSep) +{ + SString strText = szRes ? szRes : ""; + char cPathSep; + + // Handle which path sep char +#ifdef WIN32 + if (!bConvertToUnixPathSep) + { + cPathSep = '\\'; + szPath = szPath.Replace("/", "\\"); + strText = strText.Replace("/", "\\"); + } + else +#endif + { + cPathSep = '/'; + szPath = szPath.Replace("\\", "/"); + strText = strText.Replace("\\", "/"); + } + + // Remove up to first occurrence + int iPos = strText.find(szPath); + if (iPos >= 0) + return SString("%s%s", szPath.c_str(), strText.substr(iPos + szPath.length()).c_str()); + + if (strText.substr(0, 3) == "...") + { + // Remove up to first '/' + int iPos = strText.find(cPathSep); + if (iPos >= 0) + return SString("%s%s", szPath.c_str(), strText.substr(iPos + 1).c_str()); + } + + return strText; +} + namespace SharedUtil { CArgMap::CArgMap(const SString& strArgSep, const SString& strPartsSep, const SString& strExtraDisallowedChars) diff --git a/vendor/lua/src/lauxlib.h b/vendor/lua/src/lauxlib.h index 34258235dbe..fad2c246835 100644 --- a/vendor/lua/src/lauxlib.h +++ b/vendor/lua/src/lauxlib.h @@ -172,3 +172,8 @@ LUALIB_API void (luaL_pushresult) (luaL_Buffer *B); #endif +///////////////////////////// +// MTA EXTENSIONS +///////////////////////////// +LUALIB_API int luaL_loader_C(lua_State *L, const char* name, const char* filename); + diff --git a/vendor/lua/src/loadlib.c b/vendor/lua/src/loadlib.c index 6158c5353df..7b4fd6880e6 100644 --- a/vendor/lua/src/loadlib.c +++ b/vendor/lua/src/loadlib.c @@ -664,3 +664,16 @@ LUALIB_API int luaopen_package (lua_State *L) { return 1; /* return 'package' table */ } + +///////////////////////////// +// MTA EXTENSIONS +///////////////////////////// + +// API to direct load a C library. +LUA_API int luaL_loader_C(lua_State* L, const char* name, const char* filename) +{ + const char* funcname = mkfuncname(L, name); + if (ll_loadfunc(L, filename, funcname) != 0) + return 0; + return 1; /* library loaded successfully */ +} \ No newline at end of file