Ejemplo n.º 1
0
 private static void ThrowIfError(ulong code)
 {
     if (Zstandard64NativeMethods.ZSTD_isError(code))
     {
         var errorPtr = Zstandard64NativeMethods.ZSTD_getErrorName(code);
         var errorMsg = Marshal.PtrToStringAnsi(errorPtr);
         throw new IOException(errorMsg);
     }
 }
        public void Dispose()
        {
            switch (_compressionMode)
            {
            case CompressionMode.Compress:
                Zstandard64NativeMethods.ZSTD_freeCStream(_zstreamPointer);
                break;

            case CompressionMode.Decompress:
                Zstandard64NativeMethods.ZSTD_freeDStream(_zstreamPointer);
                break;
            }
        }
        private void InitializeIfNotAlreadyInitialized()
        {
            if (!_operationInitialized)
            {
                _operationInitialized = true;

                switch (_compressionMode)
                {
                case CompressionMode.Compress:
                    Zstandard64NativeMethods.ZSTD_initCStream(_zstreamPointer, _compressionLevel);     // start a new compression operation
                    break;

                case CompressionMode.Decompress:
                    Zstandard64NativeMethods.ZSTD_initDStream(_zstreamPointer);     // start a new decompression operation
                    break;
                }
            }
        }
        public void Decompress(
            OperationContext operationContext,
            int compressedOffset,
            int inputCompressedSize,
            int inputUncompressedSize,
            out int compressedBytesProcessed,
            out int uncompressedBytesProcessed)
        {
            Ensure.IsNotNull(operationContext, nameof(operationContext));
            Ensure.That(_compressionMode == CompressionMode.Decompress, nameof(_compressionMode));
            Ensure.IsGreaterThanOrEqualToZero(inputCompressedSize, nameof(inputCompressedSize));
            Ensure.IsGreaterThanOrEqualToZero(inputUncompressedSize, nameof(inputUncompressedSize));

            InitializeIfNotAlreadyInitialized();

            // apply reading progress on CompressedPinnedBufferWalker
            operationContext.CompressedPinnedBufferWalker.Offset = compressedOffset;
            // compressed data
            var inputNativeBuffer = CreateNativeBuffer(
                inputCompressedSize <= 0 ? null : operationContext.CompressedPinnedBufferWalker,
                inputCompressedSize <= 0 ? 0 : (ulong)inputCompressedSize);

            // uncompressed data
            var outputNativeBuffer = CreateNativeBuffer(
                operationContext.UncompressedPinnedBufferWalker, // operation result
                (ulong)inputUncompressedSize);

            // decompress inputNativeBuffer to outputNativeBuffer
            _ = Zstandard64NativeMethods.ZSTD_decompressStream(
                _zstreamPointer,
                outputNativeBuffer,
                inputNativeBuffer);

            uncompressedBytesProcessed = (int)outputNativeBuffer.Position; // because start Position is always 0
            compressedBytesProcessed   = (int)inputNativeBuffer.Position;  // because start Position is always 0

            operationContext.UncompressedPinnedBufferWalker.Offset += uncompressedBytesProcessed;
            // CompressedPinnedBufferWalker.Offset will be calculated on stream side
        }
        public ZstandardNativeWrapper(CompressionMode compressionMode, int compressionLevel)
        {
            _compressionLevel = compressionLevel;
            _compressionMode  = compressionMode;

            switch (_compressionMode)
            {
            case CompressionMode.Compress:
                // calculate recommended size for input buffer
                _recommendedZstreamInputSize = Zstandard64NativeMethods.ZSTD_CStreamInSize();
                // calculate recommended size for output buffer. Guarantee to successfully flush at least one complete compressed block
                _recommendedZstreamOutputSize = Zstandard64NativeMethods.ZSTD_CStreamOutSize();
                _zstreamPointer = Zstandard64NativeMethods.ZSTD_createCStream();     // create resource
                break;

            case CompressionMode.Decompress:
                // calculate recommended size for input buffer
                _recommendedZstreamInputSize = Zstandard64NativeMethods.ZSTD_DStreamInSize();
                // calculate recommended size for output buffer. Guarantee to successfully flush at least one complete block in all circumstances
                _recommendedZstreamOutputSize = Zstandard64NativeMethods.ZSTD_DStreamOutSize();
                _zstreamPointer = Zstandard64NativeMethods.ZSTD_createDStream();     // create resource
                break;
            }
        }
        public IEnumerable <int> StepwiseFlush(BufferInfo compressedBufferInfo)
        {
            if (_compressionMode != CompressionMode.Compress)
            {
                throw new InvalidDataException($"{nameof(StepwiseFlush)} must be called only from Compress mode.");
            }

            using (var operationContext = InitializeOperationContext(compressedBufferInfo))
            {
                yield return(ProcessCompressedOutput(operationContext, (zcs, buffer) => Zstandard64NativeMethods.ZSTD_flushStream(zcs, buffer)));
            }

            using (var operationContext = InitializeOperationContext(compressedBufferInfo))
            {
                yield return(ProcessCompressedOutput(operationContext, (zcs, buffer) => Zstandard64NativeMethods.ZSTD_endStream(zcs, buffer)));
            }

            int ProcessCompressedOutput(OperationContext context, Action <IntPtr, NativeBufferInfo> outputAction)
            {
                var outputNativeBuffer = CreateNativeBuffer(
                    context.CompressedPinnedBufferWalker,
                    _recommendedZstreamOutputSize);

                outputAction(_zstreamPointer, outputNativeBuffer);

                return((int)outputNativeBuffer.Position);
            }
        }