1
0
forked from 0ad/0ad

Expose the same ReadJSONFile function to simulation, GUI and rmgen.

This way globalscripts/ can use the same code in all contexts, all paths
are absolute and only one function name is needed.
Remove ReadCivJSONFile which is redundant with this function as well.
Restrict read access of rmgen/ to rmgen/ and simulation/, refs
4275a8a33c, 89055ef858.

Refs #4868
Differential Revision: https://code.wildfiregames.com/D1085
Reviewed By: wraitii
Partial agreement with leper

This was SVN commit r20576.
This commit is contained in:
elexis 2017-12-03 23:02:27 +00:00
parent 5e85ca5d7b
commit 0cfe9ab153
10 changed files with 78 additions and 67 deletions

View File

@ -10,7 +10,7 @@ function Resources()
{
jsonFiles = Engine.FindJSONFiles("resources", false);
for (let file in jsonFiles)
jsonFiles[file] = "resources/" + jsonFiles[file] + ".json";
jsonFiles[file] = "simulation/data/resources/" + jsonFiles[file] + ".json";
}
// GUI context
else if (Engine.BuildDirEntList)

View File

@ -25,7 +25,7 @@ DataTemplateManager.prototype.GetTechnologyTemplate = function(template)
{
if (!this.allTechs[template])
{
this.allTechs[template] = Engine.ReadJSONFile("technologies/" + template + ".json");
this.allTechs[template] = Engine.ReadJSONFile("simulation/data/technologies/" + template + ".json");
if (!this.allTechs[template])
error("Failed to load technology \"" + template + "\"");
}
@ -37,7 +37,7 @@ DataTemplateManager.prototype.GetAuraTemplate = function(template)
{
if (!this.allAuras[template])
{
this.allAuras[template] = Engine.ReadJSONFile("auras/" + template + ".json");
this.allAuras[template] = Engine.ReadJSONFile("simulation/data/auras/" + template + ".json");
if (!this.allAuras[template])
error("Failed to load aura \"" + template + "\"");
}

View File

@ -15,14 +15,9 @@ SkirmishReplacer.prototype.Init = function()
SkirmishReplacer.prototype.Serialize = null; // We have no dynamic state to save
//this function gets the replacement entities from the {civ}.json file
function getReplacementEntities(civ)
{
var rawCivData = Engine.ReadCivJSONFile(civ+".json");
if (rawCivData && rawCivData.SkirmishReplacements)
return rawCivData.SkirmishReplacements;
warn("SkirmishReplacer.js: no replacements found in '"+civ+".json'");
return {};
return Engine.ReadJSONFile("simulation/data/civs/" + civ + ".json").SkirmishReplacements;
}
SkirmishReplacer.prototype.OnOwnershipChanged = function(msg)

View File

@ -9,20 +9,16 @@
*/
function LoadPlayerSettings(settings, newPlayers)
{
var playerDefaults = Engine.ReadJSONFile("simulation/data/settings/player_defaults.json").PlayerData;
// Default settings
if (!settings)
settings = {};
// Get default player data
var rawData = Engine.ReadJSONFile("settings/player_defaults.json");
if (!(rawData && rawData.PlayerData))
throw new Error("Player.js: Error reading player_defaults.json");
// Add gaia to simplify iteration
if (settings.PlayerData && settings.PlayerData[0])
settings.PlayerData.unshift(null);
var playerDefaults = rawData.PlayerData;
var playerData = settings.PlayerData;
var cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
@ -146,18 +142,9 @@ function LoadPlayerSettings(settings, newPlayers)
cmpPlayer.SetTeam(myTeam === undefined ? -1 : myTeam);
}
// If formations explicitly defined, use that; otherwise use civ defaults
var formations = getSetting(playerData, playerDefaults, i, "Formations");
if (formations !== undefined)
cmpPlayer.SetFormations(formations);
else
{
var rawFormations = Engine.ReadCivJSONFile(cmpPlayer.GetCiv()+".json");
if (!(rawFormations && rawFormations.Formations))
throw new Error("Player.js: Error reading " + cmpPlayer.GetCiv() + ".json");
cmpPlayer.SetFormations(rawFormations.Formations);
}
cmpPlayer.SetFormations(
getSetting(playerData, playerDefaults, i, "Formations") ||
Engine.ReadJSONFile("simulation/data/civs/" + cmpPlayer.GetCiv() + ".json").Formations);
var startCam = getSetting(playerData, playerDefaults, i, "StartingCamera");
if (startCam !== undefined)

View File

@ -100,7 +100,7 @@ bool CMapGeneratorWorker::Run()
m_ScriptInterface->LoadGlobalScripts();
// Functions for RMS
JSI_VFS::RegisterReadOnlyScriptFunctions(*m_ScriptInterface);
JSI_VFS::RegisterScriptFunctions_Maps(*m_ScriptInterface);
m_ScriptInterface->RegisterFunction<bool, std::wstring, CMapGeneratorWorker::LoadLibrary>("LoadLibrary");
m_ScriptInterface->RegisterFunction<void, JS::HandleValue, CMapGeneratorWorker::ExportMap>("ExportMap");
m_ScriptInterface->RegisterFunction<void, int, CMapGeneratorWorker::SetProgress>("SetProgress");

View File

@ -65,7 +65,6 @@ void GuiScriptingInit(ScriptInterface& scriptInterface)
JSI_SavedGame::RegisterScriptFunctions(scriptInterface);
JSI_Simulation::RegisterScriptFunctions(scriptInterface);
JSI_Sound::RegisterScriptFunctions(scriptInterface);
JSI_VFS::RegisterReadOnlyScriptFunctions(scriptInterface);
JSI_VFS::RegisterWriteScriptFunctions(scriptInterface);
JSI_VFS::RegisterScriptFunctions_GUI(scriptInterface);
JSI_VisualReplay::RegisterScriptFunctions(scriptInterface);
}

View File

@ -27,6 +27,11 @@
#include "ps/scripting/JSInterface_VFS.h"
#include "lib/file/vfs/vfs_util.h"
// Only allow engine compartments to read files they may be concerned about.
#define PathRestriction_GUI {L""}
#define PathRestriction_Simulation {L"simulation/"}
#define PathRestriction_Maps {L"simulation/", L"maps/"}
// shared error handling code
#define JS_CHECK_FILE_ERR(err)\
/* this is liable to happen often, so don't complain */\
@ -178,8 +183,11 @@ JS::Value JSI_VFS::ReadFileLines(ScriptInterface::CxPrivate* pCxPrivate, const s
return JS::ObjectValue(*line_array);
}
JS::Value JSI_VFS::ReadJSONFile(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& filePath)
JS::Value JSI_VFS::ReadJSONFile(ScriptInterface::CxPrivate* pCxPrivate, const std::vector<CStrW>& validPaths, const CStrW& filePath)
{
if (!PathRestrictionMet(pCxPrivate, validPaths, filePath))
return JS::NullValue();
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
JS::RootedValue out(cx);
@ -203,7 +211,42 @@ void JSI_VFS::WriteJSONFile(ScriptInterface::CxPrivate* pCxPrivate, const std::w
g_VFS->CreateFile(path, buf.Data(), buf.Size());
}
void JSI_VFS::RegisterReadOnlyScriptFunctions(const ScriptInterface& scriptInterface)
bool JSI_VFS::PathRestrictionMet(ScriptInterface::CxPrivate* pCxPrivate, const std::vector<CStrW>& validPaths, const CStrW& filePath)
{
for (const CStrW& validPath : validPaths)
if (filePath.find(validPath) == 0)
return true;
CStrW allowedPaths;
for (std::size_t i = 0; i < validPaths.size(); ++i)
{
if (i != 0)
allowedPaths += L", ";
allowedPaths += L"\"" + validPaths[i] + L"\"";
}
JS_ReportError(
pCxPrivate->pScriptInterface->GetContext(),
"This part of the engine may only read from %s!",
utf8_from_wstring(allowedPaths).c_str());
return false;
}
#define VFS_ScriptFunctions(context)\
JS::Value Script_ReadJSONFile_##context(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& filePath)\
{\
return JSI_VFS::ReadJSONFile(pCxPrivate, PathRestriction_##context, filePath);\
}
VFS_ScriptFunctions(GUI);
VFS_ScriptFunctions(Simulation);
VFS_ScriptFunctions(Maps);
#undef VFS_ScriptFunctions
void JSI_VFS::RegisterScriptFunctions_GUI(const ScriptInterface& scriptInterface)
{
scriptInterface.RegisterFunction<JS::Value, std::wstring, std::wstring, bool, &JSI_VFS::BuildDirEntList>("BuildDirEntList");
scriptInterface.RegisterFunction<bool, CStrW, JSI_VFS::FileExists>("FileExists");
@ -211,10 +254,18 @@ void JSI_VFS::RegisterReadOnlyScriptFunctions(const ScriptInterface& scriptInter
scriptInterface.RegisterFunction<unsigned int, std::wstring, &JSI_VFS::GetFileSize>("GetFileSize");
scriptInterface.RegisterFunction<JS::Value, std::wstring, &JSI_VFS::ReadFile>("ReadFile");
scriptInterface.RegisterFunction<JS::Value, std::wstring, &JSI_VFS::ReadFileLines>("ReadFileLines");
scriptInterface.RegisterFunction<JS::Value, std::wstring, &ReadJSONFile>("ReadJSONFile");
}
void JSI_VFS::RegisterWriteScriptFunctions(const ScriptInterface& scriptInterface)
{
scriptInterface.RegisterFunction<JS::Value, std::wstring, &Script_ReadJSONFile_GUI>("ReadJSONFile");
scriptInterface.RegisterFunction<void, std::wstring, JS::HandleValue, &WriteJSONFile>("WriteJSONFile");
}
void JSI_VFS::RegisterScriptFunctions_Simulation(const ScriptInterface& scriptInterface)
{
scriptInterface.RegisterFunction<JS::Value, std::wstring, &Script_ReadJSONFile_Simulation>("ReadJSONFile");
}
void JSI_VFS::RegisterScriptFunctions_Maps(const ScriptInterface& scriptInterface)
{
scriptInterface.RegisterFunction<JS::Value, std::wstring, std::wstring, bool, &JSI_VFS::BuildDirEntList>("BuildDirEntList");
scriptInterface.RegisterFunction<bool, CStrW, JSI_VFS::FileExists>("FileExists");
scriptInterface.RegisterFunction<JS::Value, std::wstring, &Script_ReadJSONFile_Maps>("ReadJSONFile");
}

View File

@ -56,13 +56,17 @@ namespace JSI_VFS
JS::Value ReadFileLines(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& filename);
// Return file contents parsed as a JS Object
JS::Value ReadJSONFile(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& filePath);
JS::Value ReadJSONFile(ScriptInterface::CxPrivate* pCxPrivate, const std::vector<CStrW>& validPaths, const CStrW& filePath);
// Save given JS Object to a JSON file
void WriteJSONFile(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& filePath, JS::HandleValue val1);
void RegisterReadOnlyScriptFunctions(const ScriptInterface& scriptInterface);
void RegisterWriteScriptFunctions(const ScriptInterface& scriptInterface);
// Tests whether the current script context is allowed to read from the given directory
bool PathRestrictionMet(ScriptInterface::CxPrivate* pCxPrivate, const std::vector<CStrW>& validPaths, const CStrW& filePath);
void RegisterScriptFunctions_GUI(const ScriptInterface& scriptInterface);
void RegisterScriptFunctions_Simulation(const ScriptInterface& scriptInterface);
void RegisterScriptFunctions_Maps(const ScriptInterface& scriptInterface);
}
#endif

View File

@ -30,6 +30,7 @@
#include "lib/utf8.h"
#include "ps/CLogger.h"
#include "ps/Filesystem.h"
#include "ps/scripting/JSInterface_VFS.h"
/**
* Used for script-only message types.
@ -68,6 +69,7 @@ CComponentManager::CComponentManager(CSimContext& context, shared_ptr<ScriptRunt
// these functions, so we skip registering them here in those cases
if (!skipScriptFunctions)
{
JSI_VFS::RegisterScriptFunctions_Simulation(m_ScriptInterface);
m_ScriptInterface.RegisterFunction<void, int, std::string, JS::HandleValue, CComponentManager::Script_RegisterComponentType> ("RegisterComponentType");
m_ScriptInterface.RegisterFunction<void, int, std::string, JS::HandleValue, CComponentManager::Script_RegisterSystemComponentType> ("RegisterSystemComponentType");
m_ScriptInterface.RegisterFunction<void, int, std::string, JS::HandleValue, CComponentManager::Script_ReRegisterComponentType> ("ReRegisterComponentType");
@ -84,8 +86,6 @@ CComponentManager::CComponentManager(CSimContext& context, shared_ptr<ScriptRunt
m_ScriptInterface.RegisterFunction<void, int, CComponentManager::Script_DestroyEntity> ("DestroyEntity");
m_ScriptInterface.RegisterFunction<void, CComponentManager::Script_FlushDestroyedEntities> ("FlushDestroyedEntities");
m_ScriptInterface.RegisterFunction<bool, std::wstring, CComponentManager::Script_DataFileExists> ("DataFileExists");
m_ScriptInterface.RegisterFunction<JS::Value, std::wstring, CComponentManager::Script_ReadJSONFile> ("ReadJSONFile");
m_ScriptInterface.RegisterFunction<JS::Value, std::wstring, CComponentManager::Script_ReadCivJSONFile> ("ReadCivJSONFile");
m_ScriptInterface.RegisterFunction<std::vector<std::string>, std::wstring, bool, CComponentManager::Script_FindJSONFiles> ("FindJSONFiles");
}
@ -1192,28 +1192,6 @@ bool CComponentManager::Script_DataFileExists(ScriptInterface::CxPrivate* UNUSED
return VfsFileExists(path);
}
JS::Value CComponentManager::Script_ReadJSONFile(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& fileName)
{
return ReadJSONFile(pCxPrivate, L"simulation/data", fileName);
}
JS::Value CComponentManager::Script_ReadCivJSONFile(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& fileName)
{
return ReadJSONFile(pCxPrivate, L"simulation/data/civs", fileName);
}
JS::Value CComponentManager::ReadJSONFile(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& filePath, const std::wstring& fileName)
{
CComponentManager* componentManager = static_cast<CComponentManager*> (pCxPrivate->pCBData);
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
VfsPath path = VfsPath(filePath) / fileName;
JS::RootedValue out(cx);
componentManager->GetScriptInterface().ReadJSONFile(path, &out);
return out;
}
Status CComponentManager::FindJSONFilesCallback(const VfsPath& pathname, const CFileInfo& UNUSED(fileInfo), const uintptr_t cbData)
{
FindJSONFilesCallbackData* data = (FindJSONFilesCallbackData*)cbData;

View File

@ -333,10 +333,7 @@ private:
static void Script_DestroyEntity(ScriptInterface::CxPrivate* pCxPrivate, int ent);
static void Script_FlushDestroyedEntities(ScriptInterface::CxPrivate* pCxPrivate);
static bool Script_DataFileExists(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& fileName);
static JS::Value Script_ReadJSONFile(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& fileName);
static JS::Value Script_ReadCivJSONFile(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& fileName);
static std::vector<std::string> Script_FindJSONFiles(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& subPath, bool recursive);
static JS::Value ReadJSONFile(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& filePath, const std::wstring& fileName);
// callback function to handle recursively finding files in a directory
static Status FindJSONFilesCallback(const VfsPath&, const CFileInfo&, const uintptr_t);