summaryrefslogtreecommitdiffstats
path: root/vendor/xz2/src/stream.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/xz2/src/stream.rs')
-rw-r--r--vendor/xz2/src/stream.rs843
1 files changed, 843 insertions, 0 deletions
diff --git a/vendor/xz2/src/stream.rs b/vendor/xz2/src/stream.rs
new file mode 100644
index 000000000..b005f26d8
--- /dev/null
+++ b/vendor/xz2/src/stream.rs
@@ -0,0 +1,843 @@
+//! Raw in-memory LZMA streams.
+//!
+//! The `Stream` type exported by this module is the primary type which performs
+//! encoding/decoding of LZMA streams. Each `Stream` is either an encoder or
+//! decoder and processes data in a streaming fashion.
+
+use std::collections::LinkedList;
+use std::error;
+use std::fmt;
+use std::io;
+use std::mem;
+use std::slice;
+
+use lzma_sys;
+
+/// Representation of an in-memory LZMA encoding or decoding stream.
+///
+/// Wraps the raw underlying `lzma_stream` type and provides the ability to
+/// create streams which can either decode or encode various LZMA-based formats.
+pub struct Stream {
+ raw: lzma_sys::lzma_stream,
+}
+
+unsafe impl Send for Stream {}
+unsafe impl Sync for Stream {}
+
+/// Options that can be used to configure how LZMA encoding happens.
+///
+/// This builder is consumed by a number of other methods.
+pub struct LzmaOptions {
+ raw: lzma_sys::lzma_options_lzma,
+}
+
+/// Builder to create a multi-threaded stream encoder.
+pub struct MtStreamBuilder {
+ raw: lzma_sys::lzma_mt,
+ filters: Option<Filters>,
+}
+
+/// A custom chain of filters to configure an encoding stream.
+pub struct Filters {
+ inner: Vec<lzma_sys::lzma_filter>,
+ lzma_opts: LinkedList<lzma_sys::lzma_options_lzma>,
+}
+
+/// The `action` argument for `process`,
+///
+/// After the first use of SyncFlush, FullFlush, FullBarrier, or Finish, the
+/// same `action' must is used until `process` returns `Status::StreamEnd`.
+/// Also, the amount of input must not be modified by the application until
+/// `process` returns `Status::StreamEnd`. Changing the `action' or modifying
+/// the amount of input will make `process` return `Error::Program`.
+#[derive(Copy, Clone)]
+pub enum Action {
+ /// Continue processing
+ ///
+ /// When encoding, encode as much input as possible. Some internal buffering
+ /// will probably be done (depends on the filter chain in use), which causes
+ /// latency: the input used won't usually be decodeable from the output of
+ /// the same `process` call.
+ ///
+ /// When decoding, decode as much input as possible and produce as much
+ /// output as possible.
+ Run = lzma_sys::LZMA_RUN as isize,
+
+ /// Make all the input available at output
+ ///
+ /// Normally the encoder introduces some latency. `SyncFlush` forces all the
+ /// buffered data to be available at output without resetting the internal
+ /// state of the encoder. This way it is possible to use compressed stream
+ /// for example for communication over network.
+ ///
+ /// Only some filters support `SyncFlush`. Trying to use `SyncFlush` with
+ /// filters that don't support it will make `process` return
+ /// `Error::Options`. For example, LZMA1 doesn't support `SyncFlush` but
+ /// LZMA2 does.
+ ///
+ /// Using `SyncFlush` very often can dramatically reduce the compression
+ /// ratio. With some filters (for example, LZMA2), fine-tuning the
+ /// compression options may help mitigate this problem significantly (for
+ /// example, match finder with LZMA2).
+ ///
+ /// Decoders don't support `SyncFlush`.
+ SyncFlush = lzma_sys::LZMA_SYNC_FLUSH as isize,
+
+ /// Finish encoding of the current block.
+ ///
+ /// All the input data going to the current block must have been given to
+ /// the encoder. Call `process` with `FullFlush` until it returns
+ /// `Status::StreamEnd`. Then continue normally with `Run` or finish the
+ /// Stream with `Finish`.
+ ///
+ /// This action is currently supported only by stream encoder and easy
+ /// encoder (which uses stream encoder). If there is no unfinished block, no
+ /// empty block is created.
+ FullFlush = lzma_sys::LZMA_FULL_FLUSH as isize,
+
+ /// Finish encoding of the current block.
+ ///
+ /// This is like `FullFlush` except that this doesn't necessarily wait until
+ /// all the input has been made available via the output buffer. That is,
+ /// `process` might return `Status::StreamEnd` as soon as all the input has
+ /// been consumed.
+ ///
+ /// `FullBarrier` is useful with a threaded encoder if one wants to split
+ /// the .xz Stream into blocks at specific offsets but doesn't care if the
+ /// output isn't flushed immediately. Using `FullBarrier` allows keeping the
+ /// threads busy while `FullFlush` would make `process` wait until all the
+ /// threads have finished until more data could be passed to the encoder.
+ ///
+ /// With a `Stream` initialized with the single-threaded
+ /// `new_stream_encoder` or `new_easy_encoder`, `FullBarrier` is an alias
+ /// for `FullFlush`.
+ FullBarrier = lzma_sys::LZMA_FULL_BARRIER as isize,
+
+ /// Finish the current operation
+ ///
+ /// All the input data must have been given to the encoder (the last bytes
+ /// can still be pending in next_in). Call `process` with `Finish` until it
+ /// returns `Status::StreamEnd`. Once `Finish` has been used, the amount of
+ /// input must no longer be changed by the application.
+ ///
+ /// When decoding, using `Finish` is optional unless the concatenated flag
+ /// was used when the decoder was initialized. When concatenated was not
+ /// used, the only effect of `Finish` is that the amount of input must not
+ /// be changed just like in the encoder.
+ Finish = lzma_sys::LZMA_FINISH as isize,
+}
+
+/// Return value of a `process` operation.
+#[derive(Debug, Copy, Clone, PartialEq)]
+pub enum Status {
+ /// Operation completed successfully.
+ Ok,
+
+ /// End of stream was reached.
+ ///
+ /// When encoding, this means that a sync/full flush or `Finish` was
+ /// completed. When decoding, this indicates that all data was decoded
+ /// successfully.
+ StreamEnd,
+
+ /// If the TELL_ANY_CHECK flags is specified when constructing a decoder,
+ /// this informs that the `check` method will now return the underlying
+ /// integrity check algorithm.
+ GetCheck,
+
+ /// An error has not been encountered, but no progress is possible.
+ ///
+ /// Processing can be continued normally by providing more input and/or more
+ /// output space, if possible.
+ ///
+ /// Typically the first call to `process` that can do no progress returns
+ /// `Ok` instead of `MemNeeded`. Only the second consecutive call doing no
+ /// progress will return `MemNeeded`.
+ MemNeeded,
+}
+
+/// Possible error codes that can be returned from a processing operation.
+#[derive(Debug, Clone, PartialEq)]
+pub enum Error {
+ /// The underlying data was corrupt.
+ Data,
+
+ /// Invalid or unsupported options were specified.
+ Options,
+
+ /// File format wasn't recognized.
+ Format,
+
+ /// Memory usage limit was reached.
+ ///
+ /// The memory limit can be increased with `set_memlimit`
+ MemLimit,
+
+ /// Memory couldn't be allocated.
+ Mem,
+
+ /// A programming error was encountered.
+ Program,
+
+ /// The `TELL_NO_CHECK` flag was specified and no integrity check was
+ /// available for this stream.
+ NoCheck,
+
+ /// The `TELL_UNSUPPORTED_CHECK` flag was specified and no integrity check
+ /// isn't implemented in this build of liblzma for this stream.
+ UnsupportedCheck,
+}
+
+/// Possible integrity checks that can be part of a .xz stream.
+#[allow(missing_docs)] // self explanatory mostly
+#[derive(Copy, Clone)]
+pub enum Check {
+ None = lzma_sys::LZMA_CHECK_NONE as isize,
+ Crc32 = lzma_sys::LZMA_CHECK_CRC32 as isize,
+ Crc64 = lzma_sys::LZMA_CHECK_CRC64 as isize,
+ Sha256 = lzma_sys::LZMA_CHECK_SHA256 as isize,
+}
+
+/// Compression modes
+///
+/// This selects the function used to analyze the data produced by the match
+/// finder.
+#[derive(Copy, Clone)]
+pub enum Mode {
+ /// Fast compression.
+ ///
+ /// Fast mode is usually at its best when combined with a hash chain match
+ /// finder.
+ Fast = lzma_sys::LZMA_MODE_FAST as isize,
+
+ /// Normal compression.
+ ///
+ /// This is usually notably slower than fast mode. Use this together with
+ /// binary tree match finders to expose the full potential of the LZMA1 or
+ /// LZMA2 encoder.
+ Normal = lzma_sys::LZMA_MODE_NORMAL as isize,
+}
+
+/// Match finders
+///
+/// Match finder has major effect on both speed and compression ratio. Usually
+/// hash chains are faster than binary trees.
+///
+/// If you will use `SyncFlush` often, the hash chains may be a better choice,
+/// because binary trees get much higher compression ratio penalty with
+/// `SyncFlush`.
+///
+/// The memory usage formulas are only rough estimates, which are closest to
+/// reality when dict_size is a power of two. The formulas are more complex in
+/// reality, and can also change a little between liblzma versions.
+#[derive(Copy, Clone)]
+pub enum MatchFinder {
+ /// Hash Chain with 2- and 3-byte hashing
+ HashChain3 = lzma_sys::LZMA_MF_HC3 as isize,
+ /// Hash Chain with 2-, 3-, and 4-byte hashing
+ HashChain4 = lzma_sys::LZMA_MF_HC4 as isize,
+
+ /// Binary Tree with 2-byte hashing
+ BinaryTree2 = lzma_sys::LZMA_MF_BT2 as isize,
+ /// Binary Tree with 2- and 3-byte hashing
+ BinaryTree3 = lzma_sys::LZMA_MF_BT3 as isize,
+ /// Binary Tree with 2-, 3-, and 4-byte hashing
+ BinaryTree4 = lzma_sys::LZMA_MF_BT4 as isize,
+}
+
+/// A flag passed when initializing a decoder, causes `process` to return
+/// `Status::GetCheck` as soon as the integrity check is known.
+pub const TELL_ANY_CHECK: u32 = lzma_sys::LZMA_TELL_ANY_CHECK;
+
+/// A flag passed when initializing a decoder, causes `process` to return
+/// `Error::NoCheck` if the stream being decoded has no integrity check.
+pub const TELL_NO_CHECK: u32 = lzma_sys::LZMA_TELL_NO_CHECK;
+
+/// A flag passed when initializing a decoder, causes `process` to return
+/// `Error::UnsupportedCheck` if the stream being decoded has an integrity check
+/// that cannot be verified by this build of liblzma.
+pub const TELL_UNSUPPORTED_CHECK: u32 = lzma_sys::LZMA_TELL_UNSUPPORTED_CHECK;
+
+/// A flag passed when initializing a decoder, causes the decoder to ignore any
+/// integrity checks listed.
+pub const IGNORE_CHECK: u32 = lzma_sys::LZMA_TELL_UNSUPPORTED_CHECK;
+
+/// A flag passed when initializing a decoder, indicates that the stream may be
+/// multiple concatenated xz files.
+pub const CONCATENATED: u32 = lzma_sys::LZMA_CONCATENATED;
+
+impl Stream {
+ /// Initialize .xz stream encoder using a preset number
+ ///
+ /// This is intended to be used by most for encoding data. The `preset`
+ /// argument is a number 0-9 indicating the compression level to use, and
+ /// normally 6 is a reasonable default.
+ ///
+ /// The `check` argument is the integrity check to insert at the end of the
+ /// stream. The default of `Crc64` is typically appropriate.
+ pub fn new_easy_encoder(preset: u32, check: Check) -> Result<Stream, Error> {
+ unsafe {
+ let mut init = Stream { raw: mem::zeroed() };
+ cvt(lzma_sys::lzma_easy_encoder(&mut init.raw,
+ preset,
+ check as lzma_sys::lzma_check))?;
+ Ok(init)
+ }
+ }
+
+ /// Initialize .lzma encoder (legacy file format)
+ ///
+ /// The .lzma format is sometimes called the LZMA_Alone format, which is the
+ /// reason for the name of this function. The .lzma format supports only the
+ /// LZMA1 filter. There is no support for integrity checks like CRC32.
+ ///
+ /// Use this function if and only if you need to create files readable by
+ /// legacy LZMA tools such as LZMA Utils 4.32.x. Moving to the .xz format
+ /// (the `new_easy_encoder` function) is strongly recommended.
+ ///
+ /// The valid action values for `process` are `Run` and `Finish`. No kind
+ /// of flushing is supported, because the file format doesn't make it
+ /// possible.
+ pub fn new_lzma_encoder(options: &LzmaOptions) -> Result<Stream, Error> {
+ unsafe {
+ let mut init = Stream { raw: mem::zeroed() };
+ cvt(lzma_sys::lzma_alone_encoder(&mut init.raw, &options.raw))?;
+ Ok(init)
+ }
+ }
+
+ /// Initialize .xz Stream encoder using a custom filter chain
+ ///
+ /// This function is similar to `new_easy_encoder` but a custom filter chain
+ /// is specified.
+ pub fn new_stream_encoder(filters: &Filters,
+ check: Check) -> Result<Stream, Error> {
+ unsafe {
+ let mut init = Stream { raw: mem::zeroed() };
+ cvt(lzma_sys::lzma_stream_encoder(&mut init.raw,
+ filters.inner.as_ptr(),
+ check as lzma_sys::lzma_check))?;
+ Ok(init)
+ }
+ }
+
+ /// Initialize a .xz stream decoder.
+ ///
+ /// The maximum memory usage can be specified along with flags such as
+ /// `TELL_ANY_CHECK`, `TELL_NO_CHECK`, `TELL_UNSUPPORTED_CHECK`,
+ /// `TELL_IGNORE_CHECK`, or `CONCATENATED`.
+ pub fn new_stream_decoder(memlimit: u64,
+ flags: u32) -> Result<Stream, Error> {
+ unsafe {
+ let mut init = Stream { raw: mem::zeroed() };
+ cvt(lzma_sys::lzma_stream_decoder(&mut init.raw,
+ memlimit,
+ flags))?;
+ Ok(init)
+ }
+ }
+
+ /// Initialize a .lzma stream decoder.
+ ///
+ /// The maximum memory usage can also be specified.
+ pub fn new_lzma_decoder(memlimit: u64) -> Result<Stream, Error> {
+ unsafe {
+ let mut init = Stream { raw: mem::zeroed() };
+ cvt(lzma_sys::lzma_alone_decoder(&mut init.raw,
+ memlimit))?;
+ Ok(init)
+ }
+ }
+
+ /// Initialize a decoder which will choose a stream/lzma formats depending
+ /// on the input stream.
+ pub fn new_auto_decoder(memlimit: u64, flags: u32) -> Result<Stream, Error> {
+ unsafe {
+ let mut init = Stream { raw: mem::zeroed() };
+ cvt(lzma_sys::lzma_auto_decoder(&mut init.raw,
+ memlimit,
+ flags))?;
+ Ok(init)
+ }
+ }
+
+ /// Processes some data from input into an output buffer.
+ ///
+ /// This will perform the appropriate encoding or decoding operation
+ /// depending on the kind of underlying stream. Documentation for the
+ /// various `action` arguments can be found on the respective variants.
+ pub fn process(&mut self,
+ input: &[u8],
+ output: &mut [u8],
+ action: Action) -> Result<Status, Error> {
+ self.raw.next_in = input.as_ptr();
+ self.raw.avail_in = input.len();
+ self.raw.next_out = output.as_mut_ptr();
+ self.raw.avail_out = output.len();
+ let action = action as lzma_sys::lzma_action;
+ unsafe {
+ cvt(lzma_sys::lzma_code(&mut self.raw, action))
+ }
+ }
+
+ /// Performs the same data as `process`, but places output data in a `Vec`.
+ ///
+ /// This function will use the extra capacity of `output` as a destination
+ /// for bytes to be placed. The length of `output` will automatically get
+ /// updated after the operation has completed.
+ pub fn process_vec(&mut self,
+ input: &[u8],
+ output: &mut Vec<u8>,
+ action: Action) -> Result<Status, Error> {
+ let cap = output.capacity();
+ let len = output.len();
+
+ unsafe {
+ let before = self.total_out();
+ let ret = {
+ let ptr = output.as_mut_ptr().offset(len as isize);
+ let out = slice::from_raw_parts_mut(ptr, cap - len);
+ self.process(input, out, action)
+ };
+ output.set_len((self.total_out() - before) as usize + len);
+ return ret
+ }
+ }
+
+ /// Returns the total amount of input bytes consumed by this stream.
+ pub fn total_in(&self) -> u64 {
+ self.raw.total_in
+ }
+
+ /// Returns the total amount of bytes produced by this stream.
+ pub fn total_out(&self) -> u64 {
+ self.raw.total_out
+ }
+
+ /// Get the current memory usage limit.
+ ///
+ /// This is only supported if the underlying stream supports a memlimit.
+ pub fn memlimit(&self) -> u64 {
+ unsafe { lzma_sys::lzma_memlimit_get(&self.raw) }
+ }
+
+ /// Set the current memory usage limit.
+ ///
+ /// This can return `Error::MemLimit` if the new limit is too small or
+ /// `Error::Program` if this stream doesn't take a memory limit.
+ pub fn set_memlimit(&mut self, limit: u64) -> Result<(), Error> {
+ cvt(unsafe { lzma_sys::lzma_memlimit_set(&mut self.raw, limit) })
+ .map(|_| ())
+ }
+}
+
+impl LzmaOptions {
+ /// Creates a new blank set of options for encoding.
+ ///
+ /// The `preset` argument is the compression level to use, typically in the
+ /// range of 0-9.
+ pub fn new_preset(preset: u32) -> Result<LzmaOptions, Error> {
+ unsafe {
+ let mut options = LzmaOptions { raw: mem::zeroed() };
+ let ret = lzma_sys::lzma_lzma_preset(&mut options.raw, preset);
+ if ret != 0 {
+ Err(Error::Program)
+ } else {
+ Ok(options)
+ }
+ }
+ }
+
+ /// Configures the dictionary size, in bytes
+ ///
+ /// Dictionary size indicates how many bytes of the recently processed
+ /// uncompressed data is kept in memory.
+ ///
+ /// The minimum dictionary size is 4096 bytes and the default is 2^23, 8MB.
+ pub fn dict_size(&mut self, size: u32) -> &mut LzmaOptions {
+ self.raw.dict_size = size;
+ self
+ }
+
+ /// Configures the number of literal context bits.
+ ///
+ /// How many of the highest bits of the previous uncompressed eight-bit byte
+ /// (also known as `literal') are taken into account when predicting the
+ /// bits of the next literal.
+ ///
+ /// The maximum value to this is 4 and the default is 3. It is not currently
+ /// supported if this plus `literal_position_bits` is greater than 4.
+ pub fn literal_context_bits(&mut self, bits: u32) -> &mut LzmaOptions {
+ self.raw.lc = bits;
+ self
+ }
+
+ /// Configures the number of literal position bits.
+ ///
+ /// This affects what kind of alignment in the uncompressed data is assumed
+ /// when encoding literals. A literal is a single 8-bit byte. See
+ /// `position_bits` for more information about alignment.
+ ///
+ /// The default for this is 0.
+ pub fn literal_position_bits(&mut self, bits: u32) -> &mut LzmaOptions {
+ self.raw.lp = bits;
+ self
+ }
+
+ /// Configures the number of position bits.
+ ///
+ /// Position bits affects what kind of alignment in the uncompressed data is
+ /// assumed in general. The default of 2 means four-byte alignment (2^ pb
+ /// =2^2=4), which is often a good choice when there's no better guess.
+ ///
+ /// When the aligment is known, setting pb accordingly may reduce the file
+ /// size a little. E.g. with text files having one-byte alignment (US-ASCII,
+ /// ISO-8859-*, UTF-8), setting pb=0 can improve compression slightly. For
+ /// UTF-16 text, pb=1 is a good choice. If the alignment is an odd number
+ /// like 3 bytes, pb=0 might be the best choice.
+ ///
+ /// Even though the assumed alignment can be adjusted with pb and lp, LZMA1
+ /// and LZMA2 still slightly favor 16-byte alignment. It might be worth
+ /// taking into account when designing file formats that are likely to be
+ /// often compressed with LZMA1 or LZMA2.
+ pub fn position_bits(&mut self, bits: u32) -> &mut LzmaOptions {
+ self.raw.pb = bits;
+ self
+ }
+
+ /// Configures the compression mode.
+ pub fn mode(&mut self, mode: Mode) -> &mut LzmaOptions {
+ self.raw.mode = mode as lzma_sys::lzma_mode;
+ self
+ }
+
+ /// Configures the nice length of a match.
+ ///
+ /// This determines how many bytes the encoder compares from the match
+ /// candidates when looking for the best match. Once a match of at least
+ /// `nice_len` bytes long is found, the encoder stops looking for better
+ /// candidates and encodes the match. (Naturally, if the found match is
+ /// actually longer than `nice_len`, the actual length is encoded; it's not
+ /// truncated to `nice_len`.)
+ ///
+ /// Bigger values usually increase the compression ratio and compression
+ /// time. For most files, 32 to 128 is a good value, which gives very good
+ /// compression ratio at good speed.
+ ///
+ /// The exact minimum value depends on the match finder. The maximum is 273,
+ /// which is the maximum length of a match that LZMA1 and LZMA2 can encode.
+ pub fn nice_len(&mut self, len: u32) -> &mut LzmaOptions {
+ self.raw.nice_len = len;
+ self
+ }
+
+ /// Configures the match finder ID.
+ pub fn match_finder(&mut self, mf: MatchFinder) -> &mut LzmaOptions {
+ self.raw.mf = mf as lzma_sys::lzma_match_finder;
+ self
+ }
+
+ /// Maximum search depth in the match finder.
+ ///
+ /// For every input byte, match finder searches through the hash chain or
+ /// binary tree in a loop, each iteration going one step deeper in the chain
+ /// or tree. The searching stops if
+ ///
+ /// - a match of at least `nice_len` bytes long is found;
+ /// - all match candidates from the hash chain or binary tree have
+ /// been checked; or
+ /// - maximum search depth is reached.
+ ///
+ /// Maximum search depth is needed to prevent the match finder from wasting
+ /// too much time in case there are lots of short match candidates. On the
+ /// other hand, stopping the search before all candidates have been checked
+ /// can reduce compression ratio.
+ ///
+ /// Setting depth to zero tells liblzma to use an automatic default value,
+ /// that depends on the selected match finder and nice_len. The default is
+ /// in the range [4, 200] or so (it may vary between liblzma versions).
+ ///
+ /// Using a bigger depth value than the default can increase compression
+ /// ratio in some cases. There is no strict maximum value, but high values
+ /// (thousands or millions) should be used with care: the encoder could
+ /// remain fast enough with typical input, but malicious input could cause
+ /// the match finder to slow down dramatically, possibly creating a denial
+ /// of service attack.
+ pub fn depth(&mut self, depth: u32) -> &mut LzmaOptions {
+ self.raw.depth = depth;
+ self
+ }
+}
+
+impl Check {
+ /// Test if this check is supported in this build of liblzma.
+ pub fn is_supported(&self) -> bool {
+ let ret = unsafe {
+ lzma_sys::lzma_check_is_supported(*self as lzma_sys::lzma_check)
+ };
+ ret != 0
+ }
+}
+
+impl MatchFinder {
+ /// Test if this match finder is supported in this build of liblzma.
+ pub fn is_supported(&self) -> bool {
+ let ret = unsafe {
+ lzma_sys::lzma_mf_is_supported(*self as lzma_sys::lzma_match_finder)
+ };
+ ret != 0
+ }
+}
+
+impl Filters {
+ /// Creates a new filter chain with no filters.
+ pub fn new() -> Filters {
+ Filters {
+ inner: vec![lzma_sys::lzma_filter {
+ id: lzma_sys::LZMA_VLI_UNKNOWN,
+ options: 0 as *mut _,
+ }],
+ lzma_opts: LinkedList::new(),
+ }
+ }
+
+ /// Add an LZMA1 filter.
+ ///
+ /// LZMA1 is the very same thing as what was called just LZMA in LZMA Utils,
+ /// 7-Zip, and LZMA SDK. It's called LZMA1 here to prevent developers from
+ /// accidentally using LZMA when they actually want LZMA2.
+ ///
+ /// LZMA1 shouldn't be used for new applications unless you _really_ know
+ /// what you are doing. LZMA2 is almost always a better choice.
+ pub fn lzma1(&mut self, opts: &LzmaOptions) -> &mut Filters {
+ self.lzma_opts.push_back(opts.raw);
+ let ptr = self.lzma_opts.back().unwrap() as *const _ as *mut _;
+ self.push(lzma_sys::lzma_filter {
+ id: lzma_sys::LZMA_FILTER_LZMA1,
+ options: ptr,
+ })
+ }
+
+ /// Add an LZMA2 filter.
+ ///
+ /// Usually you want this instead of LZMA1. Compared to LZMA1, LZMA2 adds
+ /// support for `SyncFlush`, uncompressed chunks (smaller expansion when
+ /// trying to compress uncompressible data), possibility to change
+ /// `literal_context_bits`/`literal_position_bits`/`position_bits` in the
+ /// middle of encoding, and some other internal improvements.
+ pub fn lzma2(&mut self, opts: &LzmaOptions) -> &mut Filters {
+ self.lzma_opts.push_back(opts.raw);
+ let ptr = self.lzma_opts.back().unwrap() as *const _ as *mut _;
+ self.push(lzma_sys::lzma_filter {
+ id: lzma_sys::LZMA_FILTER_LZMA2,
+ options: ptr,
+ })
+ }
+
+ // TODO: delta filter
+
+ /// Add a filter for x86 binaries.
+ pub fn x86(&mut self) -> &mut Filters {
+ self.push(lzma_sys::lzma_filter {
+ id: lzma_sys::LZMA_FILTER_X86,
+ options: 0 as *mut _,
+ })
+ }
+
+ /// Add a filter for PowerPC binaries.
+ pub fn powerpc(&mut self) -> &mut Filters {
+ self.push(lzma_sys::lzma_filter {
+ id: lzma_sys::LZMA_FILTER_POWERPC,
+ options: 0 as *mut _,
+ })
+ }
+
+ /// Add a filter for IA-64 (itanium) binaries.
+ pub fn ia64(&mut self) -> &mut Filters {
+ self.push(lzma_sys::lzma_filter {
+ id: lzma_sys::LZMA_FILTER_IA64,
+ options: 0 as *mut _,
+ })
+ }
+
+ /// Add a filter for ARM binaries.
+ pub fn arm(&mut self) -> &mut Filters {
+ self.push(lzma_sys::lzma_filter {
+ id: lzma_sys::LZMA_FILTER_ARM,
+ options: 0 as *mut _,
+ })
+ }
+
+ /// Add a filter for ARM-Thumb binaries.
+ pub fn arm_thumb(&mut self) -> &mut Filters {
+ self.push(lzma_sys::lzma_filter {
+ id: lzma_sys::LZMA_FILTER_ARMTHUMB,
+ options: 0 as *mut _,
+ })
+ }
+
+ /// Add a filter for SPARC binaries.
+ pub fn sparc(&mut self) -> &mut Filters {
+ self.push(lzma_sys::lzma_filter {
+ id: lzma_sys::LZMA_FILTER_SPARC,
+ options: 0 as *mut _,
+ })
+ }
+
+ fn push(&mut self, filter: lzma_sys::lzma_filter) -> &mut Filters {
+ let pos = self.inner.len() - 1;
+ self.inner.insert(pos, filter);
+ self
+ }
+}
+
+impl MtStreamBuilder {
+ /// Creates a new blank builder to create a multithreaded encoding `Stream`.
+ pub fn new() -> MtStreamBuilder {
+ unsafe {
+ let mut init = MtStreamBuilder {
+ raw: mem::zeroed(),
+ filters: None,
+ };
+ init.raw.threads = 1;
+ return init
+ }
+ }
+
+ /// Configures the number of worker threads to use
+ pub fn threads(&mut self, threads: u32) -> &mut Self {
+ self.raw.threads = threads;
+ self
+ }
+
+ /// Configures the maximum uncompressed size of a block
+ ///
+ /// The encoder will start a new .xz block every `block_size` bytes.
+ /// Using `FullFlush` or `FullBarrier` with `process` the caller may tell
+ /// liblzma to start a new block earlier.
+ ///
+ /// With LZMA2, a recommended block size is 2-4 times the LZMA2 dictionary
+ /// size. With very small dictionaries, it is recommended to use at least 1
+ /// MiB block size for good compression ratio, even if this is more than
+ /// four times the dictionary size. Note that these are only recommendations
+ /// for typical use cases; feel free to use other values. Just keep in mind
+ /// that using a block size less than the LZMA2 dictionary size is waste of
+ /// RAM.
+ ///
+ /// Set this to 0 to let liblzma choose the block size depending on the
+ /// compression options. For LZMA2 it will be 3*`dict_size` or 1 MiB,
+ /// whichever is more.
+ ///
+ /// For each thread, about 3 * `block_size` bytes of memory will be
+ /// allocated. This may change in later liblzma versions. If so, the memory
+ /// usage will probably be reduced, not increased.
+ pub fn block_size(&mut self, block_size: u64) -> &mut Self {
+ self.raw.block_size = block_size;
+ self
+ }
+
+ /// Timeout to allow `process` to return early
+ ///
+ /// Multithreading can make liblzma to consume input and produce output in a
+ /// very bursty way: it may first read a lot of input to fill internal
+ /// buffers, then no input or output occurs for a while.
+ ///
+ /// In single-threaded mode, `process` won't return until it has either
+ /// consumed all the input or filled the output buffer. If this is done in
+ /// multithreaded mode, it may cause a call `process` to take even tens of
+ /// seconds, which isn't acceptable in all applications.
+ ///
+ /// To avoid very long blocking times in `process`, a timeout (in
+ /// milliseconds) may be set here. If `process would block longer than
+ /// this number of milliseconds, it will return with `Ok`. Reasonable
+ /// values are 100 ms or more. The xz command line tool uses 300 ms.
+ ///
+ /// If long blocking times are fine for you, set timeout to a special
+ /// value of 0, which will disable the timeout mechanism and will make
+ /// `process` block until all the input is consumed or the output
+ /// buffer has been filled.
+ pub fn timeout_ms(&mut self, timeout: u32) -> &mut Self {
+ self.raw.timeout = timeout;
+ self
+ }
+
+ /// Compression preset (level and possible flags)
+ ///
+ /// The preset is set just like with `Stream::new_easy_encoder`. The preset
+ /// is ignored if filters below have been specified.
+ pub fn preset(&mut self, preset: u32) -> &mut Self {
+ self.raw.preset = preset;
+ self
+ }
+
+ /// Configure a custom filter chain
+ pub fn filters(&mut self, filters: Filters) -> &mut Self {
+ self.raw.filters = filters.inner.as_ptr();
+ self.filters = Some(filters);
+ self
+ }
+
+ /// Configures the integrity check type
+ pub fn check(&mut self, check: Check) -> &mut Self {
+ self.raw.check = check as lzma_sys::lzma_check;
+ self
+ }
+
+ /// Calculate approximate memory usage of multithreaded .xz encoder
+ pub fn memusage(&self) -> u64 {
+ unsafe { lzma_sys::lzma_stream_encoder_mt_memusage(&self.raw) }
+ }
+
+ /// Initialize multithreaded .xz stream encoder.
+ pub fn encoder(&self) -> Result<Stream, Error> {
+ unsafe {
+ let mut init = Stream { raw: mem::zeroed() };
+ cvt(lzma_sys::lzma_stream_encoder_mt(&mut init.raw,
+ &self.raw))?;
+ Ok(init)
+ }
+ }
+}
+
+fn cvt(rc: lzma_sys::lzma_ret) -> Result<Status, Error> {
+ match rc {
+ lzma_sys::LZMA_OK => Ok(Status::Ok),
+ lzma_sys::LZMA_STREAM_END => Ok(Status::StreamEnd),
+ lzma_sys::LZMA_NO_CHECK => Err(Error::NoCheck),
+ lzma_sys::LZMA_UNSUPPORTED_CHECK => Err(Error::UnsupportedCheck),
+ lzma_sys::LZMA_GET_CHECK => Ok(Status::GetCheck),
+ lzma_sys::LZMA_MEM_ERROR => Err(Error::Mem),
+ lzma_sys::LZMA_MEMLIMIT_ERROR => Err(Error::MemLimit),
+ lzma_sys::LZMA_FORMAT_ERROR => Err(Error::Format),
+ lzma_sys::LZMA_OPTIONS_ERROR => Err(Error::Options),
+ lzma_sys::LZMA_DATA_ERROR => Err(Error::Data),
+ lzma_sys::LZMA_BUF_ERROR => Ok(Status::MemNeeded),
+ lzma_sys::LZMA_PROG_ERROR => Err(Error::Program),
+ c => panic!("unknown return code: {}", c),
+ }
+}
+
+impl From<Error> for io::Error {
+ fn from(e: Error) -> io::Error {
+ io::Error::new(io::ErrorKind::Other, e)
+ }
+}
+
+impl error::Error for Error {
+ fn description(&self) -> &str { "lzma data error" }
+}
+
+impl fmt::Display for Error {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ error::Error::description(self).fmt(f)
+ }
+}
+
+impl Drop for Stream {
+ fn drop(&mut self) {
+ unsafe {
+ lzma_sys::lzma_end(&mut self.raw);
+ }
+ }
+}
+