Index: source/ps/scripting/JSInterface_VFS.cpp =================================================================== --- source/ps/scripting/JSInterface_VFS.cpp +++ source/ps/scripting/JSInterface_VFS.cpp @@ -31,10 +31,26 @@ namespace JSI_VFS { +enum class Compartment +{ + GUI, + Simulation, + Maps +}; + // Only allow engine compartments to read files they may be concerned about. -#define PathRestriction_GUI {L"gui/", L"simulation/", L"maps/", L"campaigns/", L"saves/campaigns/", L"config/matchsettings.json", L"config/matchsettings.mp.json", L"moddata"} -#define PathRestriction_Simulation {L"simulation/"} -#define PathRestriction_Maps {L"simulation/", L"maps/"} +template +const std::array PathRestriction{}; + +template<> +const std::array PathRestriction{L"gui/", L"simulation/", L"maps/", L"campaigns/", + L"saves/campaigns/", L"config/matchsettings.json", L"config/matchsettings.mp.json", L"moddata"}; + +template<> +const std::array PathRestriction{L"simulation/"}; + +template<> +const std::array PathRestriction{L"simulation/", L"maps/"}; // shared error handling code #define JS_CHECK_FILE_ERR(err)\ @@ -50,8 +66,11 @@ // Tests whether the current script context is allowed to read from the given directory -bool PathRestrictionMet(const ScriptRequest& rq, const std::vector& validPaths, const CStrW& filePath) +template +bool PathRestrictionMet(const ScriptRequest& rq, const CStrW& filePath) { + const auto& validPaths = PathRestriction; + for (const CStrW& validPath : validPaths) if (filePath.find(validPath) == 0) return true; @@ -104,9 +123,11 @@ // specified directory. // filter_string: default "" matches everything; otherwise, see vfs_next_dirent. // recurse: should subdirectories be included in the search? default false. -JS::Value BuildDirEntList(const ScriptRequest& rq, const std::vector& validPaths, const std::wstring& path, const std::wstring& filterStr, bool recurse) +template +JS::Value BuildDirEntList(const ScriptRequest& rq, const std::wstring& path, const std::wstring& filterStr, + bool recurse) { - if (!PathRestrictionMet(rq, validPaths, path)) + if (!PathRestrictionMet(rq, path)) return JS::NullValue(); // convert to const wchar_t*; if there's no filter, pass 0 for speed @@ -125,9 +146,10 @@ } // Return true iff the file exits -bool FileExists(const ScriptRequest& rq, const std::vector& validPaths, const CStrW& filename) +template +bool FileExists(const ScriptRequest& rq, const CStrW& filename) { - return PathRestrictionMet(rq, validPaths, filename) && g_VFS->GetFileInfo(filename, 0) == INFO::OK; + return PathRestrictionMet(rq, filename) && g_VFS->GetFileInfo(filename, 0) == INFO::OK; } // Return time [seconds since 1970] of the last modification to the specified file. @@ -151,9 +173,10 @@ } // Return file contents in a string. Assume file is UTF-8 encoded text. -JS::Value ReadFile(const ScriptRequest& rq, const std::vector& validPaths, const CStrW& filename) +template +JS::Value ReadFile(const ScriptRequest& rq, const CStrW& filename) { - if (!PathRestrictionMet(rq, validPaths, filename)) + if (!PathRestrictionMet(rq, filename)) return JS::NullValue(); CVFSFile file; @@ -172,9 +195,10 @@ } // Return file contents as an array of lines. Assume file is UTF-8 encoded text. -JS::Value ReadFileLines(const ScriptRequest& rq, const std::vector& validPaths, const CStrW& filename) +template +JS::Value ReadFileLines(const ScriptRequest& rq, const CStrW& filename) { - if (!PathRestrictionMet(rq, validPaths, filename)) + if (!PathRestrictionMet(rq, filename)) return JS::NullValue(); CVFSFile file; @@ -207,10 +231,11 @@ } // Return file contents parsed as a JS Object -JS::Value ReadJSONFile(const ScriptInterface& scriptInterface, const std::vector& validPaths, const CStrW& filePath) +template +JS::Value ReadJSONFile(const ScriptInterface& scriptInterface, const CStrW& filePath) { ScriptRequest rq(scriptInterface); - if (!PathRestrictionMet(rq, validPaths, filePath)) + if (!PathRestrictionMet(rq, filePath)) return JS::NullValue(); JS::RootedValue out(rq.cx); @@ -219,10 +244,11 @@ } // Save given JS Object to a JSON file -void WriteJSONFile(const ScriptInterface& scriptInterface, const std::vector& validPaths, const CStrW& filePath, JS::HandleValue val1) +template +void WriteJSONFile(const ScriptInterface& scriptInterface, const CStrW& filePath, JS::HandleValue val1) { ScriptRequest rq(scriptInterface); - if (!PathRestrictionMet(rq, validPaths, filePath)) + if (!PathRestrictionMet(rq, filePath)) return; // TODO: This is a workaround because we need to pass a MutableHandle to StringifyJSON. @@ -255,61 +281,30 @@ wunlink(realPath) == 0; } -#define VFS_ScriptFunctions(context)\ -JS::Value Script_ReadJSONFile_##context(const ScriptInterface& scriptInterface, const std::wstring& filePath)\ -{\ - return ReadJSONFile(scriptInterface, PathRestriction_##context, filePath);\ -}\ -void Script_WriteJSONFile_##context(const ScriptInterface& scriptInterface, const std::wstring& filePath, JS::HandleValue val1)\ -{\ - return WriteJSONFile(scriptInterface, PathRestriction_##context, filePath, val1);\ -}\ -JS::Value Script_ReadFile_##context(const ScriptInterface& scriptInterface, const std::wstring& filePath)\ -{\ - return ReadFile(scriptInterface, PathRestriction_##context, filePath);\ -}\ -JS::Value Script_ReadFileLines_##context(const ScriptInterface& scriptInterface, const std::wstring& filePath)\ -{\ - return ReadFileLines(scriptInterface, PathRestriction_##context, filePath);\ -}\ -JS::Value Script_ListDirectoryFiles_##context(const ScriptInterface& scriptInterface, const std::wstring& path, const std::wstring& filterStr, bool recurse)\ -{\ - return BuildDirEntList(scriptInterface, PathRestriction_##context, path, filterStr, recurse);\ -}\ -bool Script_FileExists_##context(const ScriptInterface& scriptInterface, const std::wstring& filePath)\ -{\ - return FileExists(scriptInterface, PathRestriction_##context, filePath);\ -}\ - -VFS_ScriptFunctions(GUI); -VFS_ScriptFunctions(Simulation); -VFS_ScriptFunctions(Maps); -#undef VFS_ScriptFunctions - void RegisterScriptFunctions_ReadWriteAnywhere(const ScriptRequest& rq) { - ScriptFunction::Register<&Script_ListDirectoryFiles_GUI>(rq, "ListDirectoryFiles"); - ScriptFunction::Register<&Script_FileExists_GUI>(rq, "FileExists"); + ScriptFunction::Register<&BuildDirEntList>(rq, "ListDirectoryFiles"); + ScriptFunction::Register<&FileExists>(rq, "FileExists"); ScriptFunction::Register<&GetFileMTime>(rq, "GetFileMTime"); ScriptFunction::Register<&GetFileSize>(rq, "GetFileSize"); - ScriptFunction::Register<&Script_ReadFile_GUI>(rq, "ReadFile"); - ScriptFunction::Register<&Script_ReadFileLines_GUI>(rq, "ReadFileLines"); - ScriptFunction::Register<&Script_ReadJSONFile_GUI>(rq, "ReadJSONFile"); - ScriptFunction::Register<&Script_WriteJSONFile_GUI>(rq, "WriteJSONFile"); + ScriptFunction::Register<&ReadFile>(rq, "ReadFile"); + ScriptFunction::Register<&ReadFileLines>(rq, "ReadFileLines"); + ScriptFunction::Register<&ReadJSONFile>(rq, "ReadJSONFile"); + ScriptFunction::Register<&WriteJSONFile>(rq, "WriteJSONFile"); ScriptFunction::Register<&DeleteCampaignSave>(rq, "DeleteCampaignSave"); } void RegisterScriptFunctions_ReadOnlySimulation(const ScriptRequest& rq) { - ScriptFunction::Register<&Script_ListDirectoryFiles_Simulation>(rq, "ListDirectoryFiles"); - ScriptFunction::Register<&Script_FileExists_Simulation>(rq, "FileExists"); - ScriptFunction::Register<&Script_ReadJSONFile_Simulation>(rq, "ReadJSONFile"); + ScriptFunction::Register<&BuildDirEntList>(rq, "ListDirectoryFiles"); + ScriptFunction::Register<&FileExists>(rq, "FileExists"); + ScriptFunction::Register<&ReadJSONFile>(rq, "ReadJSONFile"); } void RegisterScriptFunctions_ReadOnlySimulationMaps(const ScriptRequest& rq) { - ScriptFunction::Register<&Script_ListDirectoryFiles_Maps>(rq, "ListDirectoryFiles"); - ScriptFunction::Register<&Script_FileExists_Maps>(rq, "FileExists"); - ScriptFunction::Register<&Script_ReadJSONFile_Maps>(rq, "ReadJSONFile"); + ScriptFunction::Register<&BuildDirEntList>(rq, "ListDirectoryFiles"); + ScriptFunction::Register<&FileExists>(rq, "FileExists"); + ScriptFunction::Register<&ReadJSONFile>(rq, "ReadJSONFile"); } }