1use std::ffi::c_int;
2
3pub struct Decompress(libz_rs_sys::z_stream);
5
6unsafe impl Sync for Decompress {}
7unsafe impl Send for Decompress {}
8
9impl Default for Decompress {
10 fn default() -> Self {
11 Self::new()
12 }
13}
14
15impl Decompress {
16 pub fn total_in(&self) -> u64 {
18 self.0.total_in as _
19 }
20
21 pub fn total_out(&self) -> u64 {
23 self.0.total_out as _
24 }
25
26 pub fn new() -> Self {
28 let mut this = libz_rs_sys::z_stream::default();
29
30 unsafe {
31 libz_rs_sys::inflateInit_(
32 &mut this,
33 libz_rs_sys::zlibVersion(),
34 core::mem::size_of::<libz_rs_sys::z_stream>() as core::ffi::c_int,
35 );
36 }
37
38 Self(this)
39 }
40
41 pub fn reset(&mut self) {
43 unsafe { libz_rs_sys::inflateReset(&mut self.0) };
44 }
45
46 pub fn decompress(
48 &mut self,
49 input: &[u8],
50 output: &mut [u8],
51 flush: FlushDecompress,
52 ) -> Result<Status, DecompressError> {
53 self.0.avail_in = input.len() as _;
54 self.0.avail_out = output.len() as _;
55
56 self.0.next_in = input.as_ptr();
57 self.0.next_out = output.as_mut_ptr();
58
59 match unsafe { libz_rs_sys::inflate(&mut self.0, flush as _) } {
60 libz_rs_sys::Z_OK => Ok(Status::Ok),
61 libz_rs_sys::Z_BUF_ERROR => Ok(Status::BufError),
62 libz_rs_sys::Z_STREAM_END => Ok(Status::StreamEnd),
63
64 libz_rs_sys::Z_STREAM_ERROR => Err(DecompressError::StreamError),
65 libz_rs_sys::Z_DATA_ERROR => Err(DecompressError::DataError),
66 libz_rs_sys::Z_MEM_ERROR => Err(DecompressError::InsufficientMemory),
67 err => Err(DecompressError::Unknown { err }),
68 }
69 }
70}
71
72impl Drop for Decompress {
73 fn drop(&mut self) {
74 unsafe { libz_rs_sys::inflateEnd(&mut self.0) };
75 }
76}
77
78#[derive(Debug, thiserror::Error)]
80#[allow(missing_docs)]
81pub enum DecompressError {
82 #[error("stream error")]
83 StreamError,
84 #[error("Not enough memory")]
85 InsufficientMemory,
86 #[error("Invalid input data")]
87 DataError,
88 #[error("An unknown error occurred: {err}")]
89 Unknown { err: c_int },
90}
91
92#[derive(Debug, Clone, Copy, PartialEq, Eq)]
94pub enum Status {
95 Ok,
98 BufError,
100 StreamEnd,
102}
103
104#[derive(Copy, Clone, PartialEq, Eq, Debug)]
107#[non_exhaustive]
108#[allow(clippy::unnecessary_cast)]
109pub enum FlushDecompress {
110 None = libz_rs_sys::Z_NO_FLUSH as isize,
114
115 Sync = libz_rs_sys::Z_SYNC_FLUSH as isize,
123
124 Finish = libz_rs_sys::Z_FINISH as isize,
129}
130
131pub mod inflate {
133 #[derive(Debug, thiserror::Error)]
135 #[allow(missing_docs)]
136 pub enum Error {
137 #[error("Could not write all bytes when decompressing content")]
138 WriteInflated(#[from] std::io::Error),
139 #[error("Could not decode zip stream, status was '{0}'")]
140 Inflate(#[from] super::DecompressError),
141 #[error("The zlib status indicated an error, status was '{0:?}'")]
142 Status(super::Status),
143 }
144}
145
146#[derive(Default)]
148pub struct Inflate {
149 pub state: Decompress,
151}
152
153impl Inflate {
154 pub fn once(&mut self, input: &[u8], out: &mut [u8]) -> Result<(Status, usize, usize), inflate::Error> {
156 let before_in = self.state.total_in();
157 let before_out = self.state.total_out();
158 let status = self.state.decompress(input, out, FlushDecompress::None)?;
159 Ok((
160 status,
161 (self.state.total_in() - before_in) as usize,
162 (self.state.total_out() - before_out) as usize,
163 ))
164 }
165
166 pub fn reset(&mut self) {
168 self.state.reset();
169 }
170}
171
172pub mod stream;