Esempio n. 1
0
        private static BufferedStreamReader Decompress_Internal_Init(Stream stream, ArchiveCompressorOptions options, out byte[] decompressedBuffer)
        {
            var endianByteStream = GetStreamFromEndian(stream, options.BigEndian, options.BufferSize, out var bufferedStreamReader);

            endianByteStream.Seek(_decompSizeOffset, SeekOrigin.Current);
            decompressedBuffer = GC.AllocateUninitializedArray <byte>(endianByteStream.Read <int>());
            return(bufferedStreamReader);
        }
Esempio n. 2
0
        /// <summary>
        /// Compresses the contents of a stream
        /// </summary>
        /// <param name="source">The source of where the data should be compressed from.</param>
        /// <param name="numBytes">Number of bytes from the stream that should be compressed.</param>
        /// <param name="options">Options for the file compressor.</param>
        public static unsafe Span <byte> CompressFast(Stream source, int numBytes, ArchiveCompressorOptions options)
        {
            // TODO: Optimize this.

            // Read the data to be compressed into memory.
            var dataToCompress = GC.AllocateUninitializedArray <byte>(numBytes);

            source.Read(dataToCompress);

            // Initialize Writer.
            using var memoryStream = new MemoryStream(numBytes);
            var byteStream = new StreamByteStream(memoryStream);
            var writer     = new BitStream <StreamByteStream>(byteStream);

            // Write header
            // Writer is big endian by nature, so we inverse it.
            writer.Write(!options.BigEndian ? Endian.Reverse(_signature) : _signature);
            writer.Write(!options.BigEndian ? Endian.Reverse(numBytes) : numBytes);
            writer.Seek(options.StartOffset);

            // Compress the data.
            fixed(byte *dataPtr = &dataToCompress[0])
            {
                int pointer    = 0;
                int maxPointer = dataToCompress.Length;

                while (pointer < maxPointer)
                {
                    var match = Lz77GetLongestMatch(dataPtr, maxPointer, pointer, byte.MaxValue, byte.MaxValue);

                    /*
                     *  1 XXXXXXXX YYYYYYYY
                     | |        |
                     | |        1 byte length
                     | 1 byte offset.
                     |  compression flag
                     */

                    // Compressed 2 bytes:   17 / 16 = 1.0625 bits
                    // Uncompressed 2 bytes: 18 / 16 = 1.125 bits
                    // Conclusion: Compression effective if length >= 2.
                    if (match.Length >= 2)
                    {
                        writer.WriteBit(1);
                        writer.Write((byte)(match.Offset * -1));
                        writer.Write((byte)match.Length);
                        pointer += match.Length;
                    }
                    else
                    {
                        writer.WriteBit(0);
                        writer.Write(dataPtr[pointer++]);
                    }
                }
            }

            return(memoryStream.GetBuffer().AsSpan(0, writer.NextByteIndex));
        }
Esempio n. 3
0
        /// <summary>
        /// Reads a compressed archive and decompresses its contents.
        /// Also see <see cref="DecompressFast"/> for a slightly
        /// better performance version; should you know the file length.
        /// </summary>
        /// <param name="stream">The originating stream. Start of stream should be at start of file.</param>
        /// <param name="options">The options to use for decompressing.</param>
        public static unsafe byte[] DecompressSlow(Stream stream, ArchiveCompressorOptions options)
        {
            // Get Decompressed File Buffer
            using var endianByteStream = Decompress_Internal_Init(stream, options, out var decompressedBuffer);

            // Setup compressed buffer reading
            var byteStream = new BufferedStreamReaderByteStream(endianByteStream);
            var bitStream  = new BitStream <BufferedStreamReaderByteStream>(byteStream);

            // Start decompressing
            fixed(byte *resultPtr = decompressedBuffer)
            Decompress_Internal(resultPtr, decompressedBuffer.Length, options.StartOffset, ref bitStream);

            stream.Position = endianByteStream.Position();
            return(decompressedBuffer);
        }
Esempio n. 4
0
        /// <summary>
        /// Reads a compressed archive and decompresses its contents.
        /// </summary>
        /// <param name="stream">The originating stream. Start of stream should be at start of file.</param>
        /// <param name="fileLength">The length between the first byte of the file in the stream and the last byte.</param>
        /// <param name="options">The options to use for decompressing.</param>
        public static unsafe byte[] DecompressFast(Stream stream, int fileLength, ArchiveCompressorOptions options)
        {
            var startPos = stream.Position;

            // Get Decompressed File Buffer
            using var endianByteStream = Decompress_Internal_Init(stream, options, out var decompressedBuffer);

            // Setup compressed buffer reading
            var compressedData = endianByteStream.ReadBytes(startPos, fileLength);
            var byteStream     = new ArrayByteStream(compressedData);
            var bitStream      = new BitStream <ArrayByteStream>(byteStream);

            // Start decompressing
            fixed(byte *resultPtr = decompressedBuffer)
            Decompress_Internal(resultPtr, decompressedBuffer.Length, options.StartOffset, ref bitStream);

            // Advance underlying stream
            stream.Position = startPos + fileLength;
            return(decompressedBuffer);
        }