// Copyright 2023 The LightningBolt Authors
// SPDX-License-Identifier: MIT
#include
#include
#include
namespace lightningbolt {
/// Elf structures, only applicable to Simpsons Skateboarding
namespace elf {
/// Table entry in the ELF. We use this to create file names.
struct [[gnu::packed]] BoltTableEntry {
/// Pointer to filename. Should be adjusted
u32 filenamePtr;
u16 entryId; // (GID >> 8) | ID
u16 groupId; // (entryId & 0xff00)
};
/// Offsets in the ELF to the table.
struct BoltTableOffsets {
u32 usTable;
};
/// Convert a address to ELF file offset.
constexpr u32 AddressToElfFileOffset(u32 address) {
constexpr u32 LoadAddress = 0x00100000;
constexpr u32 SectionOffset = 0x80;
return (address - LoadAddress) + SectionOffset;
}
static constexpr BoltTableOffsets BoltTableOffsets = { .usTable = AddressToElfFileOffset(0x0033d400) };
} // namespace elf
struct [[gnu::packed]] BoltGroupEntry {
u32 unk;
u32 fileSize;
u32 fileOffset;
u32 unk3; // name hash?
};
struct [[gnu::packed]] BoltGroupDescriptor {
u8 unk;
u8 unk2;
u8 unk3;
u8 entryCount;
u32 groupSize;
u32 groupOffset;
// PS2 pointer padding; bolt library stuffs something here
u32 pad;
u32 EntryCount() {
// Special case: 0x0 == 256 entries.
// I have NO idea why they did it like this,
// this really seems extra when they could have
// used a short field in the same exact space.
if(entryCount == 0x0)
return 256;
return entryCount;
}
std::span Entries(u8* base) { return { std::bit_cast(&base[groupOffset]), EntryCount() }; }
};
struct [[gnu::packed]] BoltLibraryHeader {
static constexpr char VALID_MAGIC[] = "BOLT";
char magic[4];
u8 unkmaybemagic[2]; // could be platform flags ?
u8 unk;
u8 unk2;
u8 unk3;
u8 unk4;
u8 unk5;
u8 groupCount;
u32 libSize;
std::span GroupDescriptors() {
// The group descriptors are after the primary library header
return { std::bit_cast(this + 1), groupCount };
}
inline bool Validate() const { return !std::memcmp(&magic[0], &VALID_MAGIC[0], sizeof(magic)); }
};
} // namespace lightningbolt