/// <summary> /// Initializes a new instance of the <see cref="XZInputStream"/> class. /// </summary> /// <param name="stream"> /// The underlying <see cref="Stream"/> from which to decompress the data. /// </param> /// <param name="format"> /// The lzma formats which are supported. /// </param> /// <param name="ownership"> /// Determines whether the underlying stream should be disposed of, or not. /// </param> public XZInputStream(Stream stream, LzmaFormat format = LzmaFormat.Auto, Ownership ownership = Ownership.None) { this.innerStream = stream ?? throw new ArgumentNullException(nameof(stream)); this.ownership = ownership; LzmaResult ret; switch (format) { case LzmaFormat.Lzma: ret = NativeMethods.lzma_alone_decoder(ref this.lzmaStream, ulong.MaxValue); break; case LzmaFormat.Xz: ret = NativeMethods.lzma_stream_decoder(ref this.lzmaStream, ulong.MaxValue, LzmaDecodeFlags.Concatenated); break; default: case LzmaFormat.Auto: ret = NativeMethods.lzma_auto_decoder(ref this.lzmaStream, ulong.MaxValue, LzmaDecodeFlags.Concatenated); break; } this.inbuf = Marshal.AllocHGlobal(BufSize); this.outbuf = Marshal.AllocHGlobal(BufSize); this.lzmaStream.AvailIn = 0; this.lzmaStream.NextIn = (byte *)this.inbuf; this.lzmaStream.NextOut = (byte *)this.outbuf; this.lzmaStream.AvailOut = BufSize; LzmaException.ThrowOnError(ret); }
/// <summary> /// Reads bytes from stream. /// </summary> /// <param name="buffer"> /// The buffer into which to read the data. /// </param> /// <param name="offset"> /// The offset at which to start writing the data. /// </param> /// <param name="count"> /// The number of bytes to read. /// </param> /// <returns>byte read or -1 on end of stream.</returns> public unsafe override int Read(byte[] buffer, int offset, int count) { Verify.NotDisposed(this); // Make sure data is available in the output buffer. while ((int)this.lzmaStream.AvailOut == BufSize - this.outbufProcessed) { LzmaAction action = LzmaAction.Run; if (this.lzmaStream.AvailOut == 0) { this.lzmaStream.AvailOut = BufSize; this.lzmaStream.NextOut = (byte *)this.outbuf; this.outbufProcessed = 0; } if (this.lzmaStream.AvailIn == 0) { Span <byte> inputBuffer = new Span <byte>((void *)this.inbuf, BufSize); this.lzmaStream.AvailIn = (uint)this.innerStream.Read(inputBuffer); this.lzmaStream.NextIn = (byte *)this.inbuf; if (this.lzmaStream.AvailIn == 0) { action = LzmaAction.Finish; } } // Decode the data. var ret = NativeMethods.lzma_code(ref this.lzmaStream, action); if (ret == LzmaResult.StreamEnd) { break; } else if (ret != LzmaResult.OK) { NativeMethods.lzma_end(ref this.lzmaStream); LzmaException.ThrowOnError(ret); } } // Get the amount of data which can be copied var canRead = Math.Min( BufSize - (int)this.lzmaStream.AvailOut - this.outbufProcessed, count); var source = new Span <byte>((byte *)this.outbuf + this.outbufProcessed, canRead); var target = new Span <byte>(buffer, offset, canRead); source.CopyTo(target); this.outbufProcessed += canRead; this.position += canRead; return(canRead); }
public XZOutputStream(Stream stream, int threads, uint preset, bool leaveOpen) { if (stream == null) { throw new ArgumentNullException(nameof(stream)); } this.innerStream = stream; this.leaveOpen = leaveOpen; LzmaResult ret; if (threads == 1 || !NativeMethods.SupportsMultiThreading) { ret = NativeMethods.lzma_easy_encoder(ref this.lzmaStream, preset, LzmaCheck.Crc64); } else { if (threads <= 0) { throw new ArgumentOutOfRangeException(nameof(threads)); } if (threads > Environment.ProcessorCount) { Trace.TraceWarning("{0} threads required, but only {1} processors available", threads, Environment.ProcessorCount); threads = Environment.ProcessorCount; } var mt = new LzmaMT() { preset = preset, check = LzmaCheck.Crc64, threads = (uint)threads, }; ret = NativeMethods.lzma_stream_encoder_mt(ref this.lzmaStream, ref mt); } if (ret == LzmaResult.OK) { this.outbuf = new byte[BufSize]; this.lzmaStream.AvailOut = BufSize; return; } GC.SuppressFinalize(this); LzmaException.ThrowOnError(ret); }
public static byte[] Encode(byte[] buffer, uint preset = DefaultPreset) { var res = new byte[(long)NativeMethods.lzma_stream_buffer_bound((UIntPtr)buffer.Length)]; UIntPtr outPos; var ret = NativeMethods.lzma_easy_buffer_encode(preset, LzmaCheck.Crc64, null, buffer, (UIntPtr)buffer.Length, res, &outPos, (UIntPtr)res.Length); LzmaException.ThrowOnError(ret); if ((long)outPos < res.Length) { Array.Resize(ref res, (int)(ulong)outPos); } return(res); }
public override void Write(byte[] buffer, int offset, int count) { Verify.NotDisposed(this); if (count == 0) { return; } var guard = buffer[checked ((uint)offset + (uint)count) - 1]; if (this.lzmaStream.AvailIn != 0) { throw new InvalidOperationException(); } this.lzmaStream.AvailIn = (uint)count; do { LzmaResult ret; fixed(byte *inbuf = &buffer[offset]) { this.lzmaStream.NextIn = inbuf; fixed(byte *outbuf = &this.outbuf[BufSize - this.lzmaStream.AvailOut]) { this.lzmaStream.NextOut = outbuf; ret = NativeMethods.lzma_code(ref this.lzmaStream, LzmaAction.Run); } offset += (int)((ulong)this.lzmaStream.NextIn - (ulong)(IntPtr)inbuf); } if (ret != LzmaResult.OK) { NativeMethods.lzma_end(ref this.lzmaStream); LzmaException.ThrowOnError(ret); } if (this.lzmaStream.AvailOut == 0) { this.innerStream.Write(this.outbuf, 0, BufSize); this.lzmaStream.AvailOut = BufSize; } }while (this.lzmaStream.AvailIn != 0); }
protected override void Dispose(bool disposing) { // finish encoding only if all input has been successfully processed if (this.lzmaStream.InternalState != null && this.lzmaStream.AvailIn == 0) { LzmaResult ret; do { fixed(byte *outbuf = &this.outbuf[BufSize - (int)this.lzmaStream.AvailOut]) { this.lzmaStream.NextOut = outbuf; ret = NativeMethods.lzma_code(ref this.lzmaStream, LzmaAction.Finish); } if (ret > LzmaResult.StreamEnd) { NativeMethods.lzma_end(ref this.lzmaStream); LzmaException.ThrowOnError(ret); } var writeSize = BufSize - (int)this.lzmaStream.AvailOut; if (writeSize != 0) { this.innerStream.Write(this.outbuf, 0, writeSize); this.lzmaStream.AvailOut = BufSize; } }while (ret != LzmaResult.StreamEnd); } NativeMethods.lzma_end(ref this.lzmaStream); if (disposing && !this.leaveOpen) { this.innerStream?.Dispose(); } base.Dispose(disposing); this.IsDisposed = true; }
/// <summary> /// Initializes a new instance of the <see cref="XZDecompressor" /> class. /// </summary> /// <param name="format"> /// The format of the data to decompress. /// </param> public XZDecompressor(LzmaFormat format = LzmaFormat.Auto) { LzmaResult ret; switch (format) { case LzmaFormat.Lzma: ret = NativeMethods.lzma_alone_decoder(ref this.lzmaStream, ulong.MaxValue); break; case LzmaFormat.Xz: ret = NativeMethods.lzma_stream_decoder(ref this.lzmaStream, ulong.MaxValue, LzmaDecodeFlags.Concatenated); break; default: case LzmaFormat.Auto: ret = NativeMethods.lzma_auto_decoder(ref this.lzmaStream, ulong.MaxValue, LzmaDecodeFlags.Concatenated); break; } LzmaException.ThrowOnError(ret); }