/// <summary> /// learn from 01_compress_easy.c /// </summary> /// <param name="buffer"></param> /// <param name="offset"></param> /// <param name="count"></param> public override void Write(byte[] buffer, int offset, int count) { if (buffer == null) { throw new ArgumentNullException(nameof(buffer)); } if (offset < 0) { throw new ArgumentOutOfRangeException(nameof(offset)); } if (count < 0) { throw new ArgumentOutOfRangeException(nameof(count)); } if (count + offset > buffer.Length) { throw new ArgumentOutOfRangeException(nameof(count), "offset+count > buffer.length"); } if (count == 0) { return; } int bytesProcessed = 0; while (true) { // Fill the input buffer if it is empty. if (_lzma_stream.avail_in == UIntPtr.Zero) { int bytesToProcess = Math.Min(count - bytesProcessed, BUFSIZE); if (bytesToProcess == 0) { break; // no more data to compress } _lzma_stream.next_in = _inbuf; _lzma_stream.avail_in = (UIntPtr)bytesToProcess; Marshal.Copy(buffer, offset + bytesProcessed, _inbuf, bytesToProcess); bytesProcessed += bytesToProcess; } // do compress, RUN action should return LZMA_OK on success var ret = Native.lzma_code(_lzma_stream, lzma_action.LZMA_RUN); if (ret != lzma_ret.LZMA_OK) { throw new Exception($"lzma_code returns {ret}"); } // check output buffer if (_lzma_stream.avail_out == UIntPtr.Zero) { var data = ArrayPool <byte> .Shared.Rent(BUFSIZE); Marshal.Copy(_outbuf, data, 0, BUFSIZE); _stream.Write(data, 0, BUFSIZE); ArrayPool <byte> .Shared.Return(data); // Reset next_out and avail_out. _lzma_stream.next_out = _outbuf; _lzma_stream.avail_out = (UIntPtr)BUFSIZE; } } }