/// <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); if (Format == 0x0C) { bw.WriteInt64(0x18); } else if (Format == 0x70) { bw.WriteInt64(0x1C); } else { bw.WriteInt64(0x24); } bw.ReserveInt64("DataStart"); bw.WriteBoolean(Unicode); bw.WriteByte(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++) { Files[i].Write(bw, i, Format); } for (int i = 0; i < Files.Count; i++) { File file = Files[i]; bw.FillInt32($"FileName{i}", (int)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++) { File file = Files[i]; if (file.Bytes.LongLength > 0) { bw.Pad(0x10); } bw.FillInt32($"FileData{i}", (int)bw.Position); byte[] bytes = file.Bytes; int compressedSize = bytes.Length; if (file.Flags == 0x03 || file.Flags == 0xC0) { compressedSize = SFUtil.WriteZlib(bw, 0x9C, bytes); } else { bw.WriteBytes(bytes); } bw.FillInt64($"CompressedSize{i}", bytes.Length); } }
internal void Write(BinaryWriterEx bw, List <BinderFile> files) { bw.BigEndian = BigEndian; bw.WriteASCII("BHF4"); 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.WriteInt64(0); 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++) { FileHeader.Write(bw, files[i], i, 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 BXF4."); } 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); } } }
public static void Write(BinaryWriterEx bw, List <BinderFileHeader> files) { 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("Could not determine hash group count."); } 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.ReserveInt64("HashesOffset"); bw.WriteUInt32(groupCount); bw.WriteByte(0x10); bw.WriteByte(8); bw.WriteByte(8); bw.WriteByte(0); foreach (HashGroup hashGroup in hashGroups) { hashGroup.Write(bw); } bw.FillInt64("HashesOffset", bw.Position); foreach (PathHash pathHash in pathHashes) { pathHash.Write(bw); } }