#pragma once
#include <whiteout/common_types.h>
#include <array>
#include <optional>
#include <span>
#include <string>
#include <utility>
#include <vector>
namespace whiteout::storages::mpq {
static constexpr u32 kMpqMagic = 0x1A51504D;
static constexpr u32 kMpqUserDataMagic = 0x1B51504D;
static constexpr u32 kHeaderSearchAlignment = 0x200;
struct MpqHeader {
u32 magic = kMpqMagic;
u32 headerSize = 32;
u32 archiveSize = 0; u16 formatVersion = 0; u16 sectorSizeShift = 3; u32 hashTableOffset = 0;
u32 blockTableOffset = 0;
u32 hashTableEntries = 0;
u32 blockTableEntries = 0;
u64 hiBlockTableOffset = 0;
u16 hashTableOffsetHi = 0;
u16 blockTableOffsetHi = 0;
u64 archiveSize64 = 0;
u64 betTableOffset = 0;
u64 hetTableOffset = 0;
u64 hashTableSize64 = 0;
u64 blockTableSize64 = 0;
u64 hiBlockTableSize64 = 0;
u64 hetTableSize64 = 0;
u64 betTableSize64 = 0;
u32 rawChunkSize = 0;
std::array<u8, 16> blockTableMd5{};
std::array<u8, 16> hashTableMd5{};
std::array<u8, 16> hiBlockTableMd5{};
std::array<u8, 16> betTableMd5{};
std::array<u8, 16> hetTableMd5{};
std::array<u8, 16> mpqHeaderMd5{};
[[nodiscard]] u64 hashTableByteOffset() const {
return hashTableOffset | (static_cast<u64>(hashTableOffsetHi) << 32);
}
[[nodiscard]] u64 blockTableByteOffset() const {
return blockTableOffset | (static_cast<u64>(blockTableOffsetHi) << 32);
}
[[nodiscard]] u32 sectorSize() const {
return 512u << sectorSizeShift;
}
};
struct UserData {
u32 magic = kMpqUserDataMagic;
u32 userDataSize = 0; u32 headerOffset = 0; u32 userDataHeaderSize = 0;
std::vector<u8> data; };
struct HeaderParseResult {
MpqHeader header;
size_t archiveOffset = 0; std::optional<UserData> userData;
};
[[nodiscard]] std::optional<HeaderParseResult> findAndParseHeader(std::span<const u8> fileData);
[[nodiscard]] MpqHeader buildHeader(u16 formatVersion, u32 hashTableSize, u16 sectorSizeShift);
[[nodiscard]] u32 nextPowerOf2(u32 v);
}