Пример #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;
                var isCompressed = (flags & ChunkFlags.Compressed) != 0;

                var originalLength   = (int)ReadVarInt();
                var compressedLength = isCompressed ? (int)ReadVarInt() : originalLength;
                if (compressedLength > originalLength)
                {
                    throw EndOfStream();                                                    // corrupted
                }
                if (compressedDataBuffer == null || compressedDataBuffer.Length < compressedLength)
                {
                    compressedDataBuffer = new byte[compressedLength];
                }
                var chunk = ReadBlock(compressedDataBuffer, 0, compressedLength);

                if (chunk != compressedLength)
                {
                    throw EndOfStream();                                            // currupted
                }
                if (!isCompressed)
                {
                    // swap the buffers
                    var oldDataBuffer = dataBuffer;
                    dataBuffer           = compressedDataBuffer; // no compression on this chunk
                    compressedDataBuffer = oldDataBuffer;        // ensure that compressedDataBuffer and dataBuffer are different

                    bufferLength = compressedLength;
                }
                else
                {
                    if (dataBuffer == null || dataBuffer.Length < originalLength)
                    {
                        dataBuffer = new byte[originalLength];
                    }
                    var passes = (int)flags >> 2;
                    if (passes != 0)
                    {
                        throw new NotSupportedException("Chunks with multiple passes are not supported.");
                    }
                    LZ4Codec.Decode(compressedDataBuffer, 0, compressedLength, dataBuffer, 0, originalLength, true);
                    bufferLength = originalLength;
                }

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

            return(true);
        }
Пример #2
0
        /// <summary>Flushes current chunk.</summary>
        private void FlushCurrentChunk()
        {
            if (bufferOffset <= 0)
            {
                return;
            }

            var compressed       = new byte[bufferOffset];
            var compressedLength = highCompression
                                ? LZ4Codec.EncodeHC(dataBuffer, 0, bufferOffset, compressed, 0, bufferOffset)
                                : LZ4Codec.Encode(dataBuffer, 0, bufferOffset, compressed, 0, bufferOffset);

            if (compressedLength <= 0 || compressedLength >= bufferOffset)
            {
                // uncompressible block
                compressed       = dataBuffer;
                compressedLength = bufferOffset;
            }

            var 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);
            innerStreamPosition += compressedLength;

            bufferOffset = 0;
        }