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}