liblzma/stream.rs
1//! Raw in-memory LZMA streams.
2//!
3//! The [`Stream`] type in this module is the primary type which performs
4//! encoding/decoding of LZMA streams. Each [`Stream`] is either an encoder or
5//! decoder and processes data in a streaming fashion.
6
7use std::collections::LinkedList;
8use std::error;
9use std::fmt;
10use std::io;
11use std::mem;
12
13/// Representation of an in-memory LZMA encoding or decoding stream.
14///
15/// Wraps the raw underlying `lzma_stream` type and provides the ability to
16/// create streams which can either decode or encode various LZMA-based formats.
17pub struct Stream {
18    raw: liblzma_sys::lzma_stream,
19}
20
21unsafe impl Send for Stream {}
22unsafe impl Sync for Stream {}
23
24/// Options that can be used to configure how LZMA encoding happens.
25///
26/// This builder is consumed by a number of other methods.
27pub struct LzmaOptions {
28    raw: liblzma_sys::lzma_options_lzma,
29}
30
31/// Builder to create a multithreaded stream encoder.
32#[cfg(feature = "parallel")]
33pub struct MtStreamBuilder {
34    raw: liblzma_sys::lzma_mt,
35    filters: Option<Filters>,
36}
37
38/// A custom chain of filters to configure an encoding stream.
39pub struct Filters {
40    inner: Vec<liblzma_sys::lzma_filter>,
41    lzma_opts: LinkedList<liblzma_sys::lzma_options_lzma>,
42}
43
44/// The `action` argument for [`Stream::process`],
45#[derive(Debug, Copy, Clone)]
46pub enum Action {
47    /// Continue processing
48    ///
49    /// When encoding, encode as much input as possible. Some internal buffering
50    /// will probably be done (depends on the filter chain in use), which causes
51    /// latency: the input used won't usually be decodeable from the output of
52    /// the same [`Stream::process`] call.
53    ///
54    /// When decoding, decode as much input as possible and produce as much
55    /// output as possible.
56    Run = liblzma_sys::LZMA_RUN as isize,
57
58    /// Make all the input available at output
59    ///
60    /// Normally the encoder introduces some latency. `SyncFlush` forces all the
61    /// buffered data to be available at output without resetting the internal
62    /// state of the encoder. This way it is possible to use compressed stream
63    /// for example for communication over network.
64    ///
65    /// Only some filters support `SyncFlush`. Trying to use `SyncFlush` with
66    /// filters that don't support it will make [`Stream::process`] return
67    /// `Error::Options`. For example, LZMA1 doesn't support `SyncFlush` but
68    /// LZMA2 does.
69    ///
70    /// Using `SyncFlush` very often can dramatically reduce the compression
71    /// ratio. With some filters (for example, LZMA2), fine-tuning the
72    /// compression options may help mitigate this problem significantly (for
73    /// example, match finder with LZMA2).
74    ///
75    /// Decoders don't support `SyncFlush`.
76    SyncFlush = liblzma_sys::LZMA_SYNC_FLUSH as isize,
77
78    /// Finish encoding of the current block.
79    ///
80    /// All the input data going to the current block must have been given to
81    /// the encoder. Call [`Stream::process`] with `FullFlush` until it returns
82    /// `Status::StreamEnd`. Then continue normally with `Run` or finish the
83    /// Stream with `Finish`.
84    ///
85    /// This action is currently supported only by stream encoder and easy
86    /// encoder (which uses stream encoder). If there is no unfinished block, no
87    /// empty block is created.
88    FullFlush = liblzma_sys::LZMA_FULL_FLUSH as isize,
89
90    /// Finish encoding of the current block.
91    ///
92    /// This is like `FullFlush` except that this doesn't necessarily wait until
93    /// all the input has been made available via the output buffer. That is,
94    /// [`Stream::process`] might return `Status::StreamEnd` as soon as all the input has
95    /// been consumed.
96    ///
97    /// `FullBarrier` is useful with a threaded encoder if one wants to split
98    /// the .xz Stream into blocks at specific offsets but doesn't care if the
99    /// output isn't flushed immediately. Using `FullBarrier` allows keeping the
100    /// threads busy while `FullFlush` would make [`Stream::process`] wait until all the
101    /// threads have finished until more data could be passed to the encoder.
102    ///
103    /// With a `Stream` initialized with the single-threaded
104    /// `new_stream_encoder` or `new_easy_encoder`, `FullBarrier` is an alias
105    /// for `FullFlush`.
106    FullBarrier = liblzma_sys::LZMA_FULL_BARRIER as isize,
107
108    /// Finish the current operation
109    ///
110    /// All the input data must have been given to the encoder (the last bytes
111    /// can still be pending in next_in). Call [`Stream::process`] with `Finish` until it
112    /// returns `Status::StreamEnd`. Once `Finish` has been used, the amount of
113    /// input must no longer be changed by the application.
114    ///
115    /// When decoding, using `Finish` is optional unless the concatenated flag
116    /// was used when the decoder was initialized. When concatenated was not
117    /// used, the only effect of `Finish` is that the amount of input must not
118    /// be changed just like in the encoder.
119    Finish = liblzma_sys::LZMA_FINISH as isize,
120}
121
122/// Return value of a [`Stream::process`] operation.
123#[derive(Debug, Copy, Clone, Eq, PartialEq)]
124pub enum Status {
125    /// Operation completed successfully.
126    Ok,
127
128    /// End of stream was reached.
129    ///
130    /// When encoding, this means that a sync/full flush or `Finish` was
131    /// completed. When decoding, this indicates that all data was decoded
132    /// successfully.
133    StreamEnd,
134
135    /// If the TELL_ANY_CHECK flags is specified when constructing a decoder,
136    /// this informs that the `check` method will now return the underlying
137    /// integrity check algorithm.
138    GetCheck,
139
140    /// An error has not been encountered, but no progress is possible.
141    ///
142    /// Processing can be continued normally by providing more input and/or more
143    /// output space, if possible.
144    ///
145    /// Typically the first call to [`Stream::process`] that can do no progress returns
146    /// `Ok` instead of `MemNeeded`. Only the second consecutive call doing no
147    /// progress will return `MemNeeded`.
148    MemNeeded,
149}
150
151/// Possible error codes that can be returned from a processing operation.
152#[derive(Debug, Clone, Copy, Eq, PartialEq)]
153pub enum Error {
154    /// The underlying data was corrupt.
155    Data,
156
157    /// Invalid or unsupported options were specified.
158    Options,
159
160    /// File format wasn't recognized.
161    Format,
162
163    /// Memory usage limit was reached.
164    ///
165    /// The memory limit can be increased with `set_memlimit`
166    MemLimit,
167
168    /// Memory couldn't be allocated.
169    Mem,
170
171    /// A programming error was encountered.
172    Program,
173
174    /// The `TELL_NO_CHECK` flag was specified and no integrity check was
175    /// available for this stream.
176    NoCheck,
177
178    /// The `TELL_UNSUPPORTED_CHECK` flag was specified and no integrity check
179    /// isn't implemented in this build of liblzma for this stream.
180    UnsupportedCheck,
181}
182
183/// Possible integrity checks that can be part of a .xz stream.
184#[allow(missing_docs)] // self-explanatory mostly
185#[derive(Debug, Copy, Clone)]
186pub enum Check {
187    None = liblzma_sys::LZMA_CHECK_NONE as isize,
188    Crc32 = liblzma_sys::LZMA_CHECK_CRC32 as isize,
189    Crc64 = liblzma_sys::LZMA_CHECK_CRC64 as isize,
190    Sha256 = liblzma_sys::LZMA_CHECK_SHA256 as isize,
191}
192
193/// Compression modes
194///
195/// This selects the function used to analyze the data produced by the match
196/// finder.
197#[derive(Debug, Copy, Clone)]
198pub enum Mode {
199    /// Fast compression.
200    ///
201    /// Fast mode is usually at its best when combined with a hash chain match
202    /// finder.
203    Fast = liblzma_sys::LZMA_MODE_FAST as isize,
204
205    /// Normal compression.
206    ///
207    /// This is usually notably slower than fast mode. Use this together with
208    /// binary tree match finders to expose the full potential of the LZMA1 or
209    /// LZMA2 encoder.
210    Normal = liblzma_sys::LZMA_MODE_NORMAL as isize,
211}
212
213/// Match finders
214///
215/// Match finder has major effect on both speed and compression ratio. Usually
216/// hash chains are faster than binary trees.
217///
218/// If you will use `SyncFlush` often, the hash chains may be a better choice,
219/// because binary trees get much higher compression ratio penalty with
220/// `SyncFlush`.
221///
222/// The memory usage formulas are only rough estimates, which are closest to
223/// reality when dict_size is a power of two. The formulas are  more complex in
224/// reality, and can also change a little between liblzma versions.
225#[derive(Debug, Copy, Clone)]
226pub enum MatchFinder {
227    /// Hash Chain with 2- and 3-byte hashing
228    HashChain3 = liblzma_sys::LZMA_MF_HC3 as isize,
229    /// Hash Chain with 2-, 3-, and 4-byte hashing
230    HashChain4 = liblzma_sys::LZMA_MF_HC4 as isize,
231
232    /// Binary Tree with 2-byte hashing
233    BinaryTree2 = liblzma_sys::LZMA_MF_BT2 as isize,
234    /// Binary Tree with 2- and 3-byte hashing
235    BinaryTree3 = liblzma_sys::LZMA_MF_BT3 as isize,
236    /// Binary Tree with 2-, 3-, and 4-byte hashing
237    BinaryTree4 = liblzma_sys::LZMA_MF_BT4 as isize,
238}
239
240/// A flag passed when initializing a decoder, causes [`Stream::process`] to return
241/// [`Status::GetCheck`] as soon as the integrity check is known.
242pub const TELL_ANY_CHECK: u32 = liblzma_sys::LZMA_TELL_ANY_CHECK;
243
244/// A flag passed when initializing a decoder, causes [`Stream::process`] to return
245/// [`Error::NoCheck`] if the stream being decoded has no integrity check.
246pub const TELL_NO_CHECK: u32 = liblzma_sys::LZMA_TELL_NO_CHECK;
247
248/// A flag passed when initializing a decoder, causes [`Stream::process`] to return
249/// [`Error::UnsupportedCheck`] if the stream being decoded has an integrity check
250/// that cannot be verified by this build of liblzma.
251pub const TELL_UNSUPPORTED_CHECK: u32 = liblzma_sys::LZMA_TELL_UNSUPPORTED_CHECK;
252
253/// A flag passed when initializing a decoder, causes the decoder to ignore any
254/// integrity checks listed.
255pub const IGNORE_CHECK: u32 = liblzma_sys::LZMA_TELL_UNSUPPORTED_CHECK;
256
257/// A flag passed when initializing a decoder, indicates that the stream may be
258/// multiple concatenated xz files.
259pub const CONCATENATED: u32 = liblzma_sys::LZMA_CONCATENATED;
260
261/// Encoder-related functions
262impl Stream {
263    /// Initialize .xz stream encoder using a preset number
264    ///
265    /// This is intended to be used by most for encoding data. The `preset`
266    /// argument is a number 0-9 indicating the compression level to use, and
267    /// normally 6 is a reasonable default.
268    ///
269    /// The `check` argument is the integrity check to insert at the end of the
270    /// stream. The default of `Crc64` is typically appropriate.
271    #[inline]
272    pub fn new_easy_encoder(preset: u32, check: Check) -> Result<Stream, Error> {
273        let mut init = unsafe { Stream::zeroed() };
274        cvt(unsafe {
275            liblzma_sys::lzma_easy_encoder(&mut init.raw, preset, check as liblzma_sys::lzma_check)
276        })?;
277        Ok(init)
278    }
279
280    /// Initialize .lzma encoder (legacy file format)
281    ///
282    /// The .lzma format is sometimes called the LZMA_Alone format, which is the
283    /// reason for the name of this function. The .lzma format supports only the
284    /// LZMA1 filter. There is no support for integrity checks like CRC32.
285    ///
286    /// Use this function if and only if you need to create files readable by
287    /// legacy LZMA tools such as LZMA Utils 4.32.x. Moving to the .xz format
288    /// (the `new_easy_encoder` function) is strongly recommended.
289    ///
290    /// The valid action values for [`Stream::process`] are [`Action::Run`] and [`Action::Finish`].
291    /// No flushing is supported, because the file format doesn't support it.
292    #[inline]
293    pub fn new_lzma_encoder(options: &LzmaOptions) -> Result<Stream, Error> {
294        let mut init = unsafe { Stream::zeroed() };
295        cvt(unsafe { liblzma_sys::lzma_alone_encoder(&mut init.raw, &options.raw) })?;
296        Ok(init)
297    }
298
299    /// Initialize .xz Stream encoder using a custom filter chain
300    ///
301    /// This function is similar to `new_easy_encoder` but a custom filter chain
302    /// is specified.
303    #[inline]
304    pub fn new_stream_encoder(filters: &Filters, check: Check) -> Result<Stream, Error> {
305        let mut init = unsafe { Stream::zeroed() };
306        cvt(unsafe {
307            liblzma_sys::lzma_stream_encoder(
308                &mut init.raw,
309                filters.inner.as_ptr(),
310                check as liblzma_sys::lzma_check,
311            )
312        })?;
313        Ok(init)
314    }
315
316    /// Initialize an encoder stream using a custom filter chain.
317    #[inline]
318    pub fn new_raw_encoder(filters: &Filters) -> Result<Stream, Error> {
319        let mut init = unsafe { Self::zeroed() };
320        cvt(unsafe { liblzma_sys::lzma_raw_encoder(&mut init.raw, filters.inner.as_ptr()) })?;
321        Ok(init)
322    }
323}
324
325/// Decoder-related functions
326impl Stream {
327    /// Initialize a decoder which will choose a stream/lzma formats depending
328    /// on the input stream.
329    #[inline]
330    pub fn new_auto_decoder(memlimit: u64, flags: u32) -> Result<Stream, Error> {
331        let mut init = unsafe { Self::zeroed() };
332        cvt(unsafe { liblzma_sys::lzma_auto_decoder(&mut init.raw, memlimit, flags) })?;
333        Ok(init)
334    }
335
336    /// Initialize a .xz stream decoder.
337    ///
338    /// The maximum memory usage can be specified along with flags such as
339    /// [`TELL_ANY_CHECK`], [`TELL_NO_CHECK`], [`TELL_UNSUPPORTED_CHECK`],
340    /// [`IGNORE_CHECK`], or [`CONCATENATED`].
341    #[inline]
342    pub fn new_stream_decoder(memlimit: u64, flags: u32) -> Result<Stream, Error> {
343        let mut init = unsafe { Self::zeroed() };
344        cvt(unsafe { liblzma_sys::lzma_stream_decoder(&mut init.raw, memlimit, flags) })?;
345        Ok(init)
346    }
347
348    /// Initialize a .lzma stream decoder.
349    ///
350    /// The maximum memory usage can also be specified.
351    #[inline]
352    pub fn new_lzma_decoder(memlimit: u64) -> Result<Stream, Error> {
353        let mut init = unsafe { Self::zeroed() };
354        cvt(unsafe { liblzma_sys::lzma_alone_decoder(&mut init.raw, memlimit) })?;
355        Ok(init)
356    }
357
358    /// Initialize a .lz stream decoder.
359    #[inline]
360    pub fn new_lzip_decoder(memlimit: u64, flags: u32) -> Result<Self, Error> {
361        let mut init = unsafe { Self::zeroed() };
362        cvt(unsafe { liblzma_sys::lzma_lzip_decoder(&mut init.raw, memlimit, flags) })?;
363        Ok(init)
364    }
365
366    /// Initialize a decoder stream using a custom filter chain.
367    #[inline]
368    pub fn new_raw_decoder(filters: &Filters) -> Result<Stream, Error> {
369        let mut init = unsafe { Self::zeroed() };
370        cvt(unsafe { liblzma_sys::lzma_raw_decoder(&mut init.raw, filters.inner.as_ptr()) })?;
371        Ok(init)
372    }
373}
374
375/// Generic functions
376impl Stream {
377    #[inline]
378    unsafe fn zeroed() -> Self {
379        Self {
380            raw: unsafe { mem::zeroed() },
381        }
382    }
383
384    #[inline]
385    unsafe fn process_inner(
386        &mut self,
387        input: &[u8],
388        output_ptr: *mut u8,
389        output_len: usize,
390        action: Action,
391    ) -> Result<Status, Error> {
392        self.raw.next_in = input.as_ptr();
393        self.raw.avail_in = input.len();
394        self.raw.next_out = output_ptr;
395        self.raw.avail_out = output_len;
396        let action = action as liblzma_sys::lzma_action;
397        unsafe { cvt(liblzma_sys::lzma_code(&mut self.raw, action)) }
398    }
399
400    /// Processes some data from input into an output buffer.
401    ///
402    /// This will perform the appropriate encoding or decoding operation
403    /// depending on the kind of underlying stream. See [`Action`] for the
404    /// possible actions that can be taken.
405    ///
406    /// After the first use of [`Action::SyncFlush`], [`Action::FullFlush`],
407    /// [`Action::FullBarrier`], or [`Action::Finish`], the same [`Action`]
408    /// must be used until this returns [`Status::StreamEnd`]. Not doing so
409    /// will result in a [`Error::Program`].
410    ///
411    /// The amount of input must not be modified by the application until
412    /// this returns [`Status::StreamEnd`], otherwise [`Error::Program`] will
413    /// be returned.
414    #[inline]
415    pub fn process(
416        &mut self,
417        input: &[u8],
418        output: &mut [u8],
419        action: Action,
420    ) -> Result<Status, Error> {
421        unsafe { self.process_inner(input, output.as_mut_ptr(), output.len(), action) }
422    }
423
424    /// Same as [`Self::process`] but accepts uninitialized buffer.
425    ///
426    /// To retrieve bytes written into the `output`, please call [`Self::total_out()`] before
427    /// and after the call to [`Self::process_uninit`] and the diff of `total_out` would be
428    /// the bytes written to the `output`.
429    #[inline]
430    pub fn process_uninit(
431        &mut self,
432        input: &[u8],
433        output: &mut [mem::MaybeUninit<u8>],
434        action: Action,
435    ) -> Result<Status, Error> {
436        unsafe { self.process_inner(input, output.as_mut_ptr() as *mut _, output.len(), action) }
437    }
438
439    /// Performs the same data as [`Stream::process`], but places output data in a [`Vec`].
440    ///
441    /// This function will use the extra capacity of `output` as a destination
442    /// for bytes to be placed. The length of `output` will automatically get
443    /// updated after the operation has completed.
444    ///
445    /// See [`Stream::process`] for the other arguments.
446    #[inline]
447    pub fn process_vec(
448        &mut self,
449        input: &[u8],
450        output: &mut Vec<u8>,
451        action: Action,
452    ) -> Result<Status, Error> {
453        let len = output.len();
454
455        unsafe {
456            let before = self.total_out();
457            let ret = self.process_uninit(input, output.spare_capacity_mut(), action);
458            output.set_len((self.total_out() - before) as usize + len);
459            ret
460        }
461    }
462
463    /// Returns the total amount of input bytes consumed by this stream.
464    #[inline]
465    pub fn total_in(&self) -> u64 {
466        self.raw.total_in
467    }
468
469    /// Returns the total amount of bytes produced by this stream.
470    #[inline]
471    pub fn total_out(&self) -> u64 {
472        self.raw.total_out
473    }
474
475    /// Get the current memory usage limit.
476    ///
477    /// This is only supported if the underlying stream supports a memlimit.
478    #[inline]
479    pub fn memlimit(&self) -> u64 {
480        unsafe { liblzma_sys::lzma_memlimit_get(&self.raw) }
481    }
482
483    /// Set the current memory usage limit.
484    ///
485    /// This can return [`Error::MemLimit`] if the new limit is too small or
486    /// [`Error::Program`] if this stream doesn't take a memory limit.
487    #[inline]
488    pub fn set_memlimit(&mut self, limit: u64) -> Result<(), Error> {
489        cvt(unsafe { liblzma_sys::lzma_memlimit_set(&mut self.raw, limit) }).map(|_| ())
490    }
491}
492
493impl LzmaOptions {
494    /// Creates a new blank set of options.
495    #[inline]
496    pub fn new() -> LzmaOptions {
497        LzmaOptions {
498            raw: unsafe { mem::zeroed() },
499        }
500    }
501
502    /// Creates a new blank set of options for encoding.
503    ///
504    /// The `preset` argument is the compression level to use, typically in the
505    /// range of 0-9.
506    #[inline]
507    pub fn new_preset(preset: u32) -> Result<LzmaOptions, Error> {
508        unsafe {
509            let mut options = Self::new();
510            let ret = liblzma_sys::lzma_lzma_preset(&mut options.raw, preset);
511            if ret != 0 {
512                Err(Error::Program)
513            } else {
514                Ok(options)
515            }
516        }
517    }
518
519    /// Configures the dictionary size, in bytes
520    ///
521    /// Dictionary size indicates how many bytes of the recently processed
522    /// uncompressed data is kept in memory.
523    ///
524    /// The minimum dictionary size is 4096 bytes and the default is 2^23 = 8MB.
525    #[inline]
526    pub fn dict_size(&mut self, size: u32) -> &mut LzmaOptions {
527        self.raw.dict_size = size;
528        self
529    }
530
531    /// Configures the number of literal context bits.
532    ///
533    /// How many of the highest bits of the previous uncompressed eight-bit byte
534    /// (also known as `literal') are taken into account when predicting the
535    /// bits of the next literal.
536    ///
537    /// The maximum value to this is 4 and the default is 3. It is not currently
538    /// supported if this plus [`LzmaOptions::literal_position_bits`] is greater than 4.
539    #[inline]
540    pub fn literal_context_bits(&mut self, bits: u32) -> &mut LzmaOptions {
541        self.raw.lc = bits;
542        self
543    }
544
545    /// Configures the number of literal position bits.
546    ///
547    /// This affects what kind of alignment in the uncompressed data is assumed
548    /// when encoding literals. A literal is a single 8-bit byte. See
549    /// [`LzmaOptions::position_bits`] for more information about alignment.
550    ///
551    /// The default for this is 0.
552    #[inline]
553    pub fn literal_position_bits(&mut self, bits: u32) -> &mut LzmaOptions {
554        self.raw.lp = bits;
555        self
556    }
557
558    /// Configures the number of position bits.
559    ///
560    /// Position bits affects what kind of alignment in the uncompressed data is
561    /// assumed in general. The default of 2 means four-byte alignment (2^pb
562    /// = 2^2 = 4), which is often a good choice when there's no better guess.
563    ///
564    /// When the alignment is known, setting pb accordingly may reduce the file
565    /// size a little. E.g. with text files having one-byte alignment (US-ASCII,
566    /// ISO-8859-*, UTF-8), setting pb=0 can improve compression slightly. For
567    /// UTF-16 text, pb=1 is a good choice. If the alignment is an odd number
568    /// like 3 bytes, pb=0 might be the best choice.
569    ///
570    /// Even though the assumed alignment can be adjusted with pb and lp, LZMA1
571    /// and LZMA2 still slightly favor 16-byte alignment. It might be worth
572    /// taking into account when designing file formats that are likely to be
573    /// often compressed with LZMA1 or LZMA2.
574    #[inline]
575    pub fn position_bits(&mut self, bits: u32) -> &mut LzmaOptions {
576        self.raw.pb = bits;
577        self
578    }
579
580    /// Configures the compression mode.
581    #[inline]
582    pub fn mode(&mut self, mode: Mode) -> &mut LzmaOptions {
583        self.raw.mode = mode as liblzma_sys::lzma_mode;
584        self
585    }
586
587    /// Configures the nice length of a match.
588    ///
589    /// This determines how many bytes the encoder compares from the match
590    /// candidates when looking for the best match. Once a match of at least
591    /// `len` bytes long is found, the encoder stops looking for better
592    /// candidates and encodes the match. (Naturally, if the found match is
593    /// actually longer than `len`, the actual length is encoded; it's not
594    /// truncated to `len`.)
595    ///
596    /// Bigger values usually increase the compression ratio and compression
597    /// time. For most files, 32 to 128 is a good value, which gives very good
598    /// compression ratio at good speed.
599    ///
600    /// The exact minimum value depends on the match finder. The maximum is 273,
601    /// which is the maximum length of a match that LZMA1 and LZMA2 can encode.
602    #[inline]
603    pub fn nice_len(&mut self, len: u32) -> &mut LzmaOptions {
604        self.raw.nice_len = len;
605        self
606    }
607
608    /// Configures the match finder ID.
609    #[inline]
610    pub fn match_finder(&mut self, mf: MatchFinder) -> &mut LzmaOptions {
611        self.raw.mf = mf as liblzma_sys::lzma_match_finder;
612        self
613    }
614
615    /// Maximum search depth in the match finder.
616    ///
617    /// For every input byte, match finder searches through the hash chain or
618    /// binary tree in a loop, each iteration going one step deeper in the chain
619    /// or tree. The searching stops if
620    ///
621    ///  - a match of at least [`LzmaOptions::nice_len`] bytes long is found;
622    ///  - all match candidates from the hash chain or binary tree have
623    ///    been checked; or
624    ///  - maximum search depth is reached.
625    ///
626    /// Maximum search depth is needed to prevent the match finder from wasting
627    /// too much time in case there are lots of short match candidates. On the
628    /// other hand, stopping the search before all candidates have been checked
629    /// can reduce compression ratio.
630    ///
631    /// Setting depth to zero tells liblzma to use an automatic default value,
632    /// that depends on the selected match finder and [`LzmaOptions::nice_len`].
633    /// The default is in the range [4, 200] or so (it may vary between liblzma
634    /// versions).
635    ///
636    /// Using a bigger depth value than the default can increase compression
637    /// ratio in some cases. There is no strict maximum value, but high values
638    /// (thousands or millions) should be used with care: the encoder could
639    /// remain fast enough with typical input, but malicious input could cause
640    /// the match finder to slow down dramatically, possibly creating a denial
641    /// of service attack.
642    #[inline]
643    pub fn depth(&mut self, depth: u32) -> &mut LzmaOptions {
644        self.raw.depth = depth;
645        self
646    }
647}
648
649impl Check {
650    /// Test if this check is supported in this build of liblzma.
651    #[inline]
652    pub fn is_supported(&self) -> bool {
653        let ret = unsafe { liblzma_sys::lzma_check_is_supported(*self as liblzma_sys::lzma_check) };
654        ret != 0
655    }
656}
657
658impl MatchFinder {
659    /// Test if this match finder is supported in this build of liblzma.
660    #[inline]
661    pub fn is_supported(&self) -> bool {
662        let ret =
663            unsafe { liblzma_sys::lzma_mf_is_supported(*self as liblzma_sys::lzma_match_finder) };
664        ret != 0
665    }
666}
667
668impl Filters {
669    /// Creates a new filter chain with no filters.
670    #[inline]
671    pub fn new() -> Filters {
672        Filters {
673            inner: vec![liblzma_sys::lzma_filter {
674                id: liblzma_sys::LZMA_VLI_UNKNOWN,
675                options: std::ptr::null_mut(),
676            }],
677            lzma_opts: LinkedList::new(),
678        }
679    }
680
681    /// Add an LZMA1 filter.
682    ///
683    /// LZMA1 is the very same thing as what was called just LZMA in LZMA Utils,
684    /// 7-Zip, and LZMA SDK. It's called LZMA1 here to prevent developers from
685    /// accidentally using LZMA when they actually want LZMA2.
686    ///
687    /// LZMA1 shouldn't be used for new applications unless you _really_ know
688    /// what you are doing.  LZMA2 is almost always a better choice.
689    #[inline]
690    pub fn lzma1(&mut self, opts: &LzmaOptions) -> &mut Filters {
691        self.lzma_opts.push_back(opts.raw);
692        let ptr = self.lzma_opts.back().unwrap() as *const _ as *mut _;
693        self.push(liblzma_sys::lzma_filter {
694            id: liblzma_sys::LZMA_FILTER_LZMA1,
695            options: ptr,
696        })
697    }
698
699    /// Add an LZMA1 filter with properties.
700    #[inline]
701    pub fn lzma1_properties(&mut self, properties: &[u8]) -> Result<&mut Filters, Error> {
702        let filter = liblzma_sys::lzma_filter {
703            id: liblzma_sys::LZMA_FILTER_LZMA1,
704            options: std::ptr::null_mut(),
705        };
706        self.push_with_properties(filter, properties)
707    }
708
709    /// Add an LZMA2 filter.
710    ///
711    /// Usually you want this instead of LZMA1. Compared to LZMA1, LZMA2 adds
712    /// support for [`Action::SyncFlush`], uncompressed chunks (smaller expansion when
713    /// trying to compress uncompressible data), possibility to change
714    /// [`literal_context_bits`]/[`literal_position_bits`]/[`position_bits`] in the
715    /// middle of encoding, and some other internal improvements.
716    ///
717    /// [`literal_context_bits`]: LzmaOptions::literal_context_bits
718    /// [`literal_position_bits`]: LzmaOptions::literal_position_bits
719    /// [`position_bits`]: LzmaOptions::position_bits
720    #[inline]
721    pub fn lzma2(&mut self, opts: &LzmaOptions) -> &mut Filters {
722        self.lzma_opts.push_back(opts.raw);
723        let ptr = self.lzma_opts.back().unwrap() as *const _ as *mut _;
724        self.push(liblzma_sys::lzma_filter {
725            id: liblzma_sys::LZMA_FILTER_LZMA2,
726            options: ptr,
727        })
728    }
729
730    /// Add an LZMA2 filter with properties.
731    #[inline]
732    pub fn lzma2_properties(&mut self, properties: &[u8]) -> Result<&mut Filters, Error> {
733        let filter = liblzma_sys::lzma_filter {
734            id: liblzma_sys::LZMA_FILTER_LZMA2,
735            options: std::ptr::null_mut(),
736        };
737        self.push_with_properties(filter, properties)
738    }
739
740    /// Add a DELTA filter.
741    ///
742    /// # Examples
743    /// ```
744    /// use liblzma::stream::{Filters, LzmaOptions};
745    ///
746    /// let dict_size = 0x40000;
747    /// let mut opts = LzmaOptions::new_preset(6).unwrap();
748    /// opts.dict_size(dict_size);
749    /// let mut filters = Filters::new();
750    /// filters.delta();
751    /// filters.lzma2(&opts);
752    /// ```
753    #[inline]
754    pub fn delta(&mut self) -> &mut Filters {
755        self.push(liblzma_sys::lzma_filter {
756            id: liblzma_sys::LZMA_FILTER_DELTA,
757            options: std::ptr::null_mut(),
758        })
759    }
760
761    /// Add a DELTA filter with properties.
762    ///
763    /// # Examples
764    /// ```
765    /// use liblzma::stream::{Filters, LzmaOptions};
766    ///
767    /// let mut filters = Filters::new();
768    /// filters.delta_properties(&[0x00]).unwrap();
769    /// ```
770    #[inline]
771    pub fn delta_properties(&mut self, properties: &[u8]) -> Result<&mut Filters, Error> {
772        let filter = liblzma_sys::lzma_filter {
773            id: liblzma_sys::LZMA_FILTER_DELTA,
774            options: std::ptr::null_mut(),
775        };
776        self.push_with_properties(filter, properties)
777    }
778
779    /// Add a filter for x86 binaries.
780    ///
781    /// # Examples
782    /// ```
783    /// use liblzma::stream::{Filters, LzmaOptions};
784    ///
785    /// let dict_size = 0x40000;
786    /// let mut opts = LzmaOptions::new_preset(6).unwrap();
787    /// opts.dict_size(dict_size);
788    /// let mut filters = Filters::new();
789    /// filters.x86();
790    /// filters.lzma2(&opts);
791    /// ```
792    #[inline]
793    pub fn x86(&mut self) -> &mut Filters {
794        self.push(liblzma_sys::lzma_filter {
795            id: liblzma_sys::LZMA_FILTER_X86,
796            options: std::ptr::null_mut(),
797        })
798    }
799
800    /// Add a filter for x86 binaries with properties.
801    ///
802    /// # Examples
803    /// ```
804    /// use liblzma::stream::{Filters, LzmaOptions};
805    ///
806    /// let mut filters = Filters::new();
807    /// filters.x86_properties(&[0x00, 0x00, 0x00, 0x00]).unwrap();
808    /// ```
809    #[inline]
810    pub fn x86_properties(&mut self, properties: &[u8]) -> Result<&mut Filters, Error> {
811        let filter = liblzma_sys::lzma_filter {
812            id: liblzma_sys::LZMA_FILTER_X86,
813            options: std::ptr::null_mut(),
814        };
815        self.push_with_properties(filter, properties)
816    }
817
818    /// Add a filter for PowerPC binaries.
819    ///
820    /// # Examples
821    /// ```
822    /// use liblzma::stream::{Filters, LzmaOptions};
823    ///
824    /// let dict_size = 0x40000;
825    /// let mut opts = LzmaOptions::new_preset(6).unwrap();
826    /// opts.dict_size(dict_size);
827    /// let mut filters = Filters::new();
828    /// filters.powerpc();
829    /// filters.lzma2(&opts);
830    /// ```
831    #[inline]
832    pub fn powerpc(&mut self) -> &mut Filters {
833        self.push(liblzma_sys::lzma_filter {
834            id: liblzma_sys::LZMA_FILTER_POWERPC,
835            options: std::ptr::null_mut(),
836        })
837    }
838
839    /// Add a filter for PowerPC binaries with properties.
840    ///
841    /// # Examples
842    /// ```
843    /// use liblzma::stream::{Filters, LzmaOptions};
844    ///
845    /// let mut filters = Filters::new();
846    /// filters.powerpc_properties(&[0x00, 0x00, 0x00, 0x00]).unwrap();
847    /// ```
848    #[inline]
849    pub fn powerpc_properties(&mut self, properties: &[u8]) -> Result<&mut Filters, Error> {
850        let filter = liblzma_sys::lzma_filter {
851            id: liblzma_sys::LZMA_FILTER_POWERPC,
852            options: std::ptr::null_mut(),
853        };
854        self.push_with_properties(filter, properties)
855    }
856
857    /// Add a filter for IA-64 (itanium) binaries.
858    ///
859    /// # Examples
860    /// ```
861    /// use liblzma::stream::{Filters, LzmaOptions};
862    ///
863    /// let dict_size = 0x40000;
864    /// let mut opts = LzmaOptions::new_preset(6).unwrap();
865    /// opts.dict_size(dict_size);
866    /// let mut filters = Filters::new();
867    /// filters.ia64();
868    /// filters.lzma2(&opts);
869    /// ```
870    #[inline]
871    pub fn ia64(&mut self) -> &mut Filters {
872        self.push(liblzma_sys::lzma_filter {
873            id: liblzma_sys::LZMA_FILTER_IA64,
874            options: std::ptr::null_mut(),
875        })
876    }
877
878    /// Add a filter for IA-64 (itanium) binaries with properties.
879    ///
880    /// # Examples
881    /// ```
882    /// use liblzma::stream::{Filters, LzmaOptions};
883    ///
884    /// let mut filters = Filters::new();
885    /// filters.ia64_properties(&[0x00, 0x00, 0x00, 0x00]).unwrap();
886    /// ```
887    #[inline]
888    pub fn ia64_properties(&mut self, properties: &[u8]) -> Result<&mut Filters, Error> {
889        let filter = liblzma_sys::lzma_filter {
890            id: liblzma_sys::LZMA_FILTER_IA64,
891            options: std::ptr::null_mut(),
892        };
893        self.push_with_properties(filter, properties)
894    }
895
896    /// Add a filter for ARM binaries.
897    ///
898    /// # Examples
899    /// ```
900    /// use liblzma::stream::{Filters, LzmaOptions};
901    ///
902    /// let dict_size = 0x40000;
903    /// let mut opts = LzmaOptions::new_preset(6).unwrap();
904    /// opts.dict_size(dict_size);
905    /// let mut filters = Filters::new();
906    /// filters.arm();
907    /// filters.lzma2(&opts);
908    /// ```
909    #[inline]
910    pub fn arm(&mut self) -> &mut Filters {
911        self.push(liblzma_sys::lzma_filter {
912            id: liblzma_sys::LZMA_FILTER_ARM,
913            options: std::ptr::null_mut(),
914        })
915    }
916
917    /// Add a filter for ARM binaries with properties.
918    ///
919    /// # Examples
920    /// ```
921    /// use liblzma::stream::{Filters, LzmaOptions};
922    ///
923    /// let mut filters = Filters::new();
924    /// filters.arm_properties(&[0x00, 0x00, 0x00, 0x00]).unwrap();
925    /// ```
926    #[inline]
927    pub fn arm_properties(&mut self, properties: &[u8]) -> Result<&mut Filters, Error> {
928        let filter = liblzma_sys::lzma_filter {
929            id: liblzma_sys::LZMA_FILTER_ARM,
930            options: std::ptr::null_mut(),
931        };
932        self.push_with_properties(filter, properties)
933    }
934
935    /// Add a filter for ARM64 binaries.
936    ///
937    /// # Examples
938    /// ```
939    /// use liblzma::stream::{Filters, LzmaOptions};
940    ///
941    /// let dict_size = 0x40000;
942    /// let mut opts = LzmaOptions::new_preset(6).unwrap();
943    /// opts.dict_size(dict_size);
944    /// let mut filters = Filters::new();
945    /// filters.arm64();
946    /// filters.lzma2(&opts);
947    /// ```
948    #[inline]
949    pub fn arm64(&mut self) -> &mut Filters {
950        self.push(liblzma_sys::lzma_filter {
951            id: liblzma_sys::LZMA_FILTER_ARM64,
952            options: std::ptr::null_mut(),
953        })
954    }
955
956    /// Add a filter for ARM64 binaries with properties.
957    ///
958    /// # Examples
959    /// ```
960    /// use liblzma::stream::{Filters, LzmaOptions};
961    ///
962    /// let mut filters = Filters::new();
963    /// filters.arm64_properties(&[0x00, 0x00, 0x00, 0x00]).unwrap();
964    /// ```
965    #[inline]
966    pub fn arm64_properties(&mut self, properties: &[u8]) -> Result<&mut Filters, Error> {
967        let filter = liblzma_sys::lzma_filter {
968            id: liblzma_sys::LZMA_FILTER_ARM64,
969            options: std::ptr::null_mut(),
970        };
971        self.push_with_properties(filter, properties)
972    }
973
974    /// Add a filter for RISCV binaries.
975    ///
976    /// # Examples
977    /// ```
978    /// use liblzma::stream::{Filters, LzmaOptions};
979    ///
980    /// let dict_size = 0x40000;
981    /// let mut opts = LzmaOptions::new_preset(6).unwrap();
982    /// opts.dict_size(dict_size);
983    /// let mut filters = Filters::new();
984    /// filters.riscv();
985    /// filters.lzma2(&opts);
986    /// ```
987    #[inline]
988    pub fn riscv(&mut self) -> &mut Filters {
989        self.push(liblzma_sys::lzma_filter {
990            id: liblzma_sys::LZMA_FILTER_RISCV,
991            options: std::ptr::null_mut(),
992        })
993    }
994
995    /// Add a filter for RISCV binaries with properties.
996    ///
997    /// # Examples
998    /// ```
999    /// use liblzma::stream::{Filters, LzmaOptions};
1000    ///
1001    /// let mut filters = Filters::new();
1002    /// filters.riscv_properties(&[0x00, 0x00, 0x00, 0x00]).unwrap();
1003    /// ```
1004    #[inline]
1005    pub fn riscv_properties(&mut self, properties: &[u8]) -> Result<&mut Filters, Error> {
1006        let filter = liblzma_sys::lzma_filter {
1007            id: liblzma_sys::LZMA_FILTER_RISCV,
1008            options: std::ptr::null_mut(),
1009        };
1010        self.push_with_properties(filter, properties)
1011    }
1012
1013    /// Add a filter for ARM-Thumb binaries.
1014    ///
1015    /// # Examples
1016    /// ```
1017    /// use liblzma::stream::{Filters, LzmaOptions};
1018    ///
1019    /// let dict_size = 0x40000;
1020    /// let mut opts = LzmaOptions::new_preset(6).unwrap();
1021    /// opts.dict_size(dict_size);
1022    /// let mut filters = Filters::new();
1023    /// filters.arm_thumb();
1024    /// filters.lzma2(&opts);
1025    /// ```
1026    #[inline]
1027    pub fn arm_thumb(&mut self) -> &mut Filters {
1028        self.push(liblzma_sys::lzma_filter {
1029            id: liblzma_sys::LZMA_FILTER_ARMTHUMB,
1030            options: std::ptr::null_mut(),
1031        })
1032    }
1033
1034    /// Add a filter for ARM-Thumb binaries with properties.
1035    ///
1036    /// # Examples
1037    /// ```
1038    /// use liblzma::stream::{Filters, LzmaOptions};
1039    ///
1040    /// let mut filters = Filters::new();
1041    /// filters.arm_thumb_properties(&[0x00, 0x00, 0x00, 0x00]).unwrap();
1042    /// ```
1043    #[inline]
1044    pub fn arm_thumb_properties(&mut self, properties: &[u8]) -> Result<&mut Filters, Error> {
1045        let filter = liblzma_sys::lzma_filter {
1046            id: liblzma_sys::LZMA_FILTER_ARMTHUMB,
1047            options: std::ptr::null_mut(),
1048        };
1049        self.push_with_properties(filter, properties)
1050    }
1051
1052    /// Add a filter for SPARC binaries.
1053    ///
1054    /// # Examples
1055    /// ```
1056    /// use liblzma::stream::{Filters, LzmaOptions};
1057    ///
1058    /// let dict_size = 0x40000;
1059    /// let mut opts = LzmaOptions::new_preset(6).unwrap();
1060    /// opts.dict_size(dict_size);
1061    /// let mut filters = Filters::new();
1062    /// filters.sparc();
1063    /// filters.lzma2(&opts);
1064    /// ```
1065    #[inline]
1066    pub fn sparc(&mut self) -> &mut Filters {
1067        self.push(liblzma_sys::lzma_filter {
1068            id: liblzma_sys::LZMA_FILTER_SPARC,
1069            options: std::ptr::null_mut(),
1070        })
1071    }
1072
1073    /// Add a filter for SPARC binaries with properties.
1074    ///
1075    /// # Examples
1076    /// ```
1077    /// use liblzma::stream::{Filters, LzmaOptions};
1078    ///
1079    /// let mut filters = Filters::new();
1080    /// filters.sparc_properties(&[0x00, 0x00, 0x00, 0x00]).unwrap();
1081    /// ```
1082    #[inline]
1083    pub fn sparc_properties(&mut self, properties: &[u8]) -> Result<&mut Filters, Error> {
1084        let filter = liblzma_sys::lzma_filter {
1085            id: liblzma_sys::LZMA_FILTER_SPARC,
1086            options: std::ptr::null_mut(),
1087        };
1088        self.push_with_properties(filter, properties)
1089    }
1090
1091    #[inline]
1092    fn push(&mut self, filter: liblzma_sys::lzma_filter) -> &mut Filters {
1093        let pos = self.inner.len() - 1;
1094        self.inner.insert(pos, filter);
1095        self
1096    }
1097
1098    #[inline]
1099    fn push_with_properties(
1100        &mut self,
1101        mut filter: liblzma_sys::lzma_filter,
1102        properties: &[u8],
1103    ) -> Result<&mut Filters, Error> {
1104        cvt(unsafe {
1105            liblzma_sys::lzma_properties_decode(
1106                &mut filter,
1107                std::ptr::null(),
1108                properties.as_ptr(),
1109                properties.len(),
1110            )
1111        })?;
1112        let pos = self.inner.len() - 1;
1113        self.inner.insert(pos, filter);
1114        Ok(self)
1115    }
1116
1117    /// Recommend a Block size for multithreaded encoding
1118    ///
1119    /// # Examples
1120    /// ```
1121    /// use liblzma::stream::{Filters, LzmaOptions};
1122    ///
1123    /// let dict_size = 0x40000;
1124    /// let mut opts = LzmaOptions::new_preset(6).unwrap();
1125    /// opts.dict_size(dict_size);
1126    /// let mut filters = Filters::new();
1127    /// filters.lzma2(&opts);
1128    /// assert_eq!(filters.mt_block_size(), 1 << 20);
1129    /// ```
1130    #[cfg(feature = "parallel")]
1131    #[inline]
1132    pub fn mt_block_size(&self) -> u64 {
1133        unsafe { liblzma_sys::lzma_mt_block_size(self.inner.as_ptr()) }
1134    }
1135}
1136
1137#[cfg(feature = "parallel")]
1138impl MtStreamBuilder {
1139    /// Creates a new blank builder to create a multithreaded encoding [`Stream`].
1140    #[inline]
1141    pub fn new() -> Self {
1142        let mut init = Self {
1143            raw: unsafe { mem::zeroed() },
1144            filters: None,
1145        };
1146        init.raw.threads = 1;
1147        init
1148    }
1149
1150    /// Configures the number of worker threads to use
1151    #[inline]
1152    pub fn threads(&mut self, threads: u32) -> &mut Self {
1153        self.raw.threads = threads;
1154        self
1155    }
1156
1157    /// Configures the maximum uncompressed size of a block
1158    ///
1159    /// The encoder will start a new .xz block every `block_size` bytes.
1160    /// Using [`Action::FullFlush`] or [`Action::FullBarrier`] with
1161    /// [`Stream::process`] the caller may tell liblzma to start a new block earlier.
1162    ///
1163    /// With LZMA2, a recommended block size is 2-4 times the LZMA2 dictionary
1164    /// size. With very small dictionaries, it is recommended to use at least 1
1165    /// MiB block size for good compression ratio, even if this is more than
1166    /// four times the dictionary size. Note that these are only recommendations
1167    /// for typical use cases; feel free to use other values. Just keep in mind
1168    /// that using a block size less than the LZMA2 dictionary size is waste of
1169    /// RAM.
1170    ///
1171    /// Set this to 0 to let liblzma choose the block size depending on the
1172    /// compression options. For LZMA2 it will be 3*`dict_size` or 1 MiB,
1173    /// whichever is more.
1174    ///
1175    /// For each thread, about 3 * `block_size` bytes of memory will be
1176    /// allocated. This may change in later liblzma versions. If so, the memory
1177    /// usage will probably be reduced, not increased.
1178    #[inline]
1179    pub fn block_size(&mut self, block_size: u64) -> &mut Self {
1180        self.raw.block_size = block_size;
1181        self
1182    }
1183
1184    /// Timeout to allow [`Stream::process`] to return early
1185    ///
1186    /// Multithreading can make liblzma to consume input and produce output in a
1187    /// very bursty way: it may first read a lot of input to fill internal
1188    /// buffers, then no input or output occurs for a while.
1189    ///
1190    /// In single-threaded mode, [`Stream::process`] won't return until it has either
1191    /// consumed all the input or filled the output buffer. If this is done in
1192    /// multithreaded mode, it may cause a call [`Stream::process`] to take even tens of
1193    /// seconds, which isn't acceptable in all applications.
1194    ///
1195    /// To avoid very long blocking times in [`Stream::process`], a timeout (in
1196    /// milliseconds) may be set here. If `process would block longer than
1197    /// this number of milliseconds, it will return with `Ok`. Reasonable
1198    /// values are 100 ms or more. The xz command line tool uses 300 ms.
1199    ///
1200    /// If long blocking times are fine for you, set timeout to a special
1201    /// value of 0, which will disable the timeout mechanism and will make
1202    /// [`Stream::process`] block until all the input is consumed or the output
1203    /// buffer has been filled.
1204    #[inline]
1205    pub fn timeout_ms(&mut self, timeout: u32) -> &mut Self {
1206        self.raw.timeout = timeout;
1207        self
1208    }
1209
1210    /// Compression preset (level and possible flags)
1211    ///
1212    /// The preset is set just like with [`Stream::new_easy_encoder`]. The preset
1213    /// is ignored if filters below have been specified.
1214    #[inline]
1215    pub fn preset(&mut self, preset: u32) -> &mut Self {
1216        self.raw.preset = preset;
1217        self
1218    }
1219
1220    /// Configure a custom filter chain
1221    #[inline]
1222    pub fn filters(&mut self, filters: Filters) -> &mut Self {
1223        self.raw.filters = filters.inner.as_ptr();
1224        self.filters = Some(filters);
1225        self
1226    }
1227
1228    /// Configures the integrity check type
1229    #[inline]
1230    pub fn check(&mut self, check: Check) -> &mut Self {
1231        self.raw.check = check as liblzma_sys::lzma_check;
1232        self
1233    }
1234
1235    /// Memory usage limit to reduce the number of threads
1236    #[inline]
1237    pub fn memlimit_threading(&mut self, memlimit: u64) -> &mut Self {
1238        self.raw.memlimit_threading = memlimit;
1239        self
1240    }
1241
1242    /// Memory usage limit that should never be exceeded
1243    #[inline]
1244    pub fn memlimit_stop(&mut self, memlimit: u64) -> &mut Self {
1245        self.raw.memlimit_stop = memlimit;
1246        self
1247    }
1248
1249    /// Calculate approximate memory usage of multithreaded .xz encoder
1250    #[inline]
1251    pub fn memusage(&self) -> u64 {
1252        unsafe { liblzma_sys::lzma_stream_encoder_mt_memusage(&self.raw) }
1253    }
1254
1255    /// Initialize multithreaded .xz stream encoder.
1256    #[inline]
1257    pub fn encoder(&self) -> Result<Stream, Error> {
1258        let mut init = unsafe { Stream::zeroed() };
1259        cvt(unsafe { liblzma_sys::lzma_stream_encoder_mt(&mut init.raw, &self.raw) })?;
1260        Ok(init)
1261    }
1262
1263    /// Initialize multithreaded .xz stream decoder.
1264    #[inline]
1265    pub fn decoder(&self) -> Result<Stream, Error> {
1266        let mut init = unsafe { Stream::zeroed() };
1267        cvt(unsafe { liblzma_sys::lzma_stream_decoder_mt(&mut init.raw, &self.raw) })?;
1268        Ok(init)
1269    }
1270}
1271
1272fn cvt(rc: liblzma_sys::lzma_ret) -> Result<Status, Error> {
1273    match rc {
1274        liblzma_sys::LZMA_OK => Ok(Status::Ok),
1275        liblzma_sys::LZMA_STREAM_END => Ok(Status::StreamEnd),
1276        liblzma_sys::LZMA_NO_CHECK => Err(Error::NoCheck),
1277        liblzma_sys::LZMA_UNSUPPORTED_CHECK => Err(Error::UnsupportedCheck),
1278        liblzma_sys::LZMA_GET_CHECK => Ok(Status::GetCheck),
1279        liblzma_sys::LZMA_MEM_ERROR => Err(Error::Mem),
1280        liblzma_sys::LZMA_MEMLIMIT_ERROR => Err(Error::MemLimit),
1281        liblzma_sys::LZMA_FORMAT_ERROR => Err(Error::Format),
1282        liblzma_sys::LZMA_OPTIONS_ERROR => Err(Error::Options),
1283        liblzma_sys::LZMA_DATA_ERROR => Err(Error::Data),
1284        liblzma_sys::LZMA_BUF_ERROR => Ok(Status::MemNeeded),
1285        liblzma_sys::LZMA_PROG_ERROR => Err(Error::Program),
1286        c => panic!("unknown return code: {}", c),
1287    }
1288}
1289
1290impl From<Error> for io::Error {
1291    #[inline]
1292    fn from(e: Error) -> io::Error {
1293        let kind = match e {
1294            Error::Data => io::ErrorKind::InvalidData,
1295            Error::Options => io::ErrorKind::InvalidInput,
1296            Error::Format => io::ErrorKind::InvalidData,
1297            Error::MemLimit => io::ErrorKind::Other,
1298            Error::Mem => io::ErrorKind::Other,
1299            Error::Program => io::ErrorKind::Other,
1300            Error::NoCheck => io::ErrorKind::InvalidInput,
1301            Error::UnsupportedCheck => io::ErrorKind::Other,
1302        };
1303
1304        io::Error::new(kind, e)
1305    }
1306}
1307
1308impl error::Error for Error {}
1309
1310impl fmt::Display for Error {
1311    #[inline]
1312    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1313        match self {
1314            Error::Data => "lzma data error",
1315            Error::Options => "invalid options",
1316            Error::Format => "stream/file format not recognized",
1317            Error::MemLimit => "memory limit reached",
1318            Error::Mem => "can't allocate memory",
1319            Error::Program => "liblzma internal error",
1320            Error::NoCheck => "no integrity check was available",
1321            Error::UnsupportedCheck => "liblzma not built with check support",
1322        }
1323        .fmt(f)
1324    }
1325}
1326
1327impl Drop for Stream {
1328    #[inline]
1329    fn drop(&mut self) {
1330        unsafe {
1331            liblzma_sys::lzma_end(&mut self.raw);
1332        }
1333    }
1334}