private void ReadTSY1(BinaryReaderX br) { TSY1.Identifier = br.ReadBytes(4); TSY1.SectionSize = br.ReadUInt32(); TSY1.Unknown1 = br.ReadBytes(8); TSY1.Unknown2 = br.ReadBytes((int)TSY1.SectionSize); // Read in the entire section at once since we don't know what it's for PaddingSeek(br); }
public static string Extract(string filename, string path, bool overwrite = true) { string result = "Files successfully extracted."; if (File.Exists(filename) && new FileInfo(filename).Length > 0) { FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.None); BinaryReaderX br = new BinaryReaderX(fs); try { string magic = Encoding.ASCII.GetString(br.ReadBytes(4)); if (magic != "BG4\0") { throw new InvalidBG4Exception("The file provided is not a valid BG4 archive."); } ushort Constant1 = br.ReadUInt16(); ushort NumberOfHeaders = br.ReadUInt16(); uint SizeOfHeaders = br.ReadUInt32(); ushort NumberOfHeadersDerived = br.ReadUInt16(); ushort NumberOfHeadersMultiplier = br.ReadUInt16(); // Read in file headers List <FileEntry> entries = new List <FileEntry>(); FileEntry entry = new FileEntry(); for (int i = 0; i < NumberOfHeaders; i++) { uint offsetTemp = br.ReadUInt32(); if ((offsetTemp & 0x80000000) == 0x80000000) { entry.Compressed = true; } entry.Offset = entry.Compressed ? (offsetTemp ^ 0x80000000) : offsetTemp; entry.Size = br.ReadUInt32(); entry.Unknown1 = br.ReadUInt32(); entry.NameIndex = br.ReadUInt16(); if (entry.Unknown1 != 0xFFFFFFFF) { entries.Add(entry); } entry = new FileEntry(); } // Sort the file entries into NameIndex order entries.Sort(); // Read in file names bool eofn = false; List <string> filenames = new List <string>(); while (!eofn) { if (br.PeekString(2) == Encoding.ASCII.GetString(new byte[] { 0xFF, 0xFF })) { eofn = true; } else { bool eos = false; string name = string.Empty; while (!eos) { byte chr = br.ReadByte(); if (chr == 0x00) { eos = true; } else { name += (char)chr; } } if (name != "(invalid)") { filenames.Add(name); } } } // Extract! for (int i = 0; i < entries.Count; i++) { FileEntry fe = entries[i]; string extension = (!Regex.IsMatch(filenames[i], @"\..*?$") ? ".bin" : string.Empty); if (extension != string.Empty) { br.BaseStream.Seek(fe.Offset, SeekOrigin.Begin); magic = Encoding.ASCII.GetString(br.ReadBytes(8)); if (magic.StartsWith("MsgStdBn")) { extension = ".msbt"; } else if (magic.StartsWith("BCH")) { extension = ".bch"; } else if (magic.StartsWith("PTX")) { extension = ".ptx"; } // TODO: Add more known magic/extension pairs } Debug.Print("[" + fe.Offset.ToString("X8") + "] " + fe.NameIndex + " (" + fe.Unknown1 + ") " + filenames[i] + extension); FileInfo fi = new FileInfo(filename); FileStream fsr = new FileStream(Path.Combine(path, filenames[i] + extension), FileMode.Create, FileAccess.Write, FileShare.None); BinaryWriterX bw = new BinaryWriterX(fsr); br.BaseStream.Seek(fe.Offset, SeekOrigin.Begin); bw.Write(br.ReadBytes((int)fe.Size)); bw.Close(); } result = NumberOfHeaders + " header(s) were scanned and " + entries.Count + " files were successfully extracted!"; } catch (InvalidBG4Exception ibex) { result = ibex.Message; } catch (Exception ex) { result = ex.Message; } finally { br.Close(); } } return(result); }
private void ReadTXT2(BinaryReaderX br) { TXT2.Identifier = br.ReadBytes(4); TXT2.SectionSize = br.ReadUInt32(); TXT2.Unknown1 = br.ReadBytes(8); long startOfStrings = br.BaseStream.Position; TXT2.NumberOfStrings = br.ReadUInt32(); List <UInt32> offsets = new List <UInt32>(); for (int i = 0; i < TXT2.NumberOfStrings; i++) { offsets.Add(br.ReadUInt32()); } for (int i = 0; i < TXT2.NumberOfStrings; i++) { Entry entry = new Entry(); bool eos = false; UInt32 nextOffset = (i + 1 < offsets.Count) ? ((UInt32)startOfStrings + offsets[i + 1]) : ((UInt32)startOfStrings + TXT2.SectionSize); br.BaseStream.Seek(startOfStrings + offsets[i], SeekOrigin.Begin); List <byte> result = new List <byte>(); while (!eos) { if (br.BaseStream.Position == nextOffset || br.BaseStream.Position == Header.FileSize) { eos = true; } else { byte[] unichar = br.ReadBytes(2); if (Header.ByteOrderMark[0] == 0xFE) { Array.Reverse(unichar); } if (unichar[0] != 0x0 || unichar[1] != 0x0) { result.AddRange(unichar); } else { Value val = new Value(); val.Data = result.ToArray(); if (result.Count == 0) { val.Editable = false; } entry.Values.Add(val); result.Clear(); } } } // Strange extended string without null termination if (result.Count > 1) { Value finalVal = new Value(); finalVal.Data = result.ToArray(); finalVal.Editable = false; finalVal.NullTerminated = false; entry.Values.Add(finalVal); } entry.ID = i; TXT2.OriginalEntries.Add(entry); // Duplicate entries for editing Entry entryEdited = new Entry(); foreach (Value value in entry.Values) { Value val = new Value(); val.Data = value.Data; val.Editable = value.Editable; val.NullTerminated = value.NullTerminated; entryEdited.Values.Add(val); } entryEdited.Value = entry.Value; entryEdited.ID = entry.ID; TXT2.Entries.Add(entryEdited); } PaddingSeek(br); }
public MSBT(string filename) { File = new FileInfo(filename); if (File.Exists && filename.Length > 0) { FileStream fs = System.IO.File.Open(File.FullName, FileMode.Open, FileAccess.Read, FileShare.None); BinaryReaderX br = new BinaryReaderX(fs); // Initialize Members LBL1.Labels = new List <Entry>(); ATR1.Attributes = new List <UInt32>(); TXT2.OriginalEntries = new List <Entry>(); TXT2.Entries = new List <Entry>(); // Header Header.Identifier = br.ReadBytes(8); if (Encoding.ASCII.GetString(Header.Identifier) != "MsgStdBn") { throw new Exception("File is not a valid MSBT."); } Header.ByteOrderMark = br.ReadBytes(2); // Byte Order br.ByteOrder = Header.ByteOrderMark[0] == 0xFF ? ByteOrder.LittleEndian : ByteOrder.BigEndian; Header.Unknown1 = br.ReadUInt16(); Header.Unknown2 = br.ReadUInt16(); Header.NumberOfSections = br.ReadUInt16(); Header.Unknown3 = br.ReadUInt16(); Header.FileSizeOffset = (UInt32)br.BaseStream.Position; Header.FileSize = br.ReadUInt32(); Header.Unknown4 = br.ReadBytes(10); SectionOrder.Clear(); for (int i = 0; i < Header.NumberOfSections; i++) { // Section Detection if (br.PeekString() == "LBL1") { ReadLBL1(br); SectionOrder.Add("LBL1"); } else if (br.PeekString() == "NLI1") { ReadNLI1(br); SectionOrder.Add("NLI1"); } else if (br.PeekString() == "ATR1") { ReadATR1(br); SectionOrder.Add("ATR1"); } else if (br.PeekString() == "TSY1") { ReadTSY1(br); SectionOrder.Add("TSY1"); } else if (br.PeekString() == "TXT2") { ReadTXT2(br); SectionOrder.Add("TXT2"); } } br.Close(); } }
public MSBT(string filename = "null") { if (filename != "null") { File = new FileInfo(filename); if (File.Exists && filename.Length > 0) { FileStream fs = System.IO.File.Open(File.FullName, FileMode.Open, FileAccess.Read, FileShare.Read); BinaryReaderX br = new BinaryReaderX(fs); // Initialize Members LBL1.Groups = new List <Group>(); LBL1.Labels = new List <IEntry>(); TXT2.Strings = new List <IEntry>(); TXT2.OriginalStrings = new List <IEntry>(); // Header Header.Identifier = br.ReadString(8); if (Header.Identifier != "MsgStdBn") { throw new InvalidMSBTException("The file provided is not a valid MSBT file."); } // Byte Order Header.ByteOrderMark = br.ReadBytes(2); br.ByteOrder = Header.ByteOrderMark[0] > Header.ByteOrderMark[1] ? ByteOrder.LittleEndian : ByteOrder.BigEndian; Header.Unknown1 = br.ReadUInt16(); // Encoding Header.EncodingByte = (EncodingByte)br.ReadByte(); FileEncoding = (Header.EncodingByte == EncodingByte.UTF8 ? Encoding.UTF8 : Encoding.Unicode); Header.Unknown2 = br.ReadByte(); Header.NumberOfSections = br.ReadUInt16(); Header.Unknown3 = br.ReadUInt16(); Header.FileSizeOffset = (UInt32)br.BaseStream.Position; // Record offset for future use Header.FileSize = br.ReadUInt32(); Header.Unknown4 = br.ReadBytes(10); if (Header.FileSize != br.BaseStream.Length) { throw new InvalidMSBTException("The file provided is not a valid MSBT file."); } SectionOrder.Clear(); for (int i = 0; i < Header.NumberOfSections; i++) { switch (br.PeekString()) { case "LBL1": ReadLBL1(br); SectionOrder.Add("LBL1"); break; case "NLI1": ReadNLI1(br); SectionOrder.Add("NLI1"); break; case "ATO1": ReadATO1(br); SectionOrder.Add("ATO1"); break; case "ATR1": ReadATR1(br); SectionOrder.Add("ATR1"); break; case "TSY1": ReadTSY1(br); SectionOrder.Add("TSY1"); break; case "TXT2": ReadTXT2(br); SectionOrder.Add("TXT2"); break; } } br.Close(); } } else { // Initialize Members LBL1.Groups = new List <Group>(); LBL1.Labels = new List <IEntry>(); TXT2.Strings = new List <IEntry>(); TXT2.OriginalStrings = new List <IEntry>(); } }
private void ReadTXT2(BinaryReaderX br) { TXT2.Identifier = br.ReadString(4); TXT2.SectionSize = br.ReadUInt32(); TXT2.Padding1 = br.ReadBytes(8); long startOfStrings = br.BaseStream.Position; TXT2.NumberOfStrings = br.ReadUInt32(); List <UInt32> offsets = new List <UInt32>(); for (int i = 0; i < TXT2.NumberOfStrings; i++) { offsets.Add(br.ReadUInt32()); } for (int i = 0; i < TXT2.NumberOfStrings; i++) { String str = new String(); UInt32 nextOffset = (i + 1 < offsets.Count) ? ((UInt32)startOfStrings + offsets[i + 1]) : ((UInt32)startOfStrings + TXT2.SectionSize); br.BaseStream.Seek(startOfStrings + offsets[i], SeekOrigin.Begin); List <byte> result = new List <byte>(); while (br.BaseStream.Position < nextOffset && br.BaseStream.Position < Header.FileSize) { if (Header.EncodingByte == EncodingByte.UTF8) { result.Add(br.ReadByte()); } else { byte[] unichar = br.ReadBytes(2); if (br.ByteOrder == ByteOrder.BigEndian) { Array.Reverse(unichar); } result.AddRange(unichar); } } str.Value = result.ToArray(); str.Index = (uint)i; TXT2.OriginalStrings.Add(str); // Duplicate entries for editing String estr = new String(); estr.Value = str.Value; estr.Index = str.Index; TXT2.Strings.Add(estr); } // Tie in LBL1 labels foreach (Label lbl in LBL1.Labels) { lbl.String = TXT2.Strings[(int)lbl.Index]; } PaddingSeek(br); }
private void ReadTXT2(BinaryReaderX br) { TXT2.Identifier = br.ReadBytes(4); TXT2.SectionSize = br.ReadUInt32(); TXT2.Unknown1 = br.ReadBytes(8); long startOfStrings = br.BaseStream.Position; TXT2.NumberOfStrings = br.ReadUInt32(); List<UInt32> offsets = new List<UInt32>(); for (int i = 0; i < TXT2.NumberOfStrings; i++) offsets.Add(br.ReadUInt32()); for (int i = 0; i < TXT2.NumberOfStrings; i++) { Entry entry = new Entry(); bool eos = false; UInt32 nextOffset = (i + 1 < offsets.Count) ? ((UInt32)startOfStrings + offsets[i + 1]) : ((UInt32)startOfStrings + TXT2.SectionSize); br.BaseStream.Seek(startOfStrings + offsets[i], SeekOrigin.Begin); List<byte> result = new List<byte>(); while (!eos) { if (br.BaseStream.Position == nextOffset || br.BaseStream.Position == Header.FileSize) eos = true; else { byte[] unichar = br.ReadBytes(2); if (Header.ByteOrderMark[0] == 0xFE) Array.Reverse(unichar); if (unichar[0] != 0x0 || unichar[1] != 0x0) result.AddRange(unichar); else { Value val = new Value(); val.Data = result.ToArray(); if (result.Count == 0) val.Editable = false; entry.Values.Add(val); result.Clear(); } } } // Strange extended string without null termination if (result.Count > 1) { Value finalVal = new Value(); finalVal.Data = result.ToArray(); finalVal.Editable = false; finalVal.NullTerminated = false; entry.Values.Add(finalVal); } entry.Index = i; TXT2.OriginalEntries.Add(entry); // Duplicate entries for editing Entry entryEdited = new Entry(); foreach (Value value in entry.Values) { Value val = new Value(); val.Data = value.Data; val.Editable = value.Editable; val.NullTerminated = value.NullTerminated; entryEdited.Values.Add(val); } entryEdited.Value = entry.Value; entryEdited.Index = entry.Index; TXT2.Entries.Add(entryEdited); } PaddingSeek(br); }
private void ReadATR1(BinaryReaderX br) { ATR1.Identifier = br.ReadBytes(4); ATR1.SectionSize = br.ReadUInt32(); ATR1.Unknown1 = br.ReadBytes(8); ATR1.NumberOfAttributes = br.ReadUInt32(); ATR1.Unknown2 = br.ReadBytes((int)ATR1.SectionSize - sizeof(UInt32)); // Read in the rest of the section at once since we don't know what it's for PaddingSeek(br); }
private void ReadLBL1(BinaryReaderX br) { // TODO: Continue reverse engineering the LBL1 section because the magic value below shouldn't be the end game long offset = br.BaseStream.Position; LBL1.Identifier = br.ReadBytes(4); LBL1.SectionSize = br.ReadUInt32(); LBL1.Unknown1 = br.ReadBytes(8); LBL1.Unknown2 = br.ReadBytes(8); uint startOfLabels = 0x35C; // Magic LBL1 label start position LBL1.Unknown3 = br.ReadBytes((int)(startOfLabels - br.BaseStream.Position)); while (br.BaseStream.Position < (offset + LBL1.Identifier.Length + sizeof(UInt32) + LBL1.Unknown1.Length + LBL1.SectionSize)) { Entry lbl = new Entry(); lbl.Length = Convert.ToUInt32(br.ReadByte()); lbl.Value = br.ReadBytes((int)lbl.Length); lbl.Index = br.ReadInt32(); LBL1.Labels.Add(lbl); } HasLabels = LBL1.Labels.Count > 0; PaddingSeek(br); }
public MSBT(string filename) { File = new FileInfo(filename); if (File.Exists && filename.Length > 0) { FileStream fs = System.IO.File.Open(File.FullName, FileMode.Open, FileAccess.Read, FileShare.None); BinaryReaderX br = new BinaryReaderX(fs); // Initialize Members LBL1.Labels = new List<Entry>(); ATR1.Attributes = new List<UInt32>(); TXT2.OriginalEntries = new List<Entry>(); TXT2.Entries = new List<Entry>(); // Header Header.Identifier = br.ReadBytes(8); if (Encoding.ASCII.GetString(Header.Identifier) != "MsgStdBn") throw new InvalidMSBTException("The file provided is not a valid MSBT file."); Header.ByteOrderMark = br.ReadBytes(2); // Byte Order br.ByteOrder = Header.ByteOrderMark[0] > Header.ByteOrderMark[1] ? ByteOrder.LittleEndian : ByteOrder.BigEndian; Header.Unknown1 = br.ReadUInt16(); Header.Unknown2 = br.ReadUInt16(); Header.NumberOfSections = br.ReadUInt16(); Header.Unknown3 = br.ReadUInt16(); Header.FileSizeOffset = (UInt32)br.BaseStream.Position; Header.FileSize = br.ReadUInt32(); Header.Unknown4 = br.ReadBytes(10); if (Header.FileSize != br.BaseStream.Length) throw new InvalidMSBTException("The file provided is not a valid MSBT file."); SectionOrder.Clear(); for (int i = 0; i < Header.NumberOfSections; i++) { // Section Detection if (br.PeekString() == "LBL1") { ReadLBL1(br); SectionOrder.Add("LBL1"); } else if (br.PeekString() == "NLI1") { ReadNLI1(br); SectionOrder.Add("NLI1"); } else if (br.PeekString() == "ATR1") { ReadATR1(br); SectionOrder.Add("ATR1"); } else if (br.PeekString() == "TSY1") { ReadTSY1(br); SectionOrder.Add("TSY1"); } else if (br.PeekString() == "TXT2") { ReadTXT2(br); SectionOrder.Add("TXT2"); } } br.Close(); } }