Exemple #1
0
        /// <summary>Reads the next chunk from stream.</summary>
        /// <returns>
        ///     <c>true</c> if next has been read, or <c>false</c> if it is legitimate end of file.
        ///     Throws <see cref="EndOfStreamException" /> if end of stream was unexpected.
        /// </returns>
        private bool AcquireNextChunk()
        {
            do
            {
                ulong varint;
                if (!TryReadVarInt(out varint))
                {
                    return(false);
                }
                var  flags        = (ChunkFlags)varint;
                bool isCompressed = (flags & ChunkFlags.Compressed) != 0;

                var originalLength   = (int)ReadVarInt();
                int compressedLength = isCompressed ? (int)ReadVarInt() : originalLength;
                if (compressedLength > originalLength)
                {
                    throw EndOfStream(); // corrupted
                }

                var compressed = new byte[compressedLength];
                int chunk      = ReadBlock(compressed, 0, compressedLength);

                if (chunk != compressedLength)
                {
                    throw EndOfStream(); // corrupted
                }

                if (!isCompressed)
                {
                    _buffer       = compressed; // no compression on this chunk
                    _bufferLength = compressedLength;
                }
                else
                {
                    if (_buffer == null || _buffer.Length < originalLength)
                    {
                        _buffer = new byte[originalLength];
                    }
                    int passes = (int)flags >> 2;
                    if (passes != 0)
                    {
                        throw new NotSupportedException("Chunks with multiple passes are not supported.");
                    }
                    LZ4Codec.Decode(compressed, 0, compressedLength, _buffer, 0, originalLength, true);
                    _bufferLength = originalLength;
                }

                _bufferOffset = 0;
            } while (_bufferLength == 0); // skip empty block (shouldn't happen but...)

            return(true);
        }
Exemple #2
0
        /// <summary>
        ///     When overridden in a derived class, reads a sequence of bytes from the current stream and advances the
        ///     position within the stream by the number of bytes read.
        /// </summary>
        /// <param name="buffer">
        ///     An array of bytes. When this method returns, the buffer contains the specified byte array with the
        ///     values between <paramref name="offset" /> and (<paramref name="offset" /> + <paramref name="count" /> - 1) replaced
        ///     by the bytes read from the current source.
        /// </param>
        /// <param name="offset">
        ///     The zero-based byte offset in <paramref name="buffer" /> at which to begin storing the data read
        ///     from the current stream.
        /// </param>
        /// <param name="count">The maximum number of bytes to be read from the current stream.</param>
        /// <returns>
        ///     The total number of bytes read into the buffer. This can be less than the number of bytes requested if that
        ///     many bytes are not currently available, or zero (0) if the end of the stream has been reached.
        /// </returns>
        public override int Read(byte[] buffer, int offset, int count)
        {
            if (!CanRead)
            {
                throw NotSupported("Read");
            }

            int total = 0;

            while (count > 0)
            {
                int chunk = Math.Min(count, _bufferLength - _bufferOffset);
                if (chunk > 0)
                {
#if INCLUDE_UNSAFE
                    unsafe
                    {
                        fixed(byte *srcPtr = _buffer)
                        {
                            fixed(byte *dstPtr = buffer)
                            {
                                LZ4Codec.BlockCopy(srcPtr + _bufferOffset, dstPtr + offset, chunk);
                            }
                        }
                    }
#else
                    Buffer.BlockCopy(_buffer, _bufferOffset, buffer, offset, chunk);
#endif
                    _bufferOffset += chunk;
                    offset        += chunk;
                    count         -= chunk;
                    total         += chunk;
                }
                else
                {
                    if (!AcquireNextChunk())
                    {
                        break;
                    }
                }
            }

            return(total);
        }
Exemple #3
0
        /// <summary>
        ///     When overridden in a derived class, writes a sequence of bytes to the current stream and advances the current
        ///     position within this stream by the number of bytes written.
        /// </summary>
        /// <param name="buffer">
        ///     An array of bytes. This method copies <paramref name="count" /> bytes from
        ///     <paramref name="buffer" /> to the current stream.
        /// </param>
        /// <param name="offset">
        ///     The zero-based byte offset in <paramref name="buffer" /> at which to begin copying bytes to the
        ///     current stream.
        /// </param>
        /// <param name="count">The number of bytes to be written to the current stream.</param>
        public override void Write(byte[] buffer, int offset, int count)
        {
            if (!CanWrite)
            {
                throw NotSupported("Write");
            }

            if (_buffer == null)
            {
                _buffer       = new byte[_blockSize];
                _bufferLength = _blockSize;
                _bufferOffset = 0;
            }

            while (count > 0)
            {
                int chunk = Math.Min(count, _bufferLength - _bufferOffset);
                if (chunk > 0)
                {
#if INCLUDE_UNSAFE
                    unsafe
                    {
                        fixed(byte *srcPtr = buffer)
                        {
                            fixed(byte *dstPtr = _buffer)
                            {
                                LZ4Codec.BlockCopy(srcPtr + offset, dstPtr + _bufferOffset, chunk);
                            }
                        }
                    }
#else
                    Buffer.BlockCopy(buffer, offset, _buffer, _bufferOffset, chunk);
#endif
                    offset        += chunk;
                    count         -= chunk;
                    _bufferOffset += chunk;
                }
                else
                {
                    FlushCurrentChunk();
                }
            }
        }
Exemple #4
0
        /// <summary>Flushes current chunk.</summary>
        private void FlushCurrentChunk()
        {
            if (_bufferOffset <= 0)
            {
                return;
            }

            var compressed       = new byte[_bufferOffset];
            int compressedLength = LZ4Codec.Encode(_buffer, 0, _bufferOffset, compressed, 0, _bufferOffset,
                                                   _highCompression);

            if (compressedLength <= 0 || compressedLength >= _bufferOffset)
            {
                // incompressible block
                compressed       = _buffer;
                compressedLength = _bufferOffset;
            }

            bool isCompressed = compressedLength < _bufferOffset;
            var  flags        = ChunkFlags.None;

            if (isCompressed)
            {
                flags |= ChunkFlags.Compressed;
            }
            if (_highCompression)
            {
                flags |= ChunkFlags.HighCompression;
            }

            WriteVarInt((ulong)flags);
            WriteVarInt((ulong)_bufferOffset);
            if (isCompressed)
            {
                WriteVarInt((ulong)compressedLength);
            }

            _innerStream.Write(compressed, 0, compressedLength);
            _bufferOffset = 0;
        }