diff --git a/src/common/FSNodeZIP.cxx b/src/common/FSNodeZIP.cxx index f88714841..ab961a33a 100644 --- a/src/common/FSNodeZIP.cxx +++ b/src/common/FSNodeZIP.cxx @@ -134,8 +134,8 @@ void FilesystemNodeZIP::setFlags(const string& zipfile, { _path += ("/" + _virtualPath); _shortPath += ("/" + _virtualPath); - _name = lastPathComponent(_path); } + _name = lastPathComponent(_path); _error = zip_error::NONE; if(!_realNode->isFile()) @@ -145,8 +145,7 @@ void FilesystemNodeZIP::setFlags(const string& zipfile, } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool FilesystemNodeZIP::getChildren(AbstractFSList& myList, ListMode mode, - bool hidden) const +bool FilesystemNodeZIP::getChildren(AbstractFSList& myList, ListMode mode) const { // Files within ZIP archives don't contain children if(!isDirectory() || _error != zip_error::NONE) diff --git a/src/common/FSNodeZIP.hxx b/src/common/FSNodeZIP.hxx index c76cca1c1..70d1c0cd2 100644 --- a/src/common/FSNodeZIP.hxx +++ b/src/common/FSNodeZIP.hxx @@ -48,9 +48,11 @@ class FilesystemNodeZIP : public AbstractFSNode explicit FilesystemNodeZIP(const string& path); bool exists() const override { return _realNode && _realNode->exists(); } - const string& getName() const override { return _name; } + const string& getName() const override { return _name; } + void setName(const string& name) override { _name = name; } const string& getPath() const override { return _path; } string getShortPath() const override { return _shortPath; } + bool hasParent() const override { return true; } bool isDirectory() const override { return _isDirectory; } bool isFile() const override { return _isFile; } bool isReadable() const override { return _realNode && _realNode->isReadable(); } @@ -62,7 +64,7 @@ class FilesystemNodeZIP : public AbstractFSNode bool rename(const string& newfile) override { return false; } ////////////////////////////////////////////////////////// - bool getChildren(AbstractFSList& list, ListMode mode, bool hidden) const override; + bool getChildren(AbstractFSList& list, ListMode mode) const override; AbstractFSNodePtr getParent() const override; uInt32 read(ByteBuffer& image) const override; diff --git a/src/emucore/FSNode.cxx b/src/emucore/FSNode.cxx index 77654edbe..d22db333a 100644 --- a/src/emucore/FSNode.cxx +++ b/src/emucore/FSNode.cxx @@ -37,7 +37,7 @@ FilesystemNode::FilesystemNode(const string& p) { // Is this potentially a ZIP archive? #if defined(ZIP_SUPPORT) - if(BSPF::containsIgnoreCase(p, ".zip")) + if (BSPF::containsIgnoreCase(p, ".zip")) _realNode = FilesystemNodeFactory::create(p, FilesystemNodeFactory::Type::ZIP); else #endif @@ -51,7 +51,7 @@ bool FilesystemNode::exists() const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool FilesystemNode::getChildren(FSList& fslist, ListMode mode, bool hidden) const +bool FilesystemNode::getChildren(FSList& fslist, ListMode mode) const { if (!_realNode || !_realNode->isDirectory()) return false; @@ -59,11 +59,48 @@ bool FilesystemNode::getChildren(FSList& fslist, ListMode mode, bool hidden) con AbstractFSList tmp; tmp.reserve(fslist.capacity()); - if (!_realNode->getChildren(tmp, mode, hidden)) + if (!_realNode->getChildren(tmp, mode)) return false; + std::sort(tmp.begin(), tmp.end(), + [](const AbstractFSNodePtr& node1, const AbstractFSNodePtr& node2) + { + if (node1->isDirectory() != node2->isDirectory()) + return node1->isDirectory(); + else + return BSPF::compareIgnoreCase(node1->getName(), node2->getName()) < 0; + } + ); + + // Add parent node, if it is valid to do so + if (hasParent()) + { + FilesystemNode parent = getParent(); + parent.setName(" [..]"); + fslist.emplace_back(parent); + } + + // And now add the rest of the entries for (const auto& i: tmp) - fslist.emplace_back(FilesystemNode(i)); + { + #if defined(ZIP_SUPPORT) + // Force ZIP c'tor to be called + if (BSPF::endsWithIgnoreCase(i->getPath(), ".zip")) + { + AbstractFSNodePtr ptr = FilesystemNodeFactory::create(i->getPath(), + FilesystemNodeFactory::Type::ZIP); + fslist.emplace_back(FilesystemNode(ptr)); + } + else + #endif + { + // Make directories stand out + if (i->isDirectory()) + i->setName(" [" + i->getName() + "]"); + + fslist.emplace_back(FilesystemNode(i)); + } + } return true; } @@ -74,6 +111,13 @@ const string& FilesystemNode::getName() const return _realNode->getName(); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FilesystemNode::setName(const string& name) +{ + _realNode->setName(name); +} + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const string& FilesystemNode::getPath() const { @@ -109,7 +153,7 @@ string FilesystemNode::getPathWithExt(const string& ext) const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FilesystemNode::hasParent() const { - return _realNode ? (_realNode->getParent() != nullptr) : false; + return _realNode ? _realNode->hasParent() : false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -164,23 +208,23 @@ uInt32 FilesystemNode::read(ByteBuffer& image) const uInt32 size = 0; // File must actually exist - if(!(exists() && isReadable())) + if (!(exists() && isReadable())) throw runtime_error("File not found/readable"); // First let the private subclass attempt to open the file - if((size = _realNode->read(image)) > 0) + if ((size = _realNode->read(image)) > 0) return size; // Otherwise, the default behaviour is to read from a normal C++ ifstream image = make_unique(512 * 1024); ifstream in(getPath(), std::ios::binary); - if(in) + if (in) { in.seekg(0, std::ios::end); std::streampos length = in.tellg(); in.seekg(0, std::ios::beg); - if(length == 0) + if (length == 0) throw runtime_error("Zero-byte file"); size = std::min(uInt32(length), 512u * 1024u); diff --git a/src/emucore/FSNode.hxx b/src/emucore/FSNode.hxx index 408bed559..e4f92af53 100644 --- a/src/emucore/FSNode.hxx +++ b/src/emucore/FSNode.hxx @@ -94,18 +94,6 @@ class FilesystemNode FilesystemNode(const FilesystemNode&) = default; FilesystemNode& operator=(const FilesystemNode&) = default; - /** - * Compare the name of this node to the name of another. Directories - * go before normal files. - */ - inline bool operator<(const FilesystemNode& node) const - { - if (isDirectory() != node.isDirectory()) - return isDirectory(); - - return BSPF::compareIgnoreCase(getName(), node.getName()) < 0; - } - /** * Compare the name of this node to the name of another, testing for * equality, @@ -139,11 +127,10 @@ class FilesystemNode * @return true if successful, false otherwise (e.g. when the directory * does not exist). */ - bool getChildren(FSList& fslist, ListMode mode = ListMode::DirectoriesOnly, - bool hidden = false) const; + bool getChildren(FSList& fslist, ListMode mode = ListMode::DirectoriesOnly) const; /** - * Return a string representation of the name of the file. This is can be + * Set/get a string representation of the name of the file. This is can be * used e.g. by detection code that relies on matching the name of a given * file. But it is *not* suitable for use with fopen / File::open, nor * should it be archived. @@ -151,6 +138,7 @@ class FilesystemNode * @return the file name */ const string& getName() const; + void setName(const string& name); /** * Return a string representation of the file which can be passed to fopen(). @@ -300,12 +288,11 @@ class AbstractFSNode * * @param list List to put the contents of the directory in. * @param mode Mode to use while listing the directory. - * @param hidden Whether to include hidden files or not in the results. * * @return true if successful, false otherwise (e.g. when the directory * does not exist). */ - virtual bool getChildren(AbstractFSList& list, ListMode mode, bool hidden) const = 0; + virtual bool getChildren(AbstractFSList& list, ListMode mode) const = 0; /** * Returns the last component of the path pointed by this FilesystemNode. @@ -318,6 +305,7 @@ class AbstractFSNode * implementation for more information. */ virtual const string& getName() const = 0; + virtual void setName(const string& name) = 0; /** * Returns the 'path' of the current node, usable in fopen(). @@ -330,6 +318,17 @@ class AbstractFSNode virtual string getShortPath() const = 0; + /** + * Determine whether this node has a parent. + */ + virtual bool hasParent() const = 0; + + /** + * The parent node of this directory. + * The parent of the root is 'nullptr'. + */ + virtual AbstractFSNodePtr getParent() const = 0; + /** * Indicates whether this path refers to a directory or not. */ @@ -392,12 +391,6 @@ class AbstractFSNode * a try-catch block. */ virtual uInt32 read(ByteBuffer& buffer) const { return 0; } - - /** - * The parent node of this directory. - * The parent of the root is the root itself. - */ - virtual AbstractFSNodePtr getParent() const = 0; }; #endif diff --git a/src/gui/FileListWidget.cxx b/src/gui/FileListWidget.cxx index 2d778a4fd..451c57d5a 100644 --- a/src/gui/FileListWidget.cxx +++ b/src/gui/FileListWidget.cxx @@ -18,16 +18,21 @@ #include "ScrollBarWidget.hxx" #include "FileListWidget.hxx" -#include "Bankswitch.hxx" -#include "MD5.hxx" #include "bspf.hxx" +/** + TODO: + - extension handling not handled + - add lambda filter to selectively choose files based on pattern + - history of selected folders/files +*/ + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FileListWidget::FileListWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h) : StringListWidget(boss, font, x, y, w, h), _fsmode(FilesystemNode::ListMode::All), - _selectedPos(0) + _selected(0) { // This widget is special, in that it catches signals and redirects them setTarget(this); @@ -45,36 +50,15 @@ void FileListWidget::setLocation(const FilesystemNode& node, string select) _node = _node.getParent(); } - // Start with empty list - _gameList.clear(); - - // Read in the data from the file system - FSList content; - content.reserve(512); - _node.getChildren(content, _fsmode); - - // Add '[..]' to indicate previous folder - if(_node.hasParent()) - _gameList.appendGame(" [..]", _node.getParent().getPath(), "", true); - - // Now add the directory entries - for(const auto& file: content) - { - string name = file.getName(); - bool isDir = file.isDirectory(); - if(isDir) - name = " [" + name + "]"; - else if(!BSPF::endsWithIgnoreCase(name, _extension)) - continue; - - _gameList.appendGame(name, file.getPath(), "", isDir); - } - _gameList.sortByName(); + // Read in the data from the file system (start with an empty list) + _fileList.clear(); + _fileList.reserve(512); + _node.getChildren(_fileList, _fsmode); // Now fill the list widget with the contents of the GameList StringList l; - for(uInt32 i = 0; i < _gameList.size(); ++i) - l.push_back(_gameList.name(i)); + for(const auto& file: _fileList) + l.push_back(file.getName()); setList(l); setSelected(select); @@ -96,20 +80,7 @@ void FileListWidget::selectParent() void FileListWidget::reload() { if(_node.exists()) - setLocation(_node, _gameList.name(_selectedPos)); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const string& FileListWidget::selectedMD5() -{ - if(_selected.isDirectory() || !Bankswitch::isValidRomName(_selected)) - return EmptyString; - - // Make sure we have a valid md5 for this ROM - if(_gameList.md5(_selectedPos) == "") - _gameList.setMd5(_selectedPos, MD5::hash(_selected)); - - return _gameList.md5(_selectedPos); + setLocation(_node, selected().getName()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -123,19 +94,16 @@ void FileListWidget::handleCommand(CommandSender* sender, int cmd, int data, int case ListWidget::kSelectionChangedCmd: cmd = ItemChanged; - _selected = FilesystemNode(_gameList.path(data)); - _selectedPos = data; + _selected = data; break; case ListWidget::kActivatedCmd: case ListWidget::kDoubleClickedCmd: - if(_gameList.isDir(data)) + _selected = data; + if(selected().isDirectory()) { cmd = ItemChanged; - if(_gameList.name(data) == " [..]") - selectParent(); - else - setLocation(FilesystemNode(_gameList.path(data))); + setLocation(selected()); } else cmd = ItemActivated; diff --git a/src/gui/FileListWidget.hxx b/src/gui/FileListWidget.hxx index 501fad3ac..38c5fd6e0 100644 --- a/src/gui/FileListWidget.hxx +++ b/src/gui/FileListWidget.hxx @@ -21,7 +21,6 @@ class CommandSender; #include "FSNode.hxx" -#include "GameList.hxx" #include "StringListWidget.hxx" /** @@ -64,26 +63,19 @@ class FileListWidget : public StringListWidget void reload(); /** Gets current node(s) */ - const FilesystemNode& selected() const { return _selected; } - const FilesystemNode& currentDir() const { return _node; } - - /** Gets MD5sum of the current node, if it is a file, and caches the result. - Otherwise, does nothing. - - @return MD5sum of selected file, else EmptyString - */ - const string& selectedMD5(); + const FilesystemNode& selected() const { return _fileList[_selected]; } + const FilesystemNode& currentDir() const { return _node; } private: void handleCommand(CommandSender* sender, int cmd, int data, int id) override; private: FilesystemNode::ListMode _fsmode; - FilesystemNode _node, _selected; - GameList _gameList; + FilesystemNode _node; + FSList _fileList; string _extension; - uInt32 _selectedPos; + uInt32 _selected; private: // Following constructors and assignment operators not supported diff --git a/src/gui/GameList.cxx b/src/gui/GameList.cxx deleted file mode 100644 index 96440f292..000000000 --- a/src/gui/GameList.cxx +++ /dev/null @@ -1,58 +0,0 @@ -//============================================================================ -// -// SSSS tt lll lll -// SS SS tt ll ll -// SS tttttt eeee ll ll aaaa -// SSSS tt ee ee ll ll aa -// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" -// SS SS tt ee ll ll aa aa -// SSSS ttt eeeee llll llll aaaaa -// -// Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony -// and the Stella Team -// -// See the file "License.txt" for information on usage and redistribution of -// this file, and for a DISCLAIMER OF ALL WARRANTIES. -// -// Based on code from KStella - Stella frontend -// Copyright (C) 2003-2005 Stephen Anthony -//============================================================================ - -#include -#include - -#include "GameList.hxx" - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void GameList::sortByName() -{ - if(myArray.size() < 2) - return; - - auto cmp = [](const Entry& a, const Entry& b) - { - // directories always first - if(a._isdir != b._isdir) - return a._isdir; - - auto it1 = a._name.cbegin(), it2 = b._name.cbegin(); - - // Account for ending ']' character in directory entries - auto end1 = a._isdir ? a._name.cend() - 1 : a._name.cend(); - auto end2 = b._isdir ? b._name.cend() - 1 : b._name.cend(); - - // Stop when either string's end has been reached - while((it1 != end1) && (it2 != end2)) - { - if(toupper(*it1) != toupper(*it2)) // letters differ? - return toupper(*it1) < toupper(*it2); - - // proceed to the next character in each string - ++it1; - ++it2; - } - return a._name.size() < b._name.size(); - }; - - sort(myArray.begin(), myArray.end(), cmp); -} diff --git a/src/gui/GameList.hxx b/src/gui/GameList.hxx deleted file mode 100644 index 95f21ba49..000000000 --- a/src/gui/GameList.hxx +++ /dev/null @@ -1,75 +0,0 @@ -//============================================================================ -// -// SSSS tt lll lll -// SS SS tt ll ll -// SS tttttt eeee ll ll aaaa -// SSSS tt ee ee ll ll aa -// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" -// SS SS tt ee ll ll aa aa -// SSSS ttt eeeee llll llll aaaaa -// -// Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony -// and the Stella Team -// -// See the file "License.txt" for information on usage and redistribution of -// this file, and for a DISCLAIMER OF ALL WARRANTIES. -// -// Based on code from KStella - Stella frontend -// Copyright (C) 2003-2005 Stephen Anthony -//============================================================================ - -#ifndef GAME_LIST_HXX -#define GAME_LIST_HXX - -#include "bspf.hxx" - -/** - Holds the list of game info for the ROM launcher. -*/ -class GameList -{ - public: - GameList() = default; - - const string& name(uInt32 i) const - { return i < myArray.size() ? myArray[i]._name : EmptyString; } - const string& path(uInt32 i) const - { return i < myArray.size() ? myArray[i]._path : EmptyString; } - const string& md5(uInt32 i) const - { return i < myArray.size() ? myArray[i]._md5 : EmptyString; } - bool isDir(uInt32 i) const - { return i < myArray.size() ? myArray[i]._isdir: false; } - - void setMd5(uInt32 i, const string& md5) - { myArray[i]._md5 = md5; } - - uInt32 size() const { return uInt32(myArray.size()); } - void clear() { myArray.clear(); } - - void appendGame(const string& name, const string& path, const string& md5, - bool isDir = false) { - myArray.emplace_back(name, path, md5, isDir); - } - void sortByName(); - - private: - struct Entry { - string _name; - string _path; - string _md5; - bool _isdir; - - Entry(string name, string path, string md5, bool isdir) - : _name(name), _path(path), _md5(md5), _isdir(isdir) { } - }; - vector myArray; - - private: - // Following constructors and assignment operators not supported - GameList(const GameList&) = delete; - GameList(GameList&&) = delete; - GameList& operator=(const GameList&) = delete; - GameList& operator=(GameList&&) = delete; -}; - -#endif diff --git a/src/gui/LauncherDialog.cxx b/src/gui/LauncherDialog.cxx index 5e754ca55..046b4c706 100644 --- a/src/gui/LauncherDialog.cxx +++ b/src/gui/LauncherDialog.cxx @@ -16,6 +16,7 @@ //============================================================================ #include "bspf.hxx" +#include "Bankswitch.hxx" #include "BrowserDialog.hxx" #include "ContextMenu.hxx" #include "DialogContainer.hxx" @@ -23,7 +24,7 @@ #include "EditTextWidget.hxx" #include "FileListWidget.hxx" #include "FSNode.hxx" -#include "GameList.hxx" +#include "MD5.hxx" #include "OptionsDialog.hxx" #include "GlobalPropsDialog.hxx" #include "StellaSettingsDialog.hxx" @@ -46,7 +47,7 @@ TODO: - show all files / only ROMs - connect to 'matchPattern' - - history of selected folders/files + - create lambda filter to pass these to FileListWidget */ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -246,7 +247,19 @@ const string& LauncherDialog::selectedRom() const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const string& LauncherDialog::selectedRomMD5() { - return myList->selectedMD5(); + if(currentNode().isDirectory() || !Bankswitch::isValidRomName(currentNode())) + return EmptyString; + + // Attempt to conserve memory + if(myMD5List.size() > 500) + myMD5List.clear(); + + // Lookup MD5, and if not present, cache it + auto iter = myMD5List.find(currentNode().getPath()); + if(iter == myMD5List.end()) + myMD5List[currentNode().getPath()] = MD5::hash(currentNode()); + + return myMD5List[currentNode().getPath()]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -612,7 +625,7 @@ void LauncherDialog::handleCommand(CommandSender* sender, int cmd, // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void LauncherDialog::loadRom() { - const string& result = instance().createConsole(currentNode(), myList->selectedMD5()); + const string& result = instance().createConsole(currentNode(), selectedRomMD5()); if(result == EmptyString) { instance().settings().setValue("lastrom", myList->getSelectedString()); diff --git a/src/gui/LauncherDialog.hxx b/src/gui/LauncherDialog.hxx index 6a2a24b46..8942805c2 100644 --- a/src/gui/LauncherDialog.hxx +++ b/src/gui/LauncherDialog.hxx @@ -36,6 +36,8 @@ namespace GUI { class MessageBox; } +#include + #include "bspf.hxx" #include "Dialog.hxx" #include "FSNode.hxx" @@ -122,6 +124,7 @@ class LauncherDialog : public Dialog CheckboxWidget* myAllFiles; RomInfoWidget* myRomInfoWidget; + std::unordered_map myMD5List; int mySelectedItem; diff --git a/src/gui/module.mk b/src/gui/module.mk index fff96d32a..82c14c391 100644 --- a/src/gui/module.mk +++ b/src/gui/module.mk @@ -19,7 +19,6 @@ MODULE_OBJS := \ src/gui/FileListWidget.o \ src/gui/Font.o \ src/gui/GameInfoDialog.o \ - src/gui/GameList.o \ src/gui/GlobalPropsDialog.o \ src/gui/HelpDialog.o \ src/gui/InputDialog.o \ diff --git a/src/libretro/FSNodeLIBRETRO.cxx b/src/libretro/FSNodeLIBRETRO.cxx index b12305337..cd3b71fa2 100644 --- a/src/libretro/FSNodeLIBRETRO.cxx +++ b/src/libretro/FSNodeLIBRETRO.cxx @@ -19,14 +19,11 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FilesystemNodeLIBRETRO::FilesystemNodeLIBRETRO() + : _name("rom"), + _isDirectory(false), + _isFile(true), + _isValid(true) { - _displayName = "rom"; - _path = ""; - - _isDirectory = false; - _isFile = true; - _isPseudoRoot = false; - _isValid = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -60,7 +57,7 @@ string FilesystemNodeLIBRETRO::getShortPath() const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FilesystemNodeLIBRETRO:: - getChildren(AbstractFSList& myList, ListMode mode, bool hidden) const + getChildren(AbstractFSList& myList, ListMode mode) const { return false; } diff --git a/src/libretro/FSNodeLIBRETRO.hxx b/src/libretro/FSNodeLIBRETRO.hxx index b2790d767..677d6a6ad 100644 --- a/src/libretro/FSNodeLIBRETRO.hxx +++ b/src/libretro/FSNodeLIBRETRO.hxx @@ -20,9 +20,6 @@ #include "FSNode.hxx" -// TODO - fix isFile() functionality so that it actually determines if something -// is a file; for now, it assumes a file if it isn't a directory - /* * Implementation of the Stella file system API based on LIBRETRO API. * @@ -37,9 +34,11 @@ class FilesystemNodeLIBRETRO : public AbstractFSNode explicit FilesystemNodeLIBRETRO(const string& path); bool exists() const override; - const string& getName() const override { return _displayName; } - const string& getPath() const override { return _path; } + const string& getName() const override { return _name; } + void setName(const string& name) override { _name = name; } + const string& getPath() const override { return _path; } string getShortPath() const override; + bool hasParent() const override { return false; } bool isDirectory() const override { return _isDirectory; } bool isFile() const override { return _isFile; } bool isReadable() const override; @@ -47,13 +46,13 @@ class FilesystemNodeLIBRETRO : public AbstractFSNode bool makeDir() override; bool rename(const string& newfile) override; - bool getChildren(AbstractFSList& list, ListMode mode, bool hidden) const override; + bool getChildren(AbstractFSList& list, ListMode mode) const override; AbstractFSNodePtr getParent() const override; uInt32 read(ByteBuffer& image) const override; protected: - string _displayName; + string _name; string _path; bool _isDirectory; bool _isFile; diff --git a/src/unix/FSNodePOSIX.cxx b/src/unix/FSNodePOSIX.cxx index 91009cdd0..fb5d97c66 100644 --- a/src/unix/FSNodePOSIX.cxx +++ b/src/unix/FSNodePOSIX.cxx @@ -53,13 +53,13 @@ FilesystemNodePOSIX::FilesystemNodePOSIX() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -FilesystemNodePOSIX::FilesystemNodePOSIX(const string& p, bool verify) +FilesystemNodePOSIX::FilesystemNodePOSIX(const string& path, bool verify) : _isValid(true), _isFile(false), _isDirectory(true) { // Default to home directory - _path = p.length() > 0 ? p : "~"; + _path = path.length() > 0 ? path : "~"; // Expand '~' to the HOME environment variable if(_path[0] == '~') @@ -99,8 +99,13 @@ string FilesystemNodePOSIX::getShortPath() const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool FilesystemNodePOSIX::getChildren(AbstractFSList& myList, ListMode mode, - bool hidden) const +bool FilesystemNodePOSIX::hasParent() const +{ + return _path != "" && _path != ROOT_DIR; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool FilesystemNodePOSIX::getChildren(AbstractFSList& myList, ListMode mode) const { assert(_isDirectory); @@ -112,12 +117,8 @@ bool FilesystemNodePOSIX::getChildren(AbstractFSList& myList, ListMode mode, struct dirent* dp; while ((dp = readdir(dirp)) != nullptr) { - // Skip 'invisible' files if necessary - if (dp->d_name[0] == '.' && !hidden) - continue; - - // Skip '.' and '..' to avoid cycles - if ((dp->d_name[0] == '.' && dp->d_name[1] == 0) || (dp->d_name[0] == '.' && dp->d_name[1] == '.')) + // Ignore all hidden files + if (dp->d_name[0] == '.') continue; string newPath(_path); diff --git a/src/unix/FSNodePOSIX.hxx b/src/unix/FSNodePOSIX.hxx index 119027149..fdd964e70 100644 --- a/src/unix/FSNodePOSIX.hxx +++ b/src/unix/FSNodePOSIX.hxx @@ -61,9 +61,11 @@ class FilesystemNodePOSIX : public AbstractFSNode FilesystemNodePOSIX(const string& path, bool verify = true); bool exists() const override { return access(_path.c_str(), F_OK) == 0; } - const string& getName() const override { return _displayName; } + const string& getName() const override { return _displayName; } + void setName(const string& name) override { _displayName = name; } const string& getPath() const override { return _path; } string getShortPath() const override; + bool hasParent() const override; bool isDirectory() const override { return _isDirectory; } bool isFile() const override { return _isFile; } bool isReadable() const override { return access(_path.c_str(), R_OK) == 0; } @@ -71,7 +73,7 @@ class FilesystemNodePOSIX : public AbstractFSNode bool makeDir() override; bool rename(const string& newfile) override; - bool getChildren(AbstractFSList& list, ListMode mode, bool hidden) const override; + bool getChildren(AbstractFSList& list, ListMode mode) const override; AbstractFSNodePtr getParent() const override; protected: