/// <summary> /// Estimates the file size of the resulting archive. /// </summary> public int EstimateFileSize(ArchiveWriterOptions options) { int result = 0; result += sizeof(int); // Number of items. result += Groups.Count; // Number of items for each id. result = Utilities.RoundUp(result, 4); // Alignment result += Groups.Keys.Count * sizeof(int); // First item index for each group & ID for each group. // Calculate number of total items. int totalItems = 0; foreach (var group in Groups) { totalItems += group.Value.Files.Count; } // Align starting offset. result = Utilities.RoundUp((int)result + (sizeof(int) * totalItems), options.Alignment); foreach (var group in Groups) { foreach (var file in group.Value.Files) { result += file.Data.Length; result = Utilities.RoundUp(result, options.Alignment); } } return(result); }
/// <summary> /// Writes the contents of the archive to be generated to the stream. /// </summary> /// <param name="writeStream">The stream to write to.</param> /// <param name="options">The options for packing this archive.</param> public void Write(Stream writeStream, ArchiveWriterOptions options) { using var stream = new ExtendedMemoryStream(EstimateFileSize(options) + 1); using EndianMemoryStream endianStream = options.BigEndian ? (EndianMemoryStream) new BigEndianMemoryStream(stream) : new LittleEndianMemoryStream(stream); // Number of items. endianStream.Write <int>(Groups.Keys.Count); // Number of items for each id. foreach (var group in Groups) { endianStream.Write <byte>((byte)group.Value.Files.Count); } endianStream.AddPadding(0x00, 4); // Write first item index for each group. ushort totalItems = 0; foreach (var group in Groups) { endianStream.Write <ushort>(totalItems); totalItems += (ushort)group.Value.Files.Count; } // Write ID for each group. foreach (var group in Groups) { endianStream.Write <ushort>(group.Value.Id); } // Write offsets for each file and pad. int firstWriteOffset = Utilities.RoundUp((int)endianStream.Stream.Position + (sizeof(int) * totalItems), options.Alignment); if (firstWriteOffset < options.MinOffset) { firstWriteOffset = options.MinOffset; } int fileWriteOffset = firstWriteOffset; foreach (var group in Groups) { foreach (var file in group.Value.Files) { endianStream.Write <int>(file.Data.Length <= 0 ? 0 : fileWriteOffset); fileWriteOffset += file.Data.Length; fileWriteOffset = Utilities.RoundUp(fileWriteOffset, options.Alignment); } } // Write files. endianStream.Write(new byte[(int)(firstWriteOffset - endianStream.Stream.Position)]); // Alignment foreach (var file in Groups.SelectMany(x => x.Value.Files)) { endianStream.Write(file.Data); endianStream.AddPadding(options.Alignment); } writeStream.Write(endianStream.ToArray()); }