Adding support for disc images.
With this, games can now be loaded! Of course, prep fails.
This commit is contained in:
parent
f78fdba9c3
commit
7f846afdfc
|
@ -25,7 +25,7 @@ xe_mmap_ref xe_mmap_open(xe_pal_ref pal, const xe_file_mode mode,
|
||||||
const size_t offset, const size_t length);
|
const size_t offset, const size_t length);
|
||||||
xe_mmap_ref xe_mmap_retain(xe_mmap_ref mmap);
|
xe_mmap_ref xe_mmap_retain(xe_mmap_ref mmap);
|
||||||
void xe_mmap_release(xe_mmap_ref mmap);
|
void xe_mmap_release(xe_mmap_ref mmap);
|
||||||
void *xe_mmap_get_addr(xe_mmap_ref mmap);
|
uint8_t* xe_mmap_get_addr(xe_mmap_ref mmap);
|
||||||
size_t xe_mmap_get_length(xe_mmap_ref mmap);
|
size_t xe_mmap_get_length(xe_mmap_ref mmap);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -92,8 +92,8 @@ void xe_mmap_release(xe_mmap_ref mmap) {
|
||||||
xe_ref_release((xe_ref)mmap, (xe_ref_dealloc_t)xe_mmap_dealloc);
|
xe_ref_release((xe_ref)mmap, (xe_ref_dealloc_t)xe_mmap_dealloc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* xe_mmap_get_addr(xe_mmap_ref mmap) {
|
uint8_t* xe_mmap_get_addr(xe_mmap_ref mmap) {
|
||||||
return mmap->addr;
|
return (uint8_t*)mmap->addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t xe_mmap_get_length(xe_mmap_ref mmap) {
|
size_t xe_mmap_get_length(xe_mmap_ref mmap) {
|
||||||
|
|
|
@ -123,7 +123,7 @@ void xe_mmap_release(xe_mmap_ref mmap) {
|
||||||
xe_ref_release((xe_ref)mmap, (xe_ref_dealloc_t)xe_mmap_dealloc);
|
xe_ref_release((xe_ref)mmap, (xe_ref_dealloc_t)xe_mmap_dealloc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* xe_mmap_get_addr(xe_mmap_ref mmap) {
|
uint8_t* xe_mmap_get_addr(xe_mmap_ref mmap) {
|
||||||
return mmap->addr;
|
return mmap->addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,22 +9,105 @@
|
||||||
|
|
||||||
#include "kernel/fs/devices/disc_image_device.h"
|
#include "kernel/fs/devices/disc_image_device.h"
|
||||||
|
|
||||||
|
#include "kernel/fs/gdfx.h"
|
||||||
|
|
||||||
|
|
||||||
using namespace xe;
|
using namespace xe;
|
||||||
using namespace xe::kernel;
|
using namespace xe::kernel;
|
||||||
using namespace xe::kernel::fs;
|
using namespace xe::kernel::fs;
|
||||||
|
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
|
||||||
|
class DiscImageMemoryMapping : public MemoryMapping {
|
||||||
|
public:
|
||||||
|
DiscImageMemoryMapping(uint8_t* address, size_t length, xe_mmap_ref mmap) :
|
||||||
|
MemoryMapping(address, length) {
|
||||||
|
mmap_ = xe_mmap_retain(mmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~DiscImageMemoryMapping() {
|
||||||
|
xe_mmap_release(mmap_);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
xe_mmap_ref mmap_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class DiscImageFileEntry : public FileEntry {
|
||||||
|
public:
|
||||||
|
DiscImageFileEntry(Device* device, const char* path,
|
||||||
|
xe_mmap_ref mmap, GDFXEntry* gdfx_entry) :
|
||||||
|
FileEntry(device, path),
|
||||||
|
gdfx_entry_(gdfx_entry) {
|
||||||
|
mmap_ = xe_mmap_retain(mmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~DiscImageFileEntry() {
|
||||||
|
delete gdfx_entry_;
|
||||||
|
xe_mmap_release(mmap_);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual MemoryMapping* CreateMemoryMapping(
|
||||||
|
xe_file_mode file_mode, const size_t offset, const size_t length) {
|
||||||
|
if (file_mode & kXEFileModeWrite) {
|
||||||
|
// Only allow reads.
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t real_offset = gdfx_entry_->offset + offset;
|
||||||
|
size_t real_length = length ?
|
||||||
|
MIN(length, gdfx_entry_->size) : gdfx_entry_->size;
|
||||||
|
return new DiscImageMemoryMapping(
|
||||||
|
xe_mmap_get_addr(mmap_) + real_offset,
|
||||||
|
real_length,
|
||||||
|
mmap_);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
xe_mmap_ref mmap_;
|
||||||
|
GDFXEntry* gdfx_entry_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
DiscImageDevice::DiscImageDevice(xe_pal_ref pal, const char* path,
|
DiscImageDevice::DiscImageDevice(xe_pal_ref pal, const char* path,
|
||||||
const xechar_t* local_path) :
|
const xechar_t* local_path) :
|
||||||
Device(pal, path) {
|
Device(pal, path) {
|
||||||
local_path_ = xestrdup(local_path);
|
local_path_ = xestrdup(local_path);
|
||||||
|
mmap_ = NULL;
|
||||||
|
gdfx_ = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
DiscImageDevice::~DiscImageDevice() {
|
DiscImageDevice::~DiscImageDevice() {
|
||||||
|
delete gdfx_;
|
||||||
|
xe_mmap_release(mmap_);
|
||||||
xe_free(local_path_);
|
xe_free(local_path_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int DiscImageDevice::Init() {
|
||||||
|
mmap_ = xe_mmap_open(pal_, kXEFileModeRead, local_path_, 0, 0);
|
||||||
|
if (!mmap_) {
|
||||||
|
XELOGE(XT("Disc image could not be mapped"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
gdfx_ = new GDFX(mmap_);
|
||||||
|
GDFX::Error error = gdfx_->Load();
|
||||||
|
if (error != GDFX::kSuccess) {
|
||||||
|
XELOGE(XT("GDFX init failed: %d"), error);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//gdfx_->Dump();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
Entry* DiscImageDevice::ResolvePath(const char* path) {
|
Entry* DiscImageDevice::ResolvePath(const char* path) {
|
||||||
// The filesystem will have stripped our prefix off already, so the path will
|
// The filesystem will have stripped our prefix off already, so the path will
|
||||||
// be in the form:
|
// be in the form:
|
||||||
|
@ -32,5 +115,44 @@ Entry* DiscImageDevice::ResolvePath(const char* path) {
|
||||||
|
|
||||||
XELOGFS(XT("DiscImageDevice::ResolvePath(%s)"), path);
|
XELOGFS(XT("DiscImageDevice::ResolvePath(%s)"), path);
|
||||||
|
|
||||||
|
GDFXEntry* gdfx_entry = gdfx_->root_entry();
|
||||||
|
|
||||||
|
// Walk the path, one separator at a time.
|
||||||
|
// We copy it into the buffer and shift it left over and over.
|
||||||
|
char remaining[XE_MAX_PATH];
|
||||||
|
XEIGNORE(xestrcpya(remaining, XECOUNT(remaining), path));
|
||||||
|
while (remaining[0]) {
|
||||||
|
char* next_slash = xestrchra(remaining, '\\');
|
||||||
|
if (next_slash == remaining) {
|
||||||
|
// Leading slash - shift
|
||||||
|
XEIGNORE(xestrcpya(remaining, XECOUNT(remaining), remaining + 1));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make the buffer just the name.
|
||||||
|
if (next_slash) {
|
||||||
|
*next_slash = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look up in the entry.
|
||||||
|
gdfx_entry = gdfx_entry->GetChild(remaining);
|
||||||
|
if (!gdfx_entry) {
|
||||||
|
// Not found.
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Shift the buffer down, unless we are at the end.
|
||||||
|
if (!next_slash) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
XEIGNORE(xestrcpya(remaining, XECOUNT(remaining), next_slash + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gdfx_entry->attributes & GDFXEntry::kAttrFolder) {
|
||||||
|
//return new DiscImageDirectoryEntry(mmap_, gdfx_entry);
|
||||||
|
XEASSERTALWAYS();
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
return new DiscImageFileEntry(this, path, mmap_, gdfx_entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -21,15 +21,22 @@ namespace kernel {
|
||||||
namespace fs {
|
namespace fs {
|
||||||
|
|
||||||
|
|
||||||
|
class GDFX;
|
||||||
|
|
||||||
|
|
||||||
class DiscImageDevice : public Device {
|
class DiscImageDevice : public Device {
|
||||||
public:
|
public:
|
||||||
DiscImageDevice(xe_pal_ref pal, const char* path, const xechar_t* local_path);
|
DiscImageDevice(xe_pal_ref pal, const char* path, const xechar_t* local_path);
|
||||||
virtual ~DiscImageDevice();
|
virtual ~DiscImageDevice();
|
||||||
|
|
||||||
|
int Init();
|
||||||
|
|
||||||
virtual Entry* ResolvePath(const char* path);
|
virtual Entry* ResolvePath(const char* path);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
xechar_t* local_path_;
|
xechar_t* local_path_;
|
||||||
|
xe_mmap_ref mmap_;
|
||||||
|
GDFX* gdfx_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,10 @@ int FileSystem::RegisterLocalDirectoryDevice(
|
||||||
|
|
||||||
int FileSystem::RegisterDiscImageDevice(
|
int FileSystem::RegisterDiscImageDevice(
|
||||||
const char* path, const xechar_t* local_path) {
|
const char* path, const xechar_t* local_path) {
|
||||||
Device* device = new DiscImageDevice(pal_, path, local_path);
|
DiscImageDevice* device = new DiscImageDevice(pal_, path, local_path);
|
||||||
|
if (device->Init()) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
return RegisterDevice(path, device);
|
return RegisterDevice(path, device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,207 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
* Major contributions to this file from:
|
||||||
|
* - abgx360
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "kernel/fs/gdfx.h"
|
||||||
|
|
||||||
|
|
||||||
|
using namespace xe;
|
||||||
|
using namespace xe::kernel;
|
||||||
|
using namespace xe::kernel::fs;
|
||||||
|
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
#define kXESectorSize 2048
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GDFXEntry::~GDFXEntry() {
|
||||||
|
for (std::vector<GDFXEntry*>::iterator it = children.begin();
|
||||||
|
it != children.end(); ++it) {
|
||||||
|
delete *it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GDFXEntry* GDFXEntry::GetChild(const char* name) {
|
||||||
|
// TODO(benvanik): a faster search
|
||||||
|
for (std::vector<GDFXEntry*>::iterator it = children.begin();
|
||||||
|
it != children.end(); ++it) {
|
||||||
|
GDFXEntry* entry = *it;
|
||||||
|
if (xestrcasecmpa(entry->name.c_str(), name) == 0) {
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GDFXEntry::Dump(int indent) {
|
||||||
|
printf("%s%s\n", std::string(indent, ' ').c_str(), name.c_str());
|
||||||
|
for (std::vector<GDFXEntry*>::iterator it = children.begin();
|
||||||
|
it != children.end(); ++it) {
|
||||||
|
GDFXEntry* entry = *it;
|
||||||
|
entry->Dump(indent + 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GDFX::GDFX(xe_mmap_ref mmap) {
|
||||||
|
mmap_ = xe_mmap_retain(mmap);
|
||||||
|
|
||||||
|
root_entry_ = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
GDFX::~GDFX() {
|
||||||
|
delete root_entry_;
|
||||||
|
|
||||||
|
xe_mmap_release(mmap_);
|
||||||
|
}
|
||||||
|
|
||||||
|
GDFXEntry* GDFX::root_entry() {
|
||||||
|
return root_entry_;
|
||||||
|
}
|
||||||
|
|
||||||
|
GDFX::Error GDFX::Load() {
|
||||||
|
Error result = kErrorOutOfMemory;
|
||||||
|
|
||||||
|
ParseState state;
|
||||||
|
xe_zero_struct(&state, sizeof(state));
|
||||||
|
|
||||||
|
state.ptr = (uint8_t*)xe_mmap_get_addr(mmap_);
|
||||||
|
state.size = xe_mmap_get_length(mmap_);
|
||||||
|
|
||||||
|
result = Verify(state);
|
||||||
|
XEEXPECTZERO(result);
|
||||||
|
|
||||||
|
result = ReadAllEntries(state, state.ptr + state.root_offset);
|
||||||
|
XEEXPECTZERO(result);
|
||||||
|
|
||||||
|
result = kSuccess;
|
||||||
|
XECLEANUP:
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GDFX::Dump() {
|
||||||
|
if (root_entry_) {
|
||||||
|
root_entry_->Dump(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GDFX::Error GDFX::Verify(ParseState& state) {
|
||||||
|
// Find sector 32 of the game partition - try at a few points.
|
||||||
|
const static size_t likely_offsets[] = {
|
||||||
|
0x00000000, 0x0000FB20, 0x00020600, 0x0FD90000,
|
||||||
|
};
|
||||||
|
bool magic_found = false;
|
||||||
|
for (size_t n = 0; n < XECOUNT(likely_offsets); n++) {
|
||||||
|
state.game_offset = likely_offsets[n];
|
||||||
|
if (VerifyMagic(state, state.game_offset + (32 * kXESectorSize))) {
|
||||||
|
magic_found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!magic_found) {
|
||||||
|
// File doesn't have the magic values - likely not a real GDFX source.
|
||||||
|
return kErrorFileMismatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read sector 32 to get FS state.
|
||||||
|
if (state.size < state.game_offset + (32 * kXESectorSize)) {
|
||||||
|
return kErrorReadError;
|
||||||
|
}
|
||||||
|
uint8_t* fs_ptr = state.ptr + state.game_offset + (32 * kXESectorSize);
|
||||||
|
state.root_sector = XEGETUINT32LE(fs_ptr + 20);
|
||||||
|
state.root_size = XEGETUINT32LE(fs_ptr + 24);
|
||||||
|
state.root_offset = state.game_offset + (state.root_sector * kXESectorSize);
|
||||||
|
if (state.root_size < 13 ||
|
||||||
|
state.root_size > 32 * 1024 * 1024) {
|
||||||
|
return kErrorDamagedFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
return kSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GDFX::VerifyMagic(ParseState& state, size_t offset) {
|
||||||
|
// Simple check to see if the given offset contains the magic value.
|
||||||
|
return memcmp(state.ptr + offset, "MICROSOFT*XBOX*MEDIA", 20) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
GDFX::Error GDFX::ReadAllEntries(ParseState& state,
|
||||||
|
const uint8_t* root_buffer) {
|
||||||
|
root_entry_ = new GDFXEntry();
|
||||||
|
root_entry_->offset = 0;
|
||||||
|
root_entry_->size = 0;
|
||||||
|
root_entry_->name = "";
|
||||||
|
root_entry_->attributes = GDFXEntry::kAttrFolder;
|
||||||
|
|
||||||
|
if (!ReadEntry(state, root_buffer, 0, root_entry_)) {
|
||||||
|
return kErrorOutOfMemory;
|
||||||
|
}
|
||||||
|
|
||||||
|
return kSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GDFX::ReadEntry(ParseState& state, const uint8_t* buffer,
|
||||||
|
uint16_t entry_ordinal, GDFXEntry* parent) {
|
||||||
|
const uint8_t* p = buffer + (entry_ordinal * 4);
|
||||||
|
|
||||||
|
uint16_t node_l = XEGETUINT16LE(p + 0);
|
||||||
|
uint16_t node_r = XEGETUINT16LE(p + 2);
|
||||||
|
size_t sector = XEGETUINT32LE(p + 4);
|
||||||
|
size_t length = XEGETUINT32LE(p + 8);
|
||||||
|
uint8_t attributes = XEGETUINT8LE(p + 12);
|
||||||
|
uint8_t name_length = XEGETUINT8LE(p + 13);
|
||||||
|
char* name = (char*)(p + 14);
|
||||||
|
|
||||||
|
if (node_l && !ReadEntry(state, buffer, node_l, parent)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
GDFXEntry* entry = new GDFXEntry();
|
||||||
|
entry->name = std::string(name, name_length);
|
||||||
|
entry->name.append(1, '\0');
|
||||||
|
entry->attributes = attributes;
|
||||||
|
|
||||||
|
// Add to parent (if we have one).
|
||||||
|
if (parent) {
|
||||||
|
parent->children.push_back(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attributes & GDFXEntry::kAttrFolder) {
|
||||||
|
// Folder.
|
||||||
|
entry->offset = 0;
|
||||||
|
entry->size = 0;
|
||||||
|
if (length) {
|
||||||
|
// Not a leaf - read in children.
|
||||||
|
if (state.size < state.game_offset + (sector * kXESectorSize)) {
|
||||||
|
// Out of bounds read.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Read child list.
|
||||||
|
uint8_t* folder_ptr =
|
||||||
|
state.ptr + state.game_offset + (sector * kXESectorSize);
|
||||||
|
if (!ReadEntry(state, folder_ptr, 0, entry)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// File.
|
||||||
|
entry->offset = state.game_offset + (sector * kXESectorSize);
|
||||||
|
entry->size = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read next file in the list.
|
||||||
|
if (node_r && !ReadEntry(state, buffer, node_r, parent)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
|
@ -0,0 +1,105 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef XENIA_KERNEL_FS_GDFX_H_
|
||||||
|
#define XENIA_KERNEL_FS_GDFX_H_
|
||||||
|
|
||||||
|
#include <xenia/common.h>
|
||||||
|
#include <xenia/core.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <xenia/kernel/fs/entry.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace kernel {
|
||||||
|
namespace fs {
|
||||||
|
|
||||||
|
|
||||||
|
class GDFX;
|
||||||
|
|
||||||
|
|
||||||
|
class GDFXEntry {
|
||||||
|
public:
|
||||||
|
enum Attributes {
|
||||||
|
kAttrNone = 0x00000000,
|
||||||
|
kAttrReadOnly = 0x00000001,
|
||||||
|
kAttrHidden = 0x00000002,
|
||||||
|
kAttrSystem = 0x00000004,
|
||||||
|
kAttrFolder = 0x00000010,
|
||||||
|
kAttrArchived = 0x00000020,
|
||||||
|
kAttrNormal = 0x00000080,
|
||||||
|
};
|
||||||
|
|
||||||
|
GDFXEntry() {}
|
||||||
|
~GDFXEntry();
|
||||||
|
|
||||||
|
GDFXEntry* GetChild(const char* name);
|
||||||
|
|
||||||
|
void Dump(int indent);
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
uint32_t attributes;
|
||||||
|
size_t offset;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
std::vector<GDFXEntry*> children;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class GDFX {
|
||||||
|
public:
|
||||||
|
enum Error {
|
||||||
|
kSuccess = 0,
|
||||||
|
kErrorOutOfMemory = -1,
|
||||||
|
kErrorReadError = -10,
|
||||||
|
kErrorFileMismatch = -30,
|
||||||
|
kErrorDamagedFile = -31,
|
||||||
|
};
|
||||||
|
|
||||||
|
GDFX(xe_mmap_ref mmap);
|
||||||
|
virtual ~GDFX();
|
||||||
|
|
||||||
|
GDFXEntry* root_entry();
|
||||||
|
|
||||||
|
Error Load();
|
||||||
|
void Dump();
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef struct {
|
||||||
|
uint8_t* ptr;
|
||||||
|
|
||||||
|
size_t size; // Size (bytes) of total image
|
||||||
|
|
||||||
|
size_t game_offset; // Offset (bytes) of game partition
|
||||||
|
|
||||||
|
size_t root_sector; // Offset (sector) of root
|
||||||
|
size_t root_offset; // Offset (bytes) of root
|
||||||
|
size_t root_size; // Size (bytes) of root
|
||||||
|
} ParseState;
|
||||||
|
|
||||||
|
Error Verify(ParseState& state);
|
||||||
|
bool VerifyMagic(ParseState& state, size_t offset);
|
||||||
|
Error ReadAllEntries(ParseState& state, const uint8_t* root_buffer);
|
||||||
|
bool ReadEntry(ParseState& state, const uint8_t* buffer,
|
||||||
|
uint16_t entry_ordinal, GDFXEntry* parent);
|
||||||
|
|
||||||
|
xe_mmap_ref mmap_;
|
||||||
|
|
||||||
|
GDFXEntry* root_entry_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace fs
|
||||||
|
} // namespace kernel
|
||||||
|
} // namespace xe
|
||||||
|
|
||||||
|
|
||||||
|
#endif // XENIA_KERNEL_FS_GDFX_H_
|
|
@ -4,6 +4,7 @@
|
||||||
'device.cc',
|
'device.cc',
|
||||||
'entry.cc',
|
'entry.cc',
|
||||||
'filesystem.cc',
|
'filesystem.cc',
|
||||||
|
'gdfx.cc',
|
||||||
],
|
],
|
||||||
|
|
||||||
'includes': [
|
'includes': [
|
||||||
|
|
Loading…
Reference in New Issue