2023-11-19 20:21:56 -05:00
|
|
|
// Copyright 2023 The LightningBolt Authors
|
|
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
|
2023-11-19 06:19:15 -05:00
|
|
|
#include <base/Types.hpp>
|
|
|
|
#include <cstring>
|
|
|
|
#include <span>
|
|
|
|
|
|
|
|
namespace lightningbolt {
|
|
|
|
|
2023-11-21 20:33:26 -05:00
|
|
|
/// Elf structures, only applicable to Simpsons Skateboarding
|
2023-11-19 06:19:15 -05:00
|
|
|
namespace elf {
|
|
|
|
|
2023-11-19 20:24:40 -05:00
|
|
|
/// Table entry in the ELF. We use this to create file names.
|
2023-11-19 06:19:15 -05:00
|
|
|
struct [[gnu::packed]] BoltTableEntry {
|
|
|
|
/// Pointer to filename. Should be adjusted
|
|
|
|
u32 filenamePtr;
|
|
|
|
u16 entryId; // (GID >> 8) | ID
|
|
|
|
u16 groupId; // (entryId & 0xff00)
|
|
|
|
};
|
|
|
|
|
2023-11-19 20:24:40 -05:00
|
|
|
/// Offsets in the ELF to the table.
|
|
|
|
struct BoltTableOffsets {
|
|
|
|
u32 usTable;
|
|
|
|
};
|
2023-11-19 06:19:15 -05:00
|
|
|
|
2023-11-19 20:24:40 -05:00
|
|
|
/// Convert a address to ELF file offset.
|
|
|
|
constexpr u32 AddressToElfFileOffset(u32 address) {
|
|
|
|
constexpr u32 LoadAddress = 0x00100000;
|
|
|
|
constexpr u32 SectionOffset = 0x80;
|
|
|
|
return (address - LoadAddress) + SectionOffset;
|
|
|
|
}
|
2023-11-19 06:19:15 -05:00
|
|
|
|
2023-11-19 20:24:40 -05:00
|
|
|
static constexpr BoltTableOffsets BoltTableOffsets = { .usTable = AddressToElfFileOffset(0x0033d400) };
|
2023-11-19 06:19:15 -05:00
|
|
|
|
|
|
|
} // 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;
|
|
|
|
|
2023-11-19 20:24:40 -05:00
|
|
|
// PS2 pointer padding; bolt library stuffs something here
|
|
|
|
u32 pad;
|
2023-11-19 06:53:11 -05:00
|
|
|
|
2023-11-19 06:19:15 -05:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2023-11-19 06:53:11 -05:00
|
|
|
std::span<BoltGroupEntry> Entries(u8* base) { return { std::bit_cast<BoltGroupEntry*>(&base[groupOffset]), EntryCount() }; }
|
2023-11-19 06:19:15 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
struct [[gnu::packed]] BoltLibraryHeader {
|
|
|
|
static constexpr char VALID_MAGIC[] = "BOLT\r\n";
|
|
|
|
char magic[6];
|
|
|
|
|
|
|
|
u8 unk;
|
|
|
|
u8 unk2;
|
|
|
|
|
|
|
|
u8 unk3;
|
|
|
|
u8 unk4;
|
|
|
|
u8 unk5;
|
|
|
|
u8 groupCount;
|
|
|
|
|
|
|
|
u32 libSize;
|
|
|
|
|
|
|
|
std::span<BoltGroupDescriptor> GroupDescriptors() {
|
|
|
|
// The group descriptors are after the primary library header
|
|
|
|
return { std::bit_cast<BoltGroupDescriptor*>(this + 1), groupCount };
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool Validate() const { return !std::memcmp(&magic[0], &VALID_MAGIC[0], sizeof(magic)); }
|
|
|
|
};
|
|
|
|
|
2023-11-19 20:24:40 -05:00
|
|
|
} // namespace lightningbolt
|