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 FilesPageHandler::listDirectory(Common::String path, Common::String &content, const Common::String &itemTemplate) { if (path == "" || path == "/") { if (ConfMan.hasKey("rootpath", "cloud")) addItem(content, itemTemplate, IT_DIRECTORY, "/root/", _("File system root")); addItem(content, itemTemplate, IT_DIRECTORY, "/saves/", _("Saved games")); return true; } if (HandlerUtils::hasForbiddenCombinations(path)) return false; Common::String prefixToRemove = "", prefixToAdd = ""; if (!transformPath(path, prefixToRemove, prefixToAdd)) return false; Common::FSNode node = Common::FSNode(path); if (path == "/") node = node.getParent(); // absolute root if (!HandlerUtils::permittedPath(node.getPath())) return false; if (!node.isDirectory()) return false; // list directory Common::FSList _nodeContent; if (!node.getChildren(_nodeContent, Common::FSNode::kListAll, false)) // do not show hidden files _nodeContent.clear(); else Common::sort(_nodeContent.begin(), _nodeContent.end()); // add parent directory link { Common::String filePath = path; if (filePath.hasPrefix(prefixToRemove)) filePath.erase(0, prefixToRemove.size()); if (filePath == "" || filePath == "/" || filePath == "\\") filePath = "/"; else filePath = parentPath(prefixToAdd + filePath); addItem(content, itemTemplate, IT_PARENT_DIRECTORY, filePath, _("Parent directory")); } // fill the content for (Common::FSList::iterator i = _nodeContent.begin(); i != _nodeContent.end(); ++i) { Common::String name = i->getDisplayName(); if (i->isDirectory()) name += "/"; Common::String filePath = i->getPath(); if (filePath.hasPrefix(prefixToRemove)) filePath.erase(0, prefixToRemove.size()); filePath = prefixToAdd + filePath; addItem(content, itemTemplate, detectType(i->isDirectory(), name), filePath, name); } return true; }
void CELauncherDialog::automaticScanDirectory(const Common::FSNode &node) { // First check if we have a recognized game in the current directory Common::FSList files; node.getChildren(files, Common::FSNode::kListFilesOnly); // detect GameList candidates(EngineMan.detectGames(files)); // insert if (candidates.size() >= 1) { GameDescriptor result = candidates[0]; result["path"] = node.getPath(); addGameToConf(result); } // Then recurse on the subdirectories Common::FSList dirs; node.getChildren(dirs, Common::FSNode::kListDirectoriesOnly); for (Common::FSList::const_iterator currentDir = dirs.begin(); currentDir != dirs.end(); ++currentDir) automaticScanDirectory(*currentDir); }
void MassAddDialog::handleTickle() { if (_scanStack.empty()) return; // We have finished scanning uint32 t = g_system->getMillis(); // Perform a breadth-first scan of the filesystem. while (!_scanStack.empty() && (g_system->getMillis() - t) < kMaxScanTime) { Common::FSNode dir = _scanStack.pop(); Common::FSList files; if (!dir.getChildren(files, Common::FSNode::kListAll)) { continue; } // Run the detector on the dir GameList candidates(EngineMan.detectGames(files)); // Just add all detected games / game variants. If we get more than one, // that either means the directory contains multiple games, or the detector // could not fully determine which game variant it was seeing. In either // case, let the user choose which entries he wants to keep. // // However, we only add games which are not already in the config file. for (GameList::const_iterator cand = candidates.begin(); cand != candidates.end(); ++cand) { GameDescriptor result = *cand; Common::String path = dir.getPath(); // Remove trailing slashes while (path != "/" && path.lastChar() == '/') path.deleteLastChar(); // Check for existing config entries for this path/gameid/lang/platform combination if (_pathToTargets.contains(path)) { bool duplicate = false; const StringArray &targets = _pathToTargets[path]; for (StringArray::const_iterator iter = targets.begin(); iter != targets.end(); ++iter) { // If the gameid, platform and language match -> skip it Common::ConfigManager::Domain *dom = ConfMan.getDomain(*iter); assert(dom); if ((*dom)["gameid"] == result["gameid"] && (*dom)["platform"] == result["platform"] && (*dom)["language"] == result["language"]) { duplicate = true; break; } } if (duplicate) { _oldGamesCount++; break; // Skip duplicates } } result["path"] = path; _games.push_back(result); _list->append(result.description()); } // Recurse into all subdirs for (Common::FSList::const_iterator file = files.begin(); file != files.end(); ++file) { if (file->isDirectory()) { _scanStack.push(*file); } } _dirsScanned++; } // Update the dialog Common::String buf; if (_scanStack.empty()) { // Enable the OK button _okButton->setEnabled(true); buf = _("Scan complete!"); _dirProgressText->setLabel(buf); buf = Common::String::format(_("Discovered %d new games, ignored %d previously added games."), _games.size(), _oldGamesCount); _gameProgressText->setLabel(buf); } else { buf = Common::String::format(_("Scanned %d directories ..."), _dirsScanned); _dirProgressText->setLabel(buf); buf = Common::String::format(_("Discovered %d new games, ignored %d previously added games ..."), _games.size(), _oldGamesCount); _gameProgressText->setLabel(buf); } if (_games.size() > 0) { _list->scrollToEnd(); } drawDialog(); }
// The following function tries to detect the language for COMI and DIG static Common::Language detectLanguage(const Common::FSList &fslist, byte id) { // First try to detect Chinese translation Common::FSNode fontFile; if (searchFSNode(fslist, "chinese_gb16x12.fnt", fontFile)) { debug(0, "Chinese detected"); return Common::ZH_CNA; } // Now try to detect COMI and Dig by language files if (id != GID_CMI && id != GID_DIG) return Common::UNK_LANG; // Check for LANGUAGE.BND (Dig) resp. LANGUAGE.TAB (CMI). // These are usually inside the "RESOURCE" subdirectory. // If found, we match based on the file size (should we // ever determine that this is insufficient, we can still // switch to MD5 based detection). const char *filename = (id == GID_CMI) ? "LANGUAGE.TAB" : "LANGUAGE.BND"; Common::File tmp; Common::FSNode langFile; if (searchFSNode(fslist, filename, langFile)) tmp.open(langFile); if (!tmp.isOpen()) { // try loading in RESOURCE sub dir... Common::FSNode resDir; Common::FSList tmpList; if (searchFSNode(fslist, "RESOURCE", resDir) && resDir.isDirectory() && resDir.getChildren(tmpList, Common::FSNode::kListFilesOnly) && searchFSNode(tmpList, filename, langFile)) { tmp.open(langFile); } } if (tmp.isOpen()) { uint size = tmp.size(); if (id == GID_CMI) { switch (size) { case 439080: // 2daf3db71d23d99d19fc9a544fcf6431 return Common::EN_ANY; case 322602: // caba99f4f5a0b69963e5a4d69e6f90af return Common::ZH_TWN; case 493252: // 5d59594b24f3f1332e7d7e17455ed533 return Common::DE_DEU; case 461746: // 35bbe0e4d573b318b7b2092c331fd1fa return Common::FR_FRA; case 443439: // 4689d013f67aabd7c35f4fd7c4b4ad69 return Common::IT_ITA; case 398613: // d1f5750d142d34c4c8f1f330a1278709 return Common::KO_KOR; case 440586: // 5a1d0f4fa00917bdbfe035a72a6bba9d return Common::PT_BRA; case 454457: // 0e5f450ec474a30254c0e36291fb4ebd case 394083: // ad684ca14c2b4bf4c21a81c1dbed49bc return Common::RU_RUS; case 449787: // 64f3fe479d45b52902cf88145c41d172 return Common::ES_ESP; } } else { // The DIG switch (size) { case 248627: // 1fd585ac849d57305878c77b2f6c74ff return Common::DE_DEU; case 257460: // 04cf6a6ba6f57e517bc40eb81862cfb0 return Common::FR_FRA; case 231402: // 93d13fcede954c78e65435592182a4db return Common::IT_ITA; case 228772: // 5d9ad90d3a88ea012d25d61791895ebe return Common::PT_BRA; case 229884: // d890074bc15c6135868403e73c5f4f36 return Common::ES_ESP; case 223107: // 64f3fe479d45b52902cf88145c41d172 return Common::JA_JPN; case 180730: // 424fdd60822722cdc75356d921dad9bf return Common::ZH_TWN; } } } return Common::UNK_LANG; }