bool ScriptInterface::LoadGlobalScriptFile(const VfsPath& path) { if (!VfsFileExists(path)) { LOGERROR(L"File '%ls' does not exist", path.string().c_str()); return false; } CVFSFile file; PSRETURN ret = file.Load(g_VFS, path); if (ret != PSRETURN_OK) { LOGERROR(L"Failed to load file '%ls': %hs", path.string().c_str(), GetErrorString(ret)); return false; } std::wstring code = wstring_from_utf8(file.DecodeUTF8()); // assume it's UTF-8 // Compile the code in strict mode, to encourage better coding practices and // to possibly help SpiderMonkey with optimisations std::wstring codeStrict = L"\"use strict\";\n" + code; utf16string codeUtf16(codeStrict.begin(), codeStrict.end()); uintN lineNo = 0; // put the automatic 'use strict' on line 0, so the real code starts at line 1 jsval rval; JSBool ok = JS_EvaluateUCScript(m->m_cx, m->m_glob, reinterpret_cast<const jschar*> (codeUtf16.c_str()), (uintN)(codeUtf16.length()), utf8_from_wstring(path.string()).c_str(), lineNo, &rval); return ok ? true : false; }
void CTerrainTextureManager::RecurseDirectory(const CTerrainPropertiesPtr& parentProps, const VfsPath& path) { //LOGMESSAGE("CTextureManager::RecurseDirectory(%s)", path.string8()); CTerrainPropertiesPtr props; // Load terrains.xml first, if it exists VfsPath pathname = path / "terrains.xml"; if (VfsFileExists(pathname)) props = GetPropertiesFromFile(parentProps, pathname); // No terrains.xml, or read failures -> use parent props (i.e. if (!props) { LOGMESSAGE("CTerrainTextureManager::RecurseDirectory(%s): no terrains.xml (or errors while loading) - using parent properties", path.string8()); props = parentProps; } // Recurse once for each subdirectory DirectoryNames subdirectoryNames; (void)g_VFS->GetDirectoryEntries(path, 0, &subdirectoryNames); for (size_t i=0;i<subdirectoryNames.size();i++) { VfsPath subdirectoryPath = path / subdirectoryNames[i] / ""; RecurseDirectory(props, subdirectoryPath); } LoadTextures(props, path); }
std::string CSimulation2::ReadJSON(VfsPath path) { std::string data; if (!VfsFileExists(path)) { LOGERROR(L"File '%ls' does not exist", path.string().c_str()); } else { // Load JSON file CVFSFile file; PSRETURN ret = file.Load(g_VFS, path); if (ret != PSRETURN_OK) { LOGERROR(L"Failed to load file '%ls': %hs", path.string().c_str(), GetErrorString(ret)); } else { data = file.DecodeUTF8(); // assume it's UTF-8 } } return data; }
bool ScriptInterface::LoadGlobalScriptFile(const VfsPath& path) { JSAutoRequest rq(m->m_cx); JS::RootedObject global(m->m_cx, m->m_glob); if (!VfsFileExists(path)) { LOGERROR("File '%s' does not exist", path.string8()); return false; } CVFSFile file; PSRETURN ret = file.Load(g_VFS, path); if (ret != PSRETURN_OK) { LOGERROR("Failed to load file '%s': %s", path.string8(), GetErrorString(ret)); return false; } std::wstring code = wstring_from_utf8(file.DecodeUTF8()); // assume it's UTF-8 utf16string codeUtf16(code.begin(), code.end()); uint lineNo = 1; // CompileOptions does not copy the contents of the filename string pointer. // Passing a temporary string there will cause undefined behaviour, so we create a separate string to avoid the temporary. std::string filenameStr = path.string8(); JS::RootedValue rval(m->m_cx); JS::CompileOptions opts(m->m_cx); opts.setFileAndLine(filenameStr.c_str(), lineNo); return JS::Evaluate(m->m_cx, global, opts, reinterpret_cast<const char16_t*>(codeUtf16.c_str()), (uint)(codeUtf16.length()), &rval); }
std::string CSimulation2::ReadJSON(VfsPath path) { std::string data; if (!VfsFileExists(path)) { LOGERROR(L"File '%ls' does not exist", path.string().c_str()); } else { // Load JSON file CVFSFile file; PSRETURN ret = file.Load(g_VFS, path); if (ret != PSRETURN_OK) { LOGERROR(L"Failed to load file '%ls': %hs", path.string().c_str(), GetErrorString(ret)); } else { data = std::string(file.GetBuffer(), file.GetBuffer() + file.GetBufferSize()); } } return data; }
bool ScriptInterface::LoadGlobalScriptFile(const VfsPath& path) { JSAutoRequest rq(m->m_cx); JS::RootedObject global(m->m_cx, m->m_glob); if (!VfsFileExists(path)) { LOGERROR("File '%s' does not exist", path.string8()); return false; } CVFSFile file; PSRETURN ret = file.Load(g_VFS, path); if (ret != PSRETURN_OK) { LOGERROR("Failed to load file '%s': %s", path.string8(), GetErrorString(ret)); return false; } std::wstring code = wstring_from_utf8(file.DecodeUTF8()); // assume it's UTF-8 utf16string codeUtf16(code.begin(), code.end()); uint lineNo = 1; JS::RootedValue rval(m->m_cx); return JS_EvaluateUCScript(m->m_cx, global, reinterpret_cast<const jschar*> (codeUtf16.c_str()), (uint)(codeUtf16.length()), utf8_from_wstring(path.string()).c_str(), lineNo, &rval); }
void CConsole::LoadHistory() { // note: we don't care if this file doesn't exist or can't be read; // just don't load anything in that case. // do this before LoadFile to avoid an error message if file not found. if (!VfsFileExists(m_sHistoryFile)) return; shared_ptr<u8> buf; size_t buflen; if (g_VFS->LoadFile(m_sHistoryFile, buf, buflen) < 0) return; CStr bytes ((char*)buf.get(), buflen); CStrW str (bytes.FromUTF8()); size_t pos = 0; while (pos != CStrW::npos) { pos = str.find('\n'); if (pos != CStrW::npos) { if (pos > 0) m_deqBufHistory.push_front(str.Left(str[pos-1] == '\r' ? pos - 1 : pos)); str = str.substr(pos + 1); } else if (str.length() > 0) m_deqBufHistory.push_front(str); } }
VfsPath L10n::LocalizePath(const VfsPath& sourcePath) const { VfsPath localizedPath = sourcePath.Parent() / L"l10n" / wstring_from_utf8(currentLocale.getLanguage()) / sourcePath.Filename(); if (!VfsFileExists(localizedPath)) return sourcePath; return localizedPath; }
Status CSimulation2Impl::ReloadChangedFile(const VfsPath& path) { // Ignore if this file wasn't loaded as a script // (TODO: Maybe we ought to load in any new .js files that are created in the right directories) if (m_LoadedScripts.find(path) == m_LoadedScripts.end()) return INFO::OK; // If the file doesn't exist (e.g. it was deleted), don't bother loading it since that'll give an error message. // (Also don't bother trying to 'unload' it from the component manager, because that's not possible) if (!VfsFileExists(path)) return INFO::OK; LOGMESSAGE(L"Reloading simulation script '%ls'", path.string().c_str()); if (!m_ComponentManager.LoadScript(path, true)) return ERR::FAIL; return INFO::OK; }
static std::string ReadJSON(const VfsPath& path) { if (!VfsFileExists(path)) { LOGERROR("File '%s' does not exist", path.string8()); return std::string(); } // Load JSON file CVFSFile file; PSRETURN ret = file.Load(g_VFS, path); if (ret != PSRETURN_OK) { LOGERROR("Failed to load file '%s': %s", path.string8(), GetErrorString(ret)); return std::string(); } return file.DecodeUTF8(); // assume it's UTF-8 }
CScriptValRooted ScriptInterface::ReadJSONFile(const VfsPath& path) { if (!VfsFileExists(path)) { LOGERROR(L"File '%ls' does not exist", path.string().c_str()); return CScriptValRooted(); } CVFSFile file; PSRETURN ret = file.Load(g_VFS, path); if (ret != PSRETURN_OK) { LOGERROR(L"Failed to load file '%ls': %hs", path.string().c_str(), GetErrorString(ret)); return CScriptValRooted(); } std::string content(file.DecodeUTF8()); // assume it's UTF-8 return ParseJSON(content); }
Status ReloadChangedFile(const VfsPath& path) { // Ignore files that aren't in the right path if (!boost::algorithm::starts_with(path.string(), L"art/skeletons/")) return INFO::OK; if (path.Extension() != L".xml") return INFO::OK; m_skeletonHashInvalidated = true; // If the file doesn't exist (e.g. it was deleted), don't bother reloading // or 'unloading' since that isn't possible if (!VfsFileExists(path)) return INFO::OK; if (!dll.IsLoaded() && !TryLoadDLL()) return ERR::FAIL; LOGMESSAGE("Hotloading skeleton definitions from '%s'", path.string8()); // Set the filename for the logger to report set_logger(ColladaLog, const_cast<void*>(static_cast<const void*>(&path))); CVFSFile skeletonFile; if (skeletonFile.Load(m_VFS, path) != PSRETURN_OK) { LOGERROR("Failed to read skeleton defintions from '%s'", path.string8()); return ERR::FAIL; } int ok = set_skeleton_definitions((const char*)skeletonFile.GetBuffer(), (int)skeletonFile.GetBufferSize()); if (ok < 0) { LOGERROR("Failed to load skeleton definitions from '%s'", path.string8()); return ERR::FAIL; } return INFO::OK; }
Status L10n::ReloadChangedFile(const VfsPath& path) { if (!boost::algorithm::starts_with(path.string(), L"l10n/")) return INFO::OK; if (path.Extension() != L".po") return INFO::OK; // If the file was deleted, ignore it if (!VfsFileExists(path)) return INFO::OK; std::wstring dictName = GetFallbackToAvailableDictLocale(currentLocale); if (useLongStrings) dictName = L"long"; if (dictName.empty()) return INFO::OK; // Only the currently used language is loaded, so ignore all others if (path.string().rfind(dictName) == std::string::npos) return INFO::OK; LOGMESSAGE("Hotloading translations from '%s'", path.string8()); CVFSFile file; if (file.Load(g_VFS, path) != PSRETURN_OK) { LOGERROR("Failed to read translations from '%s'", path.string8()); return ERR::FAIL; } std::string content = file.DecodeUTF8(); ReadPoIntoDictionary(content, dictionary); if (g_GUI) g_GUI->ReloadAllPages(); return INFO::OK; }
void ScriptInterface::ReadJSONFile(const VfsPath& path, JS::MutableHandleValue out) { if (!VfsFileExists(path)) { LOGERROR("File '%s' does not exist", path.string8()); return; } CVFSFile file; PSRETURN ret = file.Load(g_VFS, path); if (ret != PSRETURN_OK) { LOGERROR("Failed to load file '%s': %s", path.string8(), GetErrorString(ret)); return; } std::string content(file.DecodeUTF8()); // assume it's UTF-8 if (!ParseJSON(content, out)) LOGERROR("Failed to parse '%s'", path.string8()); }
void CFileUnpacker::Read(const VfsPath& filename, const char magic[4]) { // if the file doesn't exist, LoadFile would raise an annoying error dialog. // since this (unfortunately) happens so often, we perform a separate // check and "just" raise an exception for the caller to handle. // (this is nicer than somehow squelching internal VFS error reporting) if(!VfsFileExists(filename)) throw PSERROR_File_OpenFailed(); // load the whole thing into memory if(g_VFS->LoadFile(filename, m_buf, m_bufSize) < 0) throw PSERROR_File_OpenFailed(); // make sure we read enough for the header if(m_bufSize < sizeof(FileHeader)) { m_buf.reset(); m_bufSize = 0; throw PSERROR_File_ReadFailed(); } // extract data from header FileHeader* header = (FileHeader*)m_buf.get(); m_version = read_le32(&header->version_le); const size_t payloadSize = (size_t)read_le32(&header->payloadSize_le); // check we've got the right kind of file // .. and that we read exactly headerSize+payloadSize if(strncmp(header->magic, magic, 4) != 0 || m_bufSize != sizeof(FileHeader)+payloadSize) { m_buf.reset(); m_bufSize = 0; throw PSERROR_File_InvalidType(); } m_unpackPos = sizeof(FileHeader); }
bool CTemplateLoader::TemplateExists(const std::string& templateName) const { size_t pos = templateName.rfind('|'); std::string baseName(pos != std::string::npos ? templateName.substr(pos+1) : templateName); return VfsFileExists(VfsPath(TEMPLATE_ROOT) / wstring_from_utf8(baseName + ".xml")); }
VfsPath CColladaManager::GetLoadableFilename(const VfsPath& pathnameNoExtension, FileType type) { std::wstring extn; switch (type) { case PMD: extn = L".pmd"; break; case PSA: extn = L".psa"; break; // no other alternatives } /* If there is a .dae file: * Calculate a hash to identify it. * Look for a cached .pmd file matching that hash. * If it exists, load it. Else, convert the .dae into .pmd and load it. Otherwise, if there is a (non-cache) .pmd file: * Load it. Else, fail. The hash calculation ought to be fast, since normally (during development) the .dae file will exist but won't have changed recently and so the cache would be used. Hence, just hash the file's size, mtime, and the converter version number (so updates of the converter can cause regeneration of .pmds) instead of the file's actual contents. TODO (maybe): The .dae -> .pmd conversion may fail (e.g. if the .dae is invalid or unsupported), but it may take a long time to start the conversion then realise it's not going to work. That will delay the loading of the game every time, which is annoying, so maybe it should cache the error message until the .dae is updated and fixed. (Alternatively, avoid having that many broken .daes in the game.) */ // (TODO: the comments and variable names say "pmd" but actually they can // be "psa" too.) VfsPath dae(pathnameNoExtension.ChangeExtension(L".dae")); if (! VfsFileExists(dae)) { // No .dae - got to use the .pmd, assuming there is one return pathnameNoExtension.ChangeExtension(extn); } // There is a .dae - see if there's an up-to-date cached copy FileInfo fileInfo; if (g_VFS->GetFileInfo(dae, &fileInfo) < 0) { // This shouldn't occur for any sensible reasons LOGERROR(L"Failed to stat DAE file '%ls'", dae.string().c_str()); return VfsPath(); } // Build a struct of all the data we want to hash. // (Use ints and not time_t/off_t because we don't care about overflow // but do care about the fields not being 64-bit aligned) // (Remove the lowest bit of mtime because some things round it to a // resolution of 2 seconds) #pragma pack(push, 1) struct { int version; int mtime; int size; } hashSource = { COLLADA_CONVERTER_VERSION, (int)fileInfo.MTime() & ~1, (int)fileInfo.Size() }; cassert(sizeof(hashSource) == sizeof(int) * 3); // no padding, because that would be bad #pragma pack(pop) // Calculate the hash, convert to hex u32 hash = fnv_hash(static_cast<void*>(&hashSource), sizeof(hashSource)); wchar_t hashString[9]; swprintf_s(hashString, ARRAY_SIZE(hashString), L"%08x", hash); std::wstring extension(L"_"); extension += hashString; extension += extn; // realDaePath_ is "[..]/mods/whatever/art/meshes/whatever.dae" OsPath realDaePath_; Status ret = g_VFS->GetRealPath(dae, realDaePath_); ENSURE(ret == INFO::OK); wchar_t realDaeBuf[PATH_MAX]; wcscpy_s(realDaeBuf, ARRAY_SIZE(realDaeBuf), realDaePath_.string().c_str()); std::replace(realDaeBuf, realDaeBuf+ARRAY_SIZE(realDaeBuf), '\\', '/'); const wchar_t* realDaePath = wcsstr(realDaeBuf, L"mods/"); // cachedPmdVfsPath is "cache/mods/whatever/art/meshes/whatever_{hash}.pmd" VfsPath cachedPmdVfsPath = VfsPath("cache") / realDaePath; cachedPmdVfsPath = cachedPmdVfsPath.ChangeExtension(extension); // If it's not in the cache, we'll have to create it first if (! VfsFileExists(cachedPmdVfsPath)) { if (! m->Convert(dae, cachedPmdVfsPath, type)) return L""; // failed to convert } return cachedPmdVfsPath; }
// LoadMap: try to load the map from given file; reinitialise the scene to new data if successful void CMapReader::LoadMap(const VfsPath& pathname, CTerrain *pTerrain_, WaterManager* pWaterMan_, SkyManager* pSkyMan_, CLightEnv *pLightEnv_, CGameView *pGameView_, CCinemaManager* pCinema_, CTriggerManager* pTrigMan_, CSimulation2 *pSimulation2_, const CSimContext* pSimContext_, int playerID_, bool skipEntities) { // latch parameters (held until DelayedLoadFinished) pTerrain = pTerrain_; pLightEnv = pLightEnv_; pGameView = pGameView_; pWaterMan = pWaterMan_; pSkyMan = pSkyMan_; pCinema = pCinema_; pTrigMan = pTrigMan_; pSimulation2 = pSimulation2_; pSimContext = pSimContext_; m_PlayerID = playerID_; m_SkipEntities = skipEntities; m_StartingCameraTarget = INVALID_ENTITY; filename_xml = pathname.ChangeExtension(L".xml"); // In some cases (particularly tests) we don't want to bother storing a large // mostly-empty .pmp file, so we let the XML file specify basic terrain instead. // If there's an .xml file and no .pmp, then we're probably in this XML-only mode only_xml = false; if (!VfsFileExists(pathname) && VfsFileExists(filename_xml)) { only_xml = true; } file_format_version = CMapIO::FILE_VERSION; // default if there's no .pmp if (!only_xml) { // [25ms] unpacker.Read(pathname, "PSMP"); file_format_version = unpacker.GetVersion(); } // check oldest supported version if (file_format_version < FILE_READ_VERSION) throw PSERROR_File_InvalidVersion(); // delete all existing entities if (pSimulation2) pSimulation2->ResetState(); // load map settings script RegMemFun(this, &CMapReader::LoadScriptSettings, L"CMapReader::LoadScriptSettings", 50); // load player settings script (must be done before reading map) RegMemFun(this, &CMapReader::LoadPlayerSettings, L"CMapReader::LoadPlayerSettings", 50); // unpack the data if (!only_xml) RegMemFun(this, &CMapReader::UnpackMap, L"CMapReader::UnpackMap", 1200); // read the corresponding XML file RegMemFun(this, &CMapReader::ReadXML, L"CMapReader::ReadXML", 5800); // apply data to the world RegMemFun(this, &CMapReader::ApplyData, L"CMapReader::ApplyData", 5); // load map settings script (must be done after reading map) RegMemFun(this, &CMapReader::LoadMapSettings, L"CMapReader::LoadMapSettings", 5); RegMemFun(this, &CMapReader::DelayLoadFinished, L"CMapReader::DelayLoadFinished", 5); }