예제 #1
0
        /// <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);
        }
예제 #2
0
        /// <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());
        }