static Status load_sys_cursor(const PIVFS& vfs, const VfsPath& pathname, int hx, int hy, sys_cursor* cursor) { #if !ALLOW_SYS_CURSOR UNUSED2(vfs); UNUSED2(pathname); UNUSED2(hx); UNUSED2(hy); UNUSED2(cursor); return ERR::FAIL; #else shared_ptr<u8> file; size_t fileSize; RETURN_STATUS_IF_ERR(vfs->LoadFile(pathname, file, fileSize)); Tex t; RETURN_STATUS_IF_ERR(t.decode(file, fileSize)); // convert to required BGRA format. const size_t flags = (t.m_Flags | TEX_BGR) & ~TEX_DXT; RETURN_STATUS_IF_ERR(t.transform_to(flags)); void* bgra_img = t.get_data(); if(!bgra_img) WARN_RETURN(ERR::FAIL); RETURN_STATUS_IF_ERR(sys_cursor_create((int)t.m_Width, (int)t.m_Height, bgra_img, hx, hy, cursor)); return INFO::OK; #endif }
Status OpenOggNonstream(const PIVFS& vfs, const VfsPath& pathname, OggStreamPtr& stream) { shared_ptr<u8> contents; size_t size; RETURN_STATUS_IF_ERR(vfs->LoadFile(pathname, contents, size)); shared_ptr<OggStreamImpl<VorbisBufferAdapter> > tmp(new OggStreamImpl<VorbisBufferAdapter>(VorbisBufferAdapter(contents, size))); RETURN_STATUS_IF_ERR(tmp->Open()); stream = tmp; return INFO::OK; }
void NextNumberedFilename(const PIVFS& fs, const VfsPath& pathnameFormat, size_t& nextNumber, VfsPath& nextPathname) { // (first call only:) scan directory and set nextNumber according to // highest matching filename found. this avoids filling "holes" in // the number series due to deleted files, which could be confusing. // example: add 1st and 2nd; [exit] delete 1st; [restart] // add 3rd -> without this measure it would get number 1, not 3. if(nextNumber == 0) { const VfsPath nameFormat = pathnameFormat.Filename(); const VfsPath path = pathnameFormat.Parent()/""; size_t maxNumber = 0; CFileInfos files; fs->GetDirectoryEntries(path, &files, 0); for(size_t i = 0; i < files.size(); i++) { int number; if(swscanf_s(files[i].Name().string().c_str(), nameFormat.string().c_str(), &number) == 1) maxNumber = std::max(size_t(number), maxNumber); } nextNumber = maxNumber+1; } // now increment number until that file doesn't yet exist. // this is fairly slow, but typically only happens once due // to scan loop above. (we still need to provide for looping since // someone may have added files in the meantime) // we don't bother with binary search - this isn't a bottleneck. do { wchar_t pathnameBuf[PATH_MAX]; swprintf_s(pathnameBuf, ARRAY_SIZE(pathnameBuf), pathnameFormat.string().c_str(), nextNumber++); nextPathname = pathnameBuf; } while(fs->GetFileInfo(nextPathname, 0) == INFO::OK); }
Status ReloadChangedFiles() { std::vector<DirWatchNotification> notifications; RETURN_STATUS_IF_ERR(dir_watch_Poll(notifications)); for(size_t i = 0; i < notifications.size(); i++) { if(!CanIgnore(notifications[i])) { VfsPath pathname; RETURN_STATUS_IF_ERR(g_VFS->GetVirtualPath(notifications[i].Pathname(), pathname)); RETURN_STATUS_IF_ERR(g_VFS->Invalidate(pathname)); // Tell each hotloadable system about this file change: RETURN_STATUS_IF_ERR(g_GUI->ReloadChangedFiles(pathname)); for (size_t j = 0; j < g_ReloadFuncs.size(); ++j) g_ReloadFuncs[j].first(g_ReloadFuncs[j].second, pathname); RETURN_STATUS_IF_ERR(h_reload(g_VFS, pathname)); } } return INFO::OK; }
Status GetPathnames(const PIVFS& fs, const VfsPath& path, const wchar_t* filter, VfsPaths& pathnames) { std::vector<CFileInfo> files; RETURN_STATUS_IF_ERR(fs->GetDirectoryEntries(path, &files, 0)); pathnames.clear(); pathnames.reserve(files.size()); for(size_t i = 0; i < files.size(); i++) { if(match_wildcard(files[i].Name().string().c_str(), filter)) pathnames.push_back(path / files[i].Name()); } return INFO::OK; }
bool XMLWriter_File::StoreVFS(const PIVFS& vfs, const VfsPath& pathname) { if (m_LastElement) debug_warn(L"ERROR: Saving XML while an element is still open"); const size_t size = m_Data.length(); shared_ptr<u8> data; AllocateAligned(data, size, maxSectorSize); memcpy(data.get(), m_Data.data(), size); Status ret = vfs->CreateFile(pathname, data, size); if (ret < 0) { LOGERROR(L"Error saving XML data through VFS: %lld '%ls'", (long long)ret, pathname.string().c_str()); return false; } return true; }
PSRETURN CVFSFile::Load(const PIVFS& vfs, const VfsPath& filename) { // Load should never be called more than once, so complain if (m_Buffer) { DEBUG_WARN_ERR(ERR::LOGIC); return PSRETURN_CVFSFile_AlreadyLoaded; } Status ret = vfs->LoadFile(filename, m_Buffer, m_BufferSize); if (ret != INFO::OK) { LOGERROR(L"CVFSFile: file %ls couldn't be opened (vfs_load: %lld)", filename.string().c_str(), ret); return PSRETURN_CVFSFile_LoadFailed; } return PSRETURN_OK; }
// basename is e.g. "console"; the files are "fonts/console.fnt" and "fonts/console.png" // [10..70ms] static Status UniFont_reload(UniFont* f, const PIVFS& vfs, const VfsPath& basename, Handle UNUSED(h)) { // already loaded if(f->ht > 0) return INFO::OK; f->glyphs = new glyphmap(); const VfsPath path(L"fonts/"); // Read font definition file into a stringstream shared_ptr<u8> buf; size_t size; const VfsPath fntName(basename.ChangeExtension(L".fnt")); RETURN_STATUS_IF_ERR(vfs->LoadFile(path / fntName, buf, size)); // [cumulative for 12: 36ms] std::istringstream FNTStream(std::string((const char*)buf.get(), size)); int Version; FNTStream >> Version; if (Version < 100 || Version > 101) // Make sure this is from a recent version of the font builder WARN_RETURN(ERR::FAIL); int TextureWidth, TextureHeight; FNTStream >> TextureWidth >> TextureHeight; GLenum fmt_ovr = GL_ALPHA; if (Version >= 101) { std::string Format; FNTStream >> Format; if (Format == "rgba") fmt_ovr = GL_RGBA; else if (Format == "a") fmt_ovr = GL_ALPHA; else debug_warn(L"Invalid .fnt format string"); }
Status ForEachFile(const PIVFS& fs, const VfsPath& startPath, FileCallback cb, uintptr_t cbData, const wchar_t* pattern, size_t flags) { // (declare here to avoid reallocations) CFileInfos files; DirectoryNames subdirectoryNames; // (a FIFO queue is more efficient than recursion because it uses less // stack space and avoids seeks due to breadth-first traversal.) std::queue<VfsPath> pendingDirectories; pendingDirectories.push(startPath/""); while(!pendingDirectories.empty()) { const VfsPath& path = pendingDirectories.front(); RETURN_STATUS_IF_ERR(fs->GetDirectoryEntries(path, &files, &subdirectoryNames)); for(size_t i = 0; i < files.size(); i++) { const CFileInfo fileInfo = files[i]; if(!match_wildcard(fileInfo.Name().string().c_str(), pattern)) continue; const VfsPath pathname(path / fileInfo.Name()); // (CFileInfo only stores the name) RETURN_STATUS_IF_ERR(cb(pathname, fileInfo, cbData)); } if(!(flags & DIR_RECURSIVE)) break; for(size_t i = 0; i < subdirectoryNames.size(); i++) pendingDirectories.push(path / subdirectoryNames[i]/""); pendingDirectories.pop(); } return INFO::OK; }
/** * Returns a JS object containing a listing of available mods that * have a modname.json file in their modname folder. The returned * object looks like { modname1: json1, modname2: json2, ... } where * jsonN is the content of the modnameN/modnameN.json file as a JS * object. * * @return JS object with available mods as the keys of the modname.json * properties. */ JS::Value JSI_Mod::GetAvailableMods(ScriptInterface::CxPrivate* pCxPrivate) { ScriptInterface* scriptInterface = pCxPrivate->pScriptInterface; JSContext* cx = scriptInterface->GetContext(); JSAutoRequest rq(cx); JS::RootedObject obj(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr())); const Paths paths(g_args); // loop over all possible paths OsPath modPath = paths.RData()/"mods"; OsPath modUserPath = paths.UserData()/"mods"; DirectoryNames modDirs; DirectoryNames modDirsUser; GetDirectoryEntries(modPath, NULL, &modDirs); // Sort modDirs so that we can do a fast lookup below std::sort(modDirs.begin(), modDirs.end()); PIVFS vfs = CreateVfs(1); // No cache needed; TODO but 0 crashes for (DirectoryNames::iterator iter = modDirs.begin(); iter != modDirs.end(); ++iter) { vfs->Clear(); if (vfs->Mount(L"", modPath / *iter, VFS_MOUNT_MUST_EXIST) < 0) continue; CVFSFile modinfo; if (modinfo.Load(vfs, L"mod.json", false) != PSRETURN_OK) continue; JS::RootedValue json(cx); if (!scriptInterface->ParseJSON(modinfo.GetAsString(), &json)) continue; // Valid mod, add it to our structure JS_SetProperty(cx, obj, utf8_from_wstring(iter->string()).c_str(), json); } GetDirectoryEntries(modUserPath, NULL, &modDirsUser); bool dev = InDevelopmentCopy(); for (DirectoryNames::iterator iter = modDirsUser.begin(); iter != modDirsUser.end(); ++iter) { // If we are in a dev copy we do not mount mods in the user mod folder that // are already present in the mod folder, thus we skip those here. if (dev && std::binary_search(modDirs.begin(), modDirs.end(), *iter)) continue; vfs->Clear(); if (vfs->Mount(L"", modUserPath / *iter, VFS_MOUNT_MUST_EXIST) < 0) continue; CVFSFile modinfo; if (modinfo.Load(vfs, L"mod.json", false) != PSRETURN_OK) continue; JS::RootedValue json(cx); if (!scriptInterface->ParseJSON(modinfo.GetAsString(), &json)) continue; // Valid mod, add it to our structure JS_SetProperty(cx, obj, utf8_from_wstring(iter->string()).c_str(), json); } return JS::ObjectValue(*obj); }
bool VfsFileExists(const VfsPath& pathname) { return g_VFS->GetFileInfo(pathname, 0) == INFO::OK; }