/// <summary> /// Reads a text entry of a Subtitle Packet from a Stream. /// </summary> /// <param name="Reader">The reader of the Stream where the data is located</param> /// <param name="Game">The game being tampered</param> /// <returns>The entry as a object</returns> public static SubtitlePacketText FromStream(EndianBinaryReader Reader, MGSGame Game) { SubtitlePacketText PacketText = new SubtitlePacketText(); PacketText.StartTime = Reader.ReadUInt32(); PacketText.EndTime = Reader.ReadUInt32(); uint Dummy = Reader.ReadUInt32(); ushort TextLength = Reader.ReadUInt16(); PacketText.LanguageId = Reader.ReadUInt16(); byte[] TextBuffer = new byte[TextLength - 0x10]; Reader.Read(TextBuffer, 0, TextBuffer.Length); PacketText.Text = MGSText.Buffer2Text(Unpad(TextBuffer), Game); PacketText.Text = PacketText.Text.Replace(Environment.NewLine, "\\n"); return(PacketText); }
/// <summary> /// Extracts the texts and other data inside the codec.dat file from MGS. /// </summary> /// <param name="Data">The Stream with the data to be extracted</param> /// <param name="OutputFolder">The output folder where the extracted data will be placed</param> public static void Extract(Stream Data, string OutputFolder, MGSGame Game) { if (Game == MGSGame.MGS3) { MGSText.Initialize(); } BinaryReader Reader = new BinaryReader(Data); List <uint> AddressTable = new List <uint>(); uint Delimiter = Reader.ReadUInt32(); Data.Seek(0, SeekOrigin.Begin); while (Data.Position < Data.Length) { uint Position = (uint)Data.Position; uint Value = Reader.ReadUInt32(); if (Value == Delimiter) { AddressTable.Add(Position); } } AddressTable.Add((uint)Data.Length); for (int Index = 0; Index < AddressTable.Count - 1; Index++) { string OutputPath = Path.Combine(OutputFolder, string.Format("Text_{0:D5}", Index)); if (!Directory.Exists(OutputPath)) { Directory.CreateDirectory(OutputPath); } uint HeaderLength = 0; Data.Seek(AddressTable[Index], SeekOrigin.Begin); while (Reader.ReadInt32() != -1) { HeaderLength += 4; } uint BaseOffset = (uint)Data.Position; uint ScriptOffset = Reader.ReadUInt32() + BaseOffset; uint DialogsTableOffset = Reader.ReadUInt32() + BaseOffset; uint DialogsTextOffset = Reader.ReadUInt32() + BaseOffset; uint ScriptHeaderOffset = Reader.ReadUInt32() + BaseOffset; uint Key = Reader.ReadUInt32(); //Read header (with script pointers) Data.Seek(AddressTable[Index], SeekOrigin.Begin); byte[] Header = new byte[HeaderLength]; Reader.Read(Header, 0, Header.Length); MGSCrypto Crypto = new MGSCrypto(Key); StringBuilder Text = new StringBuilder(); //Read texts if (DialogsTableOffset != DialogsTextOffset) { int TextIndex = 0; bool HasText = true; while (HasText) { Data.Seek(DialogsTableOffset + TextIndex++ *4, SeekOrigin.Begin); uint Offset = (Reader.ReadUInt32() & 0x7fffffff) + DialogsTextOffset; uint NextOffset = (Reader.ReadUInt32() & 0x7fffffff) + DialogsTextOffset; if (Data.Position > DialogsTextOffset) { NextOffset = ScriptHeaderOffset; HasText = false; } Data.Seek(Offset, SeekOrigin.Begin); byte[] TextBuffer = new byte[NextOffset - Offset]; Reader.Read(TextBuffer, 0, TextBuffer.Length); TextBuffer = UnpadText(Crypto.ProcessBuffer(TextBuffer)); Text.Append(MGSText.Buffer2Text(TextBuffer, Game)); Text.Append(TextSeparator); } } if (Game == MGSGame.MGS3) { //This is probably not a header, but I don't know what this data is, so... string ScriptHeaderFile = Path.Combine(OutputPath, "ScriptHeader.bin"); Data.Seek(ScriptHeaderOffset, SeekOrigin.Begin); uint ScriptHeaderLength = ScriptOffset - ScriptHeaderOffset; byte[] ScriptHeader = new byte[ScriptHeaderLength]; Reader.Read(ScriptHeader, 0, ScriptHeader.Length); File.WriteAllBytes(ScriptHeaderFile, ScriptHeader); } //Read script Data.Seek(ScriptOffset, SeekOrigin.Begin); uint ScriptLength = AddressTable[Index + 1] - ScriptOffset; byte[] Script = new byte[ScriptLength]; Reader.Read(Script, 0, Script.Length); string HeaderFile = Path.Combine(OutputPath, "Header.bin"); string TextFile = Path.Combine(OutputPath, "Text.txt"); string ScriptFile = Path.Combine(OutputPath, "Script.bin"); File.WriteAllBytes(HeaderFile, Header); File.WriteAllText(TextFile, Text.ToString()); File.WriteAllBytes(ScriptFile, Script); if (OnStatusChanged != null) { float Percentage = (float)(Index + 1) / (AddressTable.Count - 1); OnStatusChanged(Percentage); } } }