From 1c71d69a84aed6ada14f997a79e5629d4be1a5f4 Mon Sep 17 00:00:00 2001 From: Joshua Goins Date: Wed, 9 Mar 2022 09:25:01 -0500 Subject: [PATCH] Add a fiin parser Don't know what this file format is actually used for, but it was fun to reverse engineer, and I don't think anyone has done it for this format yet! --- CMakeLists.txt | 4 +++- include/fiinparser.h | 40 +++++++++++++++++++++++++++++++++++++ src/fiinparser.cpp | 47 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 include/fiinparser.h create mode 100644 src/fiinparser.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 85b76ce..e22d809 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,7 +32,9 @@ set(SRC src/launcherwindow.cpp include/launcherwindow.h src/gamescopesettingswindow.cpp - include/gamescopesettingswindow.h) + include/gamescopesettingswindow.h + src/fiinparser.cpp + include/fiinparser.h) include(FetchContent) diff --git a/include/fiinparser.h b/include/fiinparser.h new file mode 100644 index 0000000..8e9a939 --- /dev/null +++ b/include/fiinparser.h @@ -0,0 +1,40 @@ +#pragma once + +#include +#include +#include + +// this is methods dedicated to parsing "fiin" files, commonly shown as "fileinfo.fiin" + +// header is 1024 bytes +// for some reason, they store unknown1 and unknown 2 in this weird format, +// unknown1 is capped at 256 (in decimal) and will overflow into unknown 2 +// for example, 1 is equal to unknown1 = 96 and unknown2 = 0 +// 96 / 1 == 1 +// if you have say, 14 entries, then unknown1 = 64 and unknown2 = 5 +// 5 (unknown2) * 256 = 1280 + 64 (unknown1) = 1344 +// 1344 / 96 = 14 +// i could've made a mistake and this is actually really common but i don't know +struct FileInfoHeader { + char magic[9]; + uint8_t dummy1[16]; + uint8_t unknown; // version? always seems to be 4 + uint8_t dummy2[2]; + uint8_t unknown1; + uint8_t unknown2; + uint8_t dummy[994]; +}; + +// each entry is 96 bytes +struct FileInfoEntry { + uint8_t dummy[8]; // length of file name in some format + char str[64]; // simple \0 encoded string + uint8_t dummy2[24]; // sha1 +}; + +struct FileInfo { + FileInfoHeader header; + std::vector entries; +}; + +FileInfo readFileInfo(const std::string_view path); \ No newline at end of file diff --git a/src/fiinparser.cpp b/src/fiinparser.cpp new file mode 100644 index 0000000..5bbced8 --- /dev/null +++ b/src/fiinparser.cpp @@ -0,0 +1,47 @@ +#include "fiinparser.h" + +#include +#include + +FileInfo readFileInfo(const std::string_view path) { + FILE* file = fopen(path.data(), "rb"); + if(!file) { + qInfo() << "Failed to read file info " << path.data(); + return {}; + } + + FileInfo info; + fread(&info.header, sizeof info.header, 1, file); + + char magic[9] = "FileInfo"; + if(strcmp(info.header.magic, magic) != 0) + qInfo() << "Invalid magic for fileinfo."; + else + qInfo() << "Got matching magic:" << info.header.magic; + + qInfo() << "unknown (version?) = " << info.header.unknown; + qInfo() << "unknown1 = " << info.header.unknown1; + qInfo() << "unknown2 = " << info.header.unknown2; + + int overflow = info.header.unknown2; + int extra = overflow * 256; + int first = info.header.unknown1 / 96; + int first2 = extra / 96; + int actualEntries = first + first2 + 1; // is this 1 really needed? lol + + qInfo() << "Guessed number of entries: " << actualEntries; + + int numEntries = actualEntries; + for(int i = 0; i < numEntries; i++) { + FileInfoEntry entry; + fread(&entry, sizeof entry, 1, file); + + info.entries.push_back(entry); + + qDebug() << entry.str; + } + + fclose(file); + + return info; +} \ No newline at end of file