Support for wildcard queries
Provides support for persistent wildcard file requests, as described in #96 Also moved CanonicalizePath into common code (poly::fs)
This commit is contained in:
parent
3d980dd294
commit
4f7761c5e2
|
@ -0,0 +1,194 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "poly/fs.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
namespace poly {
|
||||
namespace fs {
|
||||
|
||||
std::string CanonicalizePath(const std::string& original_path) {
|
||||
char path_separator('\\');
|
||||
std::string path(poly::fix_path_separators(original_path, path_separator));
|
||||
|
||||
std::vector<std::string::size_type> path_breaks;
|
||||
|
||||
std::string::size_type pos(path.find_first_of(path_separator));
|
||||
std::string::size_type pos_n(std::string::npos);
|
||||
|
||||
while (pos != std::string::npos) {
|
||||
if ((pos_n = path.find_first_of(path_separator, pos + 1)) == std::string::npos) {
|
||||
pos_n = path.size();
|
||||
}
|
||||
|
||||
auto diff(pos_n - pos);
|
||||
switch (diff)
|
||||
{
|
||||
case 0:
|
||||
pos_n = std::string::npos;
|
||||
break;
|
||||
case 1:
|
||||
// Duplicate separators
|
||||
path.erase(pos, 1);
|
||||
pos_n -= 1;
|
||||
break;
|
||||
case 2:
|
||||
// Potential marker for current directory
|
||||
if (path[pos + 1] == '.') {
|
||||
path.erase(pos, 2);
|
||||
pos_n -= 2;
|
||||
}
|
||||
else {
|
||||
path_breaks.push_back(pos);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
// Potential marker for parent directory
|
||||
if (path[pos + 1] == '.' && path[pos + 2] == '.'){
|
||||
if (path_breaks.empty()) {
|
||||
// Ensure we don't override the device name
|
||||
std::string::size_type loc(path.find_first_of(':'));
|
||||
auto req(pos + 3);
|
||||
if (loc == std::string::npos || loc > req) {
|
||||
path.erase(0, req);
|
||||
pos_n -= req;
|
||||
}
|
||||
else {
|
||||
path.erase(loc + 1, req - (loc + 1));
|
||||
pos_n -= req - (loc + 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
auto last(path_breaks.back());
|
||||
auto last_diff((pos + 3) - last);
|
||||
path.erase(last, last_diff);
|
||||
pos_n = last;
|
||||
// Also remove path reference
|
||||
path_breaks.erase(path_breaks.end() - 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
path_breaks.push_back(pos);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
path_breaks.push_back(pos);
|
||||
break;
|
||||
}
|
||||
|
||||
pos = pos_n;
|
||||
}
|
||||
|
||||
// Remove trailing seperator
|
||||
if (!path.empty() && path.back() == path_separator) {
|
||||
path.erase(path.size() - 1);
|
||||
}
|
||||
|
||||
// Final sanity check for dead paths
|
||||
if ((path.size() == 1 && (path[0] == '.' || path[0] == path_separator))
|
||||
|| (path.size() == 2 && path[0] == '.' && path[1] == '.')) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
WildcardFlags WildcardFlags::FIRST(true, false);
|
||||
WildcardFlags WildcardFlags::LAST(false, true);
|
||||
|
||||
WildcardFlags::WildcardFlags()
|
||||
: FromStart(false)
|
||||
, ToEnd(false)
|
||||
, WithCase(false)
|
||||
{ }
|
||||
|
||||
WildcardFlags::WildcardFlags(bool start, bool end)
|
||||
: FromStart(start)
|
||||
, ToEnd(end)
|
||||
, WithCase(false)
|
||||
{ }
|
||||
|
||||
WildcardRule::WildcardRule(std::string str_match, const WildcardFlags &flags)
|
||||
: match(str_match)
|
||||
, rules(flags)
|
||||
{ }
|
||||
|
||||
bool WildcardRule::Check(std::string& str) const
|
||||
{
|
||||
if( match.empty() ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if( str.size() < match.size() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string::size_type result(str.find(match));
|
||||
|
||||
if( result != std::string::npos ) {
|
||||
if( rules.FromStart && result != 0 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if( rules.ToEnd && result != ( ( str.size() -1 ) - match.size() ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
str.erase(0, result + match.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void WildcardEngine::PreparePattern(const std::string &pattern)
|
||||
{
|
||||
rules.clear();
|
||||
|
||||
WildcardFlags flags(WildcardFlags::FIRST);
|
||||
size_t n = 0;
|
||||
size_t last = 0;
|
||||
while ((n = pattern.find_first_of('*', last)) != pattern.npos) {
|
||||
if (last != n) {
|
||||
std::string str_str(pattern.substr(last, n - last));
|
||||
rules.push_back(WildcardRule(str_str, flags));
|
||||
}
|
||||
last = n + 1;
|
||||
flags = WildcardFlags();
|
||||
}
|
||||
if (last != pattern.size()) {
|
||||
std::string str_str(pattern.substr(last));
|
||||
rules.push_back(WildcardRule(str_str, WildcardFlags::LAST));
|
||||
}
|
||||
}
|
||||
|
||||
void WildcardEngine::SetRule(const std::string &pattern)
|
||||
{
|
||||
PreparePattern(pattern);
|
||||
}
|
||||
|
||||
bool WildcardEngine::Match(const std::string &str) const
|
||||
{
|
||||
std::string str_copy(str);
|
||||
|
||||
for (const auto& rule : rules) {
|
||||
if (!(rule.Check(str_copy))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace fs
|
||||
} // namespace poly
|
|
@ -15,6 +15,9 @@
|
|||
#include "poly/config.h"
|
||||
#include "poly/string.h"
|
||||
|
||||
#include <vector>
|
||||
#include <iterator>
|
||||
|
||||
namespace poly {
|
||||
namespace fs {
|
||||
|
||||
|
@ -35,6 +38,44 @@ struct FileInfo {
|
|||
};
|
||||
std::vector<FileInfo> ListFiles(const std::wstring& path);
|
||||
|
||||
std::string CanonicalizePath(const std::string& original_path);
|
||||
|
||||
class WildcardFlags
|
||||
{
|
||||
public:
|
||||
bool
|
||||
FromStart: 1,
|
||||
ToEnd : 1,
|
||||
WithCase : 1; // Unused for now
|
||||
|
||||
WildcardFlags();
|
||||
WildcardFlags(bool start, bool end);
|
||||
|
||||
static WildcardFlags FIRST;
|
||||
static WildcardFlags LAST;
|
||||
};
|
||||
|
||||
class WildcardRule
|
||||
{
|
||||
public:
|
||||
WildcardRule(std::string str_match, const WildcardFlags &flags);
|
||||
bool Check(std::string& str) const;
|
||||
|
||||
private:
|
||||
std::string match;
|
||||
WildcardFlags rules;
|
||||
};
|
||||
|
||||
class WildcardEngine
|
||||
{
|
||||
public:
|
||||
void SetRule(const std::string &pattern);
|
||||
bool Match(const std::string &str) const;
|
||||
private:
|
||||
std::vector<WildcardRule> rules;
|
||||
void PreparePattern(const std::string &pattern);
|
||||
};
|
||||
|
||||
} // namespace fs
|
||||
} // namespace poly
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
'config.h',
|
||||
'cxx_compat.h',
|
||||
'fs.h',
|
||||
'fs.cc',
|
||||
'logging.cc',
|
||||
'logging.h',
|
||||
'main.h',
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
|
||||
#include <algorithm>
|
||||
|
||||
#include "xenia/kernel/fs/gdfx.h"
|
||||
#include "xenia/kernel/fs/devices/disc_image_file.h"
|
||||
|
||||
namespace xe {
|
||||
|
@ -31,7 +30,7 @@ DiscImageEntry::DiscImageEntry(Device* device, const char* path,
|
|||
: Entry(device, path),
|
||||
mmap_(mmap),
|
||||
gdfx_entry_(gdfx_entry),
|
||||
gdfx_entry_iterator_(gdfx_entry->children.end()) {}
|
||||
it_(gdfx_entry->children.end()) {}
|
||||
|
||||
DiscImageEntry::~DiscImageEntry() {}
|
||||
|
||||
|
@ -51,39 +50,34 @@ X_STATUS DiscImageEntry::QueryDirectory(XDirectoryInfo* out_info, size_t length,
|
|||
const char* file_name, bool restart) {
|
||||
assert_not_null(out_info);
|
||||
|
||||
// TODO(benvanik): move to common code.
|
||||
assert_null(file_name);
|
||||
GDFXEntry* entry = nullptr;
|
||||
if (file_name) {
|
||||
// Specified filename, return just that info.
|
||||
assert_true(std::strchr(file_name, '*') == nullptr);
|
||||
entry = gdfx_entry_->GetChild(file_name);
|
||||
GDFXEntry* entry(nullptr);
|
||||
|
||||
if (file_name != nullptr) {
|
||||
// Only queries in the current directory are supported for now
|
||||
assert_true(std::strchr(file_name, '\\') == nullptr);
|
||||
|
||||
find_engine_.SetRule(file_name);
|
||||
|
||||
// Always restart the search?
|
||||
it_ = gdfx_entry_->children.begin();
|
||||
entry = gdfx_entry_->GetChild(find_engine_, it_);
|
||||
if (!entry) {
|
||||
return X_STATUS_NO_SUCH_FILE;
|
||||
}
|
||||
} else {
|
||||
if (restart == true &&
|
||||
gdfx_entry_iterator_ != gdfx_entry_->children.end()) {
|
||||
gdfx_entry_iterator_ = gdfx_entry_->children.end();
|
||||
}
|
||||
else {
|
||||
if (restart) {
|
||||
it_ = gdfx_entry_->children.begin();
|
||||
}
|
||||
|
||||
if (gdfx_entry_iterator_ == gdfx_entry_->children.end()) {
|
||||
gdfx_entry_iterator_ = gdfx_entry_->children.begin();
|
||||
if (gdfx_entry_iterator_ == gdfx_entry_->children.end()) {
|
||||
return X_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
} else {
|
||||
++gdfx_entry_iterator_;
|
||||
if (gdfx_entry_iterator_ == gdfx_entry_->children.end()) {
|
||||
return X_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
entry = gdfx_entry_->GetChild(find_engine_, it_);
|
||||
if (!entry) {
|
||||
return X_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
auto end = (uint8_t*)out_info + length;
|
||||
entry = *gdfx_entry_iterator_;
|
||||
auto entry_name = entry->name;
|
||||
if (((uint8_t*)&out_info->file_name[0]) + entry_name.size() > end) {
|
||||
gdfx_entry_iterator_ = gdfx_entry_->children.end();
|
||||
return X_STATUS_NO_MORE_FILES;
|
||||
}
|
||||
}
|
||||
|
@ -96,7 +90,7 @@ X_STATUS DiscImageEntry::QueryDirectory(XDirectoryInfo* out_info, size_t length,
|
|||
out_info->change_time = 0;
|
||||
out_info->end_of_file = entry->size;
|
||||
out_info->allocation_size = 2048;
|
||||
out_info->attributes = (X_FILE_ATTRIBUTES)entry->attributes;
|
||||
out_info->attributes = entry->attributes;
|
||||
out_info->file_name_length = static_cast<uint32_t>(entry->name.size());
|
||||
memcpy(out_info->file_name, entry->name.c_str(), entry->name.size());
|
||||
|
||||
|
|
|
@ -15,13 +15,13 @@
|
|||
#include "poly/mapped_memory.h"
|
||||
#include "xenia/common.h"
|
||||
#include "xenia/kernel/fs/entry.h"
|
||||
#include "poly/fs.h"
|
||||
#include "xenia/kernel/fs/gdfx.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace fs {
|
||||
|
||||
class GDFXEntry;
|
||||
|
||||
class DiscImageEntry : public Entry {
|
||||
public:
|
||||
DiscImageEntry(Device* device, const char* path, poly::MappedMemory* mmap,
|
||||
|
@ -45,7 +45,9 @@ class DiscImageEntry : public Entry {
|
|||
private:
|
||||
poly::MappedMemory* mmap_;
|
||||
GDFXEntry* gdfx_entry_;
|
||||
std::vector<GDFXEntry*>::iterator gdfx_entry_iterator_;
|
||||
|
||||
poly::fs::WildcardEngine find_engine_;
|
||||
GDFXEntry::child_it_t it_;
|
||||
};
|
||||
|
||||
} // namespace fs
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
#include "xenia/kernel/fs/devices/stfs_container_entry.h"
|
||||
|
||||
#include "xenia/kernel/fs/stfs.h"
|
||||
#include "xenia/kernel/fs/devices/stfs_container_file.h"
|
||||
|
||||
namespace xe {
|
||||
|
@ -22,7 +21,8 @@ STFSContainerEntry::STFSContainerEntry(Device* device, const char* path,
|
|||
: Entry(device, path),
|
||||
mmap_(mmap),
|
||||
stfs_entry_(stfs_entry),
|
||||
stfs_entry_iterator_(stfs_entry->children.end()) {}
|
||||
it_(stfs_entry_->children.end())
|
||||
{ }
|
||||
|
||||
STFSContainerEntry::~STFSContainerEntry() = default;
|
||||
|
||||
|
@ -44,37 +44,33 @@ X_STATUS STFSContainerEntry::QueryDirectory(XDirectoryInfo* out_info,
|
|||
bool restart) {
|
||||
assert_not_null(out_info);
|
||||
|
||||
// TODO(benvanik): move to common code.
|
||||
STFSEntry* entry = nullptr;
|
||||
if (file_name) {
|
||||
// Specified filename, return just that info.
|
||||
assert_true(std::strchr(file_name, '*') == nullptr);
|
||||
entry = stfs_entry_->GetChild(file_name);
|
||||
STFSEntry* entry(nullptr);
|
||||
|
||||
if( file_name != nullptr ) {
|
||||
// Only queries in the current directory are supported for now
|
||||
assert_true(std::strchr(file_name, '\\') == nullptr);
|
||||
|
||||
find_engine_.SetRule(file_name);
|
||||
|
||||
// Always restart the search?
|
||||
it_ = stfs_entry_->children.begin();
|
||||
entry = stfs_entry_->GetChild(find_engine_, it_);
|
||||
if (!entry) {
|
||||
return X_STATUS_NO_SUCH_FILE;
|
||||
}
|
||||
} else {
|
||||
if (restart && stfs_entry_iterator_ != stfs_entry_->children.end()) {
|
||||
stfs_entry_iterator_ = stfs_entry_->children.end();
|
||||
if (restart) {
|
||||
it_ = stfs_entry_->children.begin();
|
||||
}
|
||||
|
||||
if (stfs_entry_iterator_ == stfs_entry_->children.end()) {
|
||||
stfs_entry_iterator_ = stfs_entry_->children.begin();
|
||||
if (stfs_entry_iterator_ == stfs_entry_->children.end()) {
|
||||
return X_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
} else {
|
||||
++stfs_entry_iterator_;
|
||||
if (stfs_entry_iterator_ == stfs_entry_->children.end()) {
|
||||
return X_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
entry = stfs_entry_->GetChild(find_engine_, it_);
|
||||
if (!entry) {
|
||||
return X_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
auto end = (uint8_t*)out_info + length;
|
||||
entry = stfs_entry_iterator_->get();
|
||||
auto entry_name = entry->name;
|
||||
if (((uint8_t*)&out_info->file_name[0]) + entry_name.size() > end) {
|
||||
stfs_entry_iterator_ = stfs_entry_->children.end();
|
||||
return X_STATUS_NO_MORE_FILES;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,17 +11,18 @@
|
|||
#define XENIA_KERNEL_FS_DEVICES_STFS_CONTAINER_ENTRY_H_
|
||||
|
||||
#include <vector>
|
||||
#include <iterator>
|
||||
|
||||
#include "poly/mapped_memory.h"
|
||||
#include "xenia/common.h"
|
||||
#include "xenia/kernel/fs/entry.h"
|
||||
#include "poly/fs.h"
|
||||
#include "xenia/kernel/fs/stfs.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace fs {
|
||||
|
||||
class STFSEntry;
|
||||
|
||||
class STFSContainerEntry : public Entry {
|
||||
public:
|
||||
STFSContainerEntry(Device* device, const char* path, poly::MappedMemory* mmap,
|
||||
|
@ -41,7 +42,9 @@ class STFSContainerEntry : public Entry {
|
|||
private:
|
||||
poly::MappedMemory* mmap_;
|
||||
STFSEntry* stfs_entry_;
|
||||
std::vector<std::unique_ptr<STFSEntry>>::iterator stfs_entry_iterator_;
|
||||
|
||||
poly::fs::WildcardEngine find_engine_;
|
||||
STFSEntry::child_it_t it_;
|
||||
};
|
||||
|
||||
} // namespace fs
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "xenia/kernel/fs/devices/disc_image_device.h"
|
||||
#include "xenia/kernel/fs/devices/host_path_device.h"
|
||||
#include "xenia/kernel/fs/devices/stfs_container_device.h"
|
||||
#include "poly/fs.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
|
@ -147,92 +148,9 @@ int FileSystem::DeleteSymbolicLink(const std::string& path) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
std::string FileSystem::CanonicalizePath(const std::string& original_path) const {
|
||||
char path_separator('\\');
|
||||
std::string path(poly::fix_path_separators(original_path, path_separator));
|
||||
|
||||
std::vector<std::string::size_type> path_breaks;
|
||||
|
||||
std::string::size_type pos(path.find_first_of(path_separator));
|
||||
std::string::size_type pos_n(std::string::npos);
|
||||
|
||||
while (pos != std::string::npos) {
|
||||
if ((pos_n = path.find_first_of(path_separator, pos + 1)) == std::string::npos) {
|
||||
pos_n = path.size();
|
||||
}
|
||||
|
||||
auto diff(pos_n - pos);
|
||||
switch (diff)
|
||||
{
|
||||
case 0:
|
||||
pos_n = std::string::npos;
|
||||
break;
|
||||
case 1:
|
||||
// Duplicate separators
|
||||
path.erase(pos, 1);
|
||||
pos_n -= 1;
|
||||
break;
|
||||
case 2:
|
||||
// Potential marker for current directory
|
||||
if (path[pos + 1] == '.') {
|
||||
path.erase(pos, 2);
|
||||
pos_n -= 2;
|
||||
} else {
|
||||
path_breaks.push_back(pos);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
// Potential marker for parent directory
|
||||
if (path[pos + 1] == '.' && path[pos + 2] == '.'){
|
||||
if (path_breaks.empty()) {
|
||||
// Ensure we don't override the device name
|
||||
std::string::size_type loc(path.find_first_of(':'));
|
||||
auto req(pos + 3);
|
||||
if (loc == std::string::npos || loc > req) {
|
||||
path.erase(0, req);
|
||||
pos_n -= req;
|
||||
} else {
|
||||
path.erase(loc + 1, req - (loc + 1));
|
||||
pos_n -= req - (loc + 1);
|
||||
}
|
||||
} else {
|
||||
auto last(path_breaks.back());
|
||||
auto last_diff((pos + 3) - last);
|
||||
path.erase(last, last_diff);
|
||||
pos_n = last;
|
||||
// Also remove path reference
|
||||
path_breaks.erase(path_breaks.end() - 1);
|
||||
}
|
||||
} else {
|
||||
path_breaks.push_back(pos);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
path_breaks.push_back(pos);
|
||||
break;
|
||||
}
|
||||
|
||||
pos = pos_n;
|
||||
}
|
||||
|
||||
// Remove trailing seperator
|
||||
if (!path.empty() && path.back() == path_separator) {
|
||||
path.erase(path.size() - 1);
|
||||
}
|
||||
|
||||
// Final sanity check for dead paths
|
||||
if ((path.size() == 1 && (path[0] == '.' || path[0] == path_separator))
|
||||
|| (path.size() == 2 && path[0] == '.' && path[1] == '.')) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
std::unique_ptr<Entry> FileSystem::ResolvePath(const std::string& path) {
|
||||
// Resolve relative paths
|
||||
std::string normalized_path(CanonicalizePath(path));
|
||||
std::string normalized_path(poly::fs::CanonicalizePath(path));
|
||||
|
||||
// If no path (starts with a slash) do it module-relative.
|
||||
// Which for now, we just make game:.
|
||||
|
|
|
@ -57,8 +57,6 @@ class FileSystem {
|
|||
private:
|
||||
std::vector<Device*> devices_;
|
||||
std::unordered_map<std::string, std::string> symlinks_;
|
||||
|
||||
std::string CanonicalizePath(const std::string& original_path) const;
|
||||
};
|
||||
|
||||
} // namespace fs
|
||||
|
|
|
@ -29,6 +29,20 @@ GDFXEntry::~GDFXEntry() {
|
|||
}
|
||||
}
|
||||
|
||||
GDFXEntry* GDFXEntry::GetChild(const poly::fs::WildcardEngine& engine, child_it_t& ref_it)
|
||||
{
|
||||
GDFXEntry* child_entry(nullptr);
|
||||
while (ref_it != children.end()) {
|
||||
if (engine.Match((*ref_it)->name)) {
|
||||
child_entry = (*ref_it);
|
||||
++ref_it;
|
||||
break;
|
||||
}
|
||||
++ref_it;
|
||||
}
|
||||
return child_entry;
|
||||
}
|
||||
|
||||
GDFXEntry* GDFXEntry::GetChild(const char* name) {
|
||||
// TODO(benvanik): a faster search
|
||||
for (std::vector<GDFXEntry*>::iterator it = children.begin();
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "xenia/common.h"
|
||||
#include "xenia/xbox.h"
|
||||
#include "xenia/kernel/fs/entry.h"
|
||||
#include "poly/fs.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
|
@ -28,6 +29,10 @@ class GDFXEntry {
|
|||
GDFXEntry();
|
||||
~GDFXEntry();
|
||||
|
||||
typedef std::vector<GDFXEntry*> child_t;
|
||||
typedef child_t::iterator child_it_t;
|
||||
|
||||
GDFXEntry* GetChild(const poly::fs::WildcardEngine& engine, child_it_t& ref_it);
|
||||
GDFXEntry* GetChild(const char* name);
|
||||
|
||||
void Dump(int indent);
|
||||
|
@ -36,8 +41,7 @@ class GDFXEntry {
|
|||
X_FILE_ATTRIBUTES attributes;
|
||||
size_t offset;
|
||||
size_t size;
|
||||
|
||||
std::vector<GDFXEntry*> children;
|
||||
child_t children;
|
||||
};
|
||||
|
||||
class GDFX {
|
||||
|
|
|
@ -100,6 +100,20 @@ STFSEntry::STFSEntry()
|
|||
update_timestamp(0),
|
||||
access_timestamp(0) {}
|
||||
|
||||
STFSEntry* STFSEntry::GetChild(const poly::fs::WildcardEngine& engine, child_it_t& ref_it)
|
||||
{
|
||||
STFSEntry* child_entry(nullptr);
|
||||
while (ref_it != children.end()) {
|
||||
if (engine.Match((*ref_it)->name)) {
|
||||
child_entry = (*ref_it).get();
|
||||
++ref_it;
|
||||
break;
|
||||
}
|
||||
++ref_it;
|
||||
}
|
||||
return child_entry;
|
||||
}
|
||||
|
||||
STFSEntry* STFSEntry::GetChild(const char* name) {
|
||||
// TODO(benvanik): a faster search
|
||||
for (const auto& entry : children) {
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "xenia/common.h"
|
||||
#include "xenia/xbox.h"
|
||||
#include "xenia/kernel/fs/entry.h"
|
||||
#include "poly/fs.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
|
@ -131,6 +132,10 @@ class STFSEntry {
|
|||
public:
|
||||
STFSEntry();
|
||||
|
||||
typedef std::vector<std::unique_ptr<STFSEntry>> child_t;
|
||||
typedef child_t::iterator child_it_t;
|
||||
|
||||
STFSEntry* GetChild(const poly::fs::WildcardEngine& engine, child_it_t& ref_it);
|
||||
STFSEntry* GetChild(const char* name);
|
||||
|
||||
void Dump(int indent);
|
||||
|
@ -141,8 +146,7 @@ class STFSEntry {
|
|||
size_t size;
|
||||
uint32_t update_timestamp;
|
||||
uint32_t access_timestamp;
|
||||
|
||||
std::vector<std::unique_ptr<STFSEntry>> children;
|
||||
child_t children;
|
||||
|
||||
typedef struct {
|
||||
size_t offset;
|
||||
|
|
Loading…
Reference in New Issue