mirror of
https://github.com/jakcron/nstool
synced 2024-12-25 06:01:12 +00:00
[nstool] Add RomFs file previewing.
This commit is contained in:
parent
3411118e26
commit
2bfe11bf16
3 changed files with 403 additions and 6 deletions
249
programs/nstool/source/RomfsProcess.cpp
Normal file
249
programs/nstool/source/RomfsProcess.cpp
Normal file
|
@ -0,0 +1,249 @@
|
|||
#include "RomfsProcess.h"
|
||||
#include <fnd/SimpleTextOutput.h>
|
||||
#include <fnd/SimpleFile.h>
|
||||
#include <fnd/io.h>
|
||||
|
||||
void RomfsProcess::printTab(size_t tab) const
|
||||
{
|
||||
for (size_t i = 0; i < tab; i++)
|
||||
{
|
||||
printf(" ");
|
||||
}
|
||||
}
|
||||
|
||||
void RomfsProcess::displayFile(const sFile& file, size_t tab) const
|
||||
{
|
||||
printTab(tab);
|
||||
printf("%s", file.name.c_str());
|
||||
if (mCliOutputType >= OUTPUT_VERBOSE)
|
||||
{
|
||||
printf(" (offset=0x%" PRIx64 ", size=0x%" PRIx64 ")", file.offset, file.size);
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
void RomfsProcess::displayDir(const sDirectory& dir, size_t tab) const
|
||||
{
|
||||
if (dir.name.empty() == false)
|
||||
{
|
||||
printTab(tab);
|
||||
printf("%s\n", dir.name.c_str());
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < dir.dir_list.getSize(); i++)
|
||||
{
|
||||
displayDir(dir.dir_list[i], tab+1);
|
||||
}
|
||||
for (size_t i = 0; i < dir.file_list.getSize(); i++)
|
||||
{
|
||||
displayFile(dir.file_list[i], tab+1);
|
||||
}
|
||||
}
|
||||
|
||||
void RomfsProcess::displayHeader()
|
||||
{
|
||||
printf("[RomFS]\n");
|
||||
printf(" DirNum: %u\n", mDirNum);
|
||||
printf(" FileNum: %u\n", mFileNum);
|
||||
if (mMountName.empty() == false)
|
||||
printf(" MountPoint: %s%s\n", mMountName.c_str(), mMountName.at(mMountName.length()-1) != '/' ? "/" : "");
|
||||
}
|
||||
|
||||
void RomfsProcess::displayFs()
|
||||
{
|
||||
displayDir(mRootDir, 1);
|
||||
}
|
||||
|
||||
void RomfsProcess::extractFs()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool RomfsProcess::validateHeaderLayout(const nx::sRomfsHeader* hdr) const
|
||||
{
|
||||
bool validLayout = true;
|
||||
|
||||
if (hdr->header_size.get() != sizeof(nx::sRomfsHeader))
|
||||
{
|
||||
validLayout = false;
|
||||
}
|
||||
|
||||
uint64_t pos = hdr->sections[0].offset.get();
|
||||
for (size_t i = 0; i < nx::romfs::SECTION_NUM; i++)
|
||||
{
|
||||
if (hdr->sections[i].offset.get() != pos)
|
||||
{
|
||||
validLayout = false;
|
||||
}
|
||||
pos += hdr->sections[i].size.get();
|
||||
}
|
||||
|
||||
return validLayout;
|
||||
}
|
||||
|
||||
void RomfsProcess::importDirectory(uint32_t dir_offset, sDirectory& dir)
|
||||
{
|
||||
nx::sRomfsDirEntry* d_node = get_dir_node(dir_offset);
|
||||
|
||||
/*
|
||||
printf("[DIR-NODE]\n");
|
||||
printf(" parent=%08x\n", d_node->parent.get());
|
||||
printf(" sibling=%08x\n", d_node->sibling.get());
|
||||
printf(" child=%08x\n", d_node->child.get());
|
||||
printf(" file=%08x\n", d_node->file.get());
|
||||
printf(" hash=%08x\n", d_node->hash.get());
|
||||
printf(" name_size=%08x\n", d_node->name_size.get());
|
||||
printf(" name=%s\n", d_node->name);
|
||||
*/
|
||||
|
||||
for (uint32_t file_addr = d_node->file.get(); file_addr != nx::romfs::kInvalidAddr; )
|
||||
{
|
||||
nx::sRomfsFileEntry* f_node = get_file_node(file_addr);
|
||||
|
||||
/*
|
||||
printf("[FILE-NODE]\n");
|
||||
printf(" parent=%08x\n", f_node->parent.get());
|
||||
printf(" sibling=%08x\n", f_node->sibling.get());
|
||||
printf(" offset=%08" PRIx64 "\n", f_node->offset.get());
|
||||
printf(" size=%08" PRIx64 "\n", f_node->size.get());
|
||||
printf(" hash=%08x\n", f_node->hash.get());
|
||||
printf(" name_size=%08x\n", f_node->name_size.get());
|
||||
printf(" name=%s\n", f_node->name);
|
||||
*/
|
||||
|
||||
dir.file_list.addElement({std::string(f_node->name, f_node->name_size.get()), mHdr.data_offset.get() + f_node->offset.get(), f_node->size.get()});
|
||||
|
||||
file_addr = f_node->sibling.get();
|
||||
mFileNum++;
|
||||
}
|
||||
|
||||
for (uint32_t child_addr = d_node->child.get(); child_addr != nx::romfs::kInvalidAddr; )
|
||||
{
|
||||
nx::sRomfsDirEntry* c_node = get_dir_node(child_addr);
|
||||
|
||||
dir.dir_list.addElement({std::string(c_node->name, c_node->name_size.get())});
|
||||
importDirectory(child_addr, dir.dir_list.atBack());
|
||||
|
||||
child_addr = c_node->sibling.get();
|
||||
mDirNum++;
|
||||
}
|
||||
}
|
||||
|
||||
void RomfsProcess::resolveRomfs()
|
||||
{
|
||||
// read header
|
||||
mReader->read((byte_t*)&mHdr, mOffset, sizeof(nx::sRomfsHeader));
|
||||
|
||||
// logic check on the header layout
|
||||
if (validateHeaderLayout(&mHdr) == false)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "Invalid ROMFS Header");
|
||||
}
|
||||
|
||||
// read directory nodes
|
||||
mDirNodes.alloc(mHdr.sections[nx::romfs::DIR_NODE_TABLE].size.get());
|
||||
mReader->read(mDirNodes.getBytes(), mOffset + mHdr.sections[nx::romfs::DIR_NODE_TABLE].offset.get(), mDirNodes.getSize());
|
||||
//printf("[RAW DIR NODES]\n");
|
||||
//fnd::SimpleTextOutput::hxdStyleDump(mDirNodes.getBytes(), mDirNodes.getSize());
|
||||
|
||||
// read file nodes
|
||||
mFileNodes.alloc(mHdr.sections[nx::romfs::FILE_NODE_TABLE].size.get());
|
||||
mReader->read(mFileNodes.getBytes(), mOffset + mHdr.sections[nx::romfs::FILE_NODE_TABLE].offset.get(), mFileNodes.getSize());
|
||||
//printf("[RAW FILE NODES]\n");
|
||||
//fnd::SimpleTextOutput::hxdStyleDump(mFileNodes.getBytes(), mFileNodes.getSize());
|
||||
|
||||
// A logic check on the root directory node
|
||||
if ( get_dir_node(0)->parent.get() != 0 \
|
||||
|| get_dir_node(0)->sibling.get() != nx::romfs::kInvalidAddr \
|
||||
|| get_dir_node(0)->hash.get() != nx::romfs::kInvalidAddr \
|
||||
|| get_dir_node(0)->name_size.get() != 0)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "Invalid root directory node");
|
||||
}
|
||||
|
||||
// import directory into internal structure
|
||||
mDirNum = 0;
|
||||
mFileNum = 0;
|
||||
importDirectory(0, mRootDir);
|
||||
}
|
||||
|
||||
RomfsProcess::RomfsProcess() :
|
||||
mReader(nullptr),
|
||||
mOffset(0),
|
||||
mKeyset(nullptr),
|
||||
mCliOutputType(OUTPUT_NORMAL),
|
||||
mVerify(false),
|
||||
mExtractPath(),
|
||||
mExtract(false),
|
||||
mMountName(),
|
||||
mListFs(false),
|
||||
mDirNum(0),
|
||||
mFileNum(0)
|
||||
{
|
||||
mRootDir.name.clear();
|
||||
mRootDir.dir_list.clear();
|
||||
mRootDir.file_list.clear();
|
||||
}
|
||||
|
||||
void RomfsProcess::process()
|
||||
{
|
||||
if (mReader == nullptr)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "No file reader set.");
|
||||
}
|
||||
|
||||
resolveRomfs();
|
||||
|
||||
if (mCliOutputType >= OUTPUT_NORMAL)
|
||||
displayHeader();
|
||||
if (mListFs || mCliOutputType >= OUTPUT_VERBOSE)
|
||||
displayFs();
|
||||
if (mExtract)
|
||||
extractFs();
|
||||
}
|
||||
|
||||
void RomfsProcess::setInputFile(fnd::IFile& reader)
|
||||
{
|
||||
mReader = &reader;
|
||||
}
|
||||
|
||||
void RomfsProcess::setInputFileOffset(size_t offset)
|
||||
{
|
||||
mOffset = offset;
|
||||
}
|
||||
|
||||
void RomfsProcess::setKeyset(const sKeyset* keyset)
|
||||
{
|
||||
mKeyset = keyset;
|
||||
}
|
||||
|
||||
void RomfsProcess::setCliOutputMode(CliOutputType type)
|
||||
{
|
||||
mCliOutputType = type;
|
||||
}
|
||||
|
||||
void RomfsProcess::setVerifyMode(bool verify)
|
||||
{
|
||||
mVerify = verify;
|
||||
}
|
||||
|
||||
void RomfsProcess::setMountPointName(const std::string& mount_name)
|
||||
{
|
||||
mMountName = mount_name;
|
||||
}
|
||||
|
||||
void RomfsProcess::setExtractPath(const std::string& path)
|
||||
{
|
||||
mExtract = true;
|
||||
mExtractPath = path;
|
||||
}
|
||||
|
||||
void RomfsProcess::setListFs(bool list_fs)
|
||||
{
|
||||
mListFs = list_fs;
|
||||
}
|
||||
|
||||
const RomfsProcess::sDirectory& RomfsProcess::getRootDir() const
|
||||
{
|
||||
return mRootDir;
|
||||
}
|
|
@ -0,0 +1,145 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include <fnd/types.h>
|
||||
#include <fnd/IFile.h>
|
||||
#include <fnd/MemoryBlob.h>
|
||||
#include <fnd/List.h>
|
||||
#include <nx/romfs.h>
|
||||
|
||||
#include "nstool.h"
|
||||
|
||||
class RomfsProcess
|
||||
{
|
||||
public:
|
||||
struct sDirectory;
|
||||
struct sFile;
|
||||
|
||||
struct sDirectory
|
||||
{
|
||||
std::string name;
|
||||
fnd::List<sDirectory> dir_list;
|
||||
fnd::List<sFile> file_list;
|
||||
|
||||
sDirectory& operator=(const sDirectory& other)
|
||||
{
|
||||
name = other.name;
|
||||
dir_list = other.dir_list;
|
||||
file_list = other.file_list;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const sDirectory& other) const
|
||||
{
|
||||
return (name == other.name) \
|
||||
&& (dir_list == other.dir_list) \
|
||||
&& (file_list == other.file_list);
|
||||
}
|
||||
|
||||
bool operator!=(const sDirectory& other) const
|
||||
{
|
||||
return !operator==(other);
|
||||
}
|
||||
|
||||
bool operator==(const std::string& other) const
|
||||
{
|
||||
return (name == other);
|
||||
}
|
||||
|
||||
bool operator!=(const std::string& other) const
|
||||
{
|
||||
return !operator==(other);
|
||||
}
|
||||
};
|
||||
|
||||
struct sFile
|
||||
{
|
||||
std::string name;
|
||||
uint64_t offset;
|
||||
uint64_t size;
|
||||
|
||||
sFile& operator=(const sFile& other)
|
||||
{
|
||||
name = other.name;
|
||||
offset = other.offset;
|
||||
size = other.size;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const sFile& other) const
|
||||
{
|
||||
return (name == other.name) \
|
||||
&& (offset == other.offset) \
|
||||
&& (size == other.size);
|
||||
}
|
||||
|
||||
bool operator!=(const sFile& other) const
|
||||
{
|
||||
return !operator==(other);
|
||||
}
|
||||
|
||||
bool operator==(const std::string& other) const
|
||||
{
|
||||
return (name == other);
|
||||
}
|
||||
|
||||
bool operator!=(const std::string& other) const
|
||||
{
|
||||
return !operator==(other);
|
||||
}
|
||||
};
|
||||
|
||||
RomfsProcess();
|
||||
|
||||
void process();
|
||||
|
||||
// generic
|
||||
void setInputFile(fnd::IFile& reader);
|
||||
void setInputFileOffset(size_t offset);
|
||||
void setKeyset(const sKeyset* keyset);
|
||||
void setCliOutputMode(CliOutputType type);
|
||||
void setVerifyMode(bool verify);
|
||||
|
||||
// romfs specific
|
||||
void setMountPointName(const std::string& mount_name);
|
||||
void setExtractPath(const std::string& path);
|
||||
void setListFs(bool list_fs);
|
||||
|
||||
const sDirectory& getRootDir() const;
|
||||
private:
|
||||
const std::string kModuleName = "RomfsProcess";
|
||||
static const size_t kFileExportBlockSize = 0x1000000;
|
||||
|
||||
fnd::IFile* mReader;
|
||||
size_t mOffset;
|
||||
const sKeyset* mKeyset;
|
||||
CliOutputType mCliOutputType;
|
||||
bool mVerify;
|
||||
|
||||
std::string mExtractPath;
|
||||
bool mExtract;
|
||||
std::string mMountName;
|
||||
bool mListFs;
|
||||
|
||||
size_t mDirNum;
|
||||
size_t mFileNum;
|
||||
nx::sRomfsHeader mHdr;
|
||||
fnd::MemoryBlob mDirNodes;
|
||||
fnd::MemoryBlob mFileNodes;
|
||||
sDirectory mRootDir;
|
||||
|
||||
inline nx::sRomfsDirEntry* get_dir_node(uint32_t offset) { return (nx::sRomfsDirEntry*)(mDirNodes.getBytes() + offset); }
|
||||
inline nx::sRomfsFileEntry* get_file_node(uint32_t offset) { return (nx::sRomfsFileEntry*)(mFileNodes.getBytes() + offset); }
|
||||
|
||||
|
||||
void printTab(size_t tab) const;
|
||||
void displayFile(const sFile& file, size_t tab) const;
|
||||
void displayDir(const sDirectory& dir, size_t tab) const;
|
||||
|
||||
void displayHeader();
|
||||
void displayFs();
|
||||
void extractFs();
|
||||
|
||||
bool validateHeaderLayout(const nx::sRomfsHeader* hdr) const;
|
||||
void importDirectory(uint32_t dir_offset, sDirectory& dir);
|
||||
void resolveRomfs();
|
||||
};
|
|
@ -3,7 +3,7 @@
|
|||
#include "UserSettings.h"
|
||||
#include "XciProcess.h"
|
||||
#include "PfsProcess.h"
|
||||
//#include "RomfsProcess.h"
|
||||
#include "RomfsProcess.h"
|
||||
//#include "NcaProcess.h"
|
||||
#include "NpdmProcess.h"
|
||||
|
||||
|
@ -54,17 +54,20 @@ int main(int argc, char** argv)
|
|||
}
|
||||
else if (user_set.getFileType() == FILE_ROMFS)
|
||||
{
|
||||
/*
|
||||
|
||||
RomfsProcess romfs;
|
||||
|
||||
romfs.setRomfsPath(user_set.getInputPath());
|
||||
romfs.setExtractPath(user_set.getFsPath());
|
||||
romfs.setKeyset(user_set.getKeyset());
|
||||
romfs.setInputFile(inputFile);
|
||||
romfs.setKeyset(&user_set.getKeyset());
|
||||
romfs.setCliOutputMode(user_set.getCliOutputType());
|
||||
romfs.setVerifyMode(user_set.isVerifyFile());
|
||||
|
||||
if (user_set.getFsPath().isSet)
|
||||
romfs.setExtractPath(user_set.getFsPath().var);
|
||||
romfs.setListFs(user_set.isListFs());
|
||||
|
||||
romfs.process();
|
||||
*/
|
||||
|
||||
}
|
||||
else if (user_set.getFileType() == FILE_NCA)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue