Files
2026-03-28 15:03:02 -04:00

199 lines
5.4 KiB
Plaintext

#ifndef _MESSAGESTUDIOBINARYTEXT
#define _MESSAGESTUDIOBINARYTEXT
struct MSBTHeader {
char magic[8];
Assert(magic == "MsgStdBn");
ushort bom <format=hex>;
//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]<hidden=true>;
};
struct TableHeader(string expectedMagic) {
char magic[4];
Assert(magic == expectedMagic);
uint tableSize;
byte padding[8]<hidden=true>;
};
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]<optimize=false,read=LabelEntryRead>;
}
}
while (ReadUByte(FTell()) == 0xAB) {
byte padding<hidden=true>;
}
};
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<optimize=false,read=AttributeEntryRead>;
}
}
while (ReadUByte(FTell()) == 0xAB) {
byte padding<hidden=true>;
}
};
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])<optimize=false,read=TextsEntryRead>;
}
TextsEntry text(header.tableSize - offset[i])<optimize=false,read=TextsEntryRead>;
while (ReadUByte(FTell()) == 0xAB) {
byte padding<hidden=true>;
}
};
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