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 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); } } }
/// <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, Flag2); } bw.Pad(0x10); for (int i = 0; i < Textures.Count; i++) { Texture texture = Textures[i]; bw.FillUInt32($"FileName{i}", (uint)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.FillUInt32($"FileData{i}", (uint)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); }
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); } }
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 override void Write(BinaryWriterEx bw) { var connectorPoints = new ConnectorPointSection(); var connectorConditions = new ConnectorConditionSection(); foreach (Connector connector in Connectors) { connector.GivePointsAndConds(connectorPoints, connectorConditions); } bw.BigEndian = false; bw.WriteASCII("NVMA"); bw.WriteUInt32((uint)Version); bw.ReserveUInt32("FileSize"); bw.WriteInt32(Version == NVAVersion.OldBloodborne ? 8 : 9); Navmeshes.Write(bw, 0); Entries1.Write(bw, 1); Entries2.Write(bw, 2); new Section3().Write(bw, 3); Connectors.Write(bw, 4); connectorPoints.Write(bw, 5); connectorConditions.Write(bw, 6); Entries7.Write(bw, 7); if (Version != NVAVersion.OldBloodborne) { Entries8.Write(bw, 8); } bw.FillUInt32("FileSize", (uint)bw.Position); }
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 WriteEntries(BinaryWriterEx bw, int index) { if (Count == 0) { bw.FillUInt32($"EntriesOffset{index}", 0); } else { bw.FillUInt32($"EntriesOffset{index}", (uint)bw.Position); foreach (Entry entry in this) { entry.Write(bw); } bw.Pad(8); } }
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 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); }
internal void Write(BinaryWriterEx bw) { bw.WriteInt16((short)Members1.Count); bw.WriteInt16((short)Members2.Count); bw.ReserveUInt32("SekiroUnkOffset1"); bw.ReserveUInt32("SekiroUnkOffset2"); bw.WriteInt32(0); bw.WriteInt32(0); bw.WriteInt32(0); bw.WriteInt32(0); bw.WriteInt32(0); bw.FillUInt32("SekiroUnkOffset1", (uint)bw.Position); foreach (Member member in Members1) { member.Write(bw); } bw.FillUInt32("SekiroUnkOffset2", (uint)bw.Position); foreach (Member member in Members2) { member.Write(bw); } }
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); } }
public void WriteData(BinaryWriterEx bw, HKX hkx, HKXVariation variation) { uint absoluteOffset = (uint)bw.Position; bw.FillUInt32("absoffset" + SectionID, absoluteOffset); foreach (var obj in Objects) { obj.Write(hkx, this, bw, absoluteOffset, variation); } // Local fixups bw.FillUInt32("locoffset" + SectionID, (uint)bw.Position - absoluteOffset); foreach (var loc in LocalReferences) { loc.Write(bw); } while ((bw.Position % 16) != 0) { bw.WriteByte(0xFF); // 16 byte align } // Global fixups bw.FillUInt32("globoffset" + SectionID, (uint)bw.Position - absoluteOffset); foreach (var glob in GlobalReferences) { glob.Write(bw); } while ((bw.Position % 16) != 0) { bw.WriteByte(0xFF); // 16 byte align } // Virtual fixups bw.FillUInt32("virtoffset" + SectionID, (uint)bw.Position - absoluteOffset); foreach (var virt in VirtualReferences) { virt.Write(bw); } while ((bw.Position % 16) != 0) { bw.WriteByte(0xFF); // 16 byte align } bw.FillUInt32("expoffset" + SectionID, (uint)bw.Position - absoluteOffset); bw.FillUInt32("impoffset" + SectionID, (uint)bw.Position - absoluteOffset); bw.FillUInt32("endoffset" + SectionID, (uint)bw.Position - absoluteOffset); }
internal void WriteBinder4FileData(BinaryWriterEx bwHeader, BinaryWriterEx bwData, Format format, int index, byte[] bytes) { WriteFileData(bwData, bytes); bwHeader.FillInt64($"FileCompressedSize{index}", CompressedSize); if (HasCompression(format)) { bwHeader.FillInt64($"FileUncompressedSize{index}", UncompressedSize); } if (HasLongOffsets(format)) { bwHeader.FillInt64($"FileDataOffset{index}", DataOffset); } else { bwHeader.FillUInt32($"FileDataOffset{index}", (uint)DataOffset); } }
/// <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); }
private static void WriteFileData(BinderFile file, BinaryWriterEx bw, int index) { if (file.Bytes.Length > 0) { bw.Pad(0x10); } bw.FillUInt32($"FileData{index}", (uint)bw.Position); int compressedSize = file.Bytes.Length; if (Binder.IsCompressed(file.Flags)) { compressedSize = SFUtil.WriteZlib(bw, 0x9C, file.Bytes); } else { bw.WriteBytes(file.Bytes); } bw.FillInt32($"CompressedSize{index}", compressedSize); }
internal void WriteCells(BinaryWriterEx bw, byte format2D, int i, Layout layout) { if ((format2D & 0x7F) < 4) { bw.FillUInt32($"RowOffset{i}", (uint)bw.Position); } else { bw.FillInt64($"RowOffset{i}", bw.Position); } for (int j = 0; j < layout.Count; j++) { Cell cell = Cells[j]; Layout.Entry entry = layout[j]; CellType type = entry.Type; object value = cell.Value; if (entry.Name != cell.Name || type != cell.Type) { throw new FormatException("Layout does not match cells."); } void WriteBools(CellType boolType, int fieldSize) { byte[] b = new byte[fieldSize]; int k; for (k = 0; k < fieldSize * 8; k++) { if (j + k >= layout.Count || layout[j + k].Type != boolType) { break; } if ((bool)Cells[j + k].Value) { b[k / 8] |= (byte)(1 << (k % 8)); } } j += k - 1; bw.WriteBytes(b); } if (type == CellType.s8) { bw.WriteSByte((sbyte)value); } else if (type == CellType.u8 || type == CellType.x8) { bw.WriteByte((byte)value); } else if (type == CellType.s16) { bw.WriteInt16((short)value); } else if (type == CellType.u16 || type == CellType.x16) { bw.WriteUInt16((ushort)value); } else if (type == CellType.s32) { bw.WriteInt32((int)value); } else if (type == CellType.u32 || type == CellType.x32) { bw.WriteUInt32((uint)value); } else if (type == CellType.f32) { bw.WriteSingle((float)value); } else if (type == CellType.dummy8) { bw.WriteBytes((byte[])value); } else if (type == CellType.fixstr) { bw.WriteFixStr((string)value, entry.Size); } else if (type == CellType.fixstrW) { bw.WriteFixStrW((string)value, entry.Size); } else if (type == CellType.b8) { WriteBools(type, 1); } else if (type == CellType.b16) { WriteBools(type, 2); } else if (type == CellType.b32) { WriteBools(type, 4); } } }
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 = BigEndian; void WriteFormat() { bw.WriteByte((byte)(BigEndian ? 0xFF : 0x00)); bw.WriteByte(Format2D); bw.WriteByte(Format2E); bw.WriteByte(Format2F); } // DeS, DS1 if ((Format2D & 0x7F) < 3) { bw.ReserveUInt32("StringsOffset"); bw.ReserveUInt16("DataStart"); bw.WriteInt16(Unk06); bw.WriteInt16(Unk08); bw.WriteUInt16((ushort)Rows.Count); bw.WriteFixStr(ID, 0x20, 0x20); WriteFormat(); } // DS2 else if ((Format2D & 0x7F) == 3) { bw.ReserveUInt32("StringsOffset"); bw.WriteInt16(0); bw.WriteInt16(Unk06); bw.WriteInt16(Unk08); bw.WriteUInt16((ushort)Rows.Count); bw.WriteFixStr(ID, 0x20, 0x20); WriteFormat(); bw.ReserveUInt32("DataStart"); bw.WriteInt32(0); bw.WriteInt32(0); bw.WriteInt32(0); } // SotFS, BB else if ((Format2D & 0x7F) == 4) { bw.ReserveUInt32("StringsOffset"); bw.WriteInt16(0); bw.WriteInt16(Unk06); bw.WriteInt16(Unk08); bw.WriteUInt16((ushort)Rows.Count); bw.WriteFixStr(ID, 0x20, 0x00); WriteFormat(); bw.ReserveInt64("DataStart"); bw.WriteInt64(0); } // DS3, SDT else { bw.ReserveUInt32("StringsOffset"); bw.WriteInt16(0); bw.WriteInt16(Unk06); bw.WriteInt16(Unk08); bw.WriteUInt16((ushort)Rows.Count); bw.WriteInt32(0); bw.ReserveInt64("IDOffset"); bw.WritePattern(0x14, 0x00); WriteFormat(); bw.ReserveInt64("DataStart"); bw.WriteInt64(0); } for (int i = 0; i < Rows.Count; i++) { Rows[i].WriteHeader(bw, Format2D, i); } if ((Format2D & 0x7F) < 3) { bw.FillUInt16("DataStart", (ushort)bw.Position); } else if ((Format2D & 0x7F) == 3) { bw.FillUInt32("DataStart", (uint)bw.Position); } else { bw.FillInt64("DataStart", bw.Position); } for (int i = 0; i < Rows.Count; i++) { Rows[i].WriteCells(bw, Format2D, i, layout); } bw.FillUInt32("StringsOffset", (uint)bw.Position); if ((Format2D & 0x7F) > 4) { bw.FillInt64("IDOffset", bw.Position); bw.WriteASCII(ID, true); } for (int i = 0; i < Rows.Count; i++) { Rows[i].WriteName(bw, Format2D, i); } }
private static void WriteFileName(BinderFile file, BinaryWriterEx bw, int index) { bw.FillUInt32($"FileName{index}", (uint)bw.Position); bw.WriteShiftJIS(file.Name, true); }
/// <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); } }
internal void WriteCells(BinaryWriterEx bw, byte format2D, int index) { if ((format2D & 0x7F) < 4) { bw.FillUInt32($"RowOffset{index}", (uint)bw.Position); } else { bw.FillInt64($"RowOffset{index}", bw.Position); } int bitOffset = -1; PARAMDEF.DefType bitType = PARAMDEF.DefType.u8; uint bitValue = 0; for (int i = 0; i < Cells.Count; i++) { Cell cell = Cells[i]; object value = cell.Value; PARAMDEF.Field field = cell.Def; PARAMDEF.DefType type = field.DisplayType; if (type == PARAMDEF.DefType.s8) { bw.WriteSByte((sbyte)value); } else if (type == PARAMDEF.DefType.s16) { bw.WriteInt16((short)value); } else if (type == PARAMDEF.DefType.s32) { bw.WriteInt32((int)value); } else if (type == PARAMDEF.DefType.f32) { bw.WriteSingle((float)value); } else if (type == PARAMDEF.DefType.fixstr) { bw.WriteFixStr((string)value, field.ArrayLength); } else if (type == PARAMDEF.DefType.fixstrW) { bw.WriteFixStrW((string)value, field.ArrayLength * 2); } else if (ParamUtil.IsBitType(type)) { if (field.BitSize == -1) { if (type == PARAMDEF.DefType.u8) { bw.WriteByte((byte)value); } else if (type == PARAMDEF.DefType.u16) { bw.WriteUInt16((ushort)value); } else if (type == PARAMDEF.DefType.u32) { bw.WriteUInt32((uint)value); } else if (type == PARAMDEF.DefType.dummy8) { bw.WriteBytes((byte[])value); } } else { if (bitOffset == -1) { bitOffset = 0; bitType = type == PARAMDEF.DefType.dummy8 ? PARAMDEF.DefType.u8 : type; bitValue = 0; } uint shifted = 0; if (bitType == PARAMDEF.DefType.u8) { shifted = (byte)value; } else if (bitType == PARAMDEF.DefType.u16) { shifted = (ushort)value; } else if (bitType == PARAMDEF.DefType.u32) { shifted = (uint)value; } // Shift left first to clear any out-of-range bits shifted = shifted << (32 - field.BitSize) >> (32 - field.BitSize - bitOffset); bitValue |= shifted; bitOffset += field.BitSize; bool write = false; if (i == Cells.Count - 1) { write = true; } else { PARAMDEF.Field nextField = Cells[i + 1].Def; PARAMDEF.DefType nextType = nextField.DisplayType; int bitLimit = ParamUtil.GetBitLimit(bitType); if (!ParamUtil.IsBitType(nextType) || nextField.BitSize == -1 || bitOffset + nextField.BitSize > bitLimit || (nextType == PARAMDEF.DefType.dummy8 ? PARAMDEF.DefType.u8 : nextType) != bitType) { write = true; } } if (write) { bitOffset = -1; if (bitType == PARAMDEF.DefType.u8) { bw.WriteByte((byte)bitValue); } else if (bitType == PARAMDEF.DefType.u16) { bw.WriteUInt16((ushort)bitValue); } else if (bitType == PARAMDEF.DefType.u32) { bw.WriteUInt32(bitValue); } } } } else { throw new NotImplementedException($"Unsupported field type: {type}"); } } }
/// <summary> /// Serializes file data to a stream. /// </summary> protected override void Write(BinaryWriterEx bw) { if (AppliedParamdef == null) { throw new InvalidOperationException("Params cannot be written without applying a paramdef."); } bw.BigEndian = BigEndian; void WriteFormat() { bw.WriteByte((byte)(BigEndian ? 0xFF : 0x00)); bw.WriteByte(Format2D); bw.WriteByte(Format2E); bw.WriteByte(Format2F); } // DeS, DS1 if ((Format2D & 0x7F) < 3) { bw.ReserveUInt32("StringsOffset"); bw.ReserveUInt16("DataStart"); bw.WriteInt16(Unk06); bw.WriteInt16(Unk08); bw.WriteUInt16((ushort)Rows.Count); bw.WriteFixStr(ParamType, 0x20, (byte)((Format2D & 0x7F) < 2 ? 0x20 : 0x00)); WriteFormat(); } // DS2 else if ((Format2D & 0x7F) == 3) { bw.ReserveUInt32("StringsOffset"); bw.WriteInt16(0); bw.WriteInt16(Unk06); bw.WriteInt16(Unk08); bw.WriteUInt16((ushort)Rows.Count); bw.WriteFixStr(ParamType, 0x20, 0x20); WriteFormat(); bw.ReserveUInt32("DataStart"); bw.WriteInt32(0); bw.WriteInt32(0); bw.WriteInt32(0); } // SotFS, BB else if ((Format2D & 0x7F) == 4) { bw.ReserveUInt32("StringsOffset"); bw.WriteInt16(0); bw.WriteInt16(Unk06); bw.WriteInt16(Unk08); bw.WriteUInt16((ushort)Rows.Count); bw.WriteFixStr(ParamType, 0x20, 0x00); WriteFormat(); bw.ReserveInt64("DataStart"); bw.WriteInt64(0); } // DS3, SDT else { bw.ReserveUInt32("StringsOffset"); bw.WriteInt16(0); bw.WriteInt16(Unk06); bw.WriteInt16(Unk08); bw.WriteUInt16((ushort)Rows.Count); bw.WriteInt32(0); bw.ReserveInt64("IDOffset"); bw.WritePattern(0x14, 0x00); WriteFormat(); bw.ReserveInt64("DataStart"); bw.WriteInt64(0); } for (int i = 0; i < Rows.Count; i++) { Rows[i].WriteHeader(bw, Format2D, i); } if ((Format2D & 0x7F) < 2) { bw.WritePattern(0x20, 0x00); } if ((Format2D & 0x7F) < 3) { bw.FillUInt16("DataStart", (ushort)bw.Position); } else if ((Format2D & 0x7F) == 3) { bw.FillUInt32("DataStart", (uint)bw.Position); } else { bw.FillInt64("DataStart", bw.Position); } for (int i = 0; i < Rows.Count; i++) { Rows[i].WriteCells(bw, Format2D, i); } bw.FillUInt32("StringsOffset", (uint)bw.Position); if ((Format2D & 0x7F) > 4) { bw.FillInt64("IDOffset", bw.Position); bw.WriteASCII(ParamType, true); } for (int i = 0; i < Rows.Count; i++) { Rows[i].WriteName(bw, Format2D, Format2E, i); } // DeS and BB sometimes (but not always) include some useless padding here }
/// <summary> /// Serializes file data to a stream. /// </summary> protected override void Write(BinaryWriterEx bw) { if (AppliedParamdef == null) { throw new InvalidOperationException("Params cannot be written without applying a paramdef."); } bw.BigEndian = BigEndian; bw.ReserveUInt32("StringsOffset"); if (Format2D.HasFlag(FormatFlags1.Flag01) && Format2D.HasFlag(FormatFlags1.IntDataOffset) || Format2D.HasFlag(FormatFlags1.LongDataOffset)) { bw.WriteInt16(0); } else { bw.ReserveUInt16("DataStart"); } bw.WriteInt16(Unk06); bw.WriteInt16(ParamdefDataVersion); bw.WriteUInt16((ushort)Rows.Count); if (Format2D.HasFlag(FormatFlags1.OffsetParamType)) { bw.WriteInt32(0); bw.ReserveInt64("ParamTypeOffset"); bw.WritePattern(0x14, 0x00); } else { // This padding heuristic isn't completely accurate, not that it matters bw.WriteFixStr(ParamType, 0x20, (byte)(Format2D.HasFlag(FormatFlags1.Flag01) ? 0x20 : 0x00)); } bw.WriteByte((byte)(BigEndian ? 0xFF : 0x00)); bw.WriteByte((byte)Format2D); bw.WriteByte((byte)Format2E); bw.WriteByte(ParamdefFormatVersion); if (Format2D.HasFlag(FormatFlags1.Flag01) && Format2D.HasFlag(FormatFlags1.IntDataOffset)) { bw.ReserveUInt32("DataStart"); bw.WriteInt32(0); bw.WriteInt32(0); bw.WriteInt32(0); } else if (Format2D.HasFlag(FormatFlags1.LongDataOffset)) { bw.ReserveInt64("DataStart"); bw.WriteInt64(0); } for (int i = 0; i < Rows.Count; i++) { Rows[i].WriteHeader(bw, this, i); } // This is probably pretty stupid if (Format2D == FormatFlags1.Flag01) { bw.WritePattern(0x20, 0x00); } if (Format2D.HasFlag(FormatFlags1.Flag01) && Format2D.HasFlag(FormatFlags1.IntDataOffset)) { bw.FillUInt32("DataStart", (uint)bw.Position); } else if (Format2D.HasFlag(FormatFlags1.LongDataOffset)) { bw.FillInt64("DataStart", bw.Position); } else { bw.FillUInt16("DataStart", (ushort)bw.Position); } for (int i = 0; i < Rows.Count; i++) { Rows[i].WriteCells(bw, this, i); } bw.FillUInt32("StringsOffset", (uint)bw.Position); if (Format2D.HasFlag(FormatFlags1.OffsetParamType)) { bw.FillInt64("ParamTypeOffset", bw.Position); bw.WriteASCII(ParamType, true); } for (int i = 0; i < Rows.Count; i++) { Rows[i].WriteName(bw, this, i); } // DeS and BB sometimes (but not always) include some useless padding here }
public void Finish(BinaryWriterEx bw) { Length = (uint)(bw.Position - Start); bw.FillUInt32($"Block{Start:X}", Length); }