summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDr. Chat <arkolbed@gmail.com>2018-06-26 13:45:16 -0500
committerDr. Chat <arkolbed@gmail.com>2018-06-26 13:45:16 -0500
commitf89b4626a37dd4d1e5a817909252d3d4dd054299 (patch)
tree06c3c355ae8a2e07458e712fd63e93668b2dc8f2
parent827e3a0be467e54e3ac76ca5574215424bf94bdf (diff)
[VFS] Add VFS dump tool (supporting STFS only as of now)
-rw-r--r--src/xenia/vfs/premake5.lua27
-rw-r--r--src/xenia/vfs/vfs_dump.cc111
2 files changed, 138 insertions, 0 deletions
diff --git a/src/xenia/vfs/premake5.lua b/src/xenia/vfs/premake5.lua
index 8d431a1af..be71cef59 100644
--- a/src/xenia/vfs/premake5.lua
+++ b/src/xenia/vfs/premake5.lua
@@ -15,3 +15,30 @@ project("xenia-vfs")
project_root.."/third_party/gflags/src",
})
recursive_platform_files()
+ removefiles({"vfs_dump.cc"})
+
+project("xenia-vfs-dump")
+ uuid("2EF270C7-41A8-4D0E-ACC5-59693A9CCE32")
+ kind("ConsoleApp")
+ language("C++")
+ links({
+ "gflags",
+ "xenia-base",
+ "xenia-vfs",
+ })
+ flags({
+ -- "WinMain", -- Use WinMain instead of main.
+ })
+ defines({})
+ includedirs({
+ project_root.."/third_party/gflags/src",
+ })
+
+ files({
+ "vfs_dump.cc",
+ project_root.."/src/xenia/base/main_"..platform_suffix..".cc",
+ })
+ resincludedirs({
+ project_root,
+ })
+
diff --git a/src/xenia/vfs/vfs_dump.cc b/src/xenia/vfs/vfs_dump.cc
new file mode 100644
index 000000000..4e81ca690
--- /dev/null
+++ b/src/xenia/vfs/vfs_dump.cc
@@ -0,0 +1,111 @@
+/**
+ ******************************************************************************
+ * Xenia : Xbox 360 Emulator Research Project *
+ ******************************************************************************
+ * Copyright 2018 Ben Vanik. All rights reserved. *
+ * Released under the BSD license - see LICENSE in the root for more details. *
+ ******************************************************************************
+ */
+
+#include <queue>
+#include <string>
+#include <vector>
+
+#include "xenia/base/logging.h"
+#include "xenia/base/main.h"
+#include "xenia/base/math.h"
+
+#include "xenia/vfs/devices/stfs_container_device.h"
+#include "xenia/vfs/file.h"
+
+namespace xe {
+namespace vfs {
+
+int vfs_dump_main(const std::vector<std::wstring>& args) {
+ if (args.size() <= 2) {
+ XELOGE("Usage: %s [source] [dump_path]", args[0].c_str());
+ return 1;
+ }
+
+ std::wstring base_path = args[2];
+ std::unique_ptr<vfs::Device> device;
+
+ // TODO: Flags specifying the type of device.
+ device = std::make_unique<vfs::StfsContainerDevice>("", args[1]);
+ if (!device->Initialize()) {
+ XELOGE("Failed to initialize device");
+ return 1;
+ }
+
+ // Run through all the files, breadth-first style.
+ std::queue<vfs::Entry*> queue;
+ auto root = device->ResolvePath("/");
+ queue.push(root);
+
+ // Allocate a buffer when needed.
+ size_t buffer_size = 0;
+ uint8_t* buffer = nullptr;
+
+ while (!queue.empty()) {
+ auto entry = queue.front();
+ queue.pop();
+ for (auto& entry : entry->children()) {
+ queue.push(entry.get());
+ }
+
+ XELOGI("%s", entry->path().c_str());
+ auto dest_name = xe::join_paths(base_path, xe::to_wstring(entry->path()));
+ if (entry->attributes() & kFileAttributeDirectory) {
+ xe::filesystem::CreateFolder(dest_name + L"\\");
+ continue;
+ }
+
+ vfs::File* in_file = nullptr;
+ if (entry->Open(FileAccess::kFileReadData, &in_file) != X_STATUS_SUCCESS) {
+ continue;
+ }
+
+ auto file = xe::filesystem::OpenFile(dest_name, "wb");
+ if (!file) {
+ in_file->Destroy();
+ continue;
+ }
+
+ if (entry->can_map()) {
+ auto map = entry->OpenMapped(xe::MappedMemory::Mode::kRead);
+ fwrite(map->data(), map->size(), 1, file);
+ map->Close();
+ } else {
+ // Can't map the file into memory. Read it into a temporary buffer.
+ if (!buffer || entry->size() > buffer_size) {
+ // Resize the buffer.
+ if (buffer) {
+ delete[] buffer;
+ }
+
+ // Allocate a buffer rounded up to the nearest 512MB.
+ buffer_size = xe::round_up(entry->size(), 512 * 1024 * 1024);
+ buffer = new uint8_t[buffer_size];
+ }
+
+ size_t bytes_read = 0;
+ in_file->ReadSync(buffer, entry->size(), 0, &bytes_read);
+ fwrite(buffer, bytes_read, 1, file);
+ }
+
+ fclose(file);
+ in_file->Destroy();
+ }
+
+ if (buffer) {
+ delete[] buffer;
+ }
+
+ return 0;
+}
+
+} // namespace vfs
+} // namespace xe
+
+DEFINE_ENTRY_POINT(L"xenia-vfs-dump", L"xenia-vfs-dump",
+ xe::vfs::vfs_dump_main);