Example #1
0
        /// <summary>
        ///     Extracts data from a Brutal Legend package.
        /// </summary>
        /// <param name="HeaderFile">The *.~h Header file path</param>
        /// <param name="DataFile">The ~.~p Data file path</param>
        /// <param name="OutFolder">The output folder</param>
        /// <returns>False if header file is invalid, true otherwise</returns>
        public static bool Extract(string HeaderFile, string DataFile, string OutFolder)
        {
            FileStream Header = new FileStream(HeaderFile, FileMode.Open);
            FileStream Data   = new FileStream(DataFile, FileMode.Open);

            EndianBinaryReader Reader = new EndianBinaryReader(Header, Endian.Big);

            if (StringUtilities.ReadASCIIString(Header, 4) != "dfpf")
            {
                return(false);
            }

            Header.Seek(0x14, SeekOrigin.Begin);
            uint StringsTableOffset = Reader.ReadUInt32();
            uint StringsTableFlags  = Reader.ReadUInt32();
            uint StringsTableLength = Reader.ReadUInt32();
            uint FilesCount         = Reader.ReadUInt32();

            Header.Seek(0x18, SeekOrigin.Current);
            uint FilesTableOffset = Reader.ReadUInt32();

            for (int Index = 0; Index < FilesCount; Index++)
            {
                Header.Seek(FilesTableOffset + Index * 0x10, SeekOrigin.Begin);

                //Lengths
                uint DecompressedLength = Reader.ReadUInt24();
                uint LengthDifference   = (uint)(Reader.ReadUInt16() << 1) | ((DecompressedLength & 1) << 17); //Probably for "obfuscation"
                uint CompressedLength   = Reader.ReadUInt24();

                LengthDifference  |= CompressedLength >> 23;
                DecompressedLength = (DecompressedLength >> 1) + LengthDifference;
                CompressedLength   = (CompressedLength & 0x7fffff) >> 1;

                //Offsets
                uint DataOffset = Reader.ReadUInt24() << 5;
                byte DataFormat = Reader.ReadByte();
                DataOffset |= (uint)(DataFormat & 0xf8) >> 3;
                DataFormat &= 7;

                uint NameOffset = (Reader.ReadUInt24() >> 3) + StringsTableOffset;
                byte Flags      = Reader.ReadByte();

                Header.Seek(NameOffset, SeekOrigin.Begin);
                string FileName = StringUtilities.ReadASCIIString(Header);

                if (OnStatusReport != null)
                {
                    BrutalStatusReport Report = new BrutalStatusReport();

                    Report.Status         = "Extracting " + FileName + "...";
                    Report.ProcessedFiles = Index;
                    Report.TotalFiles     = (int)FilesCount;

                    OnStatusReport(null, Report);
                }

                Data.Seek(DataOffset, SeekOrigin.Begin);
                byte[] Buffer = new byte[CompressedLength];
                Data.Read(Buffer, 0, Buffer.Length);

                ICompression Decompressor;
                switch ((CompressionType)((Flags >> 1) & 3))
                {
                case CompressionType.None: Decompressor = new NoCompression(); break;

                case CompressionType.ZLib: Decompressor = new ZLib(); break;

                case CompressionType.LZX: Decompressor = new LZX(); break;

                default: throw new Exception("Unknown compression!");
                }

                Buffer = Decompressor.Decompress(Buffer, DecompressedLength);

                string FullName = Path.Combine(OutFolder, FileName);
                string DirName  = Path.GetDirectoryName(FullName);
                if (!Directory.Exists(DirName))
                {
                    Directory.CreateDirectory(DirName);
                }
                File.WriteAllBytes(FullName + ".bin", Buffer);
            }

            Header.Close();
            Data.Close();

            return(true);
        }
Example #2
0
        /// <summary>
        ///     Inserts data into a Brutal Legend package.
        /// </summary>
        /// <param name="HeaderFile">The *.~h Header file path</param>
        /// <param name="DataFile">The ~.~p Data file path</param>
        /// <param name="OutFolder">The input folder</param>
        /// <returns>False if header file is invalid, true otherwise</returns>
        public static bool Insert(string HeaderFile, string DataFile, string FileFolder)
        {
            FileStream Header = new FileStream(HeaderFile, FileMode.Open);
            FileStream Data   = new FileStream(DataFile, FileMode.Open);

            EndianBinaryReader Reader = new EndianBinaryReader(Header, Endian.Big);
            EndianBinaryWriter Writer = new EndianBinaryWriter(Header, Endian.Big);

            if (StringUtilities.ReadASCIIString(Header, 4) != "dfpf")
            {
                return(false);
            }
            string[] Files = Directory.GetFiles(FileFolder, "*.*", SearchOption.AllDirectories);

            Header.Seek(0x14, SeekOrigin.Begin);
            uint StringsTableOffset = Reader.ReadUInt32();
            uint StringsTableFlags  = Reader.ReadUInt32();
            uint StringsTableLength = Reader.ReadUInt32();
            uint FilesCount         = Reader.ReadUInt32();

            Header.Seek(0x18, SeekOrigin.Current);
            uint FilesTableOffset = Reader.ReadUInt32();

            using (MemoryStream NewData = new MemoryStream())
            {
                int Offset        = 0;
                int InsertedFiles = 0;

                for (int Index = 0; Index < FilesCount; Index++)
                {
                    Header.Seek(FilesTableOffset + Index * 0x10, SeekOrigin.Begin);

                    //Lengths
                    uint DecompressedLength = Reader.ReadUInt24();
                    uint LengthDifference   = (uint)(Reader.ReadUInt16() << 1) | ((DecompressedLength & 1) << 17); //Probably for "obfuscation"
                    uint CompressedLength   = Reader.ReadUInt24();

                    LengthDifference  |= CompressedLength >> 23;
                    DecompressedLength = (DecompressedLength >> 1) + LengthDifference;
                    CompressedLength   = (CompressedLength & 0x7fffff) >> 1;

                    //Offsets
                    uint DataOffset = Reader.ReadUInt24() << 5;
                    byte DataFormat = Reader.ReadByte();
                    DataOffset |= (uint)(DataFormat & 0xf8) >> 3;
                    DataFormat &= 7;

                    uint NameOffset = (Reader.ReadUInt24() >> 3) + StringsTableOffset;
                    byte Flags      = Reader.ReadByte();

                    Header.Seek(NameOffset, SeekOrigin.Begin);
                    string FileName = StringUtilities.ReadASCIIString(Header);

                    bool Found = false;
                    foreach (string CurrentFile in Files)
                    {
                        string Name = CurrentFile.Replace(FileFolder, string.Empty);
                        if (Name.StartsWith("\\"))
                        {
                            Name = Name.Remove(0, 1);
                        }
                        Name = Name.Replace(Path.GetExtension(Name), string.Empty);
                        Name = Name.Replace('\\', '/');

                        if (Name == FileName)
                        {
                            if (OnStatusReport != null)
                            {
                                BrutalStatusReport Report = new BrutalStatusReport();

                                Report.Status         = "Inserting " + FileName + "...";
                                Report.ProcessedFiles = InsertedFiles++;
                                Report.TotalFiles     = Files.Length;

                                OnStatusReport(null, Report);
                            }

                            ICompression Compressor;
                            switch ((CompressionType)((Flags >> 1) & 3))
                            {
                            case CompressionType.None: Compressor = new NoCompression(); break;

                            case CompressionType.ZLib: Compressor = new ZLib(); break;

                            case CompressionType.LZX: Compressor = new LZX(); break;

                            default: throw new Exception("Unknown compression!");
                            }

                            byte[] Decompressed = File.ReadAllBytes(CurrentFile);
                            byte[] Compressed   = Compressor.Compress(Decompressed);

                            NewData.Seek(Offset, SeekOrigin.Begin);
                            NewData.Write(Compressed, 0, Compressed.Length);

                            Header.Seek(FilesTableOffset + Index * 0x10, SeekOrigin.Begin);
                            Writer.Write24((uint)(((Decompressed.Length - LengthDifference) << 1) | (LengthDifference >> 17)));
                            Header.Seek(2, SeekOrigin.Current);
                            Writer.Write24((uint)((Compressed.Length << 1) & 0x7fffff) | ((LengthDifference & 1) << 23));
                            Writer.Write24((uint)(Offset >> 5));
                            Writer.Write(DataFormat);
                            Offset += Compressed.Length;

                            Found = true;
                            break;
                        }
                    }

                    if (!Found)
                    {
                        Data.Seek(DataOffset, SeekOrigin.Begin);
                        byte[] Buffer = new byte[CompressedLength];
                        Data.Read(Buffer, 0, Buffer.Length);

                        NewData.Seek(Offset, SeekOrigin.Begin);
                        NewData.Write(Buffer, 0, Buffer.Length);

                        Header.Seek(FilesTableOffset + Index * 0x10 + 8, SeekOrigin.Begin);
                        Writer.Write24((uint)(Offset >> 5));
                        Offset += Buffer.Length;
                    }

                    //Align offset to next 2KB block if necessary
                    if ((Offset & 0x7ff) != 0)
                    {
                        Offset = (Offset & ~0x7ff) + 0x800;
                    }
                }

                Header.Close();
                Data.Close();

                while ((NewData.Position & 0x7ff) != 0)
                {
                    NewData.WriteByte(0);
                }
                File.WriteAllBytes(DataFile, NewData.ToArray());
            }

            return(true);
        }