public BMG(string filename) { using (BinaryReaderX br = new BinaryReaderX(File.OpenRead(filename))) { br.BaseStream.Position = 8; if (br.ReadInt32() == br.BaseStream.Length) { br.ByteOrder = byteOrder = ByteOrder.LittleEndian; } else { br.ByteOrder = byteOrder = ByteOrder.BigEndian; } br.BaseStream.Position = 0; header = br.ReadStruct <MESGHeader>(); br.BaseStream.Position = 0x20; var strs = new List <string>(); for (int i = 0; i < header.sectionCount; i++) { br.BaseStream.Position = (br.BaseStream.Position + align - 1) & ~(align - 1); var magic = br.ReadString(4); var secSize = br.ReadInt32(); switch (magic) { //Text Index Table case "INF1": var itemCount = br.ReadInt16(); var itemLength = br.ReadInt16(); br.BaseStream.Position += 4; for (int j = 0; j < itemCount; j++) { items.Add(new Item { strOffset = br.ReadInt32(), attr = br.ReadBytes(itemLength - 4) }); } break; case "DAT1": if (items[0].strOffset == 2) { usedEncoding = Enc.UTF16; } else if (items[0].strOffset == 1) { usedEncoding = Enc.SJIS; } using (var br2 = new BinaryReaderX(new MemoryStream(br.ReadBytes(secSize - 8)))) { for (int j = 0; j < items.Count; j++) { br2.BaseStream.Position = items[j].strOffset; var str = GetString(br2.ReadBytes((j == items.Count - 1) ? (int)(br2.BaseStream.Length - br2.BaseStream.Position) : (int)(items[j + 1].strOffset - br2.BaseStream.Position))); strs.Add(str); } break; } case "MID1": midUsed = true; var idCount = br.ReadInt16(); midUnk1 = br.ReadInt16(); br.BaseStream.Position += 4; for (int j = 0; j < idCount; j++) { var id = br.ReadInt32(); Labels.Add(new Label { Name = "Entry" + id, Text = strs[j], TextID = id }); } break; } } if (Labels.Count <= 0) { for (int i = 0; i < strs.Count; i++) { Labels.Add(new Label { Name = "Entry" + i, Text = strs[i], TextID = i }); } } } }
public BMG(string filename) { using (BinaryReaderX br = new BinaryReaderX(File.OpenRead(filename))) { header = br.ReadStruct <MESGHeader>(); if (header.fileSize == br.BaseStream.Length) { br.ByteOrder = byteOrder = ByteOrder.LittleEndian; } else { br.ByteOrder = byteOrder = ByteOrder.BigEndian; br.BaseStream.Position = 0; header = br.ReadStruct <MESGHeader>(); // Reload the header now that the byte order is set. } br.BaseStream.Position = headerSize; switch (header.encoding) { case BmgEncoding.ASCII: encoding = Encoding.ASCII; break; case BmgEncoding.ShiftJIS: encoding = Encoding.GetEncoding("shift-jis"); break; case BmgEncoding.UTF16: encoding = byteOrder == ByteOrder.BigEndian ? Encoding.BigEndianUnicode : Encoding.Unicode; break; default: encoding = Encoding.Unicode; break; } // INF1 (Info) section must be loaded first to properly calculate the size of each DAT1 (data) entry. // I'm fairly certain the specification guarantees that the INF1 section will immediately follow the BMG header, // but better safe than sorry. It won't cause performance issues for files that follow the specification. do { // Since sections are 32-byte aligned, we can just search in 32 byte increments. if (br.ReadString(4) != "INF1") { br.BaseStream.Position += 0x1C; } else { break; } } while (br.BaseStream.Position < br.BaseStream.Length); // Parse the INF1 items. var infSectionSize = br.ReadUInt32(); var itemCount = br.ReadUInt16(); var itemSize = br.ReadUInt16(); br.BaseStream.Position += 4; for (var i = 0; i < itemCount; i++) { items.Add(new Item { strOffset = br.ReadInt32(), attr = br.ReadBytes(itemSize - 4) }); } // Reset the stream position to immediately after the header. br.BaseStream.Position = headerSize; var strs = new List <string>(); for (var i = 0; i < header.sectionCount - 1; i++) { br.BaseStream.Position = (br.BaseStream.Position + align) & ~align; var magic = br.ReadString(4); var secSize = br.ReadInt32(); switch (magic) { case "DAT1": using (var br2 = new BinaryReaderX(new MemoryStream(br.ReadBytes(secSize - 8)))) { for (var j = 0; j < items.Count; j++) { br2.BaseStream.Position = items[j].strOffset; var currentItem = items[j]; Item nextItem = null; // Skip any 0 offset entries. var idx = j + 1; while (idx++ < items.Count) { nextItem = items[j + 1]; if (nextItem.strOffset != 0) { break; } nextItem = null; } var size = (nextItem?.strOffset ?? (int)br.BaseStream.Length) - currentItem.strOffset; strs.Add(GetString(br2.ReadBytes(size))); } } break; case "MID1": midUsed = true; var idCount = br.ReadInt16(); midUnk1 = br.ReadInt16(); br.BaseStream.Position += 4; for (var j = 0; j < idCount; j++) { var id = br.ReadInt32(); Labels.Add(new Label { Name = "Entry" + id, Text = strs[j], TextID = id }); } break; } } if (Labels.Count <= 0) { for (int i = 0; i < strs.Count; i++) { Labels.Add(new Label { Name = "Entry" + i, Text = strs[i], TextID = i }); } } } }