diff --git a/docs/file-formats.md b/docs/file-formats.md index fb096c8..2fa0c60 100644 --- a/docs/file-formats.md +++ b/docs/file-formats.md @@ -2,8 +2,220 @@ ## `book.bin` -![](./images/file-formats/book-bin.png) +### Version 3 + +ImHex Pattern: + +```c++ +import std.mem; +import std.string; +import std.core; + +// === Configuration === +#define EXPECTED_VERSION 3 +#define MAX_STRING_LENGTH 65535 + +// === String Structure === + +struct String { + u32 length [[hidden, comment("String byte length")]]; + if (length > MAX_STRING_LENGTH) { + std::warning(std::format("Unusually large string length: {} bytes", length)); + } + char data[length] [[comment("UTF-8 string data")]]; +} [[sealed, format("format_string"), comment("Length-prefixed UTF-8 string")]]; + +fn format_string(String s) { + return s.data; +}; + +// === Metadata Structure === + +struct Metadata { + String title [[comment("Book title")]]; + String author [[comment("Book author")]]; + String coverItemHref [[comment("Path to cover image")]]; + String textReferenceHref [[comment("Path to guided first text reference")]]; +} [[comment("Book metadata information")]]; + +// === Spine Entry Structure === + +struct SpineEntry { + String href [[comment("Resource path")]]; + u32 cumulativeSize [[comment("Cumulative size in bytes"), color("FF6B6B")]]; + s16 tocIndex [[comment("Index into TOC (-1 if none)"), color("4ECDC4")]]; +} [[comment("Spine entry defining reading order")]]; + +// === TOC Entry Structure === + +struct TocEntry { + String title [[comment("Chapter/section title")]]; + String href [[comment("Resource path")]]; + String anchor [[comment("Fragment identifier")]]; + u8 level [[comment("Nesting level (0-255)"), color("95E1D3")]]; + s16 spineIndex [[comment("Index into spine (-1 if none)"), color("F38181")]]; +} [[comment("Table of contents entry")]]; + +// === Book Bin Structure === + +struct BookBin { + // Header + u8 version [[comment("Format version"), color("FFD93D")]]; + + // Version validation + if (version != EXPECTED_VERSION) { + std::error(std::format("Unsupported version: {} (expected {})", version, EXPECTED_VERSION)); + } + + u32 lutOffset [[comment("Offset to lookup tables"), color("6BCB77")]]; + u16 spineCount [[comment("Number of spine entries"), color("4D96FF")]]; + u16 tocCount [[comment("Number of TOC entries"), color("FF6B9D")]]; + + // Metadata section + Metadata metadata [[comment("Book metadata")]]; + + // Validate LUT offset alignment + u32 currentOffset = $; + if (currentOffset != lutOffset) { + std::warning(std::format("LUT offset mismatch: expected 0x{:X}, got 0x{:X}", lutOffset, currentOffset)); + } + + // Lookup Tables + u32 spineLut[spineCount] [[comment("Spine entry offsets"), color("4D96FF")]]; + u32 tocLut[tocCount] [[comment("TOC entry offsets"), color("FF6B9D")]]; + + // Data Entries + SpineEntry spines[spineCount] [[comment("Spine entries (reading order)")]]; + TocEntry toc[tocCount] [[comment("Table of contents entries")]]; +}; + +// === File Parsing === + +BookBin book @ 0x00; + +// Validate we've consumed the entire file +u32 fileSize = std::mem::size(); +u32 parsedSize = $; + +if (parsedSize != fileSize) { + std::warning(std::format("Unparsed data detected: {} bytes remaining at offset 0x{:X}", fileSize - parsedSize, parsedSize)); +} +``` ## `section.bin` -![](./images/file-formats/section-bin.png) +### Version 8 + +ImHex Pattern: + +```c++ +import std.mem; +import std.string; +import std.core; + +// === Configuration === +#define EXPECTED_VERSION 8 +#define MAX_STRING_LENGTH 65535 + +// === String Structure === + +struct String { + u32 length [[hidden, comment("String byte length")]]; + if (length > MAX_STRING_LENGTH) { + std::warning(std::format("Unusually large string length: {} bytes", length)); + } + char data[length] [[comment("UTF-8 string data")]]; +} [[sealed, format("format_string"), comment("Length-prefixed UTF-8 string")]]; + +fn format_string(String s) { + return s.data; +}; + +// === Page Structure === + +enum StorageType : u8 { + PageLine = 1 +}; + +enum WordStyle : u8 { + REGULAR = 0, + BOLD = 1, + ITALIC = 2, + BOLD_ITALIC = 3 +}; + +enum BlockStyle : u8 { + JUSTIFIED = 0, + LEFT_ALIGN = 1, + CENTER_ALIGN = 2, + RIGHT_ALIGN = 3, +}; + +struct PageLine { + s16 xPos; + s16 yPos; + u16 wordCount; + String words[wordCount]; + u16 wordXPos[wordCount]; + WordStyle wordStyle[wordCount]; + BlockStyle blockStyle; +}; + +struct PageElement { + u8 pageElementType; + if (pageElementType == 1) { + PageLine pageLine [[inline]]; + } else { + std::error(std::format("Unknown page element type: {}", pageElementType)); + } +}; + +struct Page { + u16 elementCount; + PageElement elements[elementCount] [[inline]]; +}; + +// === Section Bin Structure === + +struct SectionBin { + // Header + u8 version [[comment("Format version"), color("FFD93D")]]; + + // Version validation + if (version != EXPECTED_VERSION) { + std::error(std::format("Unsupported version: {} (expected {})", version, EXPECTED_VERSION)); + } + + // Cache busting parameters + s32 fontId; + float lineCompression; + bool extraParagraphSpacing; + u16 viewportWidth; + u16 vieportHeight; + u16 pageCount; + u32 lutOffset; + + Page page[pageCount]; + + // Validate LUT offset alignment + u32 currentOffset = $; + if (currentOffset != lutOffset) { + std::warning(std::format("LUT offset mismatch: expected 0x{:X}, got 0x{:X}", lutOffset, currentOffset)); + } + + // Lookup Tables + u32 lut[pageCount]; +}; + +// === File Parsing === + +SectionBin book @ 0x00; + +// Validate we've consumed the entire file +u32 fileSize = std::mem::size(); +u32 parsedSize = $; + +if (parsedSize != fileSize) { + std::warning(std::format("Unparsed data detected: {} bytes remaining at offset 0x{:X}", fileSize - parsedSize, parsedSize)); +} +``` diff --git a/docs/images/file-formats/book-bin.png b/docs/images/file-formats/book-bin.png deleted file mode 100644 index 07d9c2e..0000000 Binary files a/docs/images/file-formats/book-bin.png and /dev/null differ diff --git a/docs/images/file-formats/section-bin.png b/docs/images/file-formats/section-bin.png deleted file mode 100644 index 9a9691c..0000000 Binary files a/docs/images/file-formats/section-bin.png and /dev/null differ