Пример #1
0
        protected override void Dispose(bool disposing)
        {
            if (_stream == null)
            {
                return;
            }
            try
            {
                // compress all remaining data
                while (true)
                {
                    // do compress, LZMA_FINISH action should return LZMA_OK or LZMA_STREAM_END on success
                    var ret = Native.lzma_code(_lzma_stream, lzma_action.LZMA_FINISH);
                    if (ret != lzma_ret.LZMA_STREAM_END && ret != lzma_ret.LZMA_OK)
                    {
                        throw new Exception($"lzma_code returns {ret}");
                    }

                    // write output buffer to underlying stream
                    if (_lzma_stream.avail_out == UIntPtr.Zero || ret == lzma_ret.LZMA_STREAM_END)
                    {
                        int size = (int)(BUFSIZE - (uint)_lzma_stream.avail_out);
                        var data = ArrayPool <byte> .Shared.Rent(size);

                        Marshal.Copy(_outbuf, data, 0, size);
                        _stream.Write(data, 0, size);
                        ArrayPool <byte> .Shared.Return(data);

                        // Reset next_out and avail_out.
                        _lzma_stream.next_out  = _outbuf;
                        _lzma_stream.avail_out = (UIntPtr)BUFSIZE;
                    }

                    if (ret == lzma_ret.LZMA_STREAM_END)
                    {
                        break;
                    }
                }
            }
            finally
            {
                Native.lzma_end(_lzma_stream);
                Marshal.FreeHGlobal(_inbuf);
                Marshal.FreeHGlobal(_outbuf);
                _stream.Close();
                _stream = null;
            }
        }
Пример #2
0
        /// <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)
                {
                    byte[] data = new byte[BUFSIZE];
                    Marshal.Copy(_outbuf, data, 0, data.Length);
                    _stream.Write(data, 0, data.Length);

                    // Reset next_out and avail_out.
                    _lzma_stream.next_out  = _outbuf;
                    _lzma_stream.avail_out = (UIntPtr)BUFSIZE;
                }
            }
        }
Пример #3
0
        /// <summary>
        /// learn from 02_decompress.c
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="offset"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public override int Read(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(0);
            }

            int cTotalRead = 0;

            while (true)
            {
                // read from underlying stream
                if (_lzma_stream.avail_in == UIntPtr.Zero && action == lzma_action.LZMA_RUN)
                {
                    // read more data from underlying stream
                    var data      = new byte[BUFSIZE];
                    var bytesRead = _stream.Read(data, 0, BUFSIZE);
                    if (bytesRead == 0)
                    {
                        action = lzma_action.LZMA_FINISH;                 // source stream has no more data
                    }
                    _lzma_stream.next_in  = _inbuf;
                    _lzma_stream.avail_in = (UIntPtr)bytesRead;
                    Marshal.Copy(data, 0, _inbuf, bytesRead);
                }

                // try to read from existing outbuf
                int cReadable = BUFSIZE - (int)(uint)_lzma_stream.avail_out - read_pos;
                if (cReadable > 0)
                {
                    var cCopy = Math.Min(cReadable, count - cTotalRead);
                    var p     = Native.Is64Bit ? new IntPtr(_outbuf.ToInt64() + read_pos) : new IntPtr(_outbuf.ToInt32() + read_pos);
                    Marshal.Copy(p, buffer, offset + cTotalRead, cCopy);
                    cTotalRead += cCopy;
                    read_pos   += cCopy;
                    Trace.Assert(cTotalRead <= count);
                    if (cTotalRead == count)
                    {
                        return(cTotalRead);
                    }
                }

                // need to read more data from outbuf
                // if previous decode returns LZMA_STREAM_END, there will be no more data
                if (ret == lzma_ret.LZMA_STREAM_END)
                {
                    return(cTotalRead);
                }

                // otherwise, reset outbuf to recv more decompressed data from liblzma, or decompress is finished
                Trace.Assert(read_pos + (uint)_lzma_stream.avail_out <= BUFSIZE);
                if (_lzma_stream.avail_out == UIntPtr.Zero && read_pos + (uint)_lzma_stream.avail_out == BUFSIZE)
                {
                    _lzma_stream.next_out  = _outbuf;
                    _lzma_stream.avail_out = (UIntPtr)BUFSIZE;
                    read_pos = 0;
                }

                // do decompress
                ret = Native.lzma_code(_lzma_stream, action);
                if (ret != lzma_ret.LZMA_OK && ret != lzma_ret.LZMA_STREAM_END)
                {
                    throw new Exception($"lzma_code returns {ret}");
                }
            }
        }
Пример #4
0
        /// <summary>
        /// liblzma has provided lzma_stream_buffer_encode and lzma_stream_buffer_decode, but here I re-invent the wheel again...
        /// </summary>
        /// <param name="_lzma_stream"></param>
        /// <param name="data"></param>
        /// <param name="offset"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        private static byte[] CodeBuffer(lzma_stream _lzma_stream, byte[] data, int offset, int count)
        {
            const int BUFSIZE   = 4096;
            var       outStream = new MemoryStream(BUFSIZE);
            var       inbuf     = Marshal.AllocHGlobal(BUFSIZE);
            var       outbuf    = Marshal.AllocHGlobal(BUFSIZE);

            try
            {
                var action = lzma_action.LZMA_RUN;
                _lzma_stream.next_in   = inbuf;
                _lzma_stream.avail_in  = UIntPtr.Zero;
                _lzma_stream.next_out  = outbuf;
                _lzma_stream.avail_out = (UIntPtr)BUFSIZE;
                int read_pos = offset;
                while (true)
                {
                    if (_lzma_stream.avail_in == UIntPtr.Zero)
                    {
                        if (read_pos < offset + count)
                        {
                            int bytesToProcess = Math.Min(BUFSIZE, offset + count - read_pos);
                            _lzma_stream.next_in  = inbuf;
                            _lzma_stream.avail_in = (UIntPtr)bytesToProcess;
                            Marshal.Copy(data, read_pos, inbuf, bytesToProcess);
                            read_pos += bytesToProcess;
                            Trace.Assert(read_pos <= offset + count);
                        }

                        if (read_pos == offset + count)
                        {
                            action = lzma_action.LZMA_FINISH;
                        }
                    }

                    var ret = Native.lzma_code(_lzma_stream, action);
                    if (_lzma_stream.avail_out == UIntPtr.Zero || ret == lzma_ret.LZMA_STREAM_END)
                    {
                        int write_size = BUFSIZE - (int)(uint)_lzma_stream.avail_out;
                        var tmp        = new byte[write_size];
                        Marshal.Copy(outbuf, tmp, 0, write_size);
                        outStream.Write(tmp, 0, write_size);
                        _lzma_stream.next_out  = outbuf;
                        _lzma_stream.avail_out = (UIntPtr)BUFSIZE;
                    }

                    if (ret != lzma_ret.LZMA_OK)
                    {
                        if (ret == lzma_ret.LZMA_STREAM_END)
                        {
                            break;
                        }

                        throw new Exception($"lzma_code returns {ret}");
                    }
                }
            }
            finally
            {
                Marshal.FreeHGlobal(inbuf);
                Marshal.FreeHGlobal(outbuf);
            }

            return(outStream.ToArray());
        }