protected void WriteSection(BinaryWriter writer, Stream stream) { // write length writer.Write((uint)stream.Length); // copy the stream to the underlying stream of the writer stream.CopyTo(writer.BaseStream); // write padding writer.AlignPosition(16); }
// Methods internal void InternalWrite(BinaryWriter writer) { int size = GetSize(); writer.Write(size); writer.Write(_numAssignedFrames); writer.Write(_type); for (int i = 0; i < _numAssignedFrames; i++) { writer.Write(_assignedFrameIndices[i]); } writer.AlignPosition(4); for (int i = 0; i < _numAssignedFrames; i++) { switch (_type) { case 0x04: { for (int j = 0; j < 2; j++) { writer.Write((ushort)(_boneKeyData[i][j] * FIXED_POINT)); } } break; case 0x08: { for (int j = 0; j < 4; j++) { writer.Write((ushort)(_boneKeyData[i][j] * FIXED_POINT)); } } break; case 0x0C: { for (int j = 0; j < 3; j++) { writer.Write(_boneKeyData[i][j]); } } break; default: break; } } }
internal void InternalWrite(BinaryWriter writer) { writer.WriteStructure(_header); for (int i = 0; i < _header.entryCount; i++) { _subEntries[i].InternalWrite(writer); } writer.AlignPosition(16); for (int i = 0; i < _header.entryCount; i++) { if (i > 1 && _subEntries[i].Flags.HasFlagUnchecked(RecordFlags.DirectoryRecord)) { _subEntries[i].DirectoryListing.InternalWrite(writer); } } }
// Internal Methods internal override void InternalWrite(BinaryWriter writer) { int posFileStart = (int)writer.BaseStream.Position; // Seek past chunk header writer.BaseStream.Seek(HEADER_SIZE + 4, SeekOrigin.Current); // Seek past texture pack header writer.BaseStream.Seek(TextureCount * sizeof(int), SeekOrigin.Current); int[] texturePointerTable = new int[TextureCount]; // Write texture data for (int i = 0; i < TextureCount; i++) { writer.AlignPosition(64); texturePointerTable[i] = (int)(writer.BaseStream.Position - posFileStart); _textures[i].InternalWrite(writer); } // Calculate length long posFileEnd = writer.BaseStream.Position; int length = (int)(posFileEnd - posFileStart); // Write header writer.BaseStream.Seek(posFileStart, SeekOrigin.Begin); writer.Write(FLAG); writer.Write((short)0); // userID writer.Write(length); writer.WriteCString(TAG, 4); writer.Write(0); writer.Write(TextureCount); // Write pointer table writer.Write(texturePointerTable); // Seek to end writer.BaseStream.Seek(posFileEnd, SeekOrigin.Begin); }
internal override void InternalWrite(BinaryWriter writer) { // Save the position of the file in the stream long posFileStart = writer.GetPosition(); // Precalculate the first offset long posPrevDataEnd = (Entries.Count + 1) * BVPEntry.SIZE; // Write the entry table for (int i = 0; i < Entries.Count; i++) { // The offset is the position where the last data write ended, aligned to the 16 byte boundary Entries[i].FileDataOffset = (int)AlignmentHelper.Align(posPrevDataEnd, 16); // Write table entry Entries[i].WriteEntryHeader(writer); // Write data at offset writer.Write(Entries[i].Data, posFileStart + Entries[i].FileDataOffset); // Update the previous data end position posPrevDataEnd = Entries[i].FileDataOffset + Entries[i].DataLength; } // Write empty terminator entry writer.Write(0, BVPEntry.SIZE); // Seek to the last data write position, and align the file to 64 bytes writer.BaseStream.Seek(posPrevDataEnd, SeekOrigin.Begin); writer.AlignPosition(64); }
/// <summary> /// Inherited from <see cref="RWNode"/>. Writes the data beyond the header. /// </summary> /// <param name="writer">The <see cref="BinaryWriter"/> to write the data with.</param> protected internal override void InternalWriteInnerData(BinaryWriter writer) { writer.WriteCString(Value); writer.AlignPosition(4); }
internal override void InternalWrite(BinaryWriter writer) { // Save the start position to calculate the filesize and // to write out the header after we know where all the structure offsets are Stream stream = writer.BaseStream; int posFileStart = (int)stream.Position; stream.Seek(SPR4Header.SIZE, SeekOrigin.Current); // Create initial header and tables SPR4Header header = new SPR4Header(TextureCount, KeyFrameCount); TypePointerTable[] keyFramePointerTable = new TypePointerTable[header.numKeyFrames]; TypePointerTable[] texturePointerTable = new TypePointerTable[header.numTextures]; // Set the pointer table offsets and seek past the entries // as the entries will be written later header.texturePointerTableOffset = (int)(stream.Position - posFileStart); stream.Seek(TypePointerTable.SIZE * header.numTextures, SeekOrigin.Current); header.keyFramePointerTableOffset = (int)(stream.Position - posFileStart); stream.Seek(TypePointerTable.SIZE * header.numKeyFrames, SeekOrigin.Current); // Write out the keyframe data and fill up the pointer table for (int i = 0; i < header.numKeyFrames; i++) { writer.AlignPosition(16); keyFramePointerTable[i].offset = (int)(stream.Position - posFileStart); _keyFrames[i].InternalWrite(writer); } writer.Seek(16, SeekOrigin.Current); writer.AlignPosition(16); // Write out the texture data and fill up the pointer table for (int i = 0; i < header.numTextures; i++) { texturePointerTable[i].offset = (int)(stream.Position - posFileStart); _textures[i].InternalWrite(writer); writer.Seek(16, SeekOrigin.Current); } // Save the end position long posFileEnd = stream.Position; // Seek back to the tables and write out the tables stream.Seek(posFileStart + header.texturePointerTableOffset, SeekOrigin.Begin); stream.WriteStructures(texturePointerTable, header.numTextures); stream.Seek(posFileStart + header.keyFramePointerTableOffset, SeekOrigin.Begin); stream.WriteStructures(keyFramePointerTable, header.numKeyFrames); // Seek back to the file and write out the header with // the offsets to the structures in the file writer.BaseStream.Seek(posFileStart, SeekOrigin.Begin); writer.BaseStream.WriteStructure(header); // Set the file pointer back to the end of the file as expected writer.BaseStream.Seek(posFileEnd, SeekOrigin.Begin); }
internal override void InternalWrite(BinaryWriter writer) { int posFileStart = (int)writer.BaseStream.Position; // seek past the header, type table and code labels writer.BaseStream.Seek(DATA_START + (_procedures.Length * BFCodeLabel.SIZE) + (_jumpLabels.Length * BFCodeLabel.SIZE), SeekOrigin.Current); // create code label type table entries int procsLength = _procedures.Length * BFCodeLabel.SIZE; int jumpsLength = _jumpLabels.Length * BFCodeLabel.SIZE; int opCodeDataStart = (int)(writer.BaseStream.Position - posFileStart); int numProcsSet = 0; int numJumpsSet = 0; for (int i = 0; i < _opcodes.Count; i++) { int procIdx = -1; // try to find a procedure with this index if (numProcsSet != _procedures.Length) { procIdx = Array.FindIndex(_procedures, p => p.OpcodeIndex == i); if (procIdx != -1) { _procedures[procIdx].Offset = (uint)(((writer.BaseStream.Position - posFileStart) - opCodeDataStart) / 4); numProcsSet++; } } // if we haven't found a procedure, try to find a jump label with this index if (procIdx == -1 && numJumpsSet != _jumpLabels.Length) { int jumpIdx = Array.FindIndex(_jumpLabels, j => j.OpcodeIndex == i); if (jumpIdx != -1) { _jumpLabels[jumpIdx].Offset = (uint)(((writer.BaseStream.Position - posFileStart) - opCodeDataStart) / 4); numJumpsSet++; } } // write the opcode data writer.Write((ushort)_opcodes[i].Instruction); if (_opcodes[i].Operand != null) { switch (_opcodes[i].Operand.Type) { case BFOperandType.Immediate: if (_opcodes[i].Instruction == BFInstruction.PushUInt32) { writer.Write((ushort)0); writer.Write((uint)_opcodes[i].Operand.ImmediateValue); } else { writer.Write((ushort)_opcodes[i].Operand.ImmediateValue); } break; case BFOperandType.FloatingPoint: writer.Write((ushort)0); writer.Write((float)_opcodes[i].Operand.FloatValue); break; } } else { writer.Write((ushort)0); } } int opCodeDataEnd = (int)(writer.BaseStream.Position - posFileStart); // set type table entries TypeTableEntry[] typeTableEntries = new TypeTableEntry[TYPE_TABLE_COUNT]; typeTableEntries[(int)TypeTableType.Procedures] = CreateTypeTableEntry(TypeTableType.Procedures, procsLength, DATA_START); typeTableEntries[(int)TypeTableType.JumpLabels] = CreateTypeTableEntry(TypeTableType.JumpLabels, jumpsLength, DATA_START + procsLength); typeTableEntries[(int)TypeTableType.Opcodes] = CreateTypeTableEntry(TypeTableType.Opcodes, opCodeDataEnd - opCodeDataStart, opCodeDataStart); typeTableEntries[(int)TypeTableType.Messages] = CreateTypeTableEntry(TypeTableType.Messages, 0, opCodeDataEnd); typeTableEntries[(int)TypeTableType.Strings] = CreateTypeTableEntry(TypeTableType.Strings, 0xF0, opCodeDataEnd); if (_messageFile != null) { _messageFile.InternalWrite(writer); int messageDataEnd = (int)writer.BaseStream.Position - posFileStart; int messageDataSize = messageDataEnd - opCodeDataEnd; typeTableEntries[(int)TypeTableType.Strings].dataOffset += messageDataSize; typeTableEntries[(int)TypeTableType.Messages] = CreateTypeTableEntry(TypeTableType.Messages, messageDataSize, opCodeDataEnd); } // TODO: add code for the 'string' table here? haven't really seen it being used though. // fixed size zero bytes for the strings table when unused writer.Write(0, 0xF0); long posFileEnd = writer.BaseStream.Position; int length = (int)posFileEnd - posFileStart; writer.BaseStream.Seek(posFileStart, SeekOrigin.Begin); // write standard header writer.Write(TYPE); writer.Write((short)0); // userID writer.Write(length); writer.WriteCString(TAG, 4); writer.Write(0); // unused // write bf header writer.Write(typeTableEntries.Length); writer.Write(0); // some unknown value here, not sure what its for writer.AlignPosition(16); // write type table entries foreach (TypeTableEntry entry in typeTableEntries) { entry.InternalWrite(writer); } // lastly, write the code labels foreach (BFCodeLabel label in _procedures) { label.InternalWrite(writer); } foreach (BFCodeLabel label in _jumpLabels) { label.InternalWrite(writer); } }
internal override void InternalWrite(BinaryWriter writer) { int posFileStart = (int)writer.BaseStream.Position; List<int> addressList = new List<int>(); // Seek past chunk and msg header for writing later writer.BaseStream.Seek(DATA_START_ADDRESS, SeekOrigin.Current); // Write a dummy message pointer table for (int i = 0; i < DialogCount; i++) { writer.Write(0); addressList.Add((int)writer.BaseStream.Position - posFileStart); writer.Write(0); } // Write a dummy offset for writing later addressList.Add((int)writer.BaseStream.Position - posFileStart); writer.Write(0); writer.Write(ActorCount); // These are always here for some reason writer.Write(0); writer.Write(0); writer.AlignPosition(4); BMDMessageTable[] messagePointerTable = new BMDMessageTable[DialogCount]; // Write the messages and fill in the message pointer table for (int i = 0; i < DialogCount; i++) { writer.AlignPosition(4); messagePointerTable[i].Offset = (int)writer.BaseStream.Position - DATA_START_ADDRESS - posFileStart; _messages[i].InternalWrite(writer, ref addressList, posFileStart); } writer.AlignPosition(4); int actorNamePointerTableOffset = (int)writer.BaseStream.Position - DATA_START_ADDRESS - posFileStart; // Write dummy actor name pointer table if there are actors present if (ActorCount > 0) { long actorNamePointerTablePosition = writer.BaseStream.Position; for (int i = 0; i < ActorCount; i++) { addressList.Add((int)writer.BaseStream.Position - posFileStart); writer.Write(0); } int[] actorNamePointerTable = new int[ActorCount]; for (int i = 0; i < actorNamePointerTable.Length; i++) { actorNamePointerTable[i] = (int)writer.BaseStream.Position - DATA_START_ADDRESS - posFileStart; writer.WriteCString(_actorNames[i]); } long addresRelocPosition = writer.BaseStream.Position; writer.BaseStream.Seek(actorNamePointerTablePosition, SeekOrigin.Begin); writer.Write(actorNamePointerTable); writer.BaseStream.Seek(addresRelocPosition, SeekOrigin.Begin); } // Compress and write the address relocationt able byte[] addressRelocTable = PointerRelocationTableCompression.Compress(addressList, DATA_START_ADDRESS); int addressRelocTableOffset = (int)writer.BaseStream.Position - posFileStart; int addressRelocTableSize = addressRelocTable.Length; writer.Write(addressRelocTable); // Save the end offset for calculating length and seeking later long posFileEnd = writer.BaseStream.Position; int length = (int)(posFileEnd - posFileStart); // Seek back to the start writer.BaseStream.Seek(posFileStart, SeekOrigin.Begin); // Write Chunk header writer.Write(FLAG); writer.Write((short)0); // userID writer.Write(length); writer.WriteCString(TAG, 4); writer.Write(0); // Write MSG header writer.Write(addressRelocTableOffset); writer.Write(addressRelocTableSize); writer.Write(DialogCount); writer.Write(UNK_CONSTANT); for (int i = 0; i < DialogCount; i++) { writer.Write((int)messagePointerTable[i].Type); writer.Write(messagePointerTable[i].Offset); } writer.Write(actorNamePointerTableOffset); writer.BaseStream.Seek(posFileEnd, SeekOrigin.Begin); }
/*****************/ /**** Methods ****/ /*****************/ internal void InternalWrite(BinaryWriter writer) { writer.WriteCString(_name, MAX_NAME_LENGTH); writer.Write(DataLength); writer.Write(Data); writer.AlignPosition(64); }