Example #1
0
        private void Write(BinaryWriterEx bhdWriter, BinaryWriterEx bdtWriter)
        {
            BHD.Write(bhdWriter, Files);

            for (int i = 0; i < Files.Count; i++)
            {
                File file = Files[i];
                bdtWriter.Pad(0x10);

                byte[] bytes = file.Bytes;
                if (file.Flags == 0x03 || file.Flags == 0xC0)
                {
                    bytes = DCX.Compress(bytes, DCX.Type.DarkSouls1);
                }

                if (BHD.Format == 0x3E)
                {
                    bhdWriter.FillUInt64($"FileOffset{i}", (ulong)bdtWriter.Position);
                }
                else
                {
                    bhdWriter.FillUInt32($"FileOffset{i}", (uint)bdtWriter.Position);
                }

                bhdWriter.FillInt64($"FileSize{i}", bytes.LongLength);
                bdtWriter.WriteBytes(bytes);
            }
        }
Example #2
0
            internal Texture(BinaryReaderEx br, TPFPlatform platform, byte encoding)
            {
                int fileOffset = br.ReadInt32();
                int fileSize   = br.ReadInt32();

                Format  = br.ReadByte();
                Cubemap = br.ReadBoolean();
                Mipmaps = br.ReadByte();
                Flags1  = br.AssertByte(0, 1, 2, 3);

                int nameOffset = 0;

                if (platform == TPFPlatform.PC)
                {
                    Header     = null;
                    nameOffset = br.ReadInt32();
                    Flags2     = br.AssertInt32(0, 1);
                }
                else if (platform == TPFPlatform.PS3)
                {
                    Header        = new TexHeader();
                    Header.Width  = br.ReadInt16();
                    Header.Height = br.ReadInt16();
                    Header.Unk1   = br.ReadInt32();
                    Header.Unk2   = br.AssertInt32(0, 0xAAE4);
                    nameOffset    = br.ReadInt32();
                    Flags2        = br.AssertInt32(0, 1);
                }
                else if (platform == TPFPlatform.PS4 || platform == TPFPlatform.Xbone)
                {
                    Header        = new TexHeader();
                    Header.Width  = br.ReadInt16();
                    Header.Height = br.ReadInt16();

                    Header.TextureCount = br.AssertByte(1, 6);
                    br.AssertByte(0);
                    br.AssertByte(0);
                    br.AssertByte(0);

                    Header.Unk2       = br.AssertInt32(0xD);
                    nameOffset        = br.ReadInt32();
                    Flags2            = br.AssertInt32(0, 1);
                    Header.DXGIFormat = br.ReadInt32();
                }

                Bytes = br.GetBytes(fileOffset, fileSize);
                if (Flags1 == 2 || Flags1 == 3)
                {
                    Bytes = DCX.Decompress(Bytes);
                }

                if (encoding == 1)
                {
                    Name = br.GetUTF16(nameOffset);
                }
                else if (encoding == 0 || encoding == 2)
                {
                    Name = br.GetShiftJIS(nameOffset);
                }
            }
Example #3
0
 internal File(BinaryReaderEx br, BHF4.FileHeader fileHeader)
 {
     Name  = fileHeader.Name;
     Flags = fileHeader.Flags;
     ID    = fileHeader.ID;
     Bytes = br.GetBytes((long)fileHeader.Offset, (int)fileHeader.CompressedSize);
     if (Flags == 0x03 || Flags == 0xC0)
     {
         Bytes = DCX.Decompress(Bytes);
     }
 }
Example #4
0
        /// <summary>
        /// Writes TPF data to a BinaryWriterEx.
        /// </summary>
        internal override void Write(BinaryWriterEx bw)
        {
            bw.BigEndian = false;
            bw.WriteASCII("TPF\0");
            bw.ReserveInt32("DataSize");
            bw.WriteInt32(Textures.Count);
            bw.WriteByte((byte)Platform);
            bw.WriteByte(Flag2);
            bw.WriteByte(Encoding);
            bw.WriteByte(0);

            for (int i = 0; i < Textures.Count; i++)
            {
                Textures[i].Write(bw, i, Platform);
            }
            bw.Pad(0x10);

            for (int i = 0; i < Textures.Count; i++)
            {
                Texture texture = Textures[i];
                bw.FillInt32($"FileName{i}", (int)bw.Position);
                if (Encoding == 1)
                {
                    bw.WriteUTF16(texture.Name, true);
                }
                else if (Encoding == 0 || Encoding == 2)
                {
                    bw.WriteShiftJIS(texture.Name, true);
                }
            }

            int dataStart = (int)bw.Position;

            for (int i = 0; i < Textures.Count; i++)
            {
                Texture texture = Textures[i];
                if (texture.Bytes.Length > 0)
                {
                    bw.Pad(0x10);
                }

                bw.FillInt32($"FileData{i}", (int)bw.Position);

                byte[] bytes = texture.Bytes;
                if (texture.Flags1 == 2 || texture.Flags2 == 3)
                {
                    bytes = DCX.Compress(bytes, DCX.Type.ACEREDGE);
                }
                bw.FillInt32($"FileSize{i}", bytes.Length);
                bw.WriteBytes(bytes);
            }
            bw.FillInt32("DataSize", (int)bw.Position - dataStart);
        }
Example #5
0
 /// <summary>
 /// Decompresses data and returns a new BinaryReaderEx if necessary.
 /// </summary>
 public static BinaryReaderEx GetDecompressedBR(BinaryReaderEx br, out DCX.Type compression)
 {
     if (DCX.Is(br))
     {
         byte[] bytes = DCX.Decompress(br, out compression);
         return(new BinaryReaderEx(false, bytes));
     }
     else
     {
         compression = DCX.Type.None;
         return(br);
     }
 }
Example #6
0
            internal void WriteData(BinaryWriterEx bw, int index)
            {
                bw.FillUInt32($"FileData{index}", (uint)bw.Position);

                byte[] bytes = Bytes;
                if (Flags1 == 2 || Flags1 == 3)
                {
                    bytes = DCX.Compress(bytes, DCX.Type.DCP_EDGE);
                }

                bw.FillInt32($"FileSize{index}", bytes.Length);
                bw.WriteBytes(bytes);
            }
Example #7
0
 /// <summary>
 /// Writes file data to a BinaryWriterEx, compressing it afterwards if specified.
 /// </summary>
 private void Write(BinaryWriterEx bw, DCX.Type compression)
 {
     if (compression == DCX.Type.None)
     {
         Write(bw);
     }
     else
     {
         BinaryWriterEx bwUncompressed = new BinaryWriterEx(false);
         Write(bwUncompressed);
         byte[] uncompressed = bwUncompressed.FinishBytes();
         DCX.Compress(uncompressed, bw, compression);
     }
 }
Example #8
0
        internal BinderFile ReadFileData(BinaryReaderEx br)
        {
            byte[]   bytes;
            DCX.Type compressionType = DCX.Type.Zlib;
            if (IsCompressed(Flags))
            {
                bytes = br.GetBytes(DataOffset, (int)CompressedSize);
                bytes = DCX.Decompress(bytes, out compressionType);
            }
            else
            {
                bytes = br.GetBytes(DataOffset, (int)CompressedSize);
            }

            return(new BinderFile(Flags, ID, Name, bytes)
            {
                CompressionType = compressionType,
            });
        }
Example #9
0
        private void WriteFileData(BinaryWriterEx bw, byte[] bytes)
        {
            if (bytes.LongLength > 0)
            {
                bw.Pad(0x10);
            }

            DataOffset       = bw.Position;
            UncompressedSize = bytes.LongLength;
            if (IsCompressed(Flags))
            {
                byte[] compressed = DCX.Compress(bytes, CompressionType);
                CompressedSize = compressed.LongLength;
                bw.WriteBytes(compressed);
            }
            else
            {
                CompressedSize = bytes.LongLength;
                bw.WriteBytes(bytes);
            }
        }
Example #10
0
        /// <summary>
        /// Guesses the extension of a file based on its contents.
        /// </summary>
        public static string GuessExtension(byte[] bytes, bool bigEndian = false)
        {
            bool dcx = false;

            if (DCX.Is(bytes))
            {
                dcx   = true;
                bytes = DCX.Decompress(bytes);
            }

            bool checkMsb(BinaryReaderEx br)
            {
                if (br.Length < 8)
                {
                    return(false);
                }

                int offset = br.GetInt32(4);

                if (offset < 0 || offset >= br.Length - 1)
                {
                    return(false);
                }

                try
                {
                    return(br.GetASCII(offset) == "MODEL_PARAM_ST");
                }
                catch
                {
                    return(false);
                }
            }

            bool checkParam(BinaryReaderEx br)
            {
                if (br.Length < 0x2C)
                {
                    return(false);
                }

                string param = br.GetASCII(0xC, 0x20);

                return(Regex.IsMatch(param, "^[^\0]+\0 *$"));
            }

            bool checkTdf(BinaryReaderEx br)
            {
                if (br.Length < 4)
                {
                    return(false);
                }

                if (br.GetASCII(0, 1) != "\"")
                {
                    return(false);
                }

                for (int i = 1; i < br.Length; i++)
                {
                    if (br.GetASCII(i, 1) == "\"")
                    {
                        return(i < br.Length - 2 && br.GetASCII(i + 1, 2) == "\r\n");
                    }
                }
                return(false);
            }

            string ext = "";

            using (var ms = new MemoryStream(bytes))
            {
                var    br    = new BinaryReaderEx(bigEndian, ms);
                string magic = null;
                if (br.Length >= 4)
                {
                    magic = br.ReadASCII(4);
                }

                if (magic == "AISD")
                {
                    ext = ".aisd";
                }
                else if (magic == "BDF3" || magic == "BDF4")
                {
                    ext = ".bdt";
                }
                else if (magic == "BHF3" || magic == "BHF4")
                {
                    ext = ".bhd";
                }
                else if (magic == "BND3" || magic == "BND4")
                {
                    ext = ".bnd";
                }
                else if (magic == "DDS ")
                {
                    ext = ".dds";
                }
                // ESD or FFX
                else if (magic != null && magic.ToUpper() == "DLSE")
                {
                    ext = ".dlse";
                }
                else if (bigEndian && magic == "\0BRD" || !bigEndian && magic == "DRB\0")
                {
                    ext = ".drb";
                }
                else if (magic == "EDF\0")
                {
                    ext = ".edf";
                }
                else if (magic == "ELD\0")
                {
                    ext = ".eld";
                }
                else if (magic == "ENFL")
                {
                    ext = ".entryfilelist";
                }
                else if (magic != null && magic.ToUpper() == "FSSL")
                {
                    ext = ".esd";
                }
                else if (magic == "EVD\0")
                {
                    ext = ".evd";
                }
                else if (br.Length >= 3 && br.GetASCII(0, 3) == "FEV" || br.Length >= 0x10 && br.GetASCII(8, 8) == "FEV FMT ")
                {
                    ext = ".fev";
                }
                else if (br.Length >= 6 && br.GetASCII(0, 6) == "FLVER\0")
                {
                    ext = ".flver";
                }
                else if (br.Length >= 3 && br.GetASCII(0, 3) == "FSB")
                {
                    ext = ".fsb";
                }
                else if (br.Length >= 3 && br.GetASCII(0, 3) == "GFX")
                {
                    ext = ".gfx";
                }
                else if (br.Length >= 0x19 && br.GetASCII(0xC, 0xE) == "ITLIMITER_INFO")
                {
                    ext = ".itl";
                }
                else if (br.Length >= 4 && br.GetASCII(1, 3) == "Lua")
                {
                    ext = ".lua";
                }
                else if (checkMsb(br))
                {
                    ext = ".msb";
                }
                else if (br.Length >= 0x30 && br.GetASCII(0x2C, 4) == "MTD ")
                {
                    ext = ".mtd";
                }
                else if (magic == "DFPN")
                {
                    ext = ".nfd";
                }
                else if (checkParam(br))
                {
                    ext = ".param";
                }
                else if (br.Length >= 4 && br.GetASCII(1, 3) == "PNG")
                {
                    ext = ".png";
                }
                else if (br.Length >= 0x2C && br.GetASCII(0x28, 4) == "SIB ")
                {
                    ext = ".sib";
                }
                else if (magic == "TAE ")
                {
                    ext = ".tae";
                }
                else if (checkTdf(br))
                {
                    ext = ".tdf";
                }
                else if (magic == "TPF\0")
                {
                    ext = ".tpf";
                }
                else if (magic == "#BOM")
                {
                    ext = ".txt";
                }
                else if (br.Length >= 5 && br.GetASCII(0, 5) == "<?xml")
                {
                    ext = ".xml";
                }
                // This is pretty sketchy
                else if (br.Length >= 0xC && br.GetByte(0) == 0 && br.GetByte(3) == 0 && br.GetInt32(4) == br.Length && br.GetInt16(0xA) == 0)
                {
                    ext = ".fmg";
                }
            }

            if (dcx)
            {
                return(ext + ".dcx");
            }
            else
            {
                return(ext);
            }
        }
Example #11
0
        private static BinderFile ReadFile(BinaryReaderEx br, bool unicode, Binder.Format format)
        {
            Binder.FileFlags flags = br.ReadEnum8 <Binder.FileFlags>();
            br.AssertByte(0);
            br.AssertByte(0);
            br.AssertByte(0);

            br.AssertInt32(-1);
            long compressedSize = br.ReadInt64();

            if (Binder.HasUncompressedSize(format))
            {
                long uncompressedSize = br.ReadInt64();
            }

            uint fileOffset = br.ReadUInt32();

            int id = -1;

            if (Binder.HasID(format))
            {
                id = br.ReadInt32();
            }

            string name = null;

            if (Binder.HasName(format))
            {
                uint nameOffset = br.ReadUInt32();
                if (unicode)
                {
                    name = br.GetUTF16(nameOffset);
                }
                else
                {
                    name = br.GetShiftJIS(nameOffset);
                }
            }

            if (format == Binder.Format.x20)
            {
                br.AssertInt64(0);
            }

            byte[] bytes;
            if (Binder.IsCompressed(flags))
            {
                if (format == Binder.Format.x2E)
                {
                    bytes = br.GetBytes(fileOffset, (int)compressedSize);
                    bytes = DCX.Decompress(bytes, out DCX.Type type);
                    if (type != DCX.Type.DemonsSoulsEDGE)
                    {
                        throw null;
                    }
                }
                else
                {
                    br.StepIn(fileOffset);
                    bytes = SFUtil.ReadZlib(br, (int)compressedSize);
                    br.StepOut();
                }
            }
            else
            {
                bytes = br.GetBytes(fileOffset, (int)compressedSize);
            }

            return(new BinderFile(flags, id, name, bytes));
        }
Example #12
0
        /// <summary>
        /// Writes BND4 data to a BinaryWriterEx.
        /// </summary>
        internal override void Write(BinaryWriterEx bw)
        {
            bw.BigEndian = BigEndian;

            bw.WriteASCII("BND4");
            bw.WriteBoolean(Flag1);
            bw.WriteBoolean(Flag2);
            bw.WriteByte(0);
            bw.WriteByte(0);

            bw.WriteInt32(0x10000);
            bw.WriteInt32(Files.Count);
            bw.WriteInt64(0x40);
            bw.WriteFixStr(Timestamp, 8);
            bw.WriteInt64(Binder.FileHeaderSize(Format));
            bw.ReserveInt64("DataStart");

            bw.WriteBoolean(Unicode);
            bw.WriteByte((byte)Format);
            bw.WriteByte(Extended);
            bw.WriteByte(0);

            bw.WriteInt32(0);
            if (Extended == 4)
            {
                bw.ReserveInt64("HashGroups");
            }
            else
            {
                bw.WriteInt64(0);
            }

            for (int i = 0; i < Files.Count; i++)
            {
                WriteFile(Files[i], bw, i, Format);
            }

            if (Binder.HasName(Format))
            {
                for (int i = 0; i < Files.Count; i++)
                {
                    BinderFile file = Files[i];
                    bw.FillUInt32($"FileName{i}", (uint)bw.Position);
                    if (Unicode)
                    {
                        bw.WriteUTF16(file.Name, true);
                    }
                    else
                    {
                        bw.WriteShiftJIS(file.Name, true);
                    }
                }
            }

            if (Extended == 4)
            {
                uint groupCount = 0;
                for (uint p = (uint)Files.Count / 7; p <= 100000; p++)
                {
                    if (SFUtil.IsPrime(p))
                    {
                        groupCount = p;
                        break;
                    }
                }

                if (groupCount == 0)
                {
                    throw new InvalidOperationException("Hash group count not determined in BND4.");
                }

                var hashLists = new List <PathHash> [groupCount];
                for (int i = 0; i < groupCount; i++)
                {
                    hashLists[i] = new List <PathHash>();
                }

                for (int i = 0; i < Files.Count; i++)
                {
                    var  pathHash = new PathHash(i, Files[i].Name);
                    uint group    = pathHash.Hash % groupCount;
                    hashLists[group].Add(pathHash);
                }

                for (int i = 0; i < groupCount; i++)
                {
                    hashLists[i].Sort((ph1, ph2) => ph1.Hash.CompareTo(ph2.Hash));
                }

                var hashGroups = new List <HashGroup>();
                var pathHashes = new List <PathHash>();

                int count = 0;
                foreach (List <PathHash> hashList in hashLists)
                {
                    int index = count;
                    foreach (PathHash pathHash in hashList)
                    {
                        pathHashes.Add(pathHash);
                        count++;
                    }

                    hashGroups.Add(new HashGroup(index, count - index));
                }

                bw.Pad(0x8);
                bw.FillInt64("HashGroups", bw.Position);
                bw.ReserveInt64("PathHashes");
                bw.WriteUInt32(groupCount);
                bw.WriteInt32(0x00080810);

                foreach (HashGroup hashGroup in hashGroups)
                {
                    hashGroup.Write(bw);
                }

                // No padding after section 1
                bw.FillInt64("PathHashes", bw.Position);
                foreach (PathHash pathHash in pathHashes)
                {
                    pathHash.Write(bw);
                }
            }

            bw.FillInt64("DataStart", bw.Position);
            for (int i = 0; i < Files.Count; i++)
            {
                BinderFile file = Files[i];
                if (file.Bytes.LongLength > 0)
                {
                    bw.Pad(0x10);
                }

                bw.FillUInt32($"FileData{i}", (uint)bw.Position);

                int compressedSize = file.Bytes.Length;

                if (Binder.IsCompressed(file.Flags))
                {
                    if (Format == Binder.Format.x2E)
                    {
                        byte[] bytes = DCX.Compress(file.Bytes, DCX.Type.DemonsSoulsEDGE);
                        bw.WriteBytes(bytes);
                        compressedSize = bytes.Length;
                    }
                    else
                    {
                        compressedSize = SFUtil.WriteZlib(bw, 0x9C, file.Bytes);
                    }
                }
                else
                {
                    bw.WriteBytes(file.Bytes);
                }

                bw.FillInt64($"CompressedSize{i}", compressedSize);
            }
        }
Example #13
0
            internal Texture(BinaryReaderEx br, TPFPlatform platform, byte flag2, byte encoding)
            {
                uint fileOffset = br.ReadUInt32();
                int  fileSize   = br.ReadInt32();

                Format  = br.ReadByte();
                Type    = br.ReadEnum8 <TexType>();
                Mipmaps = br.ReadByte();
                Flags1  = br.AssertByte(0, 1, 2, 3);

                if (platform != TPFPlatform.PC)
                {
                    Header        = new TexHeader();
                    Header.Width  = br.ReadInt16();
                    Header.Height = br.ReadInt16();

                    if (platform == TPFPlatform.Xbox360)
                    {
                        br.AssertInt32(0);
                    }
                    else if (platform == TPFPlatform.PS3)
                    {
                        Header.Unk1 = br.ReadInt32();
                        if (flag2 != 0)
                        {
                            Header.Unk2 = br.AssertInt32(0, 0x69E0, 0xAAE4);
                        }
                    }
                    else if (platform == TPFPlatform.PS4 || platform == TPFPlatform.Xbone)
                    {
                        Header.TextureCount = br.AssertInt32(1, 6);
                        Header.Unk2         = br.AssertInt32(0xD);
                    }
                }

                uint nameOffset     = br.ReadUInt32();
                bool hasFloatStruct = br.AssertInt32(0, 1) == 1;

                if (platform == TPFPlatform.PS4 || platform == TPFPlatform.Xbone)
                {
                    Header.DXGIFormat = br.ReadInt32();
                }

                if (hasFloatStruct)
                {
                    FloatStruct = new FloatStruct(br);
                }

                Bytes = br.GetBytes(fileOffset, fileSize);
                if (Flags1 == 2 || Flags1 == 3)
                {
                    Bytes = DCX.Decompress(Bytes, out DCX.Type type);
                    if (type != DCX.Type.DCP_EDGE)
                    {
                        throw new NotImplementedException($"TPF compression is expected to be DCP_EDGE, but it was {type}");
                    }
                }

                if (encoding == 1)
                {
                    Name = br.GetUTF16(nameOffset);
                }
                else if (encoding == 0 || encoding == 2)
                {
                    Name = br.GetShiftJIS(nameOffset);
                }
            }
Example #14
0
            internal Texture(BinaryReaderEx br, TPFPlatform platform, byte flag2, byte encoding)
            {
                uint fileOffset = br.ReadUInt32();
                int  fileSize   = br.ReadInt32();

                Format  = br.ReadByte();
                Type    = br.ReadEnum8 <TexType>();
                Mipmaps = br.ReadByte();
                Flags1  = br.AssertByte(0, 1, 2, 3);

                uint nameOffset = uint.MaxValue;

                if (platform == TPFPlatform.PC)
                {
                    Header     = null;
                    nameOffset = br.ReadUInt32();
                    Flags2     = br.AssertInt32(0, 1);
                }
                else
                {
                    Header        = new TexHeader();
                    Header.Width  = br.ReadInt16();
                    Header.Height = br.ReadInt16();

                    if (platform == TPFPlatform.Xbox360)
                    {
                        br.AssertInt32(0);
                        nameOffset = br.ReadUInt32();
                        br.AssertInt32(0);
                    }
                    else if (platform == TPFPlatform.PS3)
                    {
                        Header.Unk1 = br.ReadInt32();
                        if (flag2 != 0)
                        {
                            Header.Unk2 = br.AssertInt32(0, 0xAAE4);
                        }
                        nameOffset = br.ReadUInt32();
                        Flags2     = br.AssertInt32(0, 1);
                        if (Flags2 == 1)
                        {
                            Unk20 = br.ReadInt32();
                            Unk24 = br.ReadInt32();
                            Unk28 = br.ReadSingle();
                        }
                    }
                    else if (platform == TPFPlatform.PS4 || platform == TPFPlatform.Xbone)
                    {
                        Header.TextureCount = br.AssertInt32(1, 6);
                        Header.Unk2         = br.AssertInt32(0xD);
                        nameOffset          = br.ReadUInt32();
                        Flags2            = br.AssertInt32(0, 1);
                        Header.DXGIFormat = br.ReadInt32();
                    }
                }

                Bytes = br.GetBytes(fileOffset, fileSize);
                if (Flags1 == 2 || Flags1 == 3)
                {
                    Bytes = DCX.Decompress(Bytes);
                }

                if (encoding == 1)
                {
                    Name = br.GetUTF16(nameOffset);
                }
                else if (encoding == 0 || encoding == 2)
                {
                    Name = br.GetShiftJIS(nameOffset);
                }
            }