internal void WriteStrings(BinaryWriterEx bw, bool longFormat, int index) { if (longFormat) { bw.FillInt64($"NameOffset{index}", bw.Position); bw.WriteUTF16(Name, true); if (LogicInterruptName == null) { bw.FillInt64($"LogicInterruptNameOffset{index}", 0); } else { bw.FillInt64($"LogicInterruptNameOffset{index}", bw.Position); bw.WriteUTF16(LogicInterruptName, true); } } else { bw.FillUInt32($"NameOffset{index}", (uint)bw.Position); bw.WriteShiftJIS(Name, true); if (LogicInterruptName == null) { bw.FillUInt32($"LogicInterruptNameOffset{index}", 0); } else { bw.FillUInt32($"LogicInterruptNameOffset{index}", (uint)bw.Position); bw.WriteShiftJIS(LogicInterruptName, true); } } }
internal override void Write(BinaryWriterEx bw, int id) { long start = bw.Position; bw.ReserveInt32("NameOffset"); bw.WriteUInt32((uint)Type); bw.WriteInt32(id); bw.WriteInt32(ModelIndex); bw.ReserveInt32("SibOffset"); bw.WriteVector3(Position); bw.WriteVector3(Rotation); bw.WriteVector3(Scale); bw.WriteUInt32s(DrawGroups); bw.WriteUInt32s(DispGroups); bw.ReserveInt32("EntityDataOffset"); bw.ReserveInt32("TypeDataOffset"); bw.WriteInt32(0); long stringsStart = bw.Position; bw.FillInt32("NameOffset", (int)(bw.Position - start)); bw.WriteShiftJIS(MSB.ReambiguateName(Name), true); bw.FillInt32("SibOffset", (int)(bw.Position - start)); bw.WriteShiftJIS(Placeholder, true); bw.Pad(4); if (bw.Position - stringsStart < 0x14) { bw.WritePattern((int)(0x14 - (bw.Position - stringsStart)), 0x00); } bw.FillInt32("EntityDataOffset", (int)(bw.Position - start)); bw.WriteInt32(EntityID); bw.WriteByte(LightID); bw.WriteByte(FogID); bw.WriteByte(ScatterID); bw.WriteByte(LensFlareID); bw.WriteByte(ShadowID); bw.WriteByte(DofID); bw.WriteByte(ToneMapID); bw.WriteByte(ToneCorrectID); bw.WriteByte(LanternID); bw.WriteByte(LodParamID); bw.WriteByte(0); bw.WriteByte(IsShadowSrc); bw.WriteByte(IsShadowDest); bw.WriteByte(IsShadowOnly); bw.WriteByte(DrawByReflectCam); bw.WriteByte(DrawOnlyReflectCam); bw.WriteByte(UseDepthBiasFloat); bw.WriteByte(DisablePointLightEffect); bw.WriteByte(0); bw.WriteByte(0); bw.FillInt32("TypeDataOffset", (int)(bw.Position - start)); }
internal void WriteName(BinaryWriterEx bw, byte format2D, byte format2E, int i) { long nameOffset = 0; if (Name != null) { nameOffset = bw.Position; if (format2E < 7) { bw.WriteShiftJIS(Name, true); } else { bw.WriteUTF16(Name, true); } } if ((format2D & 0x7F) < 4) { bw.FillUInt32($"NameOffset{i}", (uint)nameOffset); } else { bw.FillInt64($"NameOffset{i}", nameOffset); } }
internal void WriteDescription(BinaryWriterEx bw, PARAMDEF def, int index) { long descriptionOffset = 0; if (Description != null) { descriptionOffset = bw.Position; if (def.Unicode) { bw.WriteUTF16(Description, true); } else { bw.WriteShiftJIS(Description, true); } } if (def.Version >= 201) { bw.FillInt64($"DescriptionOffset{index}", descriptionOffset); } else { bw.FillInt32($"DescriptionOffset{index}", (int)descriptionOffset); } }
internal override void Write(BinaryWriterEx bw, int id) { long start = bw.Position; bw.ReserveInt32("NameOffset"); bw.WriteInt32(EventID); bw.WriteUInt32((uint)Type); bw.WriteInt32(id); bw.ReserveInt32("BaseDataOffset"); bw.ReserveInt32("TypeDataOffset"); bw.WriteInt32(0); bw.FillInt32("NameOffset", (int)(bw.Position - start)); bw.WriteShiftJIS(Name, true); bw.Pad(4); bw.FillInt32("BaseDataOffset", (int)(bw.Position - start)); bw.WriteInt32(PartIndex); bw.WriteInt32(RegionIndex); bw.WriteInt32(EntityID); bw.WriteInt32(0); bw.FillInt32("TypeDataOffset", (int)(bw.Position - start)); WriteTypeData(bw); }
internal void WriteName(BinaryWriterEx bw, PARAM parent, int i) { long nameOffset = 0; if (Name != null) { nameOffset = bw.Position; if (parent.Format2E.HasFlag(FormatFlags2.UnicodeRowNames)) { bw.WriteUTF16(Name, true); } else { bw.WriteShiftJIS(Name, true); } } if (parent.Format2D.HasFlag(FormatFlags1.LongDataOffset)) { bw.FillInt64($"NameOffset{i}", nameOffset); } else { bw.FillUInt32($"NameOffset{i}", (uint)nameOffset); } }
internal void WriteName(BinaryWriterEx bw, byte format2D, int i) { if (Name == null || Name == "") { if ((format2D & 0x7F) < 4) { bw.FillUInt32($"NameOffset{i}", 0); } else { bw.FillInt64($"NameOffset{i}", 0); } } else { if ((format2D & 0x7F) < 4) { bw.FillUInt32($"NameOffset{i}", (uint)bw.Position); bw.WriteShiftJIS(Name, true); } else { bw.FillInt64($"NameOffset{i}", bw.Position); bw.WriteUTF16(Name, true); } } }
internal void WriteHeader(BinaryWriterEx bw, int groupIndex, int groupHeadersOffset) { bw.FillInt32($"GroupHeaderOffset{groupIndex}", (int)bw.Position - groupHeadersOffset); bw.WriteInt32(Params.Count); bw.ReserveInt32($"ParamHeaderOffsetsOffset{groupIndex}"); bw.WriteShiftJIS(Name, true); bw.Pad(4); }
internal override void Write(BinaryWriterEx bw, int id) { long start = bw.Position; bw.ReserveInt32("NameOffset"); bw.WriteUInt32((uint)Type); bw.WriteInt32(ID); bw.ReserveInt32("SibOffset"); bw.WriteInt32(InstanceCount); bw.WriteInt32(0); bw.WriteInt32(0); bw.WriteInt32(0); bw.FillInt32("NameOffset", (int)(bw.Position - start)); bw.WriteShiftJIS(ReambiguateName(Name), true); bw.FillInt32("SibOffset", (int)(bw.Position - start)); bw.WriteShiftJIS(Placeholder, true); bw.Pad(4); }
/// <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); }
internal void WriteStrings(BinaryWriterEx bw, bool unicode, int index) { bw.FillInt32($"BoneNameOffset{index}", (int)bw.Position); if (unicode) { bw.WriteUTF16(Name, true); } else { bw.WriteShiftJIS(Name, true); } }
internal void WriteName(BinaryWriterEx bw, int index, byte encoding) { bw.FillUInt32($"FileName{index}", (uint)bw.Position); if (encoding == 1) { bw.WriteUTF16(Name, true); } else if (encoding == 0 || encoding == 2) { bw.WriteShiftJIS(Name, true); } }
internal void WriteStrings(BinaryWriterEx bw, FLVERHeader header, int index) { bw.FillInt32($"BoneName{index}", (int)bw.Position); if (header.Unicode) { bw.WriteUTF16(Name, true); } else { bw.WriteShiftJIS(Name, true); } }
internal void WriteStrings(BinaryWriterEx bw, FLVERHeader header, int index) { bw.FillInt32($"TexturePath{index}", (int)bw.Position); if (header.Unicode) { bw.WriteUTF16(Path, true); } else { bw.WriteShiftJIS(Path, true); } bw.FillInt32($"TextureType{index}", (int)bw.Position); if (header.Unicode) { bw.WriteUTF16(Type, true); } else { bw.WriteShiftJIS(Type, true); } }
internal override void Write(BinaryWriterEx bw, int id) { long start = bw.Position; bw.ReserveInt32("NameOffset"); bw.WriteUInt32((uint)Type); bw.WriteInt32(id); bw.WriteInt32(ModelIndex); bw.ReserveInt32("SibOffset"); bw.WriteVector3(Position); bw.WriteVector3(Rotation); bw.WriteVector3(Scale); bw.WriteUInt32s(DrawGroups); bw.WriteUInt32s(DispGroups); bw.ReserveInt32("EntityDataOffset"); bw.ReserveInt32("TypeDataOffset"); bw.WriteInt32(0); bw.WriteInt32(0); long stringsStart = bw.Position; bw.FillInt32("NameOffset", (int)(bw.Position - start)); bw.WriteShiftJIS(MSB.ReambiguateName(Name), true); bw.FillInt32("SibOffset", (int)(bw.Position - start)); bw.WriteShiftJIS(SibPath, true); bw.Pad(4); if (bw.Position - stringsStart < 0x10) { bw.WritePattern((int)(0x10 - (bw.Position - stringsStart)), 0x00); } bw.FillInt32("EntityDataOffset", (int)(bw.Position - start)); WriteEntityData(bw); bw.FillInt32("TypeDataOffset", (int)(bw.Position - start)); WriteTypeData(bw); }
internal void WriteParamHeader(BinaryWriterEx bw, int groupIndex, int paramIndex, int paramHeadersOffset) { bw.FillInt32($"ParamHeaderOffset{groupIndex}:{paramIndex}", (int)bw.Position - paramHeadersOffset); bw.ReserveInt32($"ValuesOffset{groupIndex}:{paramIndex}"); bw.WriteInt32(UnkOffset1); bw.WriteByte((byte)Type); bw.WriteByte((byte)Values.Count); bw.WriteByte(0); bw.WriteByte(0); bw.WriteShiftJIS(Name, true); bw.Pad(4); }
internal void WriteFileName(BinaryWriterEx bw, Format format, bool unicode, int index) { if (HasNames(format)) { bw.FillInt32($"FileNameOffset{index}", (int)bw.Position); if (unicode) { bw.WriteUTF16(Name, true); } else { bw.WriteShiftJIS(Name, true); } } }
private void Write(BinaryWriterEx bhdWriter, BinaryWriterEx bdtWriter) { bhdWriter.WriteASCII("BHF3"); bhdWriter.WriteASCII(BHDTimestamp.PadRight(8, '\0')); bhdWriter.WriteByte(Format); bhdWriter.WriteByte(0); bhdWriter.WriteByte(0); bhdWriter.WriteByte(0); bhdWriter.BigEndian = Format == 0xE0; bhdWriter.WriteInt32(Files.Count); bhdWriter.WriteInt32(0); bhdWriter.WriteInt32(0); bhdWriter.WriteInt32(0); bdtWriter.WriteASCII("BDF3"); bdtWriter.WriteASCII(BDTTimestamp.PadRight(8, '\0')); bdtWriter.WriteInt32(0); for (int i = 0; i < Files.Count; i++) { File file = Files[i]; bhdWriter.WriteByte(0x40); bhdWriter.WriteByte(0); bhdWriter.WriteByte(0); bhdWriter.WriteByte(0); bhdWriter.WriteInt32(file.Bytes.Length); bhdWriter.WriteInt32((int)bdtWriter.Position); bhdWriter.WriteInt32(i); bhdWriter.ReserveInt32($"FileName{i}"); if (Format == 0x54 || Format == 0x74) { bhdWriter.WriteInt32(file.Bytes.Length); } bdtWriter.WriteBytes(file.Bytes); bdtWriter.Pad(0x10); } for (int i = 0; i < Files.Count; i++) { File file = Files[i]; bhdWriter.FillInt32($"FileName{i}", (int)bhdWriter.Position); bhdWriter.WriteShiftJIS(file.Name, true); } }
private void Write(BinaryWriterEx bhdWriter, BinaryWriterEx bdtWriter) { bhdWriter.WriteASCII("BHF3"); bhdWriter.WriteFixStr(BHDTimestamp, 8); bhdWriter.WriteByte((byte)Format); bhdWriter.WriteByte(0); bhdWriter.WriteByte(0); bhdWriter.WriteByte(0); bhdWriter.BigEndian = Binder.ForceBigEndian(Format); bhdWriter.WriteInt32(Files.Count); bhdWriter.WriteInt32(0); bhdWriter.WriteInt32(0); bhdWriter.WriteInt32(0); bdtWriter.WriteASCII("BDF3"); bdtWriter.WriteFixStr(BDTTimestamp, 8); bdtWriter.WriteInt32(0); for (int i = 0; i < Files.Count; i++) { BinderFile file = Files[i]; bhdWriter.WriteByte(0x40); bhdWriter.WriteByte(0); bhdWriter.WriteByte(0); bhdWriter.WriteByte(0); bhdWriter.WriteInt32(file.Bytes.Length); bhdWriter.WriteUInt32((uint)bdtWriter.Position); bhdWriter.WriteInt32(i); bhdWriter.ReserveUInt32($"FileName{i}"); if (Binder.HasUncompressedSize(Format)) { bhdWriter.WriteInt32(file.Bytes.Length); } bdtWriter.WriteBytes(file.Bytes); bdtWriter.Pad(0x10); } for (int i = 0; i < Files.Count; i++) { BinderFile file = Files[i]; bhdWriter.FillUInt32($"FileName{i}", (uint)bhdWriter.Position); bhdWriter.WriteShiftJIS(file.Name, true); } }
internal void WriteHeader(BinaryWriterEx bw, GPGame game, int groupIndex, int groupHeadersOffset) { bw.FillInt32($"GroupHeaderOffset{groupIndex}", (int)bw.Position - groupHeadersOffset); bw.WriteInt32(Params.Count); bw.ReserveInt32($"ParamHeaderOffsetsOffset{groupIndex}"); if (game == GPGame.DarkSouls2) { bw.WriteShiftJIS(Name1, true); } else { bw.WriteUTF16(Name1, true); bw.WriteUTF16(Name2, true); } bw.Pad(4); }
internal void WriteName(BinaryWriterEx bw, int i, byte Unk4) { if (Name == null || Name == "") { bw.FillInt64($"NameOffset{i}", 0); } else { bw.FillInt64($"NameOffset{i}", bw.Position); if (Unk4 == 6) { bw.WriteShiftJIS(Name, true); } else if (Unk4 == 7) { bw.WriteUTF16(Name, true); } } }
internal void WriteParamHeader(BinaryWriterEx bw, GPGame game, int groupIndex, int paramIndex, int paramHeadersOffset) { bw.FillInt32($"ParamHeaderOffset{groupIndex}:{paramIndex}", (int)bw.Position - paramHeadersOffset); bw.ReserveInt32($"ValuesOffset{groupIndex}:{paramIndex}"); bw.ReserveInt32($"ValueIDsOffset{groupIndex}:{paramIndex}"); bw.WriteByte((byte)Type); bw.WriteByte((byte)Values.Count); bw.WriteByte(0); bw.WriteByte(0); if (game == GPGame.DarkSouls2) { bw.WriteShiftJIS(Name1, true); } else { bw.WriteUTF16(Name1, true); bw.WriteUTF16(Name2, true); } bw.Pad(4); }
/// <summary> /// Serializes file data to a stream. /// </summary> protected override void Write(BinaryWriterEx bw) { bw.BigEndian = BigEndian; for (int i = 0; i < Globals.Count; i++) { if (LongFormat) { bw.ReserveInt64($"Offset{i}"); } else { bw.ReserveUInt32($"Offset{i}"); } } if (LongFormat) { bw.WriteInt64(0); } else { bw.WriteUInt32(0); } for (int i = 0; i < Globals.Count; i++) { if (LongFormat) { bw.FillInt64($"Offset{i}", bw.Position); bw.WriteUTF16(Globals[i], true); } else { bw.FillUInt32($"Offset{i}", (uint)bw.Position); bw.WriteShiftJIS(Globals[i], true); } } bw.Pad(0x10); }
internal override void Write(BinaryWriterEx bw, int id) { long start = bw.Position; bw.ReserveInt32("NameOffset"); bw.WriteInt32(0); bw.WriteInt32(id); bw.WriteUInt32((uint)Shape.Type); bw.WriteVector3(Position); bw.WriteVector3(Rotation); bw.ReserveInt32("UnkOffsetA"); bw.ReserveInt32("UnkOffsetB"); bw.ReserveInt32("ShapeDataOffset"); bw.ReserveInt32("EntityDataOffset"); bw.WriteInt32(0); bw.FillInt32("NameOffset", (int)(bw.Position - start)); bw.WriteShiftJIS(MSB.ReambiguateName(Name), true); bw.Pad(4); bw.FillInt32("UnkOffsetA", (int)(bw.Position - start)); bw.WriteInt32(0); bw.FillInt32("UnkOffsetB", (int)(bw.Position - start)); bw.WriteInt32(0); if (Shape.HasShapeData) { bw.FillInt32("ShapeDataOffset", (int)(bw.Position - start)); Shape.WriteShapeData(bw); } else { bw.FillInt32("ShapeDataOffset", 0); } bw.FillInt32("EntityDataOffset", (int)(bw.Position - start)); bw.WriteInt32(EntityID); }
internal override void Write(BinaryWriterEx bw) { if (layout == null) { throw new InvalidOperationException("Params cannot be written without a layout."); } Rows.Sort((r1, r2) => r1.ID.CompareTo(r2.ID)); bw.BigEndian = false; bw.ReserveInt32("NameOffset"); bw.WriteInt16(0); bw.WriteInt16(Unk1); bw.WriteInt16(Unk2); bw.WriteUInt16((ushort)Rows.Count); if (FixStrID) { bw.WriteFixStr(ID, 0x20); } else { bw.WriteInt32(0); bw.ReserveInt32("IDOffset"); bw.WriteInt32(0); bw.WriteInt32(0); bw.WriteInt32(0); bw.WriteInt32(0); bw.WriteInt32(0); bw.WriteInt32(0); } bw.WriteByte(0); bw.WriteByte(Unk3); bw.WriteByte(Unk4); bw.WriteByte(0); bw.ReserveInt64("DataStart"); bw.WriteInt32(0); bw.WriteInt32(0); for (int i = 0; i < Rows.Count; i++) { Rows[i].WriteHeader(bw, i); } bw.FillInt64("DataStart", bw.Position); for (int i = 0; i < Rows.Count; i++) { Rows[i].WriteCells(bw, i, layout); } bw.FillInt32("NameOffset", (int)bw.Position); if (FixStrID) { if (Unk4 == 6) { bw.WriteShiftJIS(Name, true); } else if (Unk4 == 7) { bw.WriteUTF16(Name, true); } } else { bw.WriteShiftJIS(Name, true); bw.FillInt32("IDOffset", (int)bw.Position); bw.WriteASCII(ID, true); } for (int i = 0; i < Rows.Count; i++) { Rows[i].WriteName(bw, i, Unk4); } }
internal void WriteName(BinaryWriterEx bw, int index) { bw.FillInt32($"FileName{index}", (int)bw.Position); bw.WriteShiftJIS(Name, true); }
private static void WriteFileName(BinderFile file, BinaryWriterEx bw, int index) { bw.FillUInt32($"FileName{index}", (uint)bw.Position); bw.WriteShiftJIS(file.Name, true); }
internal void WriteStrings(BinaryWriterEx bw, PARAMDEF def, int index, Dictionary <string, long> sharedStringOffsets) { if (def.FormatVersion >= 202) { bw.FillInt64($"DisplayNameOffset{index}", bw.Position); bw.WriteUTF16(DisplayName, true); } long descriptionOffset = 0; if (Description != null) { descriptionOffset = bw.Position; if (def.Unicode) { bw.WriteUTF16(Description, true); } else { bw.WriteShiftJIS(Description, true); } } if (def.FormatVersion >= 200) { bw.FillInt64($"DescriptionOffset{index}", descriptionOffset); } else { bw.FillInt32($"DescriptionOffset{index}", (int)descriptionOffset); } if (def.FormatVersion >= 202) { bw.FillInt64($"InternalTypeOffset{index}", bw.Position); bw.WriteASCII(InternalType, true); bw.FillInt64($"InternalNameOffset{index}", bw.Position); bw.WriteASCII(MakeInternalName(), true); } if (def.FormatVersion >= 200) { long writeSharedStringMaybe(string str, bool unicode) { if (str == null) { return(0); } if (!sharedStringOffsets.ContainsKey(str)) { sharedStringOffsets[str] = bw.Position; if (unicode) { bw.WriteUTF16(str, true); } else { bw.WriteASCII(str, true); } } return(sharedStringOffsets[str]); } bw.FillInt64($"UnkB8Offset{index}", writeSharedStringMaybe(UnkB8, false)); bw.FillInt64($"UnkC0Offset{index}", writeSharedStringMaybe(UnkC0, false)); bw.FillInt64($"UnkC8Offset{index}", writeSharedStringMaybe(UnkC8, true)); } }
internal void Write(BinaryWriterEx bw, List <File> 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.WriteASCII(Timestamp.PadRight(8, '\0')); if (Format == 0x0C || Format == 0x30) { bw.WriteInt64(0x18); } else if (Format == 0x2E || Format == 0x74) { bw.WriteInt64(0x24); } else if (Format == 0x3E) { bw.WriteInt64(0x28); } bw.WriteInt64(0); 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++) { FileHeader.Write(bw, files[i], 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 (Util.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); } } }
/// <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); } }