diff --git a/src/Cafe/Filesystem/FST/fstUtil.h b/src/Cafe/Filesystem/FST/fstUtil.h index a1848d61..4ea9465d 100644 --- a/src/Cafe/Filesystem/FST/fstUtil.h +++ b/src/Cafe/Filesystem/FST/fstUtil.h @@ -87,17 +87,14 @@ public: } // returns true if the node names match according to FSA case-insensitivity rules - bool MatchNode(sint32 index, std::string_view name) const + static bool MatchNodeName(std::string_view name1, std::string_view name2) { - if (index < 0 || index >= (sint32)m_nodes.size()) + if (name1.size() != name2.size()) return false; - auto nodeName = GetNodeName(index); - if (nodeName.size() != name.size()) - return false; - for (size_t i = 0; i < nodeName.size(); i++) + for (size_t i = 0; i < name1.size(); i++) { - char c1 = nodeName[i]; - char c2 = name[i]; + char c1 = name1[i]; + char c2 = name2[i]; if (c1 >= 'A' && c1 <= 'Z') c1 += ('a' - 'A'); if (c2 >= 'A' && c2 <= 'Z') @@ -107,191 +104,18 @@ public: } return true; } -}; -class parsedPathW // todo - replaces this with FSCPath (using ascii/utf8 strings instead of wchar) -{ - static const int MAX_NODES = 32; - -public: - parsedPathW(std::wstring_view path) + bool MatchNodeName(sint32 index, std::string_view name) const { - // init vars - this->numNodes = 0; - // init parsed path data - if (path.front() == '/') - path.remove_prefix(1); - pathData.assign(path.begin(), path.end()); - pathData.push_back('\0'); - // start parsing - sint32 offset = 0; - sint32 startOffset = 0; - if (offset < pathData.size()-1) - { - this->nodeOffset[this->numNodes] = offset; - this->numNodes++; - } - while (offset < pathData.size() - 1) - { - if (this->pathData[offset] == '/' || this->pathData[offset] == '\\') - { - this->pathData[offset] = '\0'; - offset++; - // double slashes are ignored and instead are handled like a single slash - if (this->pathData[offset] == '/' || this->pathData[offset] == '\\') - { - // if we're in the beginning and having a \\ it's a network path - if (offset != 1) - { - this->pathData[offset] = '\0'; - offset++; - } - } - // start new node - if (this->numNodes < MAX_NODES) - { - if (offset < pathData.size() - 1) - { - this->nodeOffset[this->numNodes] = offset; - this->numNodes++; - } - } - continue; - } - offset++; - } - // handle special nodes like '.' or '..' - sint32 nodeIndex = 0; - while (nodeIndex < this->numNodes) - { - if (compareNodeName(nodeIndex, L"..")) - { - assert(false); - } - else if (compareNodeName(nodeIndex, L".")) - { - removeNode(nodeIndex); - continue; - } - nodeIndex++; - } - } - - // returns true if the names match (case sensitive) - bool compareNodeName(sint32 index, std::wstring_view name) - { - if (index < 0 || index >= this->numNodes) + if (index < 0 || index >= (sint32)m_nodes.size()) return false; - const wchar_t* nodeName = this->pathData.data() + this->nodeOffset[index]; - if (boost::iequals(nodeName, name)) - return true; - return false; + auto nodeName = GetNodeName(index); + return MatchNodeName(nodeName, name); } - - static bool compareNodeName(std::wstring_view name1, std::wstring_view name2) - { - if (boost::iequals(name1, name2)) - return true; - return false; - } - - static bool compareNodeNameCaseInsensitive(std::wstring_view name1, std::wstring_view name2) - { - if (boost::iequals(name1, name2)) - return true; - return false; - } - - const wchar_t* getNodeName(sint32 index) - { - if (index < 0 || index >= this->numNodes) - return nullptr; - return this->pathData.data() + this->nodeOffset[index]; - } - - void removeNode(sint32 index) - { - if (index < 0 || index >= numNodes) - return; - numNodes--; - for (sint32 i = 0; i < numNodes; i++) - { - nodeOffset[i] = nodeOffset[i + 1]; - } - // remove empty space - if (numNodes > 0) - updateOffsets(nodeOffset[0]); - } - - void prependNode(wchar_t* newNode) - { - if (numNodes >= MAX_NODES) - return; - sint32 len = (sint32)wcslen(newNode); - updateOffsets(-(len + 1)); - numNodes++; - for (sint32 i = numNodes - 1; i >= 1; i--) - { - nodeOffset[i] = nodeOffset[i - 1]; - } - nodeOffset[0] = 0; - memcpy(pathData.data() + 0, newNode, (len + 1) * sizeof(wchar_t)); - } - - void buildPathString(std::wstring& pathStr, bool appendSlash = false) - { - pathStr.resize(0); - for (sint32 i = 0; i < numNodes; i++) - { - if (numNodes > 1) - pathStr.append(L"/"); - pathStr.append(pathData.data() + nodeOffset[i]); - } - if(appendSlash) - pathStr.append(L"/"); - } -private: - void updateOffsets(sint32 newBaseOffset) - { - if (numNodes == 0 || newBaseOffset == 0) - return; - cemu_assert_debug(newBaseOffset <= nodeOffset[0]); - if (newBaseOffset > 0) - { - // decrease size - memmove(pathData.data(), pathData.data() + newBaseOffset, (pathData.size() - newBaseOffset) * sizeof(wchar_t)); - pathData.resize(pathData.size() - newBaseOffset); - // update node offsets - for (sint32 i = 0; i < numNodes; i++) - { - nodeOffset[i] -= newBaseOffset; - } - } - else - { - // increase size - newBaseOffset = -newBaseOffset; - pathData.resize(pathData.size() + newBaseOffset); - memmove(pathData.data() + newBaseOffset, pathData.data(), (pathData.size() - newBaseOffset) * sizeof(wchar_t)); - // update node offsets - for (sint32 i = 0; i < numNodes; i++) - { - nodeOffset[i] += newBaseOffset; - } - } - } - -private: - //std::wstring pathData; - std::vector pathData; - sint32 nodeOffset[MAX_NODES + 1]; - -public: - sint32 numNodes; }; -template -class FileTree +template +class FSAFileTree { public: @@ -303,27 +127,27 @@ private: NODETYPE_FILE, }; - typedef struct _node_t + struct node_t { - std::wstring name; - std::vector<_node_t*> subnodes; + std::string name; + std::vector subnodes; F* custom; NODETYPE type; - }node_t; + }; - node_t* getByNodePath(parsedPathW& p, sint32 numNodes, bool createAsDirectories) + node_t* getByNodePath(FSCPath& p, sint32 numNodes, bool createAsDirectories) { node_t* currentNode = &rootNode; for (sint32 i = 0; i < numNodes; i++) { // find subnode by path - node_t* foundSubnode = getSubnode(currentNode, p.getNodeName(i)); + node_t* foundSubnode = getSubnode(currentNode, p.GetNodeName(i)); if (foundSubnode == nullptr) { // no subnode found -> create new directory node (if requested) if (createAsDirectories == false) return nullptr; // path not found - currentNode = newNode(currentNode, NODETYPE_DIRECTORY, p.getNodeName(i)); + currentNode = newNode(currentNode, NODETYPE_DIRECTORY, p.GetNodeName(i)); } else { @@ -333,28 +157,20 @@ private: return currentNode; } - node_t* getSubnode(node_t* parentNode, std::wstring_view name) + node_t* getSubnode(node_t* parentNode, std::string_view name) { for (auto& sn : parentNode->subnodes) { - if constexpr (isCaseSensitive) - { - if (parsedPathW::compareNodeName(sn->name.c_str(), name)) - return sn; - } - else - { - if (parsedPathW::compareNodeNameCaseInsensitive(sn->name.c_str(), name)) - return sn; - } + if (FSCPath::MatchNodeName(sn->name, name)) + return sn; } return nullptr; } - node_t* newNode(node_t* parentNode, NODETYPE type, std::wstring_view name) + node_t* newNode(node_t* parentNode, NODETYPE type, std::string_view name) { node_t* newNode = new node_t; - newNode->name = std::wstring(name); + newNode->name.assign(name); newNode->type = type; newNode->custom = nullptr; parentNode->subnodes.push_back(newNode); @@ -362,32 +178,32 @@ private: } public: - FileTree() + FSAFileTree() { rootNode.type = NODETYPE_DIRECTORY; } - bool addFile(const wchar_t* path, F* custom) + bool addFile(std::string_view path, F* custom) { - parsedPathW p(path); - if (p.numNodes == 0) + FSCPath p(path); + if (p.GetNodeCount() == 0) return false; - node_t* directoryNode = getByNodePath(p, p.numNodes - 1, true); + node_t* directoryNode = getByNodePath(p, p.GetNodeCount() - 1, true); // check if a node with same name already exists - if (getSubnode(directoryNode, p.getNodeName(p.numNodes - 1)) != nullptr) + if (getSubnode(directoryNode, p.GetNodeName(p.GetNodeCount() - 1)) != nullptr) return false; // node already exists // add file node - node_t* fileNode = newNode(directoryNode, NODETYPE_FILE, p.getNodeName(p.numNodes - 1)); + node_t* fileNode = newNode(directoryNode, NODETYPE_FILE, p.GetNodeName(p.GetNodeCount() - 1)); fileNode->custom = custom; return true; } - bool getFile(std::wstring_view path, F* &custom) + bool getFile(std::string_view path, F* &custom) { - parsedPathW p(path); - if (p.numNodes == 0) + FSCPath p(path); + if (p.GetNodeCount() == 0) return false; - node_t* node = getByNodePath(p, p.numNodes, false); + node_t* node = getByNodePath(p, p.GetNodeCount(), false); if (node == nullptr) return false; if (node->type != NODETYPE_FILE) @@ -396,16 +212,16 @@ public: return true; } - bool removeFile(std::wstring_view path) + bool removeFile(std::string_view path) { - parsedPathW p(path); - if (p.numNodes == 0) + FSCPath p(path); + if (p.GetNodeCount() == 0) return false; - node_t* directoryNode = getByNodePath(p, p.numNodes - 1, false); + node_t* directoryNode = getByNodePath(p, p.GetNodeCount() - 1, false); if (directoryNode == nullptr) return false; // find node - node_t* fileNode = getSubnode(directoryNode, p.getNodeName(p.numNodes - 1)); + node_t* fileNode = getSubnode(directoryNode, p.GetNodeName(p.GetNodeCount() - 1)); if (fileNode == nullptr) return false; if (fileNode->type != NODETYPE_FILE) @@ -423,10 +239,10 @@ public: } template - bool listDirectory(const wchar_t* path, TFunc fn) + bool listDirectory(std::string_view path, TFunc fn) { - parsedPathW p(path); - node_t* node = getByNodePath(p, p.numNodes, false); + FSCPath p(path); + node_t* node = getByNodePath(p, p.GetNodeCount(), false); if (node == nullptr) return false; if (node->type != NODETYPE_DIRECTORY) @@ -454,28 +270,28 @@ static void FSTPathUnitTest() // test 1 FSCPath p1("/vol/content"); cemu_assert_debug(p1.GetNodeCount() == 2); - cemu_assert_debug(p1.MatchNode(0, "tst") == false); - cemu_assert_debug(p1.MatchNode(0, "vol")); - cemu_assert_debug(p1.MatchNode(1, "CONTENT")); + cemu_assert_debug(p1.MatchNodeName(0, "tst") == false); + cemu_assert_debug(p1.MatchNodeName(0, "vol")); + cemu_assert_debug(p1.MatchNodeName(1, "CONTENT")); // test 2 FSCPath p2("/vol/content/"); cemu_assert_debug(p2.GetNodeCount() == 2); - cemu_assert_debug(p2.MatchNode(0, "vol")); - cemu_assert_debug(p2.MatchNode(1, "content")); + cemu_assert_debug(p2.MatchNodeName(0, "vol")); + cemu_assert_debug(p2.MatchNodeName(1, "content")); // test 3 FSCPath p3("/vol//content/\\/"); cemu_assert_debug(p3.GetNodeCount() == 2); - cemu_assert_debug(p3.MatchNode(0, "vol")); - cemu_assert_debug(p3.MatchNode(1, "content")); + cemu_assert_debug(p3.MatchNodeName(0, "vol")); + cemu_assert_debug(p3.MatchNodeName(1, "content")); // test 4 FSCPath p4("vol/content/"); cemu_assert_debug(p4.GetNodeCount() == 2); // test 5 FSCPath p5("/vol/content/test.bin"); cemu_assert_debug(p5.GetNodeCount() == 3); - cemu_assert_debug(p5.MatchNode(0, "vol")); - cemu_assert_debug(p5.MatchNode(1, "content")); - cemu_assert_debug(p5.MatchNode(2, "TEST.BIN")); + cemu_assert_debug(p5.MatchNodeName(0, "vol")); + cemu_assert_debug(p5.MatchNodeName(1, "content")); + cemu_assert_debug(p5.MatchNodeName(2, "TEST.BIN")); // test 6 - empty paths FSCPath p6(""); cemu_assert_debug(p6.GetNodeCount() == 0); diff --git a/src/Cafe/Filesystem/fsc.cpp b/src/Cafe/Filesystem/fsc.cpp index 0f281bab..1c541a7f 100644 --- a/src/Cafe/Filesystem/fsc.cpp +++ b/src/Cafe/Filesystem/fsc.cpp @@ -86,7 +86,7 @@ FSCMountPathNode* fsc_createMountPath(const FSCPath& mountPath, sint32 priority) FSCMountPathNode* nodeSub = nullptr; // set if we found a subnode with a matching name, else this is used to store the new nodes for (auto& nodeItr : nodeParent->subnodes) { - if (mountPath.MatchNode(i, nodeItr->path)) + if (mountPath.MatchNodeName(i, nodeItr->path)) { // subnode found nodeSub = nodeItr; @@ -195,7 +195,7 @@ bool fsc_lookupPath(const char* path, std::wstring& devicePathOut, fscDeviceC** FSCMountPathNode* nodeSub = nullptr; for(auto& nodeItr : nodeParent->subnodes) { - if (parsedPath.MatchNode(i, nodeItr->path)) + if (parsedPath.MatchNodeName(i, nodeItr->path)) { nodeSub = nodeItr; break; @@ -246,7 +246,7 @@ FSCMountPathNode* fsc_lookupPathVirtualNode(const char* path, sint32 priority) FSCMountPathNode* nodeSub = nullptr; for (auto& nodeItr : nodeCurrentDir->subnodes) { - if (parsedPath.MatchNode(i, nodeItr->path)) + if (parsedPath.MatchNodeName(i, nodeItr->path)) { nodeSub = nodeItr; break; diff --git a/src/Cafe/Filesystem/fscDeviceRedirect.cpp b/src/Cafe/Filesystem/fscDeviceRedirect.cpp index 9c658eb3..d5245006 100644 --- a/src/Cafe/Filesystem/fscDeviceRedirect.cpp +++ b/src/Cafe/Filesystem/fscDeviceRedirect.cpp @@ -9,23 +9,22 @@ struct RedirectEntry sint32 priority; }; -FileTree redirectTree; +FSAFileTree redirectTree; void fscDeviceRedirect_add(std::string_view virtualSourcePath, const fs::path& targetFilePath, sint32 priority) { - std::wstring virtualSourcePathW = boost::nowide::widen(std::string(virtualSourcePath)); // check if source already has a redirection RedirectEntry* existingEntry; - if (redirectTree.getFile(virtualSourcePathW, existingEntry)) + if (redirectTree.getFile(virtualSourcePath, existingEntry)) { if (existingEntry->priority >= priority) return; // dont replace entries with equal or higher priority // unregister existing entry - redirectTree.removeFile(virtualSourcePathW.c_str()); + redirectTree.removeFile(virtualSourcePath); delete existingEntry; } RedirectEntry* entry = new RedirectEntry(targetFilePath, priority); - redirectTree.addFile(virtualSourcePathW.c_str(), entry); + redirectTree.addFile(virtualSourcePath, entry); } class fscDeviceTypeRedirect : public fscDeviceC @@ -33,7 +32,8 @@ class fscDeviceTypeRedirect : public fscDeviceC FSCVirtualFile* fscDeviceOpenByPath(std::wstring_view pathW, FSC_ACCESS_FLAG accessFlags, void* ctx, sint32* fscStatus) override { RedirectEntry* redirectionEntry; - if (redirectTree.getFile(pathW, redirectionEntry)) + std::string pathTmp = boost::nowide::narrow(pathW); + if (redirectTree.getFile(pathTmp, redirectionEntry)) return FSCVirtualFile_Host::OpenFile(redirectionEntry->dstPath, accessFlags, *fscStatus); return nullptr; }