bool CLuaMain::LoadScript ( const char* szLUAScript ) { if ( m_luaVM && !IsLuaCompiledScript( szLUAScript, strlen( szLUAScript ) ) ) { // Run the script if ( !CLuaMain::LuaLoadBuffer ( m_luaVM, szLUAScript, strlen(szLUAScript), NULL ) ) { ResetInstructionCount (); int luaSavedTop = lua_gettop ( m_luaVM ); int iret = this->PCall ( m_luaVM, 0, LUA_MULTRET, 0 ) ; if ( iret == LUA_ERRRUN || iret == LUA_ERRMEM ) { std::string strRes = ConformResourcePath ( lua_tostring( m_luaVM, -1 ) ); g_pGame->GetScriptDebugging()->LogPCallError( m_luaVM, strRes ); } // Cleanup any return values if ( lua_gettop ( m_luaVM ) > luaSavedTop ) lua_settop( m_luaVM, luaSavedTop ); } else { std::string strRes = ConformResourcePath ( lua_tostring( m_luaVM, -1 ) ); g_pGame->GetScriptDebugging()->LogError ( m_luaVM, "Loading in-line script failed: %s", strRes.c_str () ); } } else return false; return true; }
/////////////////////////////////////////////////////////////// // // CLuaMain::LuaLoadBuffer // // luaL_loadbuffer call wrapper // /////////////////////////////////////////////////////////////// int CLuaMain::LuaLoadBuffer( lua_State *L, const char *buff, size_t sz, const char *name ) { if ( IsLuaCompiledScript( buff, sz ) ) { ms_strExpectedUndumpHash = GenerateSha256HexString( buff, sz ); } int iResult = luaL_loadbuffer( L, buff, sz, name ); ms_strExpectedUndumpHash = ""; return iResult; }
/////////////////////////////////////////////////////////////// // // CResourceChecker::CheckLuaFileForIssues // // // /////////////////////////////////////////////////////////////// void CResourceChecker::CheckLuaFileForIssues ( const string& strPath, const string& strFileName, const string& strResourceName, bool bClientScript ) { // Load the original file into a string SString strFileContents; // Open the file FileLoad ( strPath, strFileContents ); if ( strFileContents.length () == 0 ) return; // Update decrypt version requirements, and do no more checking if encrypted if ( CheckLuaDecryptRequirements( strFileContents, strFileName, strResourceName, bClientScript ) ) return; // Check if a compiled script bool bCompiledScript = IsLuaCompiledScript( strFileContents.c_str(), strFileContents.length() ); // Process if ( strFileContents.length () > 1000000 ) CLogger::LogPrintf ( "Please wait...\n" ); // Ouput warnings... if ( m_bUpgradeScripts == false ) { CheckLuaSourceForIssues ( strFileContents, strFileName, strResourceName, bClientScript, bCompiledScript, ECheckerMode::WARNINGS ); } else // ..or do an upgrade (if not compiled) if ( m_bUpgradeScripts == true && !bCompiledScript ) { string strNewFileContents; CheckLuaSourceForIssues ( strFileContents, strFileName, strResourceName, bClientScript, bCompiledScript, ECheckerMode::UPGRADE, &strNewFileContents ); // Has contents changed? if ( strNewFileContents.length () > 0 && strNewFileContents != strFileContents ) { // Rename original to lua.old if( !RenameBackupFile( strPath, ".old" ) ) return; // Save new content if ( FILE* pFile = fopen ( strPath.c_str (), "wb" ) ) { fwrite ( strNewFileContents.c_str (), 1, strNewFileContents.length (), pFile ); fclose ( pFile ); CLogger::LogPrintf ( "Upgrading %s:%s ...........done\n", strResourceName.c_str (), strFileName.c_str () ); m_upgradedFullPathList.push_back( strPath ); } } } }
/////////////////////////////////////////////////////////////// // // CResourceChecker::CheckLuaDeobfuscateRequirements // // Updates version requirements and returns true if obfuscated // /////////////////////////////////////////////////////////////// bool CResourceChecker::CheckLuaDeobfuscateRequirements ( const string& strFileContents, const string& strFileName, const string& strResourceName, bool bClientScript ) { // Get embedded version requirements SScriptInfo scriptInfo; if ( !g_pRealNetServer->GetScriptInfo( strFileContents.c_str(), strFileContents.length(), &scriptInfo ) ) { if ( bClientScript && IsLuaCompiledScript( strFileContents.c_str(), strFileContents.length() ) ) { // Compiled client script with no version info #if MTA_DM_VERSION < 0x135 SString strMessage( "%s is invalid and will not work in future versions. Please re-compile at http://luac.mtasa.com/", strFileName.c_str() ); CLogger::LogPrint ( SString ( "WARNING: %s %s\n", strResourceName.c_str (), *strMessage ) ); #else SString strMessage( "%s is invalid. Please re-compile at http://luac.mtasa.com/", strFileName.c_str() ); CLogger::LogPrint ( SString ( "ERROR: %s %s\n", strResourceName.c_str (), *strMessage ) ); #endif } return false; } SString strMinServerHostVer = scriptInfo.szMinServerHostVer; SString strMinServerRunVer = scriptInfo.szMinServerRunVer; SString strMinClientRunVer = scriptInfo.szMinClientRunVer; // Check server host requirements if ( strMinServerHostVer > m_strReqServerVersion ) { m_strReqServerVersion = strMinServerHostVer; m_strReqServerReason = strFileName; } // Check run requirements if ( bClientScript && strMinClientRunVer > m_strReqClientVersion ) { m_strReqClientVersion = strMinClientRunVer; m_strReqClientReason = strFileName; } else if ( !bClientScript && strMinServerRunVer > m_strReqServerVersion ) { m_strReqServerVersion = strMinServerRunVer; m_strReqServerReason = strFileName; } return IsLuaObfuscatedScript( strFileContents.c_str(), strFileContents.length() ); }
// If compiled script, make sure correct chunkname is embedded void CLuaShared::EmbedChunkName(SString strChunkName, const char** pcpOutBuffer, uint* puiOutSize) { const char*& cpBuffer = *pcpOutBuffer; uint& uiSize = *puiOutSize; if (!IsLuaCompiledScript(cpBuffer, uiSize)) return; if (uiSize < 12) return; // Get size of name in original uint uiStringSizeOrig = *(uint*)(cpBuffer + 12); if (uiSize < 12 + 4 + uiStringSizeOrig) return; static CBuffer store; store.Clear(); CBufferWriteStream stream(store); // Ensure name starts with @ and ends with NULL if (!strChunkName.BeginsWith("@")) strChunkName = "@" + strChunkName; if (strChunkName[strChunkName.length() - 1] != '\0') strChunkName.push_back('\0'); // Header stream.WriteBytes(cpBuffer, 12); // New name size stream.Write(strChunkName.length()); // New name bytes incl zero termination stream.WriteBytes(strChunkName.c_str(), strChunkName.length()); // And the rest stream.WriteBytes(cpBuffer + 12 + 4 + uiStringSizeOrig, uiSize - 12 - 4 - uiStringSizeOrig); cpBuffer = store.GetData(); uiSize = store.GetSize(); }
bool CLuaMain::LoadScriptFromBuffer ( const char* cpInBuffer, unsigned int uiInSize, const char* szFileName ) { SString strNiceFilename = ConformResourcePath( szFileName ); // Decrypt if required const char* cpBuffer; uint uiSize; if ( !g_pRealNetServer->DecryptScript( cpInBuffer, uiInSize, &cpBuffer, &uiSize, strNiceFilename ) ) { SString strMessage( "%s is invalid. Please re-compile at http://luac.mtasa.com/", *strNiceFilename ); g_pGame->GetScriptDebugging()->LogError ( m_luaVM, "Loading script failed: %s", *strMessage ); return false; } bool bUTF8; // UTF-8 BOM? Compare by checking the standard UTF-8 BOM if ( IsUTF8BOM( cpBuffer, uiSize ) == false ) { // Maybe not UTF-8, if we have a >80% heuristic detection confidence, assume it is bUTF8 = ( GetUTF8Confidence ( (const unsigned char*)cpBuffer, uiSize ) >= 80 ); } else { // If there's a BOM, load ignoring the first 3 bytes bUTF8 = true; cpBuffer += 3; uiSize -= 3; } // If compiled script, make sure correct chunkname is embedded EmbedChunkName( strNiceFilename, &cpBuffer, &uiSize ); if ( m_luaVM ) { // Are we not marked as UTF-8 already, and not precompiled? std::string strUTFScript; if ( !bUTF8 && !IsLuaCompiledScript( cpBuffer, uiSize ) ) { std::string strBuffer = std::string(cpBuffer, uiSize); #ifdef WIN32 std::setlocale(LC_CTYPE,""); // Temporarilly use locales to read the script strUTFScript = UTF16ToMbUTF8(ANSIToUTF16( strBuffer )); std::setlocale(LC_CTYPE,"C"); #else strUTFScript = UTF16ToMbUTF8(ANSIToUTF16( strBuffer )); #endif if ( uiSize != strUTFScript.size() ) { uiSize = strUTFScript.size(); g_pGame->GetScriptDebugging()->LogWarning ( m_luaVM, "Script '%s' is not encoded in UTF-8. Loading as ANSI...", strNiceFilename.c_str() ); } } else strUTFScript = std::string(cpBuffer, uiSize); // Run the script if ( CLuaMain::LuaLoadBuffer ( m_luaVM, bUTF8 ? cpBuffer : strUTFScript.c_str(), uiSize, SString ( "@%s", *strNiceFilename ) ) ) { // Print the error std::string strRes = lua_tostring( m_luaVM, -1 ); if ( strRes.length () ) { CLogger::LogPrintf ( "SCRIPT ERROR: %s\n", strRes.c_str () ); g_pGame->GetScriptDebugging()->LogError ( m_luaVM, "Loading script failed: %s", strRes.c_str () ); } else { CLogger::LogPrint ( "SCRIPT ERROR: Unknown\n" ); g_pGame->GetScriptDebugging()->LogError ( m_luaVM, "Loading script failed for unknown reason" ); } } else { ResetInstructionCount (); int luaSavedTop = lua_gettop ( m_luaVM ); int iret = this->PCall ( m_luaVM, 0, LUA_MULTRET, 0 ) ; if ( iret == LUA_ERRRUN || iret == LUA_ERRMEM ) { SString strRes = lua_tostring( m_luaVM, -1 ); g_pGame->GetScriptDebugging()->LogPCallError( m_luaVM, strRes, true ); } // Cleanup any return values if ( lua_gettop ( m_luaVM ) > luaSavedTop ) lua_settop( m_luaVM, luaSavedTop ); return true; } } return false; }