Пример #1
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);
            }
        }
Пример #2
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);
                }
            }
        }
Пример #3
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);
        }
Пример #4
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);
        }
Пример #5
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);
                }
            }
        }
Пример #6
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);
                }
            }
        }