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