From 1a92fb22c983fc498e76512e07979c992b790efb Mon Sep 17 00:00:00 2001 From: Ivan Pavluk Date: Sun, 1 Aug 2021 04:13:12 +0700 Subject: [PATCH] add mpk unpack support --- .gitignore | 4 +++ CMakeLists.txt | 1 + include/impkfile.hpp | 34 ++++++++++++++++++++ src/impkfile.cpp | 76 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 115 insertions(+) create mode 100644 include/impkfile.hpp create mode 100644 src/impkfile.cpp diff --git a/.gitignore b/.gitignore index 3731949..3910af4 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,7 @@ include/npaversion.hpp *.dylib *.lib *.so + +src/parser.cpp +src/parser.hpp +src/lexer.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 75fc57c..c93a55e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,6 +62,7 @@ bison_target(parser ${CMAKE_SOURCE_DIR}/src/parser.y ${CMAKE_SOURCE_DIR}/src/par add_flex_bison_dependency(lexer parser) add_library(npa SHARED + src/impkfile.cpp src/inpafile.cpp src/npafile.cpp src/nsbmagic.cpp diff --git a/include/impkfile.hpp b/include/impkfile.hpp new file mode 100644 index 0000000..913c509 --- /dev/null +++ b/include/impkfile.hpp @@ -0,0 +1,34 @@ +#ifndef I_NIPA_FILE +#define I_NIPA_FILE + +#include "inpafile.hpp" + +class IMpkFile : public INpaFile +{ + struct + { + char Magic[6]; // M P K \0 \0 \0 + uint16_t Version; // \x02 \0 + uint32_t FileCount; + char Pad[0x34]; + } MPKHeader; +public: + struct MpkEntry : INpaFile::Entry + { + uint32_t Unk; + string Filename; + uint32_t FileID; + }; + + IMpkFile(const string& Name); + ~IMpkFile(); + + char* ReadFile(NpaIterator iter); + virtual char* ReadData(NpaIterator iter, uint32_t LocalOffset, uint32_t Size, void *(*Alloc)(size_t) = DefaultAlloc); + bool IsDirectory(NpaIterator iter); + +protected: + void ReadHeader(); +}; + +#endif diff --git a/src/impkfile.cpp b/src/impkfile.cpp new file mode 100644 index 0000000..c340fae --- /dev/null +++ b/src/impkfile.cpp @@ -0,0 +1,76 @@ +#include "impkfile.hpp" +#include "fscommon.hpp" +#include "buffer.hpp" +#include +#include +#include + +IMpkFile::IMpkFile(const string& Name) : INpaFile(Name) +{ + ReadHeader(); +} + +IMpkFile::~IMpkFile() +{ +} + +void IMpkFile::ReadHeader() +{ + uint32_t Size; + char* pData = fs::ReadFile(Name, Size); + if (!pData) + return; + + Npa::Buffer File(pData, Size); + File.Read(MPKHeader.Magic, 6); + assert(strncmp("MPK\x00\x00\x00", MPKHeader.Magic, 6) == 0); + + MPKHeader.Version = File.Read(); + MPKHeader.FileCount = File.Read(); + File.Read(MPKHeader.Pad, 0x34); + + char NameBuf[224]; + + for (uint32_t i = 0; i < MPKHeader.FileCount; ++i) + { + MpkEntry* MPKEntry = new MpkEntry; + MPKEntry->Unk = File.Read(); + MPKEntry->FileID = File.Read(); + MPKEntry->Offset = File.Read(); + MPKEntry->Size = File.Read(); + uint64_t Size2 = File.Read(); // ? + assert(("The second size has a hidden meaning?", MPKEntry->Size == Size2)); + File.Read(NameBuf, 224); + MPKEntry->Filename = string(NameBuf); + + string UtfPath = NpaFile::ToUtf8(MPKEntry->Filename); + boost::replace_all(UtfPath, "\\", "/"); + Registry[UtfPath] = MPKEntry; + } +} + + +char* IMpkFile::ReadFile(NpaIterator iter) +{ + return ReadData(iter, 0, ((MpkEntry*)iter->second)->Size); +} + +char* IMpkFile::ReadData(NpaIterator iter, uint32_t LocalOffset, uint32_t Size, void *(*Alloc)(size_t)) +{ + ifstream File(Name, ios::binary); + if (!File) + return nullptr; + + MpkEntry* MPKEntry = (MpkEntry*)iter->second; + uint8_t* buffer = new uint8_t[Size]; + + File.seekg(MPKEntry->Offset + LocalOffset); + File.read((char*)buffer, Size); + + return (char*)buffer; +} + +bool IMpkFile::IsDirectory(NpaIterator iter) +{ + return false; +}