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}