Example #1
0
 /// <summary>
 ///     Extracts the texts and other data inside the codec.dat file from MGS.
 /// </summary>
 /// <param name="Data">The full path to the file 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(string Data, string OutputFolder, MGSGame Game)
 {
     using (MemoryStream Input = new MemoryStream(File.ReadAllBytes(Data)))
     {
         Extract(Input, OutputFolder, Game);
     }
 }
Example #2
0
 /// <summary>
 ///     Creates a codec.dat file from a folder with the extracted data.
 /// </summary>
 /// <param name="Data">The full path to the output file where the newly created data will be placed</param>
 /// <param name="InputFolder">The input folder with the extracted data</param>
 public static void Create(string Data, string InputFolder, MGSGame Game)
 {
     using (FileStream Output = new FileStream(Data, FileMode.Create))
     {
         Create(Output, InputFolder, Game);
     }
 }
Example #3
0
        /// <summary>
        ///     Extracts the subtitles from a movie.dat.
        /// </summary>
        /// <param name="Movie">The movie.dat file path</param>
        /// <param name="Output">The output folder</param>
        /// <param name="Game">The game being tampered (MGS3 or MGS4)</param>
        private static void Extract(string Movie, string Output, MGSGame Game)
        {
            Directory.CreateDirectory(Output);
            MGSText.Initialize();

            using (FileStream Input = new FileStream(Movie, FileMode.Open))
            {
                MovieSubtitle      Out    = new MovieSubtitle();
                EndianBinaryReader Reader = null;

                switch (Game)
                {
                case MGSGame.MGSTS:
                    Reader = new EndianBinaryReader(Input, Endian.Big);
                    Game   = MGSGame.MGS3;
                    break;

                case MGSGame.MGS3: Reader = new EndianBinaryReader(Input, Endian.Little); break;

                case MGSGame.MGS4: Reader = new EndianBinaryReader(Input, Endian.Big); break;
                }

                int Index = 0;
                while (Input.Position < Input.Length)
                {
                    StreamPacket Packet = StreamPacket.FromStream(Reader, Game);

                    switch (Packet.Type)
                    {
                    case PacketType.Subtitle: Out.Subtitles.Add((SubtitlePacket)Packet); break;

                    case PacketType.EndOfStream:
                        string XmlName  = string.Format("Subtitle_{0:D5}.xml", Index++);
                        string FileName = Path.Combine(Output, XmlName);

                        XmlSerializerNamespaces NameSpaces = new XmlSerializerNamespaces();
                        NameSpaces.Add(string.Empty, string.Empty);
                        XmlWriterSettings Settings = new XmlWriterSettings
                        {
                            Encoding = Encoding.UTF8,
                            Indent   = true
                        };

                        XmlSerializer Serializer = new XmlSerializer(typeof(MovieSubtitle));
                        using (FileStream OutputStream = new FileStream(FileName, FileMode.Create))
                        {
                            XmlWriter Writer = XmlWriter.Create(OutputStream, Settings);
                            Serializer.Serialize(Writer, Out, NameSpaces);
                        }

                        Out.Subtitles.Clear();
                        break;
                    }

                    ReportProgress((float)Input.Position / Input.Length);
                }
            }
        }
Example #4
0
        /// <summary>
        ///     Writes a Packet to a Stream.
        /// </summary>
        /// <param name="Writer">The writer of the output Stream</param>
        /// <param name="PacketText">The packet to be written</param>
        /// <param name="Game">The game being tampered</param>
        public static void ToStream(EndianBinaryWriter Writer, StreamPacket Packet, MGSGame Game)
        {
            switch (Packet.Type)
            {
            case PacketType.Subtitle: SubtitlePacket.ToStream(Writer, (SubtitlePacket)Packet, Game); break;

            case PacketType.EndOfStream: EndOfStreamPacket.ToStream(Writer, (EndOfStreamPacket)Packet); break;

            case PacketType.Raw: RawPacket.ToStream(Writer, (RawPacket)Packet); break;
            }
        }
Example #5
0
        public static string Buffer2Text(byte[] Data, MGSGame Game)
        {
            switch (Game)
            {
            case MGSGame.MGS3:
                StringBuilder Output = new StringBuilder();

                for (int Index = 0; Index < Data.Length; Index++)
                {
                    if (Data[Index] < 0x20 || Data[Index] > 0x7e)
                    {
                        if (Data[Index] == 0xa)
                        {
                            Output.Append(Environment.NewLine);
                        }
                        else if (Data[Index] == 0)
                        {
                            Output.Append("[end]");
                        }
                        else
                        {
                            int Value = Data[Index];
                            if (Index + 1 < Data.Length)
                            {
                                Value = (Value << 8) | Data[++Index];
                            }

                            if (Table[Value] == null)
                            {
                                Output.Append("\\x" + Value.ToString("X4"));
                            }
                            else
                            {
                                Output.Append(Table[Value]);
                            }
                        }
                    }
                    else
                    {
                        Output.Append((char)Data[Index]);
                    }
                }

                return(Output.ToString());

            case MGSGame.MGS4: return(MGS2Text(Encoding.UTF8.GetString(Data)));
            }

            return(null);
        }
Example #6
0
        /// <summary>
        ///     Reads a 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 packet as a object</returns>
        public static StreamPacket FromStream(EndianBinaryReader Reader, MGSGame Game)
        {
            uint StreamId = Reader.ReadUInt32() & 0xff;

            Reader.Seek(-4, SeekOrigin.Current);

            switch (StreamId)
            {
            case 4: return(SubtitlePacket.FromStream(Reader, Game));

            case 0xf0: return(EndOfStreamPacket.FromStream(Reader));

            default: return(RawPacket.FromStream(Reader));
            }
        }
Example #7
0
        public static byte[] Text2Buffer(string Text, MGSGame Game)
        {
            switch (Game)
            {
            case MGSGame.MGS3:
                Text = Text2MGS(Text);

                using (MemoryStream Output = new MemoryStream())
                {
                    for (int Index = 0; Index < Text.Length; Index++)
                    {
                        if (Index < Text.Length - 1 && Text.Substring(Index, 2) == "\\x")
                        {
                            string Hex   = Text.Substring(Index + 2, 4);
                            ushort Value = ushort.Parse(Hex, NumberStyles.HexNumber);
                            Output.WriteByte((byte)(Value >> 8));
                            Output.WriteByte((byte)Value);
                            Index += 5;
                        }
                        else
                        {
                            bool InRange = Text[Index] < 0x20 || Text[Index] > 0x7e;
                            if (InRange && Text[Index] != 0 && Text[Index] != 0xa)
                            {
                                int Value = Array.IndexOf(Table, Text.Substring(Index, 1));

                                if (Value > -1)
                                {
                                    Output.WriteByte((byte)(Value >> 8));
                                    Output.WriteByte((byte)Value);
                                }
                            }
                            else
                            {
                                Output.WriteByte((byte)Text[Index]);
                            }
                        }
                    }

                    return(Output.ToArray());
                }

            case MGSGame.MGS4: return(Encoding.UTF8.GetBytes(Text2MGS(Text)));
            }

            return(null);
        }
Example #8
0
        /// <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);
        }
Example #9
0
        /// <summary>
        ///     Reads 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 packet as a object</returns>
        public new static SubtitlePacket FromStream(EndianBinaryReader Reader, MGSGame Game)
        {
            SubtitlePacket Packet       = new SubtitlePacket();
            long           BasePosition = Reader.BaseStream.Position;

            Packet.StreamId = Reader.ReadUInt32();
            uint PacketLength = Reader.ReadUInt32();
            long EndPosition  = BasePosition + PacketLength;

            Packet.BaseStartTime = Reader.ReadUInt32();
            uint Dummy      = Reader.ReadUInt32();
            uint DataLength = Reader.ReadUInt32();

            while (Reader.BaseStream.Position + 0x10 < EndPosition)
            {
                Packet.Texts.Add(SubtitlePacketText.FromStream(Reader, Game));
            }

            Reader.Seek(EndPosition, SeekOrigin.Begin);

            return(Packet);
        }
Example #10
0
        /// <summary>
        ///     Inserts extracted subtitles into a movie.dat.
        /// </summary>
        /// <param name="Movie">The movie.dat file path</param>
        /// <param name="Input">The input folder with subtitles in XML</param>
        /// <param name="Game">The game being tampered (MGS3 or MGS4)</param>
        private static void Insert(string Movie, string Input, MGSGame Game)
        {
            string[] Files = Directory.GetFiles(Input);
            MGSText.Initialize();

            string     NewFile = Path.GetTempFileName();
            FileStream In      = new FileStream(Movie, FileMode.Open);
            FileStream Out     = new FileStream(NewFile, FileMode.Create);

            Endian Endian = Endian.Default;

            switch (Game)
            {
            case MGSGame.MGSTS:
                Endian = Endian.Big;
                Game   = MGSGame.MGS3;
                break;

            case MGSGame.MGS3: Endian = Endian.Little; break;

            case MGSGame.MGS4: Endian = Endian.Big; break;
            }

            EndianBinaryReader Reader = new EndianBinaryReader(In, Endian);
            EndianBinaryWriter Writer = new EndianBinaryWriter(Out, Endian);

            int           Index    = 0;
            int           SubIndex = 0;
            MovieSubtitle Subtitle = GetSubtitle(Files[0]);

            while (In.Position < In.Length)
            {
                StreamPacket Packet = StreamPacket.FromStream(Reader, Game);

                switch (Packet.Type)
                {
                case PacketType.Subtitle: SubtitlePacket.ToStream(Writer, Subtitle.Subtitles[SubIndex++], Game); break;

                case PacketType.EndOfStream:
                    if (++Index < Files.Length)
                    {
                        Subtitle = GetSubtitle(Files[Index]);
                    }
                    SubIndex = 0;
                    break;
                }

                if (Packet.Type != PacketType.Subtitle)
                {
                    StreamPacket.ToStream(Writer, Packet, Game);
                }

                ReportProgress((float)In.Position / In.Length);
            }

            In.Close();
            Out.Close();

            File.Delete(Movie);
            File.Move(NewFile, Movie);
            File.Delete(NewFile);
        }
Example #11
0
        /// <summary>
        ///     Writes a text entry of a Subtitle Packet to a Stream.
        /// </summary>
        /// <param name="Writer">The writer of the output Stream</param>
        /// <param name="PacketText">The text entry to be written</param>
        /// <param name="Game">The game being tampered</param>
        public static void ToStream(EndianBinaryWriter Writer, SubtitlePacketText PacketText, MGSGame Game)
        {
            byte[] TextBuffer = new byte[0];

            if (PacketText.Text != null)
            {
                PacketText.Text = PacketText.Text.Replace("\\n", Environment.NewLine);
                TextBuffer      = MGSText.Text2Buffer(PacketText.Text, Game);
            }

            int Length = TextBuffer.Length + 1;

            if ((Length & 3) != 0)
            {
                Length = (Length & ~3) + 4;
            }

            Writer.Write(PacketText.StartTime);
            Writer.Write(PacketText.EndTime);
            Writer.Write(0u);
            Writer.Write((ushort)(Length + 0x10));
            Writer.Write((ushort)PacketText.LanguageId);

            Writer.Write(TextBuffer);
            Writer.Write((byte)0);

            while ((Writer.BaseStream.Position & 3) != 0)
            {
                Writer.Write((byte)0);
            }
        }
Example #12
0
        /// <summary>
        ///     Writes a Subtitle Packet to a Stream.
        /// </summary>
        /// <param name="Writer">The writer of the output Stream</param>
        /// <param name="PacketText">The packet to be written</param>
        /// <param name="Game">The game being tampered</param>
        public static void ToStream(EndianBinaryWriter Writer, SubtitlePacket Packet, MGSGame Game)
        {
            using (MemoryStream Content = new MemoryStream())
            {
                EndianBinaryWriter CWriter = new EndianBinaryWriter(Content, Writer.Endian);

                foreach (SubtitlePacketText Text in Packet.Texts)
                {
                    SubtitlePacketText.ToStream(CWriter, Text, Game);
                }

                int Length = (int)Content.Length + 0x14 + 1;
                if ((Length & 0xf) != 0)
                {
                    Length = (Length & ~0xf) + 0x10;
                }

                Writer.Write(Packet.StreamId);
                Writer.Write(Length);

                Writer.Write(Packet.BaseStartTime);
                Writer.Write(0u);
                Writer.Write((uint)Content.Length);

                Writer.Write(Content.ToArray());
                Writer.Write((byte)0);

                while ((Writer.BaseStream.Position & 0xf) != 0)
                {
                    Writer.Write((byte)0);
                }
            }
        }
Example #13
0
        /// <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);
                }
            }
        }
Example #14
0
        /// <summary>
        ///     Creates a codec.dat file from a folder with the extracted data.
        /// </summary>
        /// <param name="Data">The output stream where the newly created data will be placed</param>
        /// <param name="InputFolder">The input folder with the extracted data</param>
        public static void Create(Stream Data, string InputFolder, MGSGame Game)
        {
            if (Game == MGSGame.MGS3)
            {
                MGSText.Initialize();
            }
            BinaryWriter Writer = new BinaryWriter(Data);

            string[] Folders = Directory.GetDirectories(InputFolder);

            int CurrentFolder = 0;

            foreach (string Folder in Folders)
            {
                string HeaderFile = Path.Combine(Folder, "Header.bin");
                string TextFile   = Path.Combine(Folder, "Text.txt");
                string ScriptFile = Path.Combine(Folder, "Script.bin");

                if (File.Exists(HeaderFile) && File.Exists(TextFile) && File.Exists(ScriptFile))
                {
                    const uint Key    = 0x4805d94d;
                    MGSCrypto  Crypto = new MGSCrypto(Key);
                    Writer.Write(File.ReadAllBytes(HeaderFile));
                    Writer.Write(-1);

                    byte[] ScriptHeader       = null;
                    uint   ScriptHeaderLength = 0;
                    if (Game == MGSGame.MGS3)
                    {
                        string ScriptHeaderFile = Path.Combine(Folder, "ScriptHeader.bin");

                        if (File.Exists(ScriptHeaderFile))
                        {
                            ScriptHeader       = File.ReadAllBytes(ScriptHeaderFile);
                            ScriptHeaderLength = (uint)ScriptHeader.Length;
                        }
                    }

                    using (MemoryStream TextBlock = new MemoryStream())
                    {
                        BinaryWriter TextWriter = new BinaryWriter(TextBlock);

                        string   Text           = File.ReadAllText(TextFile);
                        string[] Texts          = Text.Split(new string[] { TextSeparator }, StringSplitOptions.RemoveEmptyEntries);
                        int      BaseTextOffset = 0x14 + Texts.Length * 4;
                        int      TextOffset     = 0;

                        TextBlock.Seek(BaseTextOffset, SeekOrigin.Begin);
                        for (int Index = 0; Index < Texts.Length; Index++)
                        {
                            TextBlock.Seek(0x14 + Index * 4, SeekOrigin.Begin);
                            TextWriter.Write((uint)(TextOffset | 0x80000000));

                            TextBlock.Seek(BaseTextOffset + TextOffset, SeekOrigin.Begin);
                            byte[] Buffer = MGSText.Text2Buffer(Texts[Index], Game);
                            TextWriter.Write(Crypto.ProcessBuffer(Buffer));
                            TextOffset += Buffer.Length;
                        }

                        int PadIndex = 0;
                        while ((TextBlock.Position & 3) != 0)
                        {
                            byte Encrypted = Crypto.ProcessByte((byte)Padding[PadIndex++]);
                            TextBlock.WriteByte(Encrypted);
                        }

                        uint ScriptHeaderOffset = (uint)TextBlock.Position;
                        uint ScriptOffset       = ScriptHeaderOffset + ScriptHeaderLength;

                        TextBlock.Seek(0, SeekOrigin.Begin);
                        TextWriter.Write(ScriptOffset);
                        TextWriter.Write(0x14);
                        TextWriter.Write(BaseTextOffset);
                        TextWriter.Write(ScriptHeaderOffset);
                        TextWriter.Write(Key);

                        Writer.Write(TextBlock.ToArray());
                    }

                    if (ScriptHeaderLength > 0)
                    {
                        Writer.Write(ScriptHeader);
                    }
                    Writer.Write(File.ReadAllBytes(ScriptFile));

                    while ((Data.Position & 0xf) != 0)
                    {
                        Data.WriteByte(0);
                    }
                }

                if (OnStatusChanged != null)
                {
                    float Percentage = (float)++CurrentFolder / Folders.Length;
                    OnStatusChanged(Percentage);
                }
            }
        }