private void WriteCompressedBlock(FileStream outputFileStream, int blockNumber, byte[] compressedData)
        {
            var compressedBlock = new ArchiveBlock
            {
                BlockNumber    = blockNumber,
                CompressedData = compressedData
            };

            List <ArchiveBlock> buffer = null;

            lock (_writeToBufferLocker)
            {
                _buffer.Add(compressedBlock);
                _writtenBlocksAmount++;
                if (BufferIsFilled())
                {
                    buffer = _buffer;
                    InitializeBuffer();
                }
            }

            if (buffer != null)
            {
                WriteBufferToOutputFileStream(buffer, outputFileStream);
            }

            if (buffer == null && CurrentBlockIsLast())
            {
                WriteBufferToOutputFileStream(_buffer, outputFileStream);
            }
        }
        private long GetDecompressedBlockPosition(ArchiveBlock archiveBlock, FileStream outputFileStream)
        {
            long blockPosition = FormatConstants.BlockSize * archiveBlock.BlockNumber;

            if (blockPosition >= outputFileStream.Length)
            {
                throw new FormatException(
                          $"Incorrect archive format. Block position {archiveBlock.BlockNumber} does not correspond to original file size = {outputFileStream.Length} bytes.");
            }
            return(blockPosition);
        }
        private void FillBuffer(FileStream inputArchiveFileStream)
        {
            if (Monitor.TryEnter(_bufferFillingLocker))
            {
                try
                {
                    while (!_buffer.IsFull())
                    {
                        var compressedDataBlockNumber = GetIntegerFromInputStream(inputArchiveFileStream);

                        if (compressedDataBlockNumber == null)
                        {
                            _readingCompleted = true;
                            return;
                        }

                        var compressedDataBlockSize = GetIntegerFromInputStream(inputArchiveFileStream);

                        if (compressedDataBlockSize == null)
                        {
                            throw new FormatException(
                                      $"Incorrect archive format. Block with information about following compressed data block length should be {sizeof(int)} bytes size, but was 0 bytes.");
                        }

                        var compressedData = new byte[compressedDataBlockSize.Value];

                        var numberOfBytesRead = inputArchiveFileStream.Read(compressedData, 0,
                                                                            compressedDataBlockSize.Value);

                        if (numberOfBytesRead != compressedDataBlockSize.Value)
                        {
                            throw new FormatException(
                                      $"Incorrect archive format. Block with compressed data block should be {compressedDataBlockSize.Value} bytes size, but was {numberOfBytesRead} bytes.");
                        }

                        var block = new ArchiveBlock
                        {
                            CompressedData = compressedData,
                            BlockNumber    = compressedDataBlockNumber.Value
                        };

                        _buffer.Push(block);
                    }
                }
                finally
                {
                    Monitor.Exit(_bufferFillingLocker);
                }
            }
        }
        private DecompressedArchiveBlockData DecompressBlock(ArchiveBlock archiveBlock)
        {
            var decompressedData = new byte[FormatConstants.BlockSize];
            int numberOfBytesDecompressed;

            using (var memoryStream = new MemoryStream(archiveBlock.CompressedData))
            {
                using (var gZipStream = new GZipStream(memoryStream, CompressionMode.Decompress))
                {
                    numberOfBytesDecompressed = gZipStream.Read(decompressedData, 0, FormatConstants.BlockSize);
                }
            }

            return(new DecompressedArchiveBlockData
            {
                DecompressedData = decompressedData,
                DecompressedDataLength = numberOfBytesDecompressed
            });
        }