Esempio n. 1
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));
        }
Esempio n. 2
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);
            }
        }