mirror of https://github.com/cemu-project/Cemu.git
FSC: Refactor to use FSCPath instead of legacy code
This commit is contained in:
parent
0e0602e8d9
commit
b8462cec8b
|
@ -1,7 +1,115 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
|
|
||||||
class parsedPathW
|
#include <boost/container/small_vector.hpp>
|
||||||
|
|
||||||
|
// path parser and utility class for Wii U paths
|
||||||
|
// optimized to be allocation-free for common path lengths
|
||||||
|
class FSCPath
|
||||||
|
{
|
||||||
|
struct PathNode
|
||||||
|
{
|
||||||
|
PathNode(uint16 offset, uint16 len) : offset(offset), len(len) {};
|
||||||
|
|
||||||
|
uint16 offset;
|
||||||
|
uint16 len;
|
||||||
|
};
|
||||||
|
|
||||||
|
boost::container::small_vector<PathNode, 8> m_nodes;
|
||||||
|
boost::container::small_vector<char, 64> m_names;
|
||||||
|
bool m_isAbsolute{};
|
||||||
|
|
||||||
|
inline bool isSlash(char c)
|
||||||
|
{
|
||||||
|
return c == '\\' || c == '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
void appendNode(const char* name, uint16 nameLen)
|
||||||
|
{
|
||||||
|
if (m_names.size() > 0xFFFF)
|
||||||
|
return;
|
||||||
|
m_nodes.emplace_back((uint16)m_names.size(), nameLen);
|
||||||
|
m_names.insert(m_names.end(), name, name + nameLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
FSCPath(std::string_view path)
|
||||||
|
{
|
||||||
|
if (path.empty())
|
||||||
|
return;
|
||||||
|
if (isSlash(path.front()))
|
||||||
|
{
|
||||||
|
m_isAbsolute = true;
|
||||||
|
path.remove_prefix(1);
|
||||||
|
// skip any additional leading slashes
|
||||||
|
while (!path.empty() && isSlash(path.front()))
|
||||||
|
path.remove_prefix(1);
|
||||||
|
}
|
||||||
|
// parse nodes
|
||||||
|
size_t n = 0;
|
||||||
|
size_t nodeNameStartIndex = 0;
|
||||||
|
while (n < path.size())
|
||||||
|
{
|
||||||
|
if (isSlash(path[n]))
|
||||||
|
{
|
||||||
|
size_t nodeNameLen = n - nodeNameStartIndex;
|
||||||
|
if (nodeNameLen > 0xFFFF)
|
||||||
|
nodeNameLen = 0xFFFF; // truncate suspiciously long node names
|
||||||
|
cemu_assert_debug(nodeNameLen > 0);
|
||||||
|
appendNode(path.data() + nodeNameStartIndex, (uint16)nodeNameLen);
|
||||||
|
// skip any repeating slashes
|
||||||
|
while (n < path.size() && isSlash(path[n]))
|
||||||
|
n++;
|
||||||
|
nodeNameStartIndex = n;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
if (nodeNameStartIndex < n)
|
||||||
|
{
|
||||||
|
size_t nodeNameLen = n - nodeNameStartIndex;
|
||||||
|
if (nodeNameLen > 0xFFFF)
|
||||||
|
nodeNameLen = 0xFFFF; // truncate suspiciously long node names
|
||||||
|
appendNode(path.data() + nodeNameStartIndex, (uint16)nodeNameLen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t GetNodeCount() const
|
||||||
|
{
|
||||||
|
return m_nodes.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string_view GetNodeName(size_t index) const
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= m_nodes.size())
|
||||||
|
return std::basic_string_view<char>();
|
||||||
|
return std::basic_string_view<char>(m_names.data() + m_nodes[index].offset, m_nodes[index].len);
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns true if the node names match according to FSA case-insensitivity rules
|
||||||
|
bool MatchNode(sint32 index, std::string_view name) const
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= (sint32)m_nodes.size())
|
||||||
|
return false;
|
||||||
|
auto nodeName = GetNodeName(index);
|
||||||
|
if (nodeName.size() != name.size())
|
||||||
|
return false;
|
||||||
|
for (size_t i = 0; i < nodeName.size(); i++)
|
||||||
|
{
|
||||||
|
char c1 = nodeName[i];
|
||||||
|
char c2 = name[i];
|
||||||
|
if (c1 >= 'A' && c1 <= 'Z')
|
||||||
|
c1 += ('a' - 'A');
|
||||||
|
if (c2 >= 'A' && c2 <= 'Z')
|
||||||
|
c2 += ('a' - 'A');
|
||||||
|
if (c1 != c2)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class parsedPathW // todo - replaces this with FSCPath (using ascii/utf8 strings instead of wchar)
|
||||||
{
|
{
|
||||||
static const int MAX_NODES = 32;
|
static const int MAX_NODES = 32;
|
||||||
|
|
||||||
|
@ -182,7 +290,6 @@ public:
|
||||||
sint32 numNodes;
|
sint32 numNodes;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template<typename F, bool isCaseSensitive>
|
template<typename F, bool isCaseSensitive>
|
||||||
class FileTree
|
class FileTree
|
||||||
{
|
{
|
||||||
|
@ -342,113 +449,6 @@ private:
|
||||||
node_t rootNode;
|
node_t rootNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
#include <boost/container/small_vector.hpp>
|
|
||||||
|
|
||||||
// path parser and utility class for Wii U paths
|
|
||||||
// optimized to be allocation-free for common path lengths
|
|
||||||
class FSCPath
|
|
||||||
{
|
|
||||||
struct PathNode
|
|
||||||
{
|
|
||||||
PathNode(uint16 offset, uint16 len) : offset(offset), len(len) {};
|
|
||||||
|
|
||||||
uint16 offset;
|
|
||||||
uint16 len;
|
|
||||||
};
|
|
||||||
|
|
||||||
boost::container::small_vector<PathNode, 8> m_nodes;
|
|
||||||
boost::container::small_vector<char, 64> m_names;
|
|
||||||
bool m_isAbsolute{};
|
|
||||||
|
|
||||||
inline bool isSlash(char c)
|
|
||||||
{
|
|
||||||
return c == '\\' || c == '/';
|
|
||||||
}
|
|
||||||
|
|
||||||
void appendNode(const char* name, uint16 nameLen)
|
|
||||||
{
|
|
||||||
if (m_names.size() > 0xFFFF)
|
|
||||||
return;
|
|
||||||
m_nodes.emplace_back((uint16)m_names.size(), nameLen);
|
|
||||||
m_names.insert(m_names.end(), name, name + nameLen);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
FSCPath(std::string_view path)
|
|
||||||
{
|
|
||||||
if (path.empty())
|
|
||||||
return;
|
|
||||||
if (isSlash(path.front()))
|
|
||||||
{
|
|
||||||
m_isAbsolute = true;
|
|
||||||
path.remove_prefix(1);
|
|
||||||
// skip any additional leading slashes
|
|
||||||
while(!path.empty() && isSlash(path.front()))
|
|
||||||
path.remove_prefix(1);
|
|
||||||
}
|
|
||||||
// parse nodes
|
|
||||||
size_t n = 0;
|
|
||||||
size_t nodeNameStartIndex = 0;
|
|
||||||
while (n < path.size())
|
|
||||||
{
|
|
||||||
if (isSlash(path[n]))
|
|
||||||
{
|
|
||||||
size_t nodeNameLen = n - nodeNameStartIndex;
|
|
||||||
if (nodeNameLen > 0xFFFF)
|
|
||||||
nodeNameLen = 0xFFFF; // truncate suspiciously long node names
|
|
||||||
cemu_assert_debug(nodeNameLen > 0);
|
|
||||||
appendNode(path.data() + nodeNameStartIndex, (uint16)nodeNameLen);
|
|
||||||
// skip any repeating slashes
|
|
||||||
while (n < path.size() && isSlash(path[n]))
|
|
||||||
n++;
|
|
||||||
nodeNameStartIndex = n;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
n++;
|
|
||||||
}
|
|
||||||
if (nodeNameStartIndex < n)
|
|
||||||
{
|
|
||||||
size_t nodeNameLen = n - nodeNameStartIndex;
|
|
||||||
if (nodeNameLen > 0xFFFF)
|
|
||||||
nodeNameLen = 0xFFFF; // truncate suspiciously long node names
|
|
||||||
appendNode(path.data() + nodeNameStartIndex, (uint16)nodeNameLen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t GetNodeCount() const
|
|
||||||
{
|
|
||||||
return m_nodes.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string_view GetNodeName(size_t index) const
|
|
||||||
{
|
|
||||||
if (index < 0 || index >= m_nodes.size())
|
|
||||||
return std::basic_string_view<char>();
|
|
||||||
return std::basic_string_view<char>(m_names.data() + m_nodes[index].offset, m_nodes[index].len);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MatchNode(sint32 index, std::string_view name) const
|
|
||||||
{
|
|
||||||
if (index < 0 || index >= (sint32)m_nodes.size())
|
|
||||||
return false;
|
|
||||||
auto nodeName = GetNodeName(index);
|
|
||||||
if (nodeName.size() != name.size())
|
|
||||||
return false;
|
|
||||||
for (size_t i = 0; i < nodeName.size(); i++)
|
|
||||||
{
|
|
||||||
char c1 = nodeName[i];
|
|
||||||
char c2 = name[i];
|
|
||||||
if (c1 >= 'A' && c1 <= 'Z')
|
|
||||||
c1 += ('a' - 'A');
|
|
||||||
if (c2 >= 'A' && c2 <= 'Z')
|
|
||||||
c2 += ('a' - 'A');
|
|
||||||
if (c1 != c2)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static void FSTPathUnitTest()
|
static void FSTPathUnitTest()
|
||||||
{
|
{
|
||||||
// test 1
|
// test 1
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "Cafe/Filesystem/fsc.h"
|
#include "Cafe/Filesystem/fsc.h"
|
||||||
|
#include "Cafe/Filesystem/FST/fstUtil.h"
|
||||||
|
|
||||||
struct FSCMountPathNode
|
struct FSCMountPathNode
|
||||||
{
|
{
|
||||||
|
@ -24,7 +25,7 @@ struct FSCMountPathNode
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// compare two file or directory names using FS rules
|
// compare two file or directory names using FSA rules
|
||||||
bool FSA_CompareNodeName(std::string_view a, std::string_view b)
|
bool FSA_CompareNodeName(std::string_view a, std::string_view b)
|
||||||
{
|
{
|
||||||
if (a.size() != b.size())
|
if (a.size() != b.size())
|
||||||
|
@ -74,25 +75,25 @@ void fsc_reset()
|
||||||
* /vol/content/data -> Map to HostFS
|
* /vol/content/data -> Map to HostFS
|
||||||
* If overlapping paths with different priority are created, then the higher priority one will be checked first
|
* If overlapping paths with different priority are created, then the higher priority one will be checked first
|
||||||
*/
|
*/
|
||||||
FSCMountPathNode* fsc_createMountPath(CoreinitFSParsedPath* parsedMountPath, sint32 priority)
|
FSCMountPathNode* fsc_createMountPath(const FSCPath& mountPath, sint32 priority)
|
||||||
{
|
{
|
||||||
cemu_assert(priority >= 0 && priority < FSC_PRIORITY_COUNT);
|
cemu_assert(priority >= 0 && priority < FSC_PRIORITY_COUNT);
|
||||||
fscEnter();
|
fscEnter();
|
||||||
FSCMountPathNode* nodeParent = s_fscRootNodePerPrio[priority];
|
FSCMountPathNode* nodeParent = s_fscRootNodePerPrio[priority];
|
||||||
for(sint32 i=0; i<parsedMountPath->numNodes; i++)
|
for (size_t i=0; i< mountPath.GetNodeCount(); i++)
|
||||||
{
|
{
|
||||||
// search for subdirectory
|
// search for subdirectory
|
||||||
FSCMountPathNode* nodeSub = nullptr; // set if we found a subnode with a matching name, else this is used to store the new nodes
|
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)
|
for (auto& nodeItr : nodeParent->subnodes)
|
||||||
{
|
{
|
||||||
if( coreinitFS_checkNodeName(parsedMountPath, i, nodeItr->path.c_str()) )
|
if (mountPath.MatchNode(i, nodeItr->path))
|
||||||
{
|
{
|
||||||
// subnode found
|
// subnode found
|
||||||
nodeSub = nodeItr;
|
nodeSub = nodeItr;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( nodeSub )
|
if (nodeSub)
|
||||||
{
|
{
|
||||||
// traverse subnode
|
// traverse subnode
|
||||||
nodeParent = nodeSub;
|
nodeParent = nodeSub;
|
||||||
|
@ -100,10 +101,10 @@ FSCMountPathNode* fsc_createMountPath(CoreinitFSParsedPath* parsedMountPath, sin
|
||||||
}
|
}
|
||||||
// no matching subnode, add new entry
|
// no matching subnode, add new entry
|
||||||
nodeSub = new FSCMountPathNode(nodeParent);
|
nodeSub = new FSCMountPathNode(nodeParent);
|
||||||
nodeSub->path = coreinitFS_getNodeName(parsedMountPath, i);
|
nodeSub->path = mountPath.GetNodeName(i);
|
||||||
nodeSub->priority = priority;
|
nodeSub->priority = priority;
|
||||||
nodeParent->subnodes.emplace_back(nodeSub);
|
nodeParent->subnodes.emplace_back(nodeSub);
|
||||||
if( i == (parsedMountPath->numNodes-1) )
|
if (i == (mountPath.GetNodeCount() - 1))
|
||||||
{
|
{
|
||||||
// last node
|
// last node
|
||||||
fscLeave();
|
fscLeave();
|
||||||
|
@ -114,7 +115,7 @@ FSCMountPathNode* fsc_createMountPath(CoreinitFSParsedPath* parsedMountPath, sin
|
||||||
}
|
}
|
||||||
// path is empty or already mounted
|
// path is empty or already mounted
|
||||||
fscLeave();
|
fscLeave();
|
||||||
if (parsedMountPath->numNodes == 0)
|
if (mountPath.GetNodeCount() == 0)
|
||||||
return nodeParent;
|
return nodeParent;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -129,12 +130,10 @@ sint32 fsc_mount(std::string_view mountPath, std::string_view targetPath, fscDev
|
||||||
if (!targetPathWithSlash.empty() && (targetPathWithSlash.back() != '/' && targetPathWithSlash.back() != '\\'))
|
if (!targetPathWithSlash.empty() && (targetPathWithSlash.back() != '/' && targetPathWithSlash.back() != '\\'))
|
||||||
targetPathWithSlash.push_back('/');
|
targetPathWithSlash.push_back('/');
|
||||||
|
|
||||||
// parse mount path
|
FSCPath parsedMountPath(mountPathTmp);
|
||||||
CoreinitFSParsedPath parsedMountPath;
|
|
||||||
coreinitFS_parsePath(&parsedMountPath, mountPathTmp.c_str());
|
|
||||||
// register path
|
// register path
|
||||||
fscEnter();
|
fscEnter();
|
||||||
FSCMountPathNode* node = fsc_createMountPath(&parsedMountPath, priority);
|
FSCMountPathNode* node = fsc_createMountPath(parsedMountPath, priority);
|
||||||
if( !node )
|
if( !node )
|
||||||
{
|
{
|
||||||
// path empty, invalid or already used
|
// path empty, invalid or already used
|
||||||
|
@ -152,9 +151,6 @@ sint32 fsc_mount(std::string_view mountPath, std::string_view targetPath, fscDev
|
||||||
bool fsc_unmount(std::string_view mountPath, sint32 priority)
|
bool fsc_unmount(std::string_view mountPath, sint32 priority)
|
||||||
{
|
{
|
||||||
std::string _tmp(mountPath);
|
std::string _tmp(mountPath);
|
||||||
CoreinitFSParsedPath parsedMountPath;
|
|
||||||
coreinitFS_parsePath(&parsedMountPath, _tmp.c_str());
|
|
||||||
|
|
||||||
fscEnter();
|
fscEnter();
|
||||||
FSCMountPathNode* mountPathNode = fsc_lookupPathVirtualNode(_tmp.c_str(), priority);
|
FSCMountPathNode* mountPathNode = fsc_lookupPathVirtualNode(_tmp.c_str(), priority);
|
||||||
if (!mountPathNode)
|
if (!mountPathNode)
|
||||||
|
@ -189,19 +185,17 @@ void fsc_unmountAll()
|
||||||
// lookup virtual path and find mounted device and relative device directory
|
// lookup virtual path and find mounted device and relative device directory
|
||||||
bool fsc_lookupPath(const char* path, std::wstring& devicePathOut, fscDeviceC** fscDeviceOut, void** ctxOut, sint32 priority = FSC_PRIORITY_BASE)
|
bool fsc_lookupPath(const char* path, std::wstring& devicePathOut, fscDeviceC** fscDeviceOut, void** ctxOut, sint32 priority = FSC_PRIORITY_BASE)
|
||||||
{
|
{
|
||||||
// parse path
|
FSCPath parsedPath(path);
|
||||||
CoreinitFSParsedPath parsedPath;
|
|
||||||
coreinitFS_parsePath(&parsedPath, path);
|
|
||||||
FSCMountPathNode* nodeParent = s_fscRootNodePerPrio[priority];
|
FSCMountPathNode* nodeParent = s_fscRootNodePerPrio[priority];
|
||||||
sint32 i;
|
size_t i;
|
||||||
fscEnter();
|
fscEnter();
|
||||||
for (i = 0; i < parsedPath.numNodes; i++)
|
for (i = 0; i < parsedPath.GetNodeCount(); i++)
|
||||||
{
|
{
|
||||||
// search for subdirectory
|
// search for subdirectory
|
||||||
FSCMountPathNode* nodeSub = nullptr;
|
FSCMountPathNode* nodeSub = nullptr;
|
||||||
for(auto& nodeItr : nodeParent->subnodes)
|
for(auto& nodeItr : nodeParent->subnodes)
|
||||||
{
|
{
|
||||||
if (coreinitFS_checkNodeName(&parsedPath, i, nodeItr->path.c_str()))
|
if (parsedPath.MatchNode(i, nodeItr->path))
|
||||||
{
|
{
|
||||||
nodeSub = nodeItr;
|
nodeSub = nodeItr;
|
||||||
break;
|
break;
|
||||||
|
@ -215,17 +209,17 @@ bool fsc_lookupPath(const char* path, std::wstring& devicePathOut, fscDeviceC**
|
||||||
// no matching subnode
|
// no matching subnode
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// find deepest device mount point
|
// if the found node is not a device mount point, then travel back towards the root until we find one
|
||||||
while (nodeParent)
|
while (nodeParent)
|
||||||
{
|
{
|
||||||
if (nodeParent->device)
|
if (nodeParent->device)
|
||||||
{
|
{
|
||||||
devicePathOut = boost::nowide::widen(nodeParent->deviceTargetPath);
|
devicePathOut = boost::nowide::widen(nodeParent->deviceTargetPath);
|
||||||
for (sint32 f = i; f < parsedPath.numNodes; f++)
|
for (size_t f = i; f < parsedPath.GetNodeCount(); f++)
|
||||||
{
|
{
|
||||||
const char* nodeName = coreinitFS_getNodeName(&parsedPath, f);
|
auto nodeName = parsedPath.GetNodeName(f);
|
||||||
devicePathOut.append(boost::nowide::widen(nodeName));
|
devicePathOut.append(boost::nowide::widen(nodeName));
|
||||||
if (f < (parsedPath.numNodes - 1))
|
if (f < (parsedPath.GetNodeCount() - 1))
|
||||||
devicePathOut.push_back('/');
|
devicePathOut.push_back('/');
|
||||||
}
|
}
|
||||||
*fscDeviceOut = nodeParent->device;
|
*fscDeviceOut = nodeParent->device;
|
||||||
|
@ -243,19 +237,16 @@ bool fsc_lookupPath(const char* path, std::wstring& devicePathOut, fscDeviceC**
|
||||||
// lookup path and find virtual device node
|
// lookup path and find virtual device node
|
||||||
FSCMountPathNode* fsc_lookupPathVirtualNode(const char* path, sint32 priority)
|
FSCMountPathNode* fsc_lookupPathVirtualNode(const char* path, sint32 priority)
|
||||||
{
|
{
|
||||||
// parse path
|
FSCPath parsedPath(path);
|
||||||
CoreinitFSParsedPath parsedPath;
|
|
||||||
coreinitFS_parsePath(&parsedPath, path);
|
|
||||||
FSCMountPathNode* nodeCurrentDir = s_fscRootNodePerPrio[priority];
|
FSCMountPathNode* nodeCurrentDir = s_fscRootNodePerPrio[priority];
|
||||||
sint32 i;
|
|
||||||
fscEnter();
|
fscEnter();
|
||||||
for (i = 0; i < parsedPath.numNodes; i++)
|
for (size_t i = 0; i < parsedPath.GetNodeCount(); i++)
|
||||||
{
|
{
|
||||||
// search for subdirectory
|
// search for subdirectory
|
||||||
FSCMountPathNode* nodeSub = nullptr;
|
FSCMountPathNode* nodeSub = nullptr;
|
||||||
for (auto& nodeItr : nodeCurrentDir->subnodes)
|
for (auto& nodeItr : nodeCurrentDir->subnodes)
|
||||||
{
|
{
|
||||||
if (coreinitFS_checkNodeName(&parsedPath, i, nodeItr->path.c_str()))
|
if (parsedPath.MatchNode(i, nodeItr->path))
|
||||||
{
|
{
|
||||||
nodeSub = nodeItr;
|
nodeSub = nodeItr;
|
||||||
break;
|
break;
|
||||||
|
@ -693,7 +684,7 @@ bool fsc_doesFileExist(const char* path, sint32 maxPriority)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper function to check if a folder exists
|
// helper function to check if a directory exists
|
||||||
bool fsc_doesDirectoryExist(const char* path, sint32 maxPriority)
|
bool fsc_doesDirectoryExist(const char* path, sint32 maxPriority)
|
||||||
{
|
{
|
||||||
fscDeviceC* fscDevice = nullptr;
|
fscDeviceC* fscDevice = nullptr;
|
||||||
|
@ -710,93 +701,7 @@ bool fsc_doesDirectoryExist(const char* path, sint32 maxPriority)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// initialize Cemu's virtual filesystem
|
||||||
void coreinitFS_parsePath(CoreinitFSParsedPath* parsedPath, const char* path)
|
|
||||||
{
|
|
||||||
// if the path starts with a '/', skip it
|
|
||||||
if (*path == '/')
|
|
||||||
path++;
|
|
||||||
// init parsedPath struct
|
|
||||||
memset(parsedPath, 0x00, sizeof(CoreinitFSParsedPath));
|
|
||||||
// init parsed path data
|
|
||||||
size_t pathLength = std::min((size_t)640, strlen(path));
|
|
||||||
memcpy(parsedPath->pathData, path, pathLength);
|
|
||||||
// start parsing
|
|
||||||
sint32 offset = 0;
|
|
||||||
sint32 startOffset = 0;
|
|
||||||
if (offset < pathLength)
|
|
||||||
{
|
|
||||||
parsedPath->nodeOffset[parsedPath->numNodes] = offset;
|
|
||||||
parsedPath->numNodes++;
|
|
||||||
}
|
|
||||||
while (offset < pathLength)
|
|
||||||
{
|
|
||||||
if (parsedPath->pathData[offset] == '/' || parsedPath->pathData[offset] == '\\')
|
|
||||||
{
|
|
||||||
parsedPath->pathData[offset] = '\0';
|
|
||||||
offset++;
|
|
||||||
// double slashes are ignored and instead are handled like a single slash
|
|
||||||
if (parsedPath->pathData[offset] == '/' || parsedPath->pathData[offset] == '\\')
|
|
||||||
{
|
|
||||||
// if we're in the beginning and having a \\ it's a network path
|
|
||||||
if (offset != 1)
|
|
||||||
{
|
|
||||||
parsedPath->pathData[offset] = '\0';
|
|
||||||
offset++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// start new node
|
|
||||||
if (parsedPath->numNodes < FSC_PARSED_PATH_NODES_MAX)
|
|
||||||
{
|
|
||||||
if (offset < pathLength)
|
|
||||||
{
|
|
||||||
parsedPath->nodeOffset[parsedPath->numNodes] = offset;
|
|
||||||
parsedPath->numNodes++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
offset++;
|
|
||||||
}
|
|
||||||
// handle special nodes like '.' or '..'
|
|
||||||
sint32 nodeIndex = 0;
|
|
||||||
while (nodeIndex < parsedPath->numNodes)
|
|
||||||
{
|
|
||||||
if (coreinitFS_checkNodeName(parsedPath, nodeIndex, ".."))
|
|
||||||
cemu_assert_suspicious(); // how does Cafe OS handle .. ?
|
|
||||||
else if (coreinitFS_checkNodeName(parsedPath, nodeIndex, "."))
|
|
||||||
{
|
|
||||||
// remove this node and shift back all following nodes by 1
|
|
||||||
parsedPath->numNodes--;
|
|
||||||
for (sint32 i = nodeIndex; i < parsedPath->numNodes; i++)
|
|
||||||
{
|
|
||||||
parsedPath->nodeOffset[i] = parsedPath->nodeOffset[i + 1];
|
|
||||||
}
|
|
||||||
// continue without increasing nodeIndex
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
nodeIndex++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool coreinitFS_checkNodeName(CoreinitFSParsedPath* parsedPath, sint32 index, const char* name)
|
|
||||||
{
|
|
||||||
if (index < 0 || index >= parsedPath->numNodes)
|
|
||||||
return false;
|
|
||||||
char* nodeName = parsedPath->pathData + parsedPath->nodeOffset[index];
|
|
||||||
if (boost::iequals(nodeName, name))
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* coreinitFS_getNodeName(CoreinitFSParsedPath* parsedPath, sint32 index)
|
|
||||||
{
|
|
||||||
if (index < 0 || index >= parsedPath->numNodes)
|
|
||||||
return nullptr;
|
|
||||||
return parsedPath->pathData + parsedPath->nodeOffset[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize Cemu's virtual filesystem
|
|
||||||
void fsc_init()
|
void fsc_init()
|
||||||
{
|
{
|
||||||
fsc_reset();
|
fsc_reset();
|
||||||
|
|
|
@ -200,20 +200,3 @@ bool FSCDeviceHostFS_Mount(std::string_view mountPath, std::string_view hostTarg
|
||||||
// redirect device
|
// redirect device
|
||||||
void fscDeviceRedirect_map();
|
void fscDeviceRedirect_map();
|
||||||
void fscDeviceRedirect_add(std::string_view virtualSourcePath, const fs::path& targetFilePath, sint32 priority);
|
void fscDeviceRedirect_add(std::string_view virtualSourcePath, const fs::path& targetFilePath, sint32 priority);
|
||||||
|
|
||||||
|
|
||||||
// Old path parser helper functions
|
|
||||||
// Replace with FSCPath
|
|
||||||
|
|
||||||
#define FSC_PARSED_PATH_NODES_MAX (32)
|
|
||||||
|
|
||||||
struct CoreinitFSParsedPath
|
|
||||||
{
|
|
||||||
char pathData[640 + 1];
|
|
||||||
uint16 nodeOffset[FSC_PARSED_PATH_NODES_MAX];
|
|
||||||
sint32 numNodes;
|
|
||||||
};
|
|
||||||
|
|
||||||
void coreinitFS_parsePath(CoreinitFSParsedPath* parsedPath, const char* path);
|
|
||||||
bool coreinitFS_checkNodeName(CoreinitFSParsedPath* parsedPath, sint32 index, const char* name);
|
|
||||||
char* coreinitFS_getNodeName(CoreinitFSParsedPath* parsedPath, sint32 index);
|
|
||||||
|
|
Loading…
Reference in New Issue