/rust/registry/src/index.crates.io-1949cf8c6b5b557f/png-0.18.0/src/decoder/zlib.rs
Line | Count | Source |
1 | | use super::{stream::FormatErrorInner, unfiltering_buffer::UnfilteringBuffer, DecodingError}; |
2 | | |
3 | | use fdeflate::Decompressor; |
4 | | |
5 | | /// An inplace buffer for decompression and filtering of PNG rowlines. |
6 | | /// |
7 | | /// The underlying data structure is a vector, with additional markers denoting a region of bytes |
8 | | /// that are utilized by the decompression but not yet available to arbitrary modifications. The |
9 | | /// caller can still shift around data between calls to the stream decompressor as long as the data |
10 | | /// in the marked region is not modified and the indices adjusted accordingly. See |
11 | | /// [`UnfilterRegion`] that contains these markers. |
12 | | /// |
13 | | /// Violating the invariants, i.e. modifying bytes in the marked region, results in absurdly wacky |
14 | | /// decompression output or panics but not undefined behavior. |
15 | | pub struct UnfilterBuf<'data> { |
16 | | /// The data container. Starts with arbitrary data unrelated to the decoder, a slice of decoder |
17 | | /// private data followed by free space for further decoder output. The regions are delimited |
18 | | /// by `filled` and `available` which must be updated accordingly. |
19 | | pub(crate) buffer: &'data mut Vec<u8>, |
20 | | /// Where we record changes to the out position. |
21 | | pub(crate) filled: &'data mut usize, |
22 | | /// Where we record changes to the available byte. |
23 | | pub(crate) available: &'data mut usize, |
24 | | } |
25 | | |
26 | | /// A region into a buffer utilized as a [`UnfilterBuf`]. |
27 | | /// |
28 | | /// The span of data denoted by `filled..available` is the region of bytes that must be preserved |
29 | | /// for use by the decompression algorithm. It may be moved, e.g. by subtracting the same amount |
30 | | /// from both of these fields. Always ensure that `filled <= available`, the library does not |
31 | | /// violate this invariant when modifying this struct as an [`UnfilterBuf`]. |
32 | | #[derive(Default, Clone, Copy)] |
33 | | pub struct UnfilterRegion { |
34 | | /// The past-the-end index of byte that are allowed to be modified. |
35 | | pub available: usize, |
36 | | /// The past-the-end of bytes that have been written to. |
37 | | pub filled: usize, |
38 | | } |
39 | | |
40 | | /// Ergonomics wrapper around `miniz_oxide::inflate::stream` for zlib compressed data. |
41 | | pub(super) struct ZlibStream { |
42 | | /// Current decoding state. |
43 | | state: Box<fdeflate::Decompressor>, |
44 | | /// If there has been a call to decompress already. |
45 | | started: bool, |
46 | | /// Ignore and do not calculate the Adler-32 checksum. Defaults to `true`. |
47 | | /// |
48 | | /// This flag overrides `TINFL_FLAG_COMPUTE_ADLER32`. |
49 | | /// |
50 | | /// This flag should not be modified after decompression has started. |
51 | | ignore_adler32: bool, |
52 | | } |
53 | | |
54 | | impl ZlibStream { |
55 | | // [PNG spec](https://www.w3.org/TR/2003/REC-PNG-20031110/#10Compression) says that |
56 | | // "deflate/inflate compression with a sliding window (which is an upper bound on the |
57 | | // distances appearing in the deflate stream) of at most 32768 bytes". |
58 | | // |
59 | | // `fdeflate` requires that we keep this many most recently decompressed bytes in the |
60 | | // `out_buffer` - this allows referring back to them when handling "length and distance |
61 | | // codes" in the deflate stream). |
62 | | const LOOKBACK_SIZE: usize = 32768; |
63 | | |
64 | 11.6k | pub(crate) fn new() -> Self { |
65 | 11.6k | ZlibStream { |
66 | 11.6k | state: Box::new(Decompressor::new()), |
67 | 11.6k | started: false, |
68 | 11.6k | ignore_adler32: true, |
69 | 11.6k | } |
70 | 11.6k | } |
71 | | |
72 | 300 | pub(crate) fn reset(&mut self) { |
73 | 300 | self.started = false; |
74 | 300 | *self.state = Decompressor::new(); |
75 | 300 | } |
76 | | |
77 | | /// Set the `ignore_adler32` flag and return `true` if the flag was |
78 | | /// successfully set. |
79 | | /// |
80 | | /// The default is `true`. |
81 | | /// |
82 | | /// This flag cannot be modified after decompression has started until the |
83 | | /// [ZlibStream] is reset. |
84 | 11.6k | pub(crate) fn set_ignore_adler32(&mut self, flag: bool) -> bool { |
85 | 11.6k | if !self.started { |
86 | 11.6k | self.ignore_adler32 = flag; |
87 | 11.6k | true |
88 | | } else { |
89 | 0 | false |
90 | | } |
91 | 11.6k | } |
92 | | |
93 | | /// Return the `ignore_adler32` flag. |
94 | 0 | pub(crate) fn ignore_adler32(&self) -> bool { |
95 | 0 | self.ignore_adler32 |
96 | 0 | } |
97 | | |
98 | | /// Fill the decoded buffer as far as possible from `data`. |
99 | | /// On success returns the number of consumed input bytes. |
100 | 2.47M | pub(crate) fn decompress( |
101 | 2.47M | &mut self, |
102 | 2.47M | data: &[u8], |
103 | 2.47M | image_data: &mut UnfilterBuf<'_>, |
104 | 2.47M | ) -> Result<usize, DecodingError> { |
105 | | // There may be more data past the adler32 checksum at the end of the deflate stream. We |
106 | | // match libpng's default behavior and ignore any trailing data. In the future we may want |
107 | | // to add a flag to control this behavior. |
108 | 2.47M | if self.state.is_done() { |
109 | 1.08k | return Ok(data.len()); |
110 | 2.47M | } |
111 | | |
112 | 2.47M | if !self.started && self.ignore_adler32 { |
113 | 6.19k | self.state.ignore_adler32(); |
114 | 2.46M | } |
115 | | |
116 | 2.47M | let (buffer, filled) = image_data.borrow_mut(); |
117 | 2.47M | let output_limit = (filled + UnfilteringBuffer::GROWTH_BYTES).min(buffer.len()); |
118 | 2.47M | let (in_consumed, out_consumed) = self |
119 | 2.47M | .state |
120 | 2.47M | .read(data, &mut buffer[..output_limit], filled, false) |
121 | 2.47M | .map_err(|err| { |
122 | 1.16k | DecodingError::Format(FormatErrorInner::CorruptFlateStream { err }.into()) |
123 | 1.16k | })?; |
124 | | |
125 | 2.47M | self.started = true; |
126 | 2.47M | let filled = filled + out_consumed; |
127 | 2.47M | image_data.filled(filled); |
128 | | |
129 | 2.47M | if self.state.is_done() { |
130 | 2.32k | image_data.commit(filled); |
131 | 2.47M | } else { |
132 | 2.47M | // See [`Self::LOOKBACK_SIZE`]. |
133 | 2.47M | image_data.commit(filled.saturating_sub(Self::LOOKBACK_SIZE)); |
134 | 2.47M | } |
135 | | |
136 | 2.47M | Ok(in_consumed) |
137 | 2.47M | } |
138 | | |
139 | | /// Called after all consecutive IDAT chunks were handled. |
140 | | /// |
141 | | /// The compressed stream can be split on arbitrary byte boundaries. This enables some cleanup |
142 | | /// within the decompressor and flushing additional data which may have been kept back in case |
143 | | /// more data were passed to it. |
144 | 376 | pub(crate) fn finish_compressed_chunks( |
145 | 376 | &mut self, |
146 | 376 | image_data: &mut UnfilterBuf<'_>, |
147 | 376 | ) -> Result<(), DecodingError> { |
148 | 376 | if !self.started { |
149 | 0 | return Ok(()); |
150 | 376 | } |
151 | | |
152 | 376 | if self.state.is_done() { |
153 | | // We can end up here only after the [`decompress`] call above has detected the state |
154 | | // to be done, too. In this case the filled and committed amount of data are already |
155 | | // equal to each other. So neither of them needs to be touched in any way. |
156 | 45 | return Ok(()); |
157 | 331 | } |
158 | | |
159 | 331 | let (_, mut filled) = image_data.borrow_mut(); |
160 | 337 | while !self.state.is_done() { |
161 | 331 | let (buffer, _) = image_data.borrow_mut(); |
162 | 6 | let (_in_consumed, out_consumed) = |
163 | 331 | self.state.read(&[], buffer, filled, true).map_err(|err| { |
164 | 325 | DecodingError::Format(FormatErrorInner::CorruptFlateStream { err }.into()) |
165 | 325 | })?; |
166 | | |
167 | 6 | filled += out_consumed; |
168 | | |
169 | 6 | if !self.state.is_done() { |
170 | 0 | image_data.flush_allocate(); |
171 | 6 | } |
172 | | } |
173 | | |
174 | 6 | image_data.filled(filled); |
175 | 6 | image_data.commit(filled); |
176 | | |
177 | 6 | Ok(()) |
178 | 376 | } |
179 | | } |
180 | | |
181 | | impl UnfilterRegion { |
182 | | /// Use this region to decompress new filtered rowline data. |
183 | | /// |
184 | | /// Pass the wrapped buffer to |
185 | | /// [`StreamingDecoder::update`][`super::stream::StreamingDecoder::update`] to fill it with |
186 | | /// data and update the region indices. |
187 | 0 | pub fn as_buf<'data>(&'data mut self, buffer: &'data mut Vec<u8>) -> UnfilterBuf<'data> { |
188 | 0 | UnfilterBuf { |
189 | 0 | buffer, |
190 | 0 | filled: &mut self.filled, |
191 | 0 | available: &mut self.available, |
192 | 0 | } |
193 | 0 | } |
194 | | } |
195 | | |
196 | | impl UnfilterBuf<'_> { |
197 | 2.47M | pub(crate) fn borrow_mut(&mut self) -> (&mut [u8], usize) { |
198 | 2.47M | (self.buffer, *self.filled) |
199 | 2.47M | } |
200 | | |
201 | 2.47M | pub(crate) fn filled(&mut self, filled: usize) { |
202 | 2.47M | *self.filled = filled; |
203 | 2.47M | } |
204 | | |
205 | 2.47M | pub(crate) fn commit(&mut self, howmany: usize) { |
206 | 2.47M | *self.available = howmany; |
207 | 2.47M | } |
208 | | |
209 | 0 | pub(crate) fn flush_allocate(&mut self) { |
210 | 0 | let len = self.buffer.len() + 32 * 1024; |
211 | 0 | self.buffer.resize(len, 0); |
212 | 0 | } |
213 | | } |