bool Debugger_EoB::cmd_saveOriginal(int argc, const char **argv) { if (!_vm->_runFlag) { DebugPrintf("This command doesn't work during intro or outro sequences,\nfrom the main menu or from the character generation.\n"); return true; } Common::String dir = ConfMan.get("savepath"); if (dir == "None") dir.clear(); Common::FSNode nd(dir); if (!nd.isDirectory()) return false; if (_vm->game() == GI_EOB1) { if (argc == 1) { if (_vm->saveAsOriginalSaveFile()) { Common::FSNode nf = nd.getChild(Common::String::format("EOBDATA.SAV")); if (nf.isReadable()) DebugPrintf("Saved to file: %s\n\n", nf.getPath().c_str()); else DebugPrintf("Failure.\n"); } else { DebugPrintf("Failure.\n"); } } else { DebugPrintf("Syntax: save_original\n (Saves game in original file format to a file which can be used with the orginal game executable.)\n\n"); } return true; } else if (argc == 2) { int slot = atoi(argv[1]); if (slot < 0 || slot > 5) { DebugPrintf("Slot must be between (including) 0 and 5.\n"); } else if (_vm->saveAsOriginalSaveFile(slot)) { Common::FSNode nf = nd.getChild(Common::String::format("EOBDATA%d.SAV", slot)); if (nf.isReadable()) DebugPrintf("Saved to file: %s\n\n", nf.getPath().c_str()); else DebugPrintf("Failure.\n"); } else { DebugPrintf("Failure.\n"); } return true; } DebugPrintf("Syntax: save_original <slot>\n (Saves game in original file format to a file which can be used with the orginal game executable.\n A save slot between 0 and 5 must be specified.)\n\n"); return true; }
bool ThemeEngine::themeConfigUsable(const Common::FSNode &node, Common::String &themeName) { Common::File stream; bool foundHeader = false; if (node.getName().matchString("*.zip", true) && !node.isDirectory()) { Common::Archive *zipArchive = Common::makeZipArchive(node); if (zipArchive && zipArchive->hasFile("THEMERC")) { // Open THEMERC from the ZIP file. stream.open("THEMERC", *zipArchive); } // Delete the ZIP archive again. Note: This only works because // stream.open() only uses ZipArchive::createReadStreamForMember, // and that in turn happens to read all the data for a given // archive member into a memory block. So there will be no dangling // reference to zipArchive anywhere. This could change if we // ever modify ZipArchive::createReadStreamForMember. delete zipArchive; } else if (node.isDirectory()) { Common::FSNode headerfile = node.getChild("THEMERC"); if (!headerfile.exists() || !headerfile.isReadable() || headerfile.isDirectory()) return false; stream.open(headerfile); } if (stream.isOpen()) { Common::String stxHeader = stream.readLine(); foundHeader = themeConfigParseHeader(stxHeader, themeName); } return foundHeader; }
void ThemeEngine::listUsableThemes(const Common::FSNode &node, Common::List<ThemeDescriptor> &list, int depth) { if (!node.exists() || !node.isReadable() || !node.isDirectory()) return; ThemeDescriptor td; // Check whether we point to a valid theme directory. if (themeConfigUsable(node, td.name)) { td.filename = node.getPath(); td.id = node.getName(); list.push_back(td); // A theme directory should never contain any other themes // thus we just return to the caller here. return; } Common::FSList fileList; // Check all files. We need this to find all themes inside ZIP archives. if (!node.getChildren(fileList, Common::FSNode::kListFilesOnly)) return; for (Common::FSList::iterator i = fileList.begin(); i != fileList.end(); ++i) { // We will only process zip files for now if (!i->getPath().matchString("*.zip", true)) continue; td.name.clear(); if (themeConfigUsable(*i, td.name)) { td.filename = i->getPath(); td.id = i->getName(); // If the name of the node object also contains // the ".zip" suffix, we will strip it. if (td.id.matchString("*.zip", true)) { for (int j = 0; j < 4; ++j) td.id.deleteLastChar(); } list.push_back(td); } } fileList.clear(); // Check if we exceeded the given recursion depth if (depth - 1 == -1) return; // As next step we will search all subdirectories if (!node.getChildren(fileList, Common::FSNode::kListDirectoriesOnly)) return; for (Common::FSList::iterator i = fileList.begin(); i != fileList.end(); ++i) listUsableThemes(*i, list, depth == -1 ? - 1 : depth - 1); }
bool diskFileExists(const Common::String &filename) { // Try directly from SearchMan first Common::ArchiveMemberList files; SearchMan.listMatchingMembers(files, filename); for (Common::ArchiveMemberList::iterator it = files.begin(); it != files.end(); ++it) { if ((*it)->getName() == filename) { return true; } } // File wasn't found in SearchMan, try to parse the path as a relative path. Common::FSNode searchNode = getNodeForRelativePath(filename); if (searchNode.exists() && !searchNode.isDirectory() && searchNode.isReadable()) { return true; } return false; }
// Parse a relative path in the game-folder, and if it exists, return a FSNode to it. static Common::FSNode getNodeForRelativePath(const Common::String &filename) { // The filename can be an explicit path, thus we need to chop it up, expecting the path the game // specifies to follow the Windows-convention of folder\subfolder\file (absolute paths should not happen) // Absolute path: These should have been handled in openDiskFile. if (filename.contains(':')) { // So just return an invalid node. return Common::FSNode(); } // Relative path: if (filename.contains('\\')) { Common::StringTokenizer path(filename, "\\"); // Start traversing relative to the game-data-dir const Common::FSNode gameDataDir(ConfMan.get("path")); Common::FSNode curNode = gameDataDir; // Parse all path-elements while (!path.empty()) { // Get the next path-component by slicing on '\\' Common::String pathPart = path.nextToken(); // Get the next FSNode in the chain, if it exists as a child from the previous. curNode = curNode.getChild(pathPart); if (!curNode.isReadable()) { // Return an invalid FSNode. return Common::FSNode(); } // Following the comments in common/fs.h, anything not a directory is a file. if (!curNode.isDirectory()) { if (!path.empty()) { error("Relative path %s reached a file before the end of the path", filename.c_str()); } return curNode; } } } // Return an invalid FSNode to mark that we didn't find the requested file. return Common::FSNode(); }
Common::SeekableReadStream *openDiskFile(const Common::String &filename) { uint32 prefixSize = 0; Common::SeekableReadStream *file = NULL; Common::String fixedFilename = filename; // Absolute path: TODO: Add specific fallbacks here. if (filename.contains(':')) { if (filename.hasPrefix("c:\\windows\\fonts\\")) { // East Side Story refers to "c:\windows\fonts\framd.ttf" fixedFilename = filename.c_str() + 17; } else { error("openDiskFile::Absolute path or invalid filename used in %s", filename.c_str()); } } // Try directly from SearchMan first Common::ArchiveMemberList files; SearchMan.listMatchingMembers(files, fixedFilename); for (Common::ArchiveMemberList::iterator it = files.begin(); it != files.end(); ++it) { if ((*it)->getName() == filename) { file = (*it)->createReadStream(); break; } } // File wasn't found in SearchMan, try to parse the path as a relative path. if (!file) { Common::FSNode searchNode = getNodeForRelativePath(filename); if (searchNode.exists() && !searchNode.isDirectory() && searchNode.isReadable()) { file = searchNode.createReadStream(); } } if (file) { uint32 magic1, magic2; magic1 = file->readUint32LE(); magic2 = file->readUint32LE(); bool compressed = false; if (magic1 == DCGF_MAGIC && magic2 == COMPRESSED_FILE_MAGIC) { compressed = true; } if (compressed) { uint32 dataOffset, compSize, uncompSize; dataOffset = file->readUint32LE(); compSize = file->readUint32LE(); uncompSize = file->readUint32LE(); byte *compBuffer = new byte[compSize]; if (!compBuffer) { error("Error allocating memory for compressed file '%s'", filename.c_str()); delete file; return NULL; } byte *data = new byte[uncompSize]; if (!data) { error("Error allocating buffer for file '%s'", filename.c_str()); delete[] compBuffer; delete file; return NULL; } file->seek(dataOffset + prefixSize, SEEK_SET); file->read(compBuffer, compSize); if (Common::uncompress(data, (unsigned long *)&uncompSize, compBuffer, compSize) != true) { error("Error uncompressing file '%s'", filename.c_str()); delete[] compBuffer; delete file; return NULL; } delete[] compBuffer; delete file; return new Common::MemoryReadStream(data, uncompSize, DisposeAfterUse::YES); } else { file->seek(0, SEEK_SET); return file; } return file; } return NULL; }