#pragma once
#include <whiteout/common_types.h>
#include <optional>
#include <span>
#include <vector>
namespace whiteout::storages::mpq {
enum class FileFlag : u32 {
None = 0,
kImplode = 0x00000100, kCompress = 0x00000200, kEncrypted = 0x00010000, kFixKey = 0x00020000, kPatchFile = 0x00100000, kSingleUnit = 0x01000000, kDeleteMarker = 0x02000000, kSectorCrc = 0x04000000, kExists = 0x80000000, };
inline FileFlag operator|(FileFlag a, FileFlag b) noexcept {
return static_cast<FileFlag>(static_cast<u32>(a) | static_cast<u32>(b));
}
inline FileFlag operator&(FileFlag a, FileFlag b) noexcept {
return static_cast<FileFlag>(static_cast<u32>(a) & static_cast<u32>(b));
}
inline FileFlag operator~(FileFlag a) noexcept {
return static_cast<FileFlag>(~static_cast<u32>(a));
}
inline FileFlag& operator|=(FileFlag& a, FileFlag b) noexcept {
a = a | b;
return a;
}
inline FileFlag& operator&=(FileFlag& a, FileFlag b) noexcept {
a = a & b;
return a;
}
inline bool hasFlag(FileFlag flags, FileFlag flag) noexcept {
return (flags & flag) != FileFlag::None;
}
struct BlockEntry {
u32 fileOffset = 0; u32 compressedSize = 0; u32 uncompressedSize = 0; FileFlag flags = FileFlag::None;
[[nodiscard]] bool exists() const {
return hasFlag(flags, FileFlag::kExists);
}
[[nodiscard]] bool isCompressed() const {
return hasFlag(flags, FileFlag::kCompress) || hasFlag(flags, FileFlag::kImplode);
}
[[nodiscard]] bool isEncrypted() const {
return hasFlag(flags, FileFlag::kEncrypted);
}
[[nodiscard]] bool hasFixKey() const {
return hasFlag(flags, FileFlag::kFixKey);
}
[[nodiscard]] bool isSingleUnit() const {
return hasFlag(flags, FileFlag::kSingleUnit);
}
[[nodiscard]] bool hasSectorCrc() const {
return hasFlag(flags, FileFlag::kSectorCrc);
}
};
static_assert(sizeof(BlockEntry) == 16, "BlockEntry must be exactly 16 bytes");
class BlockTable {
public:
BlockTable() = default;
bool parse(std::span<const u8> data, u32 count);
bool parseHiBlockTable(std::span<const u8> data, u32 count);
void createEmpty();
[[nodiscard]] u32 append(const BlockEntry& entry);
[[nodiscard]] const BlockEntry& entry(u32 index) const {
return m_entries[index];
}
[[nodiscard]] BlockEntry& entry(u32 index) {
return m_entries[index];
}
[[nodiscard]] u32 count() const {
return static_cast<u32>(m_entries.size());
}
[[nodiscard]] u64 fileOffset48(u32 index) const;
[[nodiscard]] std::vector<u8> serialize() const;
[[nodiscard]] std::vector<u8> serializeHiBlockTable() const;
[[nodiscard]] bool needsHiBlockTable() const;
private:
std::vector<BlockEntry> m_entries;
std::vector<u16> m_hiBlockOffsets; };
}