rpcs3/rpcs3/Emu/VFS.cpp
Nekotekina 5b19908996 Escape problematic characters in VFS
With full-width <>:"\|?*
2017-10-11 22:01:37 +03:00

288 lines
4.4 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "stdafx.h"
#include "IdManager.h"
#include "VFS.h"
#include <regex>
struct vfs_manager
{
shared_mutex mutex;
// Device name -> Real path
std::unordered_map<std::string, std::string> mounted;
};
const std::regex s_regex_ps3("^/+(.*?)(?:$|/)(.*)", std::regex::optimize);
const std::regex s_regex_psv("^(.*?):(.*)", std::regex::optimize);
bool vfs::mount(const std::string& dev_name, const std::string& path)
{
const auto table = fxm::get_always<vfs_manager>();
writer_lock lock(table->mutex);
return table->mounted.emplace(dev_name, path).second;
}
std::string vfs::get(const std::string& vpath, vfs::type _type)
{
const auto table = fxm::get_always<vfs_manager>();
reader_lock lock(table->mutex);
std::smatch match;
if (!std::regex_match(vpath, match, _type == type::ps3 ? s_regex_ps3 : s_regex_psv))
{
const auto found = table->mounted.find("");
if (found == table->mounted.end())
{
LOG_WARNING(GENERAL, "vfs::get(): no default directory: %s", vpath);
return {};
}
return found->second + vfs::escape(vpath);
}
if (_type == type::ps3 && match.length(1) == 0)
{
return "/";
}
const auto found = table->mounted.find(match.str(1));
if (found == table->mounted.end())
{
LOG_WARNING(GENERAL, "vfs::get(): device not found: %s", vpath);
return {};
}
if (found->second.empty())
{
// Don't escape /host_root (TODO)
return match.str(2);
}
// Escape and concatenate
return found->second + vfs::escape(match.str(2));
}
std::string vfs::escape(const std::string& path)
{
std::string result;
result.reserve(path.size());
for (std::size_t i = 0, s = path.size(); i < s; i++)
{
switch (char c = path[i])
{
case '<':
{
result += u8"";
break;
}
case '>':
{
result += u8"";
break;
}
case ':':
{
result += u8"";
break;
}
case '"':
{
result += u8"";
break;
}
case '\\':
{
result += u8"";
break;
}
case '|':
{
result += u8"";
break;
}
case '?':
{
result += u8"";
break;
}
case '*':
{
result += u8"";
break;
}
case char{u8""[0]}:
{
// Escape full-width characters 0xFF01..0xFF5e with (0xFF01)
switch (path[i + 1])
{
case char{u8""[1]}:
{
const uchar c3 = reinterpret_cast<const uchar&>(path[i + 2]);
if (c3 >= 0x81 && c3 <= 0xbf)
{
result += u8"";
}
break;
}
case char{u8""[1]}:
{
const uchar c3 = reinterpret_cast<const uchar&>(path[i + 2]);
if (c3 >= 0x80 && c3 <= 0x9e)
{
result += u8"";
}
break;
}
}
result += c;
break;
}
default:
{
result += c;
break;
}
}
}
return result;
}
std::string vfs::unescape(const std::string& path)
{
std::string result;
result.reserve(path.size());
for (std::size_t i = 0, s = path.size(); i < s; i++)
{
switch (char c = path[i])
{
case char{u8""[0]}:
{
switch (path[i + 1])
{
case char{u8""[1]}:
{
const uchar c3 = reinterpret_cast<const uchar&>(path[i + 2]);
if (c3 >= 0x81 && c3 <= 0xbf)
{
switch (path[i + 2])
{
case char{u8""[2]}:
{
i += 3;
result += c;
continue;
}
case char{u8""[2]}:
{
result += '<';
break;
}
case char{u8""[2]}:
{
result += '>';
break;
}
case char{u8""[2]}:
{
result += ':';
break;
}
case char{u8""[2]}:
{
result += '"';
break;
}
case char{u8""[2]}:
{
result += '\\';
break;
}
case char{u8""[2]}:
{
result += '?';
break;
}
case char{u8""[2]}:
{
result += '*';
break;
}
default:
{
// Unrecognized character (ignored)
break;
}
}
i += 2;
}
else
{
result += c;
}
break;
}
case char{u8""[1]}:
{
const uchar c3 = reinterpret_cast<const uchar&>(path[i + 2]);
if (c3 >= 0x80 && c3 <= 0x9e)
{
switch (path[i + 2])
{
case char{u8""[2]}:
{
result += '|';
break;
}
default:
{
// Unrecognized character (ignored)
break;
}
}
i += 2;
}
else
{
result += c;
}
break;
}
default:
{
result += c;
break;
}
}
break;
}
default:
{
result += c;
break;
}
}
}
return result;
}