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