#ifndef _MESSAGESTUDIOBINARYTEXT #define _MESSAGESTUDIOBINARYTEXT struct MSBTHeader { char magic[8]; Assert(magic == "MsgStdBn"); ushort bom ; //Assert(bom == 0xFEFF); // Big-Endian byte order //Let's check if (bom == 0xFFFE && isDKCTF) { LittleEndian(); } ushort unk1; ubyte maybeMajorVersion; ubyte maybeMinorVersion; ushort sectionCount; ushort unk3; uint fileSize; byte padding[10]; }; struct TableHeader(string expectedMagic) { char magic[4]; Assert(magic == expectedMagic); uint tableSize; byte padding[8]; }; struct LabelOffset { uint stringCount; uint stringOffset; }; struct LabelEntry { ubyte stringLength; char str[stringLength]; uint stringTableIndex; }; wstring LabelEntryRead(LabelEntry &le) { return le.str; } struct LabelsSection { TableHeader header("LBL1"); local int64 tableStart = FTell(); uint offsetCount; LabelOffset offset[offsetCount]; local uint i; for (i = 0; i < offsetCount; i++) { Assert(FTell() == tableStart + offset[i].stringOffset); if (offset[i].stringCount) { LabelEntry label[offset[i].stringCount]; } } while (ReadUByte(FTell()) == 0xAB) { byte padding; } }; struct AttributeEntry { wstring str; }; wstring AttributeEntryRead(AttributeEntry &ae) { return ae.str; } struct AttributesSection { TableHeader header("ATR1"); local int64 tableStart = FTell(); uint offsetCount; uint entrySize; // should always be 4 if (isDKCTF == 0) { uint offset[offsetCount]; local uint i; for (i = 0; i < offsetCount; i++) { Assert(FTell() == tableStart + offset[i]); AttributeEntry attribute; } } while (ReadUByte(FTell()) == 0xAB) { byte padding; } }; struct TextsEntry(int64 size) { wchar_t str[size / 2]; }; wstring TextsEntryRead(TextsEntry &te) { local wstring out; local uint i; for (i = 0; i < (sizeof te.str / 2); i++) { // MSBT includes "text commands" in strings, which are sections of binary // data with varying lengths. Parsing them is complicated, so for now we // just skip all characters below the printable range. Some random bytes // will still slip through. if (te.str[i] >= 0x20) { out += te.str[i]; } } return out; } struct TextsSection { TableHeader header("TXT2"); local int64 tableStart = FTell(); uint offsetCount; uint offset[offsetCount]; local uint i; // This is kind of hacky- these strings may contain null characters, so // we need to read between the offsets and stop at the end of the table. for (i = 0; i < offsetCount - 1; i++) { TextsEntry text(offset[i + 1] - offset[i]); } TextsEntry text(header.tableSize - offset[i]); while (ReadUByte(FTell()) == 0xAB) { byte padding; } }; struct Language (string expectedLanguage) { ChunkDescriptor languageChunkHeader; Assert(languageChunkHeader.id == expectedLanguage); // Each section here is heavily referenced from https://zeldamods.org/wiki/Msbt struct MSBTContents { MSBTHeader header; LabelsSection labels; AttributesSection attributes; TextsSection texts; if (isDKCTF) //Swap back { BigEndian(); } } contents; }; struct TableName { ChunkDescriptor tableNameChunkHeader; Assert(tableNameChunkHeader.id == "TBNM"); CStringFixed name; }; struct MessageStudioBinaryText(uint32 readerVersion, uint32 writerVersion) { Assert(readerVersion == writerVersion); if (isDKCTF == 1) { Language us_english("USEN"); Language us_french("USFR"); Language us_spanish("USSP"); Language eu_english("EUEN"); Language eu_french("EUFR"); Language eu_spanish("EUSP"); Language eu_german("EUGE"); Language eu_italian("EUIT"); Language jp_japanese("JPJP"); } else if (readerVersion == 10) { Language us_english("USEN"); Language eu_english("EUEN"); Language eu_french("EUFR"); Language us_french("USFR"); Language eu_spanish("EUSP"); Language eu_german("EUGE"); Language eu_italian("EUIT"); Language eu_dutch("EUDU"); Language jp_japanese("JPJP"); Language ko_korean("KOKO"); Language ch_traditionalchinese("CHTC"); Language ch_simplifiedchinese("CHSC"); Language us_spanish("USSP"); } else if (readerVersion == 16) { Language us_english("USEN"); Language eu_english("EUEN"); Language us_portuguese("USPO"); Language eu_french("EUFR"); Language us_french("USFR"); Language eu_spanish("EUSP"); Language us_spanish("USSP"); Language eu_german("EUGE"); Language eu_italian("EUIT"); Language eu_dutch("EUDU"); Language jp_japanese("JPJP"); Language ch_simplifiedchinese("CHSC"); Language ko_korean("KOKO"); Language ch_traditionalchinese("CHTC"); TableName tableName; } else { Assert(false, "Unsupported MSBT version!"); } }; #endif// _MESSAGESTUDIOBINARYTEXT