Skip to main content

lzma_rust2/
lib.rs

1//! LZMA / LZMA2 / LZIP / XZ compression ported from [tukaani xz for java](https://tukaani.org/xz/java.html).
2//!
3//! This is a fork of the original, unmaintained lzma-rust crate to continue the development and
4//! maintenance.
5//!
6//! ## Safety
7//!
8//! Only the `optimization` feature uses unsafe Rust features to implement optimizations, that are
9//! not possible in safe Rust. Those optimizations are properly guarded and are of course sound.
10//! This includes creation of aligned memory, handwritten assembly code for hot functions and some
11//! pointer logic. Those optimization are well localized and generally consider safe to use, even
12//! with untrusted input.
13//!
14//! Deactivating the `optimization` feature will result in 100% standard Rust code.
15//!
16//! ## Performance
17//!
18//! When compared against the `liblzma` crate, which uses the C library of the same name, this crate
19//! has improved decoding speed.
20//!
21//! Encoding is also well optimized and is surpassing `liblzma` for level 0 to 3 and matches it for
22//! level 4 to 9.
23//!
24//! ## no_std Support
25//!
26//! This crate supports `no_std` environments by disabling the default `std` feature.
27//!
28//! When used in `no_std` mode, the crate provides custom `Read`, `Write`, and `Error` types
29//! (defined in `no_std.rs`) that are compatible with `no_std` environments. These types offer
30//! similar functionality to their `std::io` counterparts but are implemented using only `core`
31//! and `alloc`.
32//!
33//! The custom types include:
34//!
35//! - [`Error`]: A custom error enum with variants for different error conditions.
36//! - [`Read`]: A trait similar to `std::io::Read` with `read()` and `read_exact()` methods.
37//! - [`Write`]: A trait similar to `std::io::Write` with `write()`, `write_all()`, and `flush()`
38//!   methods.
39//!
40//! Default implementations for `&[u8]` (Read) and `&mut [u8]` (Write) are provided.
41//!
42//! Note that multithreaded features are not available in `no_std` mode as they require
43//! standard library threading primitives.
44//!
45//! ## License
46//!
47//! Licensed under the [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0).
48
49// TODO: There is a lot of code left that only the "encode" feature uses.
50#![allow(dead_code)]
51#![warn(missing_docs)]
52#![cfg_attr(not(feature = "optimization"), forbid(unsafe_code))]
53#![cfg_attr(docsrs, feature(doc_cfg))]
54#![cfg_attr(not(feature = "std"), no_std)]
55
56extern crate alloc;
57
58mod decoder;
59mod lz;
60#[cfg(feature = "lzip")]
61mod lzip;
62mod lzma2_reader;
63mod lzma_reader;
64mod range_dec;
65mod state;
66#[cfg(feature = "std")]
67mod work_queue;
68#[cfg(feature = "xz")]
69mod xz;
70
71#[cfg(feature = "encoder")]
72mod enc;
73
74pub mod filter;
75
76#[cfg(any(feature = "lzip", feature = "xz"))]
77mod crc;
78#[cfg(feature = "std")]
79mod lzma2_reader_mt;
80#[cfg(not(feature = "std"))]
81mod no_std;
82#[cfg(feature = "std")]
83mod work_pool;
84
85#[cfg(feature = "std")]
86pub(crate) use std::io::Error;
87#[cfg(feature = "std")]
88pub(crate) use std::io::Read;
89#[cfg(feature = "std")]
90pub(crate) use std::io::Write;
91
92#[cfg(feature = "encoder")]
93pub use enc::*;
94pub use lz::MfType;
95#[cfg(feature = "lzip")]
96pub use lzip::LzipReader;
97#[cfg(all(feature = "lzip", feature = "std"))]
98pub use lzip::LzipReaderMt;
99#[cfg(all(feature = "lzip", feature = "encoder", feature = "std"))]
100pub use lzip::LzipWriterMt;
101#[cfg(all(feature = "lzip", feature = "encoder"))]
102pub use lzip::{LzipOptions, LzipWriter};
103pub use lzma_reader::{
104    LzmaReader, get_memory_usage as lzma_get_memory_usage,
105    get_memory_usage_by_props as lzma_get_memory_usage_by_props,
106};
107pub use lzma2_reader::{Lzma2Reader, get_memory_usage as lzma2_get_memory_usage};
108#[cfg(feature = "std")]
109pub use lzma2_reader_mt::Lzma2ReaderMt;
110#[cfg(not(feature = "std"))]
111pub use no_std::Error;
112#[cfg(not(feature = "std"))]
113pub use no_std::Read;
114#[cfg(not(feature = "std"))]
115pub use no_std::Write;
116use state::*;
117#[cfg(all(feature = "xz", feature = "std"))]
118pub use xz::XzReaderMt;
119#[cfg(all(feature = "xz", feature = "encoder", feature = "std"))]
120pub use xz::XzWriterMt;
121#[cfg(feature = "xz")]
122pub use xz::{CheckType, FilterConfig, FilterType, XzReader};
123#[cfg(all(feature = "xz", feature = "encoder"))]
124pub use xz::{XzOptions, XzWriter};
125
126/// Result type of the crate.
127#[cfg(feature = "std")]
128pub type Result<T> = core::result::Result<T, Error>;
129
130/// Result type of the crate.
131#[cfg(not(feature = "std"))]
132pub type Result<T> = core::result::Result<T, Error>;
133
134/// The minimal size of a dictionary.
135pub const DICT_SIZE_MIN: u32 = 4096;
136
137/// The maximal size of a dictionary.
138pub const DICT_SIZE_MAX: u32 = !15_u32;
139
140const LOW_SYMBOLS: usize = 1 << 3;
141const MID_SYMBOLS: usize = 1 << 3;
142const HIGH_SYMBOLS: usize = 1 << 8;
143
144const POS_STATES_MAX: usize = 1 << 4;
145const MATCH_LEN_MIN: usize = 2;
146const MATCH_LEN_MAX: usize = MATCH_LEN_MIN + LOW_SYMBOLS + MID_SYMBOLS + HIGH_SYMBOLS - 1;
147
148const DIST_STATES: usize = 4;
149const DIST_SLOTS: usize = 1 << 6;
150const DIST_MODEL_START: usize = 4;
151const DIST_MODEL_END: usize = 14;
152const FULL_DISTANCES: usize = 1 << (DIST_MODEL_END / 2);
153
154const ALIGN_BITS: usize = 4;
155const ALIGN_SIZE: usize = 1 << ALIGN_BITS;
156const ALIGN_MASK: usize = ALIGN_SIZE - 1;
157
158const REPS: usize = 4;
159
160const SHIFT_BITS: u32 = 8;
161const TOP_MASK: u32 = 0xFF000000;
162const BIT_MODEL_TOTAL_BITS: u32 = 11;
163const BIT_MODEL_TOTAL: u32 = 1 << BIT_MODEL_TOTAL_BITS;
164const PROB_INIT: u16 = (BIT_MODEL_TOTAL / 2) as u16;
165const MOVE_BITS: u32 = 5;
166const DIST_SPECIAL_INDEX: [usize; 10] = [0, 2, 4, 8, 12, 20, 28, 44, 60, 92];
167const DIST_SPECIAL_END: [usize; 10] = [2, 4, 8, 12, 20, 28, 44, 60, 92, 124];
168const TOP_VALUE: u32 = 0x0100_0000;
169const RC_BIT_MODEL_OFFSET: u32 = (1u32 << MOVE_BITS)
170    .wrapping_sub(1)
171    .wrapping_sub(BIT_MODEL_TOTAL);
172
173/// Helper to set the shared error state and trigger shutdown.
174#[cfg(feature = "std")]
175fn set_error(
176    error: Error,
177    error_store: &std::sync::Arc<std::sync::Mutex<Option<Error>>>,
178    shutdown_flag: &std::sync::Arc<std::sync::atomic::AtomicBool>,
179) {
180    let mut guard = error_store.lock().unwrap();
181    if guard.is_none() {
182        *guard = Some(error);
183    }
184    shutdown_flag.store(true, std::sync::atomic::Ordering::Release);
185}
186
187pub(crate) struct LzmaCoder {
188    pub(crate) pos_mask: u32,
189    pub(crate) reps: [i32; REPS],
190    pub(crate) state: State,
191    pub(crate) is_match: [[u16; POS_STATES_MAX]; STATES],
192    pub(crate) is_rep: [u16; STATES],
193    pub(crate) is_rep0: [u16; STATES],
194    pub(crate) is_rep1: [u16; STATES],
195    pub(crate) is_rep2: [u16; STATES],
196    pub(crate) is_rep0_long: [[u16; POS_STATES_MAX]; STATES],
197    pub(crate) dist_slots: [[u16; DIST_SLOTS]; DIST_STATES],
198    dist_special: [u16; 124],
199    dist_align: [u16; ALIGN_SIZE],
200}
201
202pub(crate) fn coder_get_dict_size(len: usize) -> usize {
203    if len < DIST_STATES + MATCH_LEN_MIN {
204        len - MATCH_LEN_MIN
205    } else {
206        DIST_STATES - 1
207    }
208}
209
210pub(crate) fn get_dist_state(len: u32) -> u32 {
211    (if (len as usize) < DIST_STATES + MATCH_LEN_MIN {
212        len as usize - MATCH_LEN_MIN
213    } else {
214        DIST_STATES - 1
215    }) as u32
216}
217
218impl LzmaCoder {
219    pub(crate) fn new(pb: usize) -> Self {
220        let mut c = Self {
221            pos_mask: (1 << pb) - 1,
222            reps: Default::default(),
223            state: Default::default(),
224            is_match: Default::default(),
225            is_rep: Default::default(),
226            is_rep0: Default::default(),
227            is_rep1: Default::default(),
228            is_rep2: Default::default(),
229            is_rep0_long: Default::default(),
230            dist_slots: [[Default::default(); DIST_SLOTS]; DIST_STATES],
231            dist_special: [Default::default(); 124],
232            dist_align: Default::default(),
233        };
234        c.reset();
235        c
236    }
237
238    pub(crate) fn reset(&mut self) {
239        self.reps = [0; REPS];
240        self.state.reset();
241        for ele in self.is_match.iter_mut() {
242            init_probs(ele);
243        }
244        init_probs(&mut self.is_rep);
245        init_probs(&mut self.is_rep0);
246        init_probs(&mut self.is_rep1);
247        init_probs(&mut self.is_rep2);
248
249        for ele in self.is_rep0_long.iter_mut() {
250            init_probs(ele);
251        }
252        for ele in self.dist_slots.iter_mut() {
253            init_probs(ele);
254        }
255        init_probs(&mut self.dist_special);
256        init_probs(&mut self.dist_align);
257    }
258
259    #[inline(always)]
260    pub(crate) fn get_dist_special(&mut self, i: usize) -> &mut [u16] {
261        &mut self.dist_special[DIST_SPECIAL_INDEX[i]..DIST_SPECIAL_END[i]]
262    }
263}
264
265#[inline(always)]
266pub(crate) fn init_probs(probs: &mut [u16]) {
267    probs.fill(PROB_INIT);
268}
269
270pub(crate) struct LiteralCoder {
271    lc: u32,
272    literal_pos_mask: u32,
273}
274
275#[derive(Debug, Clone, Copy)]
276pub(crate) struct LiteralSubCoder {
277    probs: [u16; 0x300],
278}
279
280impl LiteralSubCoder {
281    pub fn new() -> Self {
282        let probs = [PROB_INIT; 0x300];
283        Self { probs }
284    }
285
286    pub fn reset(&mut self) {
287        self.probs = [PROB_INIT; 0x300];
288    }
289}
290
291impl LiteralCoder {
292    pub fn new(lc: u32, lp: u32) -> Self {
293        Self {
294            lc,
295            literal_pos_mask: (1 << lp) - 1,
296        }
297    }
298
299    pub(crate) fn get_sub_coder_index(&self, prev_byte: u32, pos: u32) -> u32 {
300        let low = prev_byte >> (8 - self.lc);
301        let high = (pos & self.literal_pos_mask) << self.lc;
302        low + high
303    }
304}
305
306pub(crate) struct LengthCoder {
307    choice: [u16; 2],
308    low: [[u16; LOW_SYMBOLS]; POS_STATES_MAX],
309    mid: [[u16; MID_SYMBOLS]; POS_STATES_MAX],
310    high: [u16; HIGH_SYMBOLS],
311}
312
313impl LengthCoder {
314    pub fn new() -> Self {
315        Self {
316            choice: Default::default(),
317            low: Default::default(),
318            mid: Default::default(),
319            high: [0; HIGH_SYMBOLS],
320        }
321    }
322
323    pub fn reset(&mut self) {
324        init_probs(&mut self.choice);
325        for ele in self.low.iter_mut() {
326            init_probs(ele);
327        }
328        for ele in self.mid.iter_mut() {
329            init_probs(ele);
330        }
331        init_probs(&mut self.high);
332    }
333}
334
335trait ByteReader {
336    fn read_u8(&mut self) -> Result<u8>;
337
338    fn read_u16(&mut self) -> Result<u16>;
339
340    fn read_u16_be(&mut self) -> Result<u16>;
341
342    fn read_u32(&mut self) -> Result<u32>;
343
344    fn read_u32_be(&mut self) -> Result<u32>;
345
346    fn read_u64(&mut self) -> Result<u64>;
347}
348
349trait ByteWriter {
350    fn write_u8(&mut self, value: u8) -> Result<()>;
351
352    fn write_u16(&mut self, value: u16) -> Result<()>;
353
354    fn write_u32(&mut self, value: u32) -> Result<()>;
355
356    fn write_u64(&mut self, value: u64) -> Result<()>;
357}
358
359impl<T: Read> ByteReader for T {
360    #[inline(always)]
361    fn read_u8(&mut self) -> Result<u8> {
362        let mut buf = [0; 1];
363        self.read_exact(&mut buf)?;
364        Ok(buf[0])
365    }
366
367    #[inline(always)]
368    fn read_u16(&mut self) -> Result<u16> {
369        let mut buf = [0; 2];
370        self.read_exact(buf.as_mut())?;
371        Ok(u16::from_le_bytes(buf))
372    }
373
374    #[inline(always)]
375    fn read_u16_be(&mut self) -> Result<u16> {
376        let mut buf = [0; 2];
377        self.read_exact(buf.as_mut())?;
378        Ok(u16::from_be_bytes(buf))
379    }
380
381    #[inline(always)]
382    fn read_u32(&mut self) -> Result<u32> {
383        let mut buf = [0; 4];
384        self.read_exact(buf.as_mut())?;
385        Ok(u32::from_le_bytes(buf))
386    }
387
388    #[inline(always)]
389    fn read_u32_be(&mut self) -> Result<u32> {
390        let mut buf = [0; 4];
391        self.read_exact(buf.as_mut())?;
392        Ok(u32::from_be_bytes(buf))
393    }
394
395    #[inline(always)]
396    fn read_u64(&mut self) -> Result<u64> {
397        let mut buf = [0; 8];
398        self.read_exact(buf.as_mut())?;
399        Ok(u64::from_le_bytes(buf))
400    }
401}
402
403impl<T: Write> ByteWriter for T {
404    #[inline(always)]
405    fn write_u8(&mut self, value: u8) -> Result<()> {
406        self.write_all(&[value])
407    }
408
409    #[inline(always)]
410    fn write_u16(&mut self, value: u16) -> Result<()> {
411        self.write_all(&value.to_le_bytes())
412    }
413
414    #[inline(always)]
415    fn write_u32(&mut self, value: u32) -> Result<()> {
416        self.write_all(&value.to_le_bytes())
417    }
418
419    #[inline(always)]
420    fn write_u64(&mut self, value: u64) -> Result<()> {
421        self.write_all(&value.to_le_bytes())
422    }
423}
424
425#[cfg(feature = "std")]
426#[inline(always)]
427fn error_eof() -> Error {
428    Error::new(std::io::ErrorKind::UnexpectedEof, "unexpected EOF")
429}
430
431#[cfg(feature = "std")]
432#[inline(always)]
433fn error_other(msg: &'static str) -> Error {
434    Error::other(msg)
435}
436
437#[cfg(feature = "std")]
438#[inline(always)]
439fn error_invalid_input(msg: &'static str) -> Error {
440    Error::new(std::io::ErrorKind::InvalidInput, msg)
441}
442
443#[cfg(feature = "std")]
444#[inline(always)]
445fn error_invalid_data(msg: &'static str) -> Error {
446    Error::new(std::io::ErrorKind::InvalidData, msg)
447}
448
449#[cfg(feature = "std")]
450#[inline(always)]
451fn error_out_of_memory(msg: &'static str) -> Error {
452    Error::new(std::io::ErrorKind::OutOfMemory, msg)
453}
454
455#[cfg(feature = "std")]
456#[inline(always)]
457fn error_unsupported(msg: &'static str) -> Error {
458    Error::new(std::io::ErrorKind::Unsupported, msg)
459}
460
461#[cfg(feature = "std")]
462#[inline(always)]
463fn copy_error(error: &Error) -> Error {
464    Error::new(error.kind(), error.to_string())
465}
466
467#[cfg(not(feature = "std"))]
468#[inline(always)]
469fn error_eof() -> Error {
470    Error::Eof
471}
472
473#[cfg(not(feature = "std"))]
474#[inline(always)]
475fn error_other(msg: &'static str) -> Error {
476    Error::Other(msg)
477}
478
479#[cfg(not(feature = "std"))]
480#[inline(always)]
481fn error_invalid_input(msg: &'static str) -> Error {
482    Error::InvalidInput(msg)
483}
484
485#[cfg(not(feature = "std"))]
486#[inline(always)]
487fn error_invalid_data(msg: &'static str) -> Error {
488    Error::InvalidData(msg)
489}
490
491#[cfg(not(feature = "std"))]
492#[inline(always)]
493fn error_out_of_memory(msg: &'static str) -> Error {
494    Error::OutOfMemory(msg)
495}
496
497#[cfg(not(feature = "std"))]
498#[inline(always)]
499fn error_unsupported(msg: &'static str) -> Error {
500    Error::Unsupported(msg)
501}
502
503#[cfg(not(feature = "std"))]
504#[inline(always)]
505fn copy_error(error: &Error) -> Error {
506    *error
507}
508
509struct CountingReader<R> {
510    inner: R,
511    bytes_read: u64,
512}
513
514impl<R> CountingReader<R> {
515    fn new(inner: R) -> Self {
516        Self {
517            inner,
518            bytes_read: 0,
519        }
520    }
521
522    fn with_count(inner: R, bytes_read: u64) -> Self {
523        Self { inner, bytes_read }
524    }
525
526    fn bytes_read(&self) -> u64 {
527        self.bytes_read
528    }
529
530    fn into_inner(self) -> R {
531        self.inner
532    }
533
534    fn inner(&self) -> &R {
535        &self.inner
536    }
537
538    fn inner_mut(&mut self) -> &mut R {
539        &mut self.inner
540    }
541}
542
543impl<R: Read> Read for CountingReader<R> {
544    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
545        let read_size = self.inner.read(buf)?;
546        self.bytes_read += read_size as u64;
547        Ok(read_size)
548    }
549}
550
551#[cfg(feature = "encoder")]
552struct CountingWriter<W> {
553    inner: W,
554    bytes_written: u64,
555}
556
557#[cfg(feature = "encoder")]
558impl<W> CountingWriter<W> {
559    fn new(inner: W) -> Self {
560        Self {
561            inner,
562            bytes_written: 0,
563        }
564    }
565
566    fn bytes_written(&self) -> u64 {
567        self.bytes_written
568    }
569
570    fn into_inner(self) -> W {
571        self.inner
572    }
573
574    fn inner(&self) -> &W {
575        &self.inner
576    }
577
578    fn inner_mut(&mut self) -> &mut W {
579        &mut self.inner
580    }
581}
582
583#[cfg(feature = "encoder")]
584impl<W: Write> Write for CountingWriter<W> {
585    fn write(&mut self, buf: &[u8]) -> Result<usize> {
586        let bytes_written = self.inner.write(buf)?;
587        self.bytes_written += bytes_written as u64;
588        Ok(bytes_written)
589    }
590
591    fn flush(&mut self) -> Result<()> {
592        self.inner.flush()
593    }
594}
595
596/// A trait for writers that finishes the stream on drop.
597trait AutoFinish {
598    /// Finish writing the stream without error handling.
599    fn finish_ignore_error(self);
600}
601
602/// A wrapper around a writer that finishes the stream on drop.
603#[allow(private_bounds)]
604pub struct AutoFinisher<T: AutoFinish>(Option<T>);
605
606impl<T: AutoFinish> Drop for AutoFinisher<T> {
607    fn drop(&mut self) {
608        if let Some(writer) = self.0.take() {
609            writer.finish_ignore_error();
610        }
611    }
612}
613
614impl<T: AutoFinish> core::ops::Deref for AutoFinisher<T> {
615    type Target = T;
616
617    fn deref(&self) -> &Self::Target {
618        self.0.as_ref().unwrap()
619    }
620}
621
622impl<T: AutoFinish> core::ops::DerefMut for AutoFinisher<T> {
623    fn deref_mut(&mut self) -> &mut Self::Target {
624        self.0.as_mut().unwrap()
625    }
626}
627
628impl<T: AutoFinish + Write> Write for AutoFinisher<T> {
629    fn write(&mut self, buf: &[u8]) -> Result<usize> {
630        use core::ops::DerefMut;
631
632        self.deref_mut().write(buf)
633    }
634
635    fn flush(&mut self) -> Result<()> {
636        use core::ops::DerefMut;
637
638        self.deref_mut().flush()
639    }
640}