1#![doc(html_root_url = "https://docs.rs/liblzma/0.4.5")]
53#![deny(missing_docs)]
54
55use std::io::{self, prelude::*};
56
57pub mod stream;
58
59pub mod bufread;
60pub mod read;
61pub mod write;
62
63pub fn decode_all<R: Read>(source: R) -> io::Result<Vec<u8>> {
67    let mut vec = Vec::new();
68    let mut r = read::XzDecoder::new(source);
69    r.read_to_end(&mut vec)?;
70    Ok(vec)
71}
72
73pub fn encode_all<R: Read>(source: R, level: u32) -> io::Result<Vec<u8>> {
77    let mut vec = Vec::new();
78    let mut r = read::XzEncoder::new(source, level);
79    r.read_to_end(&mut vec)?;
80    Ok(vec)
81}
82
83pub fn copy_encode<R: Read, W: Write>(source: R, mut destination: W, level: u32) -> io::Result<()> {
87    io::copy(&mut read::XzEncoder::new(source, level), &mut destination)?;
88    Ok(())
89}
90
91pub fn copy_decode<R: Read, W: Write>(source: R, mut destination: W) -> io::Result<()> {
95    io::copy(&mut read::XzDecoder::new(source), &mut destination)?;
96    Ok(())
97}
98
99#[cfg(feature = "bindgen")]
101pub fn uncompressed_size<R: Read + Seek>(mut source: R) -> io::Result<u64> {
102    use std::mem::MaybeUninit;
103    let mut footer = [0u8; liblzma_sys::LZMA_STREAM_HEADER_SIZE as usize];
104
105    source.seek(io::SeekFrom::End(
106        0 - (liblzma_sys::LZMA_STREAM_HEADER_SIZE as i64),
107    ))?;
108    source.read_exact(&mut footer)?;
109
110    let lzma_stream_flags = unsafe {
111        let mut lzma_stream_flags = MaybeUninit::uninit();
112        let ret =
113            liblzma_sys::lzma_stream_footer_decode(lzma_stream_flags.as_mut_ptr(), footer.as_ptr());
114
115        if ret != liblzma_sys::LZMA_OK {
116            return Err(io::Error::new(
117                io::ErrorKind::Other,
118                "Failed to parse lzma footer",
119            ));
120        }
121
122        lzma_stream_flags.assume_init()
123    };
124
125    let index_plus_footer =
126        liblzma_sys::LZMA_STREAM_HEADER_SIZE as usize + lzma_stream_flags.backward_size as usize;
127
128    source.seek(io::SeekFrom::End(0 - index_plus_footer as i64))?;
129
130    let buf = source
131        .bytes()
132        .take(index_plus_footer)
133        .collect::<io::Result<Vec<u8>>>()?;
134
135    let uncompressed_size = unsafe {
136        let mut i: MaybeUninit<*mut liblzma_sys::lzma_index> = MaybeUninit::uninit();
137        let mut memlimit = u64::MAX;
138        let mut in_pos = 0usize;
139
140        let ret = liblzma_sys::lzma_index_buffer_decode(
141            i.as_mut_ptr(),
142            &mut memlimit,
143            std::ptr::null(),
144            buf.as_ptr(),
145            &mut in_pos,
146            buf.len(),
147        );
148
149        if ret != liblzma_sys::LZMA_OK {
150            return Err(io::Error::new(
151                io::ErrorKind::Other,
152                "Failed to parse lzma footer",
153            ));
154        }
155
156        let i = i.assume_init();
157
158        let uncompressed_size = liblzma_sys::lzma_index_uncompressed_size(i);
159
160        liblzma_sys::lzma_index_end(i, std::ptr::null());
161
162        uncompressed_size
163    };
164
165    Ok(uncompressed_size)
166}
167
168#[cfg(test)]
169mod tests {
170    use super::*;
171    use quickcheck::quickcheck;
172    #[cfg(all(target_family = "wasm", target_os = "unknown"))]
173    use wasm_bindgen_test::wasm_bindgen_test as test;
174
175    #[test]
176    fn all() {
177        quickcheck(test as fn(_) -> _);
178
179        fn test(v: Vec<u8>) -> bool {
180            let e = encode_all(&v[..], 6).unwrap();
181            let d = decode_all(&e[..]).unwrap();
182            v == d
183        }
184    }
185
186    #[test]
187    fn copy() {
188        quickcheck(test as fn(_) -> _);
189
190        fn test(v: Vec<u8>) -> bool {
191            let mut e = Vec::new();
192            copy_encode(&v[..], &mut e, 6).unwrap();
193            let mut d = Vec::new();
194            copy_decode(&e[..], &mut d).unwrap();
195            v == d
196        }
197    }
198
199    #[test]
200    #[cfg(feature = "bindgen")]
201    fn size() {
202        quickcheck(test as fn(_) -> _);
203
204        fn test(v: Vec<u8>) -> bool {
205            let mut e = Vec::new();
206            copy_encode(&v[..], &mut e, 6).unwrap();
207
208            let s = super::uncompressed_size(std::io::Cursor::new(e)).unwrap();
209
210            (s as usize) == v.len()
211        }
212    }
213}