Remove recursion from RomFS parse, clang-format

This commit is contained in:
offtkp 2023-07-29 17:01:44 +03:00
parent 2de35bd39d
commit fb6ec3aa5f
4 changed files with 202 additions and 194 deletions

View file

@ -1,7 +1,7 @@
#pragma once
#include <cstddef>
#include <cstring>
#include <vector>
#include "helpers.hpp"
namespace IVFC {

View file

@ -1,20 +1,21 @@
#pragma once
#include "helpers.hpp"
#include <memory>
#include <string>
#include <vector>
#include <memory>
#include "helpers.hpp"
namespace RomFS {
struct RomFSNode {
std::u16string name {};
std::u16string name;
// The file/directory offset relative to the start of the RomFS
u64 offset { 0 };
u64 size { 0 };
bool isDirectory { false };
u64 offset = 0;
u64 size = 0;
bool isDirectory = false;
std::vector<std::unique_ptr<RomFSNode>> directories {};
std::vector<std::unique_ptr<RomFSNode>> files {};
std::vector<std::unique_ptr<RomFSNode>> directories;
std::vector<std::unique_ptr<RomFSNode>> files;
};
std::unique_ptr<RomFSNode> parseRomFSTree(uintptr_t romFS, u64 romFSSize);

View file

@ -4,15 +4,15 @@ namespace IVFC {
size_t parseIVFC(uintptr_t ivfcStart, IVFC& ivfc) {
uintptr_t ivfcPointer = ivfcStart;
std::string magicIVFC((char*)ivfcPointer, 4);
ivfcPointer += 4;
if (magicIVFC != "IVFC") {
printf("Invalid IVFC magic: %s\n", magicIVFC.c_str());
char* ivfcCharPtr = (char*)ivfcPointer;
if (ivfcCharPtr[0] != 'I' || ivfcCharPtr[1] != 'V' || ivfcCharPtr[2] != 'F' || ivfcCharPtr[3] != 'C') {
printf("Invalid header on IVFC\n");
return 0;
}
ivfcPointer += 4;
uint32_t magicIdentifier = *(u32*)ivfcPointer;
u32 magicIdentifier = *(u32*)ivfcPointer;
ivfcPointer += 4;
// RomFS IVFC uses 0x10000, DISA/DIFF IVFC uses 0x20000 here

View file

@ -1,31 +1,31 @@
#include "fs/romfs.hpp"
#include <cstdio>
#include <queue>
#include <string>
#include "fs/ivfc.hpp"
#include "helpers.hpp"
#include <cstdio>
#include <memory>
#include <map>
#include <string>
namespace RomFS {
constexpr u32 metadataInvalidEntry = 0xFFFFFFFF;
struct Level3Header {
uint32_t headerSize;
uint32_t directoryHashTableOffset;
uint32_t directoryHashTableSize;
uint32_t directoryMetadataOffset;
uint32_t directoryMetadataSize;
uint32_t fileHashTableOffset;
uint32_t fileHashTableSize;
uint32_t fileMetadataOffset;
uint32_t fileMetadataSize;
uint32_t fileDataOffset;
u32 headerSize;
u32 directoryHashTableOffset;
u32 directoryHashTableSize;
u32 directoryMetadataOffset;
u32 directoryMetadataSize;
u32 fileHashTableOffset;
u32 fileHashTableSize;
u32 fileMetadataOffset;
u32 fileMetadataSize;
u32 fileDataOffset;
};
inline uintptr_t align(uintptr_t value, uintptr_t alignment) {
if (value % alignment == 0)
return value;
if (value % alignment == 0) return value;
return value + (alignment - (value % alignment));
}
@ -43,23 +43,34 @@ namespace RomFS {
indentation--;
}
std::vector<std::unique_ptr<RomFSNode>> parseDirectory(const uintptr_t metadataBase, const uintptr_t metadataOffset) {
std::vector<std::unique_ptr<RomFSNode>> directories {};
std::unique_ptr<RomFSNode> parseRootDirectory(uintptr_t metadataBase) {
std::unique_ptr<RomFSNode> rootDirectory = std::make_unique<RomFSNode>();
rootDirectory->isDirectory = true;
rootDirectory->name = u"romfs:";
rootDirectory->offset = 0;
// Get offset of first child directory
u32* metadataPtr = (u32*)(metadataBase + metadataOffset);
std::queue<RomFSNode*> directoryOffsets;
directoryOffsets.push(rootDirectory.get());
while (!directoryOffsets.empty()) {
RomFSNode* currentNode = directoryOffsets.front();
directoryOffsets.pop();
u32* metadataPtr = (u32*)(metadataBase + currentNode->offset);
metadataPtr += 2;
// Offset of first child directory
u32 currentDirectoryOffset = *metadataPtr;
// Loop over all the sibling directories of the first child to get all the children directories
// of the current directory
while (currentDirectoryOffset != metadataInvalidEntry) {
metadataPtr = (u32*)(metadataBase + currentDirectoryOffset);
metadataPtr++; // Skip the parent offset
u32 siblingDirectoryOffset = *metadataPtr++;
metadataPtr++; // Skip the child offset
metadataPtr++; // Skip the first file offset
metadataPtr++; // Skip the next directory in hash table offset
u32 nameLength = (*metadataPtr++) / 2;
u32 siblingDirectoryOffset = *metadataPtr;
// Skip the rest of the fields
metadataPtr += 4;
u32 nameLength = *metadataPtr++ / 2;
// Arbitrary limit
if (nameLength > 128) {
@ -74,17 +85,17 @@ namespace RomFS {
directory->isDirectory = true;
directory->name = name;
directory->offset = currentDirectoryOffset;
directories.push_back(std::move(directory));
currentNode->directories.push_back(std::move(directory));
currentDirectoryOffset = siblingDirectoryOffset;
}
// Loop over all the children directories to get their children
for (auto& directory : directories) {
directory->directories = parseDirectory(metadataBase, directory->offset);
for (auto& directory : currentNode->directories) {
directoryOffsets.push(directory.get());
}
}
return directories;
return rootDirectory;
}
std::unique_ptr<RomFSNode> parseRomFSTree(uintptr_t romFS, u64 romFSSize) {
@ -101,7 +112,7 @@ namespace RomFS {
// the first block after the master hash
// TODO: Find out why and explain in the comment
uintptr_t level3Offset = RomFS::align(masterHashOffset + ivfc.masterHashSize, ivfc.levels[2].blockSize);
uintptr_t const level3Base = (uintptr_t)romFS + level3Offset;
uintptr_t level3Base = (uintptr_t)romFS + level3Offset;
u32* level3Ptr = (u32*)level3Base;
Level3Header header;
@ -121,11 +132,7 @@ namespace RomFS {
return {};
}
std::unique_ptr<RomFSNode> root = std::make_unique<RomFSNode>();
root->isDirectory = true;
root->name = u"";
root->offset = 0;
root->directories = parseDirectory(level3Base + header.directoryMetadataOffset, 0);
std::unique_ptr<RomFSNode> root = parseRootDirectory(level3Base + header.directoryMetadataOffset);
// If you want to print the tree, uncomment this
// printNode(*root, 0, "");