Skip to main content

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/// Default compression preset level.
262pub const PRESET_DEFAULT: u32 = liblzma_sys::LZMA_PRESET_DEFAULT;
263
264/// Mask for extracting the preset level bits from a preset value.
265pub const PRESET_LEVEL_MASK: u32 = liblzma_sys::LZMA_PRESET_LEVEL_MASK;
266
267/// Flag to request the slower "extreme" variant of a preset.
268///
269/// Combine this with a preset level using bitwise-OR.
270/// For example: `6 | PRESET_EXTREME`.
271pub const PRESET_EXTREME: u32 = liblzma_sys::LZMA_PRESET_EXTREME;
272
273/// Encoder-related functions
274impl Stream {
275    /// Initialize .xz stream encoder using a preset number
276    ///
277    /// This is intended to be used by most for encoding data. The `preset`
278    /// argument is usually a level in the range 0-9 with 6 being a good
279    /// default. You may also bitwise-OR a level with [`PRESET_EXTREME`] to use
280    /// the slower extreme variant, for example `6 | PRESET_EXTREME`.
281    ///
282    /// The `check` argument is the integrity check to insert at the end of the
283    /// stream. The default of `Crc64` is typically appropriate.
284    #[inline]
285    pub fn new_easy_encoder(preset: u32, check: Check) -> Result<Stream, Error> {
286        let mut init = unsafe { Stream::zeroed() };
287        cvt(unsafe {
288            liblzma_sys::lzma_easy_encoder(&mut init.raw, preset, check as liblzma_sys::lzma_check)
289        })?;
290        Ok(init)
291    }
292
293    /// Initialize .lzma encoder (legacy file format)
294    ///
295    /// The .lzma format is sometimes called the LZMA_Alone format, which is the
296    /// reason for the name of this function. The .lzma format supports only the
297    /// LZMA1 filter. There is no support for integrity checks like CRC32.
298    ///
299    /// Use this function if and only if you need to create files readable by
300    /// legacy LZMA tools such as LZMA Utils 4.32.x. Moving to the .xz format
301    /// (the `new_easy_encoder` function) is strongly recommended.
302    ///
303    /// The valid action values for [`Stream::process`] are [`Action::Run`] and [`Action::Finish`].
304    /// No flushing is supported, because the file format doesn't support it.
305    #[inline]
306    pub fn new_lzma_encoder(options: &LzmaOptions) -> Result<Stream, Error> {
307        let mut init = unsafe { Stream::zeroed() };
308        cvt(unsafe { liblzma_sys::lzma_alone_encoder(&mut init.raw, &options.raw) })?;
309        Ok(init)
310    }
311
312    /// Initialize .xz Stream encoder using a custom filter chain
313    ///
314    /// This function is similar to `new_easy_encoder` but a custom filter chain
315    /// is specified.
316    #[inline]
317    pub fn new_stream_encoder(filters: &Filters, check: Check) -> Result<Stream, Error> {
318        let mut init = unsafe { Stream::zeroed() };
319        cvt(unsafe {
320            liblzma_sys::lzma_stream_encoder(
321                &mut init.raw,
322                filters.inner.as_ptr(),
323                check as liblzma_sys::lzma_check,
324            )
325        })?;
326        Ok(init)
327    }
328
329    /// Initialize an encoder stream using a custom filter chain.
330    #[inline]
331    pub fn new_raw_encoder(filters: &Filters) -> Result<Stream, Error> {
332        let mut init = unsafe { Self::zeroed() };
333        cvt(unsafe { liblzma_sys::lzma_raw_encoder(&mut init.raw, filters.inner.as_ptr()) })?;
334        Ok(init)
335    }
336}
337
338/// Decoder-related functions
339impl Stream {
340    /// Initialize a decoder which will choose a stream/lzma formats depending
341    /// on the input stream.
342    #[inline]
343    pub fn new_auto_decoder(memlimit: u64, flags: u32) -> Result<Stream, Error> {
344        let mut init = unsafe { Self::zeroed() };
345        cvt(unsafe { liblzma_sys::lzma_auto_decoder(&mut init.raw, memlimit, flags) })?;
346        Ok(init)
347    }
348
349    /// Initialize a .xz stream decoder.
350    ///
351    /// The maximum memory usage can be specified along with flags such as
352    /// [`TELL_ANY_CHECK`], [`TELL_NO_CHECK`], [`TELL_UNSUPPORTED_CHECK`],
353    /// [`IGNORE_CHECK`], or [`CONCATENATED`].
354    #[inline]
355    pub fn new_stream_decoder(memlimit: u64, flags: u32) -> Result<Stream, Error> {
356        let mut init = unsafe { Self::zeroed() };
357        cvt(unsafe { liblzma_sys::lzma_stream_decoder(&mut init.raw, memlimit, flags) })?;
358        Ok(init)
359    }
360
361    /// Initialize a .lzma stream decoder.
362    ///
363    /// The maximum memory usage can also be specified.
364    #[inline]
365    pub fn new_lzma_decoder(memlimit: u64) -> Result<Stream, Error> {
366        let mut init = unsafe { Self::zeroed() };
367        cvt(unsafe { liblzma_sys::lzma_alone_decoder(&mut init.raw, memlimit) })?;
368        Ok(init)
369    }
370
371    /// Initialize a .lz stream decoder.
372    #[inline]
373    pub fn new_lzip_decoder(memlimit: u64, flags: u32) -> Result<Self, Error> {
374        let mut init = unsafe { Self::zeroed() };
375        cvt(unsafe { liblzma_sys::lzma_lzip_decoder(&mut init.raw, memlimit, flags) })?;
376        Ok(init)
377    }
378
379    /// Initialize a decoder stream using a custom filter chain.
380    #[inline]
381    pub fn new_raw_decoder(filters: &Filters) -> Result<Stream, Error> {
382        let mut init = unsafe { Self::zeroed() };
383        cvt(unsafe { liblzma_sys::lzma_raw_decoder(&mut init.raw, filters.inner.as_ptr()) })?;
384        Ok(init)
385    }
386}
387
388/// Generic functions
389impl Stream {
390    #[inline]
391    unsafe fn zeroed() -> Self {
392        Self {
393            raw: unsafe { mem::zeroed() },
394        }
395    }
396
397    #[inline]
398    unsafe fn process_inner(
399        &mut self,
400        input: &[u8],
401        output_ptr: *mut u8,
402        output_len: usize,
403        action: Action,
404    ) -> Result<Status, Error> {
405        self.raw.next_in = input.as_ptr();
406        self.raw.avail_in = input.len();
407        self.raw.next_out = output_ptr;
408        self.raw.avail_out = output_len;
409        let action = action as liblzma_sys::lzma_action;
410        unsafe { cvt(liblzma_sys::lzma_code(&mut self.raw, action)) }
411    }
412
413    /// Processes some data from input into an output buffer.
414    ///
415    /// This will perform the appropriate encoding or decoding operation
416    /// depending on the kind of underlying stream. See [`Action`] for the
417    /// possible actions that can be taken.
418    ///
419    /// After the first use of [`Action::SyncFlush`], [`Action::FullFlush`],
420    /// [`Action::FullBarrier`], or [`Action::Finish`], the same [`Action`]
421    /// must be used until this returns [`Status::StreamEnd`]. Not doing so
422    /// will result in a [`Error::Program`].
423    ///
424    /// The amount of input must not be modified by the application until
425    /// this returns [`Status::StreamEnd`], otherwise [`Error::Program`] will
426    /// be returned.
427    #[inline]
428    pub fn process(
429        &mut self,
430        input: &[u8],
431        output: &mut [u8],
432        action: Action,
433    ) -> Result<Status, Error> {
434        unsafe { self.process_inner(input, output.as_mut_ptr(), output.len(), action) }
435    }
436
437    /// Same as [`Self::process`] but accepts uninitialized buffer.
438    ///
439    /// To retrieve bytes written into the `output`, please call [`Self::total_out()`] before
440    /// and after the call to [`Self::process_uninit`] and the diff of `total_out` would be
441    /// the bytes written to the `output`.
442    #[inline]
443    pub fn process_uninit(
444        &mut self,
445        input: &[u8],
446        output: &mut [mem::MaybeUninit<u8>],
447        action: Action,
448    ) -> Result<Status, Error> {
449        unsafe { self.process_inner(input, output.as_mut_ptr() as *mut _, output.len(), action) }
450    }
451
452    /// Performs the same data as [`Stream::process`], but places output data in a [`Vec`].
453    ///
454    /// This function will use the extra capacity of `output` as a destination
455    /// for bytes to be placed. The length of `output` will automatically get
456    /// updated after the operation has completed.
457    ///
458    /// See [`Stream::process`] for the other arguments.
459    #[inline]
460    pub fn process_vec(
461        &mut self,
462        input: &[u8],
463        output: &mut Vec<u8>,
464        action: Action,
465    ) -> Result<Status, Error> {
466        let len = output.len();
467
468        unsafe {
469            let before = self.total_out();
470            let ret = self.process_uninit(input, output.spare_capacity_mut(), action);
471            output.set_len((self.total_out() - before) as usize + len);
472            ret
473        }
474    }
475
476    /// Returns the total amount of input bytes consumed by this stream.
477    #[inline]
478    pub fn total_in(&self) -> u64 {
479        self.raw.total_in
480    }
481
482    /// Returns the total amount of bytes produced by this stream.
483    #[inline]
484    pub fn total_out(&self) -> u64 {
485        self.raw.total_out
486    }
487
488    /// Get the current memory usage limit.
489    ///
490    /// This is only supported if the underlying stream supports a memlimit.
491    #[inline]
492    pub fn memlimit(&self) -> u64 {
493        unsafe { liblzma_sys::lzma_memlimit_get(&self.raw) }
494    }
495
496    /// Set the current memory usage limit.
497    ///
498    /// This can return [`Error::MemLimit`] if the new limit is too small or
499    /// [`Error::Program`] if this stream doesn't take a memory limit.
500    #[inline]
501    pub fn set_memlimit(&mut self, limit: u64) -> Result<(), Error> {
502        cvt(unsafe { liblzma_sys::lzma_memlimit_set(&mut self.raw, limit) }).map(|_| ())
503    }
504}
505
506impl LzmaOptions {
507    /// Creates a new blank set of options.
508    #[inline]
509    pub fn new() -> LzmaOptions {
510        LzmaOptions {
511            raw: unsafe { mem::zeroed() },
512        }
513    }
514
515    /// Creates a new blank set of options for encoding.
516    ///
517    /// The `preset` argument is usually a level in the range 0-9. You may also
518    /// bitwise-OR a level with [`PRESET_EXTREME`] to use the slower extreme
519    /// variant, for example `6 | PRESET_EXTREME`.
520    #[inline]
521    pub fn new_preset(preset: u32) -> Result<LzmaOptions, Error> {
522        unsafe {
523            let mut options = Self::new();
524            let ret = liblzma_sys::lzma_lzma_preset(&mut options.raw, preset);
525            if ret != 0 {
526                Err(Error::Program)
527            } else {
528                Ok(options)
529            }
530        }
531    }
532
533    /// Configures the dictionary size, in bytes
534    ///
535    /// Dictionary size indicates how many bytes of the recently processed
536    /// uncompressed data is kept in memory.
537    ///
538    /// The minimum dictionary size is 4096 bytes and the default is 2^23 = 8MB.
539    #[inline]
540    pub fn dict_size(&mut self, size: u32) -> &mut LzmaOptions {
541        self.raw.dict_size = size;
542        self
543    }
544
545    /// Configures the number of literal context bits.
546    ///
547    /// How many of the highest bits of the previous uncompressed eight-bit byte
548    /// (also known as `literal') are taken into account when predicting the
549    /// bits of the next literal.
550    ///
551    /// The maximum value to this is 4 and the default is 3. It is not currently
552    /// supported if this plus [`LzmaOptions::literal_position_bits`] is greater than 4.
553    #[inline]
554    pub fn literal_context_bits(&mut self, bits: u32) -> &mut LzmaOptions {
555        self.raw.lc = bits;
556        self
557    }
558
559    /// Configures the number of literal position bits.
560    ///
561    /// This affects what kind of alignment in the uncompressed data is assumed
562    /// when encoding literals. A literal is a single 8-bit byte. See
563    /// [`LzmaOptions::position_bits`] for more information about alignment.
564    ///
565    /// The default for this is 0.
566    #[inline]
567    pub fn literal_position_bits(&mut self, bits: u32) -> &mut LzmaOptions {
568        self.raw.lp = bits;
569        self
570    }
571
572    /// Configures the number of position bits.
573    ///
574    /// Position bits affects what kind of alignment in the uncompressed data is
575    /// assumed in general. The default of 2 means four-byte alignment (2^pb
576    /// = 2^2 = 4), which is often a good choice when there's no better guess.
577    ///
578    /// When the alignment is known, setting pb accordingly may reduce the file
579    /// size a little. E.g. with text files having one-byte alignment (US-ASCII,
580    /// ISO-8859-*, UTF-8), setting pb=0 can improve compression slightly. For
581    /// UTF-16 text, pb=1 is a good choice. If the alignment is an odd number
582    /// like 3 bytes, pb=0 might be the best choice.
583    ///
584    /// Even though the assumed alignment can be adjusted with pb and lp, LZMA1
585    /// and LZMA2 still slightly favor 16-byte alignment. It might be worth
586    /// taking into account when designing file formats that are likely to be
587    /// often compressed with LZMA1 or LZMA2.
588    #[inline]
589    pub fn position_bits(&mut self, bits: u32) -> &mut LzmaOptions {
590        self.raw.pb = bits;
591        self
592    }
593
594    /// Configures the compression mode.
595    #[inline]
596    pub fn mode(&mut self, mode: Mode) -> &mut LzmaOptions {
597        self.raw.mode = mode as liblzma_sys::lzma_mode;
598        self
599    }
600
601    /// Configures the nice length of a match.
602    ///
603    /// This determines how many bytes the encoder compares from the match
604    /// candidates when looking for the best match. Once a match of at least
605    /// `len` bytes long is found, the encoder stops looking for better
606    /// candidates and encodes the match. (Naturally, if the found match is
607    /// actually longer than `len`, the actual length is encoded; it's not
608    /// truncated to `len`.)
609    ///
610    /// Bigger values usually increase the compression ratio and compression
611    /// time. For most files, 32 to 128 is a good value, which gives very good
612    /// compression ratio at good speed.
613    ///
614    /// The exact minimum value depends on the match finder. The maximum is 273,
615    /// which is the maximum length of a match that LZMA1 and LZMA2 can encode.
616    #[inline]
617    pub fn nice_len(&mut self, len: u32) -> &mut LzmaOptions {
618        self.raw.nice_len = len;
619        self
620    }
621
622    /// Configures the match finder ID.
623    #[inline]
624    pub fn match_finder(&mut self, mf: MatchFinder) -> &mut LzmaOptions {
625        self.raw.mf = mf as liblzma_sys::lzma_match_finder;
626        self
627    }
628
629    /// Maximum search depth in the match finder.
630    ///
631    /// For every input byte, match finder searches through the hash chain or
632    /// binary tree in a loop, each iteration going one step deeper in the chain
633    /// or tree. The searching stops if
634    ///
635    ///  - a match of at least [`LzmaOptions::nice_len`] bytes long is found;
636    ///  - all match candidates from the hash chain or binary tree have
637    ///    been checked; or
638    ///  - maximum search depth is reached.
639    ///
640    /// Maximum search depth is needed to prevent the match finder from wasting
641    /// too much time in case there are lots of short match candidates. On the
642    /// other hand, stopping the search before all candidates have been checked
643    /// can reduce compression ratio.
644    ///
645    /// Setting depth to zero tells liblzma to use an automatic default value,
646    /// that depends on the selected match finder and [`LzmaOptions::nice_len`].
647    /// The default is in the range [4, 200] or so (it may vary between liblzma
648    /// versions).
649    ///
650    /// Using a bigger depth value than the default can increase compression
651    /// ratio in some cases. There is no strict maximum value, but high values
652    /// (thousands or millions) should be used with care: the encoder could
653    /// remain fast enough with typical input, but malicious input could cause
654    /// the match finder to slow down dramatically, possibly creating a denial
655    /// of service attack.
656    #[inline]
657    pub fn depth(&mut self, depth: u32) -> &mut LzmaOptions {
658        self.raw.depth = depth;
659        self
660    }
661}
662
663impl Check {
664    /// Test if this check is supported in this build of liblzma.
665    #[inline]
666    pub fn is_supported(&self) -> bool {
667        let ret = unsafe { liblzma_sys::lzma_check_is_supported(*self as liblzma_sys::lzma_check) };
668        ret != 0
669    }
670}
671
672impl MatchFinder {
673    /// Test if this match finder is supported in this build of liblzma.
674    #[inline]
675    pub fn is_supported(&self) -> bool {
676        let ret =
677            unsafe { liblzma_sys::lzma_mf_is_supported(*self as liblzma_sys::lzma_match_finder) };
678        ret != 0
679    }
680}
681
682impl Filters {
683    /// Creates a new filter chain with no filters.
684    #[inline]
685    pub fn new() -> Filters {
686        Filters {
687            inner: vec![liblzma_sys::lzma_filter {
688                id: liblzma_sys::LZMA_VLI_UNKNOWN,
689                options: std::ptr::null_mut(),
690            }],
691            lzma_opts: LinkedList::new(),
692        }
693    }
694
695    /// Add an LZMA1 filter.
696    ///
697    /// LZMA1 is the very same thing as what was called just LZMA in LZMA Utils,
698    /// 7-Zip, and LZMA SDK. It's called LZMA1 here to prevent developers from
699    /// accidentally using LZMA when they actually want LZMA2.
700    ///
701    /// LZMA1 shouldn't be used for new applications unless you _really_ know
702    /// what you are doing.  LZMA2 is almost always a better choice.
703    #[inline]
704    pub fn lzma1(&mut self, opts: &LzmaOptions) -> &mut Filters {
705        self.lzma_opts.push_back(opts.raw);
706        let ptr = self.lzma_opts.back().unwrap() as *const _ as *mut _;
707        self.push(liblzma_sys::lzma_filter {
708            id: liblzma_sys::LZMA_FILTER_LZMA1,
709            options: ptr,
710        })
711    }
712
713    /// Add an LZMA1 filter with properties.
714    #[inline]
715    pub fn lzma1_properties(&mut self, properties: &[u8]) -> Result<&mut Filters, Error> {
716        let filter = liblzma_sys::lzma_filter {
717            id: liblzma_sys::LZMA_FILTER_LZMA1,
718            options: std::ptr::null_mut(),
719        };
720        self.push_with_properties(filter, properties)
721    }
722
723    /// Add an LZMA2 filter.
724    ///
725    /// Usually you want this instead of LZMA1. Compared to LZMA1, LZMA2 adds
726    /// support for [`Action::SyncFlush`], uncompressed chunks (smaller expansion when
727    /// trying to compress uncompressible data), possibility to change
728    /// [`literal_context_bits`]/[`literal_position_bits`]/[`position_bits`] in the
729    /// middle of encoding, and some other internal improvements.
730    ///
731    /// [`literal_context_bits`]: LzmaOptions::literal_context_bits
732    /// [`literal_position_bits`]: LzmaOptions::literal_position_bits
733    /// [`position_bits`]: LzmaOptions::position_bits
734    #[inline]
735    pub fn lzma2(&mut self, opts: &LzmaOptions) -> &mut Filters {
736        self.lzma_opts.push_back(opts.raw);
737        let ptr = self.lzma_opts.back().unwrap() as *const _ as *mut _;
738        self.push(liblzma_sys::lzma_filter {
739            id: liblzma_sys::LZMA_FILTER_LZMA2,
740            options: ptr,
741        })
742    }
743
744    /// Add an LZMA2 filter with properties.
745    #[inline]
746    pub fn lzma2_properties(&mut self, properties: &[u8]) -> Result<&mut Filters, Error> {
747        let filter = liblzma_sys::lzma_filter {
748            id: liblzma_sys::LZMA_FILTER_LZMA2,
749            options: std::ptr::null_mut(),
750        };
751        self.push_with_properties(filter, properties)
752    }
753
754    /// Add a DELTA filter.
755    ///
756    /// # Examples
757    /// ```
758    /// use liblzma::stream::{Filters, LzmaOptions};
759    ///
760    /// let dict_size = 0x40000;
761    /// let mut opts = LzmaOptions::new_preset(6).unwrap();
762    /// opts.dict_size(dict_size);
763    /// let mut filters = Filters::new();
764    /// filters.delta();
765    /// filters.lzma2(&opts);
766    /// ```
767    #[inline]
768    pub fn delta(&mut self) -> &mut Filters {
769        self.push(liblzma_sys::lzma_filter {
770            id: liblzma_sys::LZMA_FILTER_DELTA,
771            options: std::ptr::null_mut(),
772        })
773    }
774
775    /// Add a DELTA filter with properties.
776    ///
777    /// # Examples
778    /// ```
779    /// use liblzma::stream::{Filters, LzmaOptions};
780    ///
781    /// let mut filters = Filters::new();
782    /// filters.delta_properties(&[0x00]).unwrap();
783    /// ```
784    #[inline]
785    pub fn delta_properties(&mut self, properties: &[u8]) -> Result<&mut Filters, Error> {
786        let filter = liblzma_sys::lzma_filter {
787            id: liblzma_sys::LZMA_FILTER_DELTA,
788            options: std::ptr::null_mut(),
789        };
790        self.push_with_properties(filter, properties)
791    }
792
793    /// Add a filter for x86 binaries.
794    ///
795    /// # Examples
796    /// ```
797    /// use liblzma::stream::{Filters, LzmaOptions};
798    ///
799    /// let dict_size = 0x40000;
800    /// let mut opts = LzmaOptions::new_preset(6).unwrap();
801    /// opts.dict_size(dict_size);
802    /// let mut filters = Filters::new();
803    /// filters.x86();
804    /// filters.lzma2(&opts);
805    /// ```
806    #[inline]
807    pub fn x86(&mut self) -> &mut Filters {
808        self.push(liblzma_sys::lzma_filter {
809            id: liblzma_sys::LZMA_FILTER_X86,
810            options: std::ptr::null_mut(),
811        })
812    }
813
814    /// Add a filter for x86 binaries with properties.
815    ///
816    /// # Examples
817    /// ```
818    /// use liblzma::stream::{Filters, LzmaOptions};
819    ///
820    /// let mut filters = Filters::new();
821    /// filters.x86_properties(&[0x00, 0x00, 0x00, 0x00]).unwrap();
822    /// ```
823    #[inline]
824    pub fn x86_properties(&mut self, properties: &[u8]) -> Result<&mut Filters, Error> {
825        let filter = liblzma_sys::lzma_filter {
826            id: liblzma_sys::LZMA_FILTER_X86,
827            options: std::ptr::null_mut(),
828        };
829        self.push_with_properties(filter, properties)
830    }
831
832    /// Add a filter for PowerPC binaries.
833    ///
834    /// # Examples
835    /// ```
836    /// use liblzma::stream::{Filters, LzmaOptions};
837    ///
838    /// let dict_size = 0x40000;
839    /// let mut opts = LzmaOptions::new_preset(6).unwrap();
840    /// opts.dict_size(dict_size);
841    /// let mut filters = Filters::new();
842    /// filters.powerpc();
843    /// filters.lzma2(&opts);
844    /// ```
845    #[inline]
846    pub fn powerpc(&mut self) -> &mut Filters {
847        self.push(liblzma_sys::lzma_filter {
848            id: liblzma_sys::LZMA_FILTER_POWERPC,
849            options: std::ptr::null_mut(),
850        })
851    }
852
853    /// Add a filter for PowerPC binaries with properties.
854    ///
855    /// # Examples
856    /// ```
857    /// use liblzma::stream::{Filters, LzmaOptions};
858    ///
859    /// let mut filters = Filters::new();
860    /// filters.powerpc_properties(&[0x00, 0x00, 0x00, 0x00]).unwrap();
861    /// ```
862    #[inline]
863    pub fn powerpc_properties(&mut self, properties: &[u8]) -> Result<&mut Filters, Error> {
864        let filter = liblzma_sys::lzma_filter {
865            id: liblzma_sys::LZMA_FILTER_POWERPC,
866            options: std::ptr::null_mut(),
867        };
868        self.push_with_properties(filter, properties)
869    }
870
871    /// Add a filter for IA-64 (itanium) binaries.
872    ///
873    /// # Examples
874    /// ```
875    /// use liblzma::stream::{Filters, LzmaOptions};
876    ///
877    /// let dict_size = 0x40000;
878    /// let mut opts = LzmaOptions::new_preset(6).unwrap();
879    /// opts.dict_size(dict_size);
880    /// let mut filters = Filters::new();
881    /// filters.ia64();
882    /// filters.lzma2(&opts);
883    /// ```
884    #[inline]
885    pub fn ia64(&mut self) -> &mut Filters {
886        self.push(liblzma_sys::lzma_filter {
887            id: liblzma_sys::LZMA_FILTER_IA64,
888            options: std::ptr::null_mut(),
889        })
890    }
891
892    /// Add a filter for IA-64 (itanium) binaries with properties.
893    ///
894    /// # Examples
895    /// ```
896    /// use liblzma::stream::{Filters, LzmaOptions};
897    ///
898    /// let mut filters = Filters::new();
899    /// filters.ia64_properties(&[0x00, 0x00, 0x00, 0x00]).unwrap();
900    /// ```
901    #[inline]
902    pub fn ia64_properties(&mut self, properties: &[u8]) -> Result<&mut Filters, Error> {
903        let filter = liblzma_sys::lzma_filter {
904            id: liblzma_sys::LZMA_FILTER_IA64,
905            options: std::ptr::null_mut(),
906        };
907        self.push_with_properties(filter, properties)
908    }
909
910    /// Add a filter for ARM binaries.
911    ///
912    /// # Examples
913    /// ```
914    /// use liblzma::stream::{Filters, LzmaOptions};
915    ///
916    /// let dict_size = 0x40000;
917    /// let mut opts = LzmaOptions::new_preset(6).unwrap();
918    /// opts.dict_size(dict_size);
919    /// let mut filters = Filters::new();
920    /// filters.arm();
921    /// filters.lzma2(&opts);
922    /// ```
923    #[inline]
924    pub fn arm(&mut self) -> &mut Filters {
925        self.push(liblzma_sys::lzma_filter {
926            id: liblzma_sys::LZMA_FILTER_ARM,
927            options: std::ptr::null_mut(),
928        })
929    }
930
931    /// Add a filter for ARM binaries with properties.
932    ///
933    /// # Examples
934    /// ```
935    /// use liblzma::stream::{Filters, LzmaOptions};
936    ///
937    /// let mut filters = Filters::new();
938    /// filters.arm_properties(&[0x00, 0x00, 0x00, 0x00]).unwrap();
939    /// ```
940    #[inline]
941    pub fn arm_properties(&mut self, properties: &[u8]) -> Result<&mut Filters, Error> {
942        let filter = liblzma_sys::lzma_filter {
943            id: liblzma_sys::LZMA_FILTER_ARM,
944            options: std::ptr::null_mut(),
945        };
946        self.push_with_properties(filter, properties)
947    }
948
949    /// Add a filter for ARM64 binaries.
950    ///
951    /// # Examples
952    /// ```
953    /// use liblzma::stream::{Filters, LzmaOptions};
954    ///
955    /// let dict_size = 0x40000;
956    /// let mut opts = LzmaOptions::new_preset(6).unwrap();
957    /// opts.dict_size(dict_size);
958    /// let mut filters = Filters::new();
959    /// filters.arm64();
960    /// filters.lzma2(&opts);
961    /// ```
962    #[inline]
963    pub fn arm64(&mut self) -> &mut Filters {
964        self.push(liblzma_sys::lzma_filter {
965            id: liblzma_sys::LZMA_FILTER_ARM64,
966            options: std::ptr::null_mut(),
967        })
968    }
969
970    /// Add a filter for ARM64 binaries with properties.
971    ///
972    /// # Examples
973    /// ```
974    /// use liblzma::stream::{Filters, LzmaOptions};
975    ///
976    /// let mut filters = Filters::new();
977    /// filters.arm64_properties(&[0x00, 0x00, 0x00, 0x00]).unwrap();
978    /// ```
979    #[inline]
980    pub fn arm64_properties(&mut self, properties: &[u8]) -> Result<&mut Filters, Error> {
981        let filter = liblzma_sys::lzma_filter {
982            id: liblzma_sys::LZMA_FILTER_ARM64,
983            options: std::ptr::null_mut(),
984        };
985        self.push_with_properties(filter, properties)
986    }
987
988    /// Add a filter for RISCV binaries.
989    ///
990    /// # Examples
991    /// ```
992    /// use liblzma::stream::{Filters, LzmaOptions};
993    ///
994    /// let dict_size = 0x40000;
995    /// let mut opts = LzmaOptions::new_preset(6).unwrap();
996    /// opts.dict_size(dict_size);
997    /// let mut filters = Filters::new();
998    /// filters.riscv();
999    /// filters.lzma2(&opts);
1000    /// ```
1001    #[inline]
1002    pub fn riscv(&mut self) -> &mut Filters {
1003        self.push(liblzma_sys::lzma_filter {
1004            id: liblzma_sys::LZMA_FILTER_RISCV,
1005            options: std::ptr::null_mut(),
1006        })
1007    }
1008
1009    /// Add a filter for RISCV binaries with properties.
1010    ///
1011    /// # Examples
1012    /// ```
1013    /// use liblzma::stream::{Filters, LzmaOptions};
1014    ///
1015    /// let mut filters = Filters::new();
1016    /// filters.riscv_properties(&[0x00, 0x00, 0x00, 0x00]).unwrap();
1017    /// ```
1018    #[inline]
1019    pub fn riscv_properties(&mut self, properties: &[u8]) -> Result<&mut Filters, Error> {
1020        let filter = liblzma_sys::lzma_filter {
1021            id: liblzma_sys::LZMA_FILTER_RISCV,
1022            options: std::ptr::null_mut(),
1023        };
1024        self.push_with_properties(filter, properties)
1025    }
1026
1027    /// Add a filter for ARM-Thumb binaries.
1028    ///
1029    /// # Examples
1030    /// ```
1031    /// use liblzma::stream::{Filters, LzmaOptions};
1032    ///
1033    /// let dict_size = 0x40000;
1034    /// let mut opts = LzmaOptions::new_preset(6).unwrap();
1035    /// opts.dict_size(dict_size);
1036    /// let mut filters = Filters::new();
1037    /// filters.arm_thumb();
1038    /// filters.lzma2(&opts);
1039    /// ```
1040    #[inline]
1041    pub fn arm_thumb(&mut self) -> &mut Filters {
1042        self.push(liblzma_sys::lzma_filter {
1043            id: liblzma_sys::LZMA_FILTER_ARMTHUMB,
1044            options: std::ptr::null_mut(),
1045        })
1046    }
1047
1048    /// Add a filter for ARM-Thumb binaries with properties.
1049    ///
1050    /// # Examples
1051    /// ```
1052    /// use liblzma::stream::{Filters, LzmaOptions};
1053    ///
1054    /// let mut filters = Filters::new();
1055    /// filters.arm_thumb_properties(&[0x00, 0x00, 0x00, 0x00]).unwrap();
1056    /// ```
1057    #[inline]
1058    pub fn arm_thumb_properties(&mut self, properties: &[u8]) -> Result<&mut Filters, Error> {
1059        let filter = liblzma_sys::lzma_filter {
1060            id: liblzma_sys::LZMA_FILTER_ARMTHUMB,
1061            options: std::ptr::null_mut(),
1062        };
1063        self.push_with_properties(filter, properties)
1064    }
1065
1066    /// Add a filter for SPARC binaries.
1067    ///
1068    /// # Examples
1069    /// ```
1070    /// use liblzma::stream::{Filters, LzmaOptions};
1071    ///
1072    /// let dict_size = 0x40000;
1073    /// let mut opts = LzmaOptions::new_preset(6).unwrap();
1074    /// opts.dict_size(dict_size);
1075    /// let mut filters = Filters::new();
1076    /// filters.sparc();
1077    /// filters.lzma2(&opts);
1078    /// ```
1079    #[inline]
1080    pub fn sparc(&mut self) -> &mut Filters {
1081        self.push(liblzma_sys::lzma_filter {
1082            id: liblzma_sys::LZMA_FILTER_SPARC,
1083            options: std::ptr::null_mut(),
1084        })
1085    }
1086
1087    /// Add a filter for SPARC binaries with properties.
1088    ///
1089    /// # Examples
1090    /// ```
1091    /// use liblzma::stream::{Filters, LzmaOptions};
1092    ///
1093    /// let mut filters = Filters::new();
1094    /// filters.sparc_properties(&[0x00, 0x00, 0x00, 0x00]).unwrap();
1095    /// ```
1096    #[inline]
1097    pub fn sparc_properties(&mut self, properties: &[u8]) -> Result<&mut Filters, Error> {
1098        let filter = liblzma_sys::lzma_filter {
1099            id: liblzma_sys::LZMA_FILTER_SPARC,
1100            options: std::ptr::null_mut(),
1101        };
1102        self.push_with_properties(filter, properties)
1103    }
1104
1105    #[inline]
1106    fn push(&mut self, filter: liblzma_sys::lzma_filter) -> &mut Filters {
1107        let pos = self.inner.len() - 1;
1108        self.inner.insert(pos, filter);
1109        self
1110    }
1111
1112    #[inline]
1113    fn push_with_properties(
1114        &mut self,
1115        mut filter: liblzma_sys::lzma_filter,
1116        properties: &[u8],
1117    ) -> Result<&mut Filters, Error> {
1118        cvt(unsafe {
1119            liblzma_sys::lzma_properties_decode(
1120                &mut filter,
1121                std::ptr::null(),
1122                properties.as_ptr(),
1123                properties.len(),
1124            )
1125        })?;
1126        let pos = self.inner.len() - 1;
1127        self.inner.insert(pos, filter);
1128        Ok(self)
1129    }
1130
1131    /// Recommend a Block size for multithreaded encoding
1132    ///
1133    /// # Examples
1134    /// ```
1135    /// use liblzma::stream::{Filters, LzmaOptions};
1136    ///
1137    /// let dict_size = 0x40000;
1138    /// let mut opts = LzmaOptions::new_preset(6).unwrap();
1139    /// opts.dict_size(dict_size);
1140    /// let mut filters = Filters::new();
1141    /// filters.lzma2(&opts);
1142    /// assert_eq!(filters.mt_block_size(), 1 << 20);
1143    /// ```
1144    #[cfg(feature = "parallel")]
1145    #[inline]
1146    pub fn mt_block_size(&self) -> u64 {
1147        unsafe { liblzma_sys::lzma_mt_block_size(self.inner.as_ptr()) }
1148    }
1149}
1150
1151#[cfg(feature = "parallel")]
1152impl MtStreamBuilder {
1153    /// Creates a new blank builder to create a multithreaded encoding [`Stream`].
1154    #[inline]
1155    pub fn new() -> Self {
1156        let mut init = Self {
1157            raw: unsafe { mem::zeroed() },
1158            filters: None,
1159        };
1160        init.raw.threads = 1;
1161        init
1162    }
1163
1164    /// Configures the number of worker threads to use
1165    #[inline]
1166    pub fn threads(&mut self, threads: u32) -> &mut Self {
1167        self.raw.threads = threads;
1168        self
1169    }
1170
1171    /// Configures the maximum uncompressed size of a block
1172    ///
1173    /// The encoder will start a new .xz block every `block_size` bytes.
1174    /// Using [`Action::FullFlush`] or [`Action::FullBarrier`] with
1175    /// [`Stream::process`] the caller may tell liblzma to start a new block earlier.
1176    ///
1177    /// With LZMA2, a recommended block size is 2-4 times the LZMA2 dictionary
1178    /// size. With very small dictionaries, it is recommended to use at least 1
1179    /// MiB block size for good compression ratio, even if this is more than
1180    /// four times the dictionary size. Note that these are only recommendations
1181    /// for typical use cases; feel free to use other values. Just keep in mind
1182    /// that using a block size less than the LZMA2 dictionary size is waste of
1183    /// RAM.
1184    ///
1185    /// Set this to 0 to let liblzma choose the block size depending on the
1186    /// compression options. For LZMA2 it will be 3*`dict_size` or 1 MiB,
1187    /// whichever is more.
1188    ///
1189    /// For each thread, about 3 * `block_size` bytes of memory will be
1190    /// allocated. This may change in later liblzma versions. If so, the memory
1191    /// usage will probably be reduced, not increased.
1192    #[inline]
1193    pub fn block_size(&mut self, block_size: u64) -> &mut Self {
1194        self.raw.block_size = block_size;
1195        self
1196    }
1197
1198    /// Timeout to allow [`Stream::process`] to return early
1199    ///
1200    /// Multithreading can make liblzma to consume input and produce output in a
1201    /// very bursty way: it may first read a lot of input to fill internal
1202    /// buffers, then no input or output occurs for a while.
1203    ///
1204    /// In single-threaded mode, [`Stream::process`] won't return until it has either
1205    /// consumed all the input or filled the output buffer. If this is done in
1206    /// multithreaded mode, it may cause a call [`Stream::process`] to take even tens of
1207    /// seconds, which isn't acceptable in all applications.
1208    ///
1209    /// To avoid very long blocking times in [`Stream::process`], a timeout (in
1210    /// milliseconds) may be set here. If `process would block longer than
1211    /// this number of milliseconds, it will return with `Ok`. Reasonable
1212    /// values are 100 ms or more. The xz command line tool uses 300 ms.
1213    ///
1214    /// If long blocking times are fine for you, set timeout to a special
1215    /// value of 0, which will disable the timeout mechanism and will make
1216    /// [`Stream::process`] block until all the input is consumed or the output
1217    /// buffer has been filled.
1218    #[inline]
1219    pub fn timeout_ms(&mut self, timeout: u32) -> &mut Self {
1220        self.raw.timeout = timeout;
1221        self
1222    }
1223
1224    /// Compression preset (level and possible flags)
1225    ///
1226    /// The preset is set just like with [`Stream::new_easy_encoder`], including
1227    /// support for [`PRESET_EXTREME`]. The preset is ignored if filters below
1228    /// have been specified.
1229    #[inline]
1230    pub fn preset(&mut self, preset: u32) -> &mut Self {
1231        self.raw.preset = preset;
1232        self
1233    }
1234
1235    /// Configure a custom filter chain
1236    #[inline]
1237    pub fn filters(&mut self, filters: Filters) -> &mut Self {
1238        self.raw.filters = filters.inner.as_ptr();
1239        self.filters = Some(filters);
1240        self
1241    }
1242
1243    /// Configures the integrity check type
1244    #[inline]
1245    pub fn check(&mut self, check: Check) -> &mut Self {
1246        self.raw.check = check as liblzma_sys::lzma_check;
1247        self
1248    }
1249
1250    /// Memory usage limit to reduce the number of threads
1251    #[inline]
1252    pub fn memlimit_threading(&mut self, memlimit: u64) -> &mut Self {
1253        self.raw.memlimit_threading = memlimit;
1254        self
1255    }
1256
1257    /// Memory usage limit that should never be exceeded
1258    #[inline]
1259    pub fn memlimit_stop(&mut self, memlimit: u64) -> &mut Self {
1260        self.raw.memlimit_stop = memlimit;
1261        self
1262    }
1263
1264    /// Calculate approximate memory usage of multithreaded .xz encoder
1265    #[inline]
1266    pub fn memusage(&self) -> u64 {
1267        unsafe { liblzma_sys::lzma_stream_encoder_mt_memusage(&self.raw) }
1268    }
1269
1270    /// Initialize multithreaded .xz stream encoder.
1271    #[inline]
1272    pub fn encoder(&self) -> Result<Stream, Error> {
1273        let mut init = unsafe { Stream::zeroed() };
1274        cvt(unsafe { liblzma_sys::lzma_stream_encoder_mt(&mut init.raw, &self.raw) })?;
1275        Ok(init)
1276    }
1277
1278    /// Initialize multithreaded .xz stream decoder.
1279    #[inline]
1280    pub fn decoder(&self) -> Result<Stream, Error> {
1281        let mut init = unsafe { Stream::zeroed() };
1282        cvt(unsafe { liblzma_sys::lzma_stream_decoder_mt(&mut init.raw, &self.raw) })?;
1283        Ok(init)
1284    }
1285}
1286
1287fn cvt(rc: liblzma_sys::lzma_ret) -> Result<Status, Error> {
1288    match rc {
1289        liblzma_sys::LZMA_OK => Ok(Status::Ok),
1290        liblzma_sys::LZMA_STREAM_END => Ok(Status::StreamEnd),
1291        liblzma_sys::LZMA_NO_CHECK => Err(Error::NoCheck),
1292        liblzma_sys::LZMA_UNSUPPORTED_CHECK => Err(Error::UnsupportedCheck),
1293        liblzma_sys::LZMA_GET_CHECK => Ok(Status::GetCheck),
1294        liblzma_sys::LZMA_MEM_ERROR => Err(Error::Mem),
1295        liblzma_sys::LZMA_MEMLIMIT_ERROR => Err(Error::MemLimit),
1296        liblzma_sys::LZMA_FORMAT_ERROR => Err(Error::Format),
1297        liblzma_sys::LZMA_OPTIONS_ERROR => Err(Error::Options),
1298        liblzma_sys::LZMA_DATA_ERROR => Err(Error::Data),
1299        liblzma_sys::LZMA_BUF_ERROR => Ok(Status::MemNeeded),
1300        liblzma_sys::LZMA_PROG_ERROR => Err(Error::Program),
1301        c => panic!("unknown return code: {}", c),
1302    }
1303}
1304
1305impl From<Error> for io::Error {
1306    #[inline]
1307    fn from(e: Error) -> io::Error {
1308        let kind = match e {
1309            Error::Data => io::ErrorKind::InvalidData,
1310            Error::Options => io::ErrorKind::InvalidInput,
1311            Error::Format => io::ErrorKind::InvalidData,
1312            Error::MemLimit => io::ErrorKind::Other,
1313            Error::Mem => io::ErrorKind::Other,
1314            Error::Program => io::ErrorKind::Other,
1315            Error::NoCheck => io::ErrorKind::InvalidInput,
1316            Error::UnsupportedCheck => io::ErrorKind::Other,
1317        };
1318
1319        io::Error::new(kind, e)
1320    }
1321}
1322
1323impl error::Error for Error {}
1324
1325impl fmt::Display for Error {
1326    #[inline]
1327    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1328        match self {
1329            Error::Data => "lzma data error",
1330            Error::Options => "invalid options",
1331            Error::Format => "stream/file format not recognized",
1332            Error::MemLimit => "memory limit reached",
1333            Error::Mem => "can't allocate memory",
1334            Error::Program => "liblzma internal error",
1335            Error::NoCheck => "no integrity check was available",
1336            Error::UnsupportedCheck => "liblzma not built with check support",
1337        }
1338        .fmt(f)
1339    }
1340}
1341
1342impl Drop for Stream {
1343    #[inline]
1344    fn drop(&mut self) {
1345        unsafe {
1346            liblzma_sys::lzma_end(&mut self.raw);
1347        }
1348    }
1349}