/rust/registry/src/index.crates.io-6f17d22bba15001f/gif-0.13.3/src/reader/decoder.rs
Line | Count | Source (jump to first uncovered line) |
1 | | use std::borrow::Cow; |
2 | | use std::cmp; |
3 | | use std::default::Default; |
4 | | use std::error; |
5 | | use std::fmt; |
6 | | use std::io; |
7 | | use std::mem; |
8 | | use std::num::NonZeroUsize; |
9 | | |
10 | | use crate::common::{AnyExtension, Block, DisposalMethod, Extension, Frame}; |
11 | | use crate::reader::DecodeOptions; |
12 | | use crate::MemoryLimit; |
13 | | use crate::Repeat; |
14 | | |
15 | | use weezl::{decode::Decoder as LzwDecoder, BitOrder, LzwError, LzwStatus}; |
16 | | |
17 | | /// GIF palettes are RGB |
18 | | pub const PLTE_CHANNELS: usize = 3; |
19 | | |
20 | | /// An error returned in the case of the image not being formatted properly. |
21 | | #[derive(Debug)] |
22 | | pub struct DecodingFormatError { |
23 | | underlying: Box<dyn error::Error + Send + Sync + 'static>, |
24 | | } |
25 | | |
26 | | impl fmt::Display for DecodingFormatError { |
27 | | #[cold] |
28 | 0 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
29 | 0 | fmt::Display::fmt(&*self.underlying, fmt) |
30 | 0 | } |
31 | | } |
32 | | |
33 | | impl error::Error for DecodingFormatError { |
34 | | #[cold] |
35 | 0 | fn source(&self) -> Option<&(dyn error::Error + 'static)> { |
36 | 0 | Some(&*self.underlying as _) |
37 | 0 | } |
38 | | } |
39 | | |
40 | | #[derive(Debug)] |
41 | | /// Decoding error. |
42 | | pub enum DecodingError { |
43 | | /// Returned if the image is found to be malformed. |
44 | | Format(DecodingFormatError), |
45 | | /// Wraps `std::io::Error`. |
46 | | Io(io::Error), |
47 | | } |
48 | | |
49 | | impl DecodingError { |
50 | | #[cold] |
51 | 303 | pub(crate) fn format(err: &'static str) -> Self { |
52 | 303 | Self::Format(DecodingFormatError { |
53 | 303 | underlying: err.into(), |
54 | 303 | }) |
55 | 303 | } |
56 | | } |
57 | | |
58 | | impl fmt::Display for DecodingError { |
59 | | #[cold] |
60 | 0 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
61 | 0 | match *self { |
62 | 0 | Self::Format(ref d) => d.fmt(fmt), |
63 | 0 | Self::Io(ref err) => err.fmt(fmt), |
64 | | } |
65 | 0 | } |
66 | | } |
67 | | |
68 | | impl error::Error for DecodingError { |
69 | | #[cold] |
70 | 0 | fn source(&self) -> Option<&(dyn error::Error + 'static)> { |
71 | 0 | match *self { |
72 | 0 | Self::Format(ref err) => Some(err), |
73 | 0 | Self::Io(ref err) => Some(err), |
74 | | } |
75 | 0 | } |
76 | | } |
77 | | |
78 | | impl From<io::Error> for DecodingError { |
79 | | #[inline] |
80 | 265 | fn from(err: io::Error) -> Self { |
81 | 265 | Self::Io(err) |
82 | 265 | } Unexecuted instantiation: <gif::reader::decoder::DecodingError as core::convert::From<std::io::error::Error>>::from <gif::reader::decoder::DecodingError as core::convert::From<std::io::error::Error>>::from Line | Count | Source | 80 | 265 | fn from(err: io::Error) -> Self { | 81 | 265 | Self::Io(err) | 82 | 265 | } |
Unexecuted instantiation: <gif::reader::decoder::DecodingError as core::convert::From<std::io::error::Error>>::from Unexecuted instantiation: <gif::reader::decoder::DecodingError as core::convert::From<std::io::error::Error>>::from Unexecuted instantiation: <gif::reader::decoder::DecodingError as core::convert::From<std::io::error::Error>>::from Unexecuted instantiation: <gif::reader::decoder::DecodingError as core::convert::From<std::io::error::Error>>::from Unexecuted instantiation: <gif::reader::decoder::DecodingError as core::convert::From<std::io::error::Error>>::from Unexecuted instantiation: <gif::reader::decoder::DecodingError as core::convert::From<std::io::error::Error>>::from Unexecuted instantiation: <gif::reader::decoder::DecodingError as core::convert::From<std::io::error::Error>>::from Unexecuted instantiation: <gif::reader::decoder::DecodingError as core::convert::From<std::io::error::Error>>::from Unexecuted instantiation: <gif::reader::decoder::DecodingError as core::convert::From<std::io::error::Error>>::from Unexecuted instantiation: <gif::reader::decoder::DecodingError as core::convert::From<std::io::error::Error>>::from |
83 | | } |
84 | | |
85 | | impl From<io::ErrorKind> for DecodingError { |
86 | | #[cold] |
87 | 1.39k | fn from(err: io::ErrorKind) -> Self { |
88 | 1.39k | Self::Io(io::Error::from(err)) |
89 | 1.39k | } |
90 | | } |
91 | | |
92 | | impl From<DecodingFormatError> for DecodingError { |
93 | | #[inline] |
94 | 0 | fn from(err: DecodingFormatError) -> Self { |
95 | 0 | Self::Format(err) |
96 | 0 | } |
97 | | } |
98 | | |
99 | | /// Varies depending on `skip_frame_decoding` |
100 | | #[derive(Debug, Copy, Clone)] |
101 | | pub enum FrameDataType { |
102 | | /// `Frame.buffer` will be regular pixel data |
103 | | Pixels, |
104 | | /// Raw LZW data |
105 | | Lzw { |
106 | | /// Needed for decoding |
107 | | min_code_size: u8, |
108 | | }, |
109 | | } |
110 | | |
111 | | /// Indicates whether a certain object has been decoded |
112 | | #[derive(Debug)] |
113 | | #[non_exhaustive] |
114 | | pub enum Decoded { |
115 | | /// Decoded nothing. |
116 | | Nothing, |
117 | | /// Global palette. |
118 | | GlobalPalette(Box<[u8]>), |
119 | | /// Index of the background color in the global palette. |
120 | | BackgroundColor(u8), |
121 | | /// Loop count is known |
122 | | Repetitions(Repeat), |
123 | | /// Palette and optional `Application` extension have been parsed, |
124 | | /// reached frame data. |
125 | | HeaderEnd, |
126 | | /// The start of a block. |
127 | | /// `BlockStart(Block::Trailer)` is the very last decode event |
128 | | BlockStart(Block), |
129 | | /// Decoded a sub-block. More sub-block are available. |
130 | | /// |
131 | | /// Indicates the label of the extension which might be unknown. A label of `0` is used when |
132 | | /// the sub block does not belong to an extension. |
133 | | /// |
134 | | /// Call `last_ext()` to get the data |
135 | | SubBlockFinished(AnyExtension), |
136 | | /// Decoded the last (or only) sub-block of a block. |
137 | | /// |
138 | | /// Indicates the label of the extension which might be unknown. A label of `0` is used when |
139 | | /// the sub block does not belong to an extension. |
140 | | /// |
141 | | /// Call `last_ext()` to get the data |
142 | | BlockFinished(AnyExtension), |
143 | | /// Decoded all information of the next frame, except the image data. |
144 | | /// |
145 | | /// The returned frame does **not** contain any owned image data. |
146 | | /// |
147 | | /// Call `current_frame_mut()` to access the frame info. |
148 | | FrameMetadata(FrameDataType), |
149 | | /// Decoded some data of the current frame. Size is in bytes, always > 0 |
150 | | BytesDecoded(NonZeroUsize), |
151 | | /// Copied (or consumed and discarded) compressed data of the current frame. In bytes. |
152 | | LzwDataCopied(usize), |
153 | | /// No more data available the current frame. |
154 | | DataEnd, |
155 | | } |
156 | | |
157 | | /// Internal state of the GIF decoder |
158 | | #[derive(Debug, Copy, Clone)] |
159 | | enum State { |
160 | | Magic, |
161 | | ScreenDescriptor, |
162 | | ImageBlockStart, |
163 | | GlobalPalette(usize), |
164 | | BlockStart(u8), |
165 | | BlockEnd, |
166 | | ExtensionBlockStart, |
167 | | /// Collects data in ext.data |
168 | | ExtensionDataBlock(usize), |
169 | | ApplicationExtension, |
170 | | LocalPalette(usize), |
171 | | LzwInit(u8), |
172 | | /// Decompresses LZW |
173 | | DecodeSubBlock(usize), |
174 | | /// Keeps LZW compressed |
175 | | CopySubBlock(usize), |
176 | | FrameDecoded, |
177 | | Trailer, |
178 | | } |
179 | | use self::State::*; |
180 | | |
181 | | use super::converter::PixelConverter; |
182 | | |
183 | | /// Decoder for `Frame::make_lzw_pre_encoded` |
184 | | pub struct FrameDecoder { |
185 | | lzw_reader: LzwReader, |
186 | | pixel_converter: PixelConverter, |
187 | | } |
188 | | |
189 | | impl FrameDecoder { |
190 | | /// See also `set_global_palette` |
191 | | #[inline] |
192 | | #[must_use] |
193 | 0 | pub fn new(options: DecodeOptions) -> Self { |
194 | 0 | Self { |
195 | 0 | lzw_reader: LzwReader::new(options.check_for_end_code), |
196 | 0 | pixel_converter: PixelConverter::new(options.color_output, options.memory_limit), |
197 | 0 | } |
198 | 0 | } |
199 | | |
200 | | /// Palette used for RGBA conversion |
201 | | #[inline] |
202 | 0 | pub fn set_global_palette(&mut self, palette: Vec<u8>) { |
203 | 0 | self.pixel_converter.set_global_palette(palette); |
204 | 0 | } |
205 | | |
206 | | /// Converts the frame in-place, replacing its LZW buffer with pixels. |
207 | | /// |
208 | | /// If you get an error about invalid min code size, the buffer was probably pixels, not compressed data. |
209 | | #[inline] |
210 | 0 | pub fn decode_lzw_encoded_frame(&mut self, frame: &mut Frame<'_>) -> Result<(), DecodingError> { |
211 | 0 | let pixel_bytes = self.pixel_converter.check_buffer_size(frame)?; |
212 | 0 | let mut vec = vec![0; pixel_bytes]; |
213 | 0 | self.decode_lzw_encoded_frame_into_buffer(frame, &mut vec)?; |
214 | 0 | frame.buffer = Cow::Owned(vec); |
215 | 0 | frame.interlaced = false; |
216 | 0 | Ok(()) |
217 | 0 | } |
218 | | |
219 | | /// Converts into the given buffer. It must be [`buffer_size()`] bytes large. |
220 | | /// |
221 | | /// Pixels are always deinterlaced, so update `frame.interlaced` afterwards if you're putting the buffer back into the frame. |
222 | 0 | pub fn decode_lzw_encoded_frame_into_buffer( |
223 | 0 | &mut self, |
224 | 0 | frame: &Frame<'_>, |
225 | 0 | buf: &mut [u8], |
226 | 0 | ) -> Result<(), DecodingError> { |
227 | 0 | let (&min_code_size, mut data) = frame.buffer.split_first().unwrap_or((&2, &[])); |
228 | 0 | self.lzw_reader.reset(min_code_size)?; |
229 | 0 | let lzw_reader = &mut self.lzw_reader; |
230 | 0 | self.pixel_converter |
231 | 0 | .read_into_buffer(frame, buf, &mut move |out| loop { |
232 | 0 | let (bytes_read, bytes_written, status) = lzw_reader.decode_bytes(data, out)?; |
233 | 0 | data = data.get(bytes_read..).unwrap_or_default(); |
234 | 0 | if bytes_written > 0 || matches!(status, LzwStatus::NoProgress) { |
235 | 0 | return Ok(bytes_written); |
236 | 0 | } |
237 | 0 | })?; |
238 | 0 | Ok(()) |
239 | 0 | } |
240 | | |
241 | | /// Number of bytes required for `decode_lzw_encoded_frame_into_buffer` |
242 | | #[inline] |
243 | | #[must_use] |
244 | 0 | pub fn buffer_size(&self, frame: &Frame<'_>) -> usize { |
245 | 0 | self.pixel_converter.buffer_size(frame).unwrap() |
246 | 0 | } |
247 | | } |
248 | | |
249 | | struct LzwReader { |
250 | | decoder: Option<LzwDecoder>, |
251 | | min_code_size: u8, |
252 | | check_for_end_code: bool, |
253 | | } |
254 | | |
255 | | impl LzwReader { |
256 | 2.11k | pub fn new(check_for_end_code: bool) -> Self { |
257 | 2.11k | Self { |
258 | 2.11k | decoder: None, |
259 | 2.11k | min_code_size: 0, |
260 | 2.11k | check_for_end_code, |
261 | 2.11k | } |
262 | 2.11k | } |
263 | | |
264 | 1.59k | pub fn check_code_size(min_code_size: u8) -> Result<(), DecodingError> { |
265 | 1.59k | // LZW spec: max 12 bits per code. This check helps catch confusion |
266 | 1.59k | // between LZW-compressed buffers and raw pixel data |
267 | 1.59k | if min_code_size > 11 || min_code_size < 1 { |
268 | 12 | return Err(DecodingError::format("invalid minimal code size")); |
269 | 1.58k | } |
270 | 1.58k | Ok(()) |
271 | 1.59k | } |
272 | | |
273 | 1.59k | pub fn reset(&mut self, min_code_size: u8) -> Result<(), DecodingError> { |
274 | 1.59k | Self::check_code_size(min_code_size)?; |
275 | | |
276 | | // The decoder can be reused if the code size stayed the same |
277 | 1.58k | if self.min_code_size != min_code_size || self.decoder.is_none() { |
278 | 1.58k | self.min_code_size = min_code_size; |
279 | 1.58k | self.decoder = Some(LzwDecoder::new(BitOrder::Lsb, min_code_size)); |
280 | 1.58k | } else { |
281 | 0 | self.decoder.as_mut().ok_or_else(|| DecodingError::format("bad state"))?.reset(); |
282 | | } |
283 | | |
284 | 1.58k | Ok(()) |
285 | 1.59k | } |
286 | | |
287 | 469k | pub fn has_ended(&self) -> bool { |
288 | 469k | self.decoder.as_ref().map_or(true, |e| e.has_ended()) |
289 | 469k | } |
290 | | |
291 | 461k | pub fn decode_bytes( |
292 | 461k | &mut self, |
293 | 461k | lzw_data: &[u8], |
294 | 461k | decode_buffer: &mut OutputBuffer<'_>, |
295 | 461k | ) -> io::Result<(usize, usize, LzwStatus)> { |
296 | 461k | let decoder = self.decoder.as_mut().ok_or(io::ErrorKind::Unsupported)?; |
297 | | |
298 | 461k | let decode_buffer = match decode_buffer { |
299 | 461k | OutputBuffer::Slice(buf) => &mut **buf, |
300 | 0 | OutputBuffer::None => &mut [], |
301 | 0 | OutputBuffer::Vec(_) => return Err(io::Error::from(io::ErrorKind::Unsupported)), |
302 | | }; |
303 | | |
304 | 461k | let decoded = decoder.decode_bytes(lzw_data, decode_buffer); |
305 | | |
306 | 461k | let status = match decoded.status { |
307 | 460k | Ok(ok @ LzwStatus::Done | ok @ LzwStatus::Ok) => ok, |
308 | 584 | Ok(ok @ LzwStatus::NoProgress) => { |
309 | 584 | if self.check_for_end_code { |
310 | 0 | return Err(io::Error::new( |
311 | 0 | io::ErrorKind::InvalidData, |
312 | 0 | "no end code in lzw stream", |
313 | 0 | )); |
314 | 584 | } |
315 | 584 | |
316 | 584 | ok |
317 | | } |
318 | 265 | Err(err @ LzwError::InvalidCode) => { |
319 | 265 | return Err(io::Error::new(io::ErrorKind::InvalidData, err)); |
320 | | } |
321 | | }; |
322 | | |
323 | 461k | Ok((decoded.consumed_in, decoded.consumed_out, status)) |
324 | 461k | } |
325 | | } |
326 | | |
327 | | /// GIF decoder which emits [low-level events](Decoded) for items in the GIF file |
328 | | /// |
329 | | /// To just get GIF frames, use [`crate::Decoder`] instead. |
330 | | pub struct StreamingDecoder { |
331 | | state: State, |
332 | | /// Input bytes are collected here if `update` got `buf` smaller than the minimum required |
333 | | internal_buffer: [u8; 9], |
334 | | unused_internal_buffer_len: u8, |
335 | | lzw_reader: LzwReader, |
336 | | skip_frame_decoding: bool, |
337 | | check_frame_consistency: bool, |
338 | | allow_unknown_blocks: bool, |
339 | | memory_limit: MemoryLimit, |
340 | | version: Version, |
341 | | width: u16, |
342 | | height: u16, |
343 | | global_color_table: Vec<u8>, |
344 | | /// ext buffer |
345 | | ext: ExtensionData, |
346 | | /// Frame data |
347 | | current: Option<Frame<'static>>, |
348 | | /// Needs to emit `HeaderEnd` once |
349 | | header_end_reached: bool, |
350 | | } |
351 | | |
352 | | /// One version number of the GIF standard. |
353 | | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] |
354 | | pub enum Version { |
355 | | /// Version 87a, from May 1987. |
356 | | V87a, |
357 | | /// Version 89a, from July 1989. |
358 | | V89a, |
359 | | } |
360 | | |
361 | | struct ExtensionData { |
362 | | id: AnyExtension, |
363 | | data: Vec<u8>, |
364 | | is_block_end: bool, |
365 | | } |
366 | | |
367 | | /// Destination to write to for `StreamingDecoder::update` |
368 | | pub enum OutputBuffer<'a> { |
369 | | /// Overwrite bytes |
370 | | Slice(&'a mut [u8]), |
371 | | /// Append LZW bytes |
372 | | Vec(&'a mut Vec<u8>), |
373 | | /// Discard bytes |
374 | | None, |
375 | | } |
376 | | |
377 | | impl OutputBuffer<'_> { |
378 | 0 | fn append(&mut self, buf: &[u8], memory_limit: &MemoryLimit) -> Result<(usize, usize), DecodingError> { |
379 | 0 | let (consumed, copied) = match self { |
380 | 0 | OutputBuffer::Slice(slice) => { |
381 | 0 | let len = cmp::min(buf.len(), slice.len()); |
382 | 0 | slice[..len].copy_from_slice(&buf[..len]); |
383 | 0 | (len, len) |
384 | | }, |
385 | 0 | OutputBuffer::Vec(vec) => { |
386 | 0 | let vec: &mut Vec<u8> = vec; |
387 | 0 | let len = buf.len(); |
388 | 0 | memory_limit.check_size(vec.len() + len)?; |
389 | 0 | vec.try_reserve(len).map_err(|_| io::ErrorKind::OutOfMemory)?; |
390 | 0 | if vec.capacity() - vec.len() >= len { |
391 | 0 | vec.extend_from_slice(buf); |
392 | 0 | } |
393 | 0 | (len, len) |
394 | | }, |
395 | | // It's valid that bytes are discarded. For example, |
396 | | // when using next_frame_info() with skip_frame_decoding to only get metadata. |
397 | 0 | OutputBuffer::None => (buf.len(), 0), |
398 | | }; |
399 | 0 | Ok((consumed, copied)) |
400 | 0 | } |
401 | | } |
402 | | |
403 | | impl StreamingDecoder { |
404 | | /// Creates a new streaming decoder |
405 | | #[must_use] |
406 | 0 | pub fn new() -> Self { |
407 | 0 | let options = DecodeOptions::new(); |
408 | 0 | Self::with_options(&options) |
409 | 0 | } |
410 | | |
411 | 2.11k | pub(crate) fn with_options(options: &DecodeOptions) -> Self { |
412 | 2.11k | Self { |
413 | 2.11k | internal_buffer: [0; 9], |
414 | 2.11k | unused_internal_buffer_len: 0, |
415 | 2.11k | state: Magic, |
416 | 2.11k | lzw_reader: LzwReader::new(options.check_for_end_code), |
417 | 2.11k | skip_frame_decoding: options.skip_frame_decoding, |
418 | 2.11k | check_frame_consistency: options.check_frame_consistency, |
419 | 2.11k | allow_unknown_blocks: options.allow_unknown_blocks, |
420 | 2.11k | memory_limit: options.memory_limit.clone(), |
421 | 2.11k | version: Version::V87a, |
422 | 2.11k | width: 0, |
423 | 2.11k | height: 0, |
424 | 2.11k | global_color_table: Vec::new(), |
425 | 2.11k | ext: ExtensionData { |
426 | 2.11k | id: AnyExtension(0), |
427 | 2.11k | data: Vec::with_capacity(256), // 0xFF + 1 byte length |
428 | 2.11k | is_block_end: true, |
429 | 2.11k | }, |
430 | 2.11k | current: None, |
431 | 2.11k | header_end_reached: false, |
432 | 2.11k | } |
433 | 2.11k | } |
434 | | |
435 | | /// Updates the internal state of the decoder. |
436 | | /// |
437 | | /// Returns the number of bytes consumed from the input buffer |
438 | | /// and the last decoding result. |
439 | 663k | pub fn update( |
440 | 663k | &mut self, |
441 | 663k | mut buf: &[u8], |
442 | 663k | write_into: &mut OutputBuffer<'_>, |
443 | 663k | ) -> Result<(usize, Decoded), DecodingError> { |
444 | 663k | let len = buf.len(); |
445 | 1.29M | while !buf.is_empty() { |
446 | 1.28M | let (bytes, decoded) = self.next_state(buf, write_into)?; |
447 | 1.28M | buf = buf.get(bytes..).unwrap_or_default(); |
448 | 1.28M | match decoded { |
449 | 626k | Decoded::Nothing => {}, |
450 | 661k | result => { |
451 | 661k | return Ok((len-buf.len(), result)); |
452 | | }, |
453 | | }; |
454 | | } |
455 | 1.55k | Ok((len - buf.len(), Decoded::Nothing)) |
456 | 663k | } |
457 | | |
458 | | /// Returns the data of the last extension that has been decoded. |
459 | | #[must_use] |
460 | 0 | pub fn last_ext(&self) -> (AnyExtension, &[u8], bool) { |
461 | 0 | (self.ext.id, &self.ext.data, self.ext.is_block_end) |
462 | 0 | } |
463 | | |
464 | | /// Current frame info as a mutable ref. |
465 | | #[must_use] |
466 | | #[track_caller] |
467 | 1.58k | pub fn current_frame_mut(&mut self) -> &mut Frame<'static> { |
468 | 1.58k | self.current.as_mut().unwrap() |
469 | 1.58k | } |
470 | | |
471 | | /// Current frame info as a ref. |
472 | | #[track_caller] |
473 | | #[must_use] |
474 | 0 | pub fn current_frame(&self) -> &Frame<'static> { |
475 | 0 | self.current.as_ref().unwrap() |
476 | 0 | } |
477 | | |
478 | | /// Current frame info as a mutable ref. |
479 | | #[inline(always)] |
480 | 255 | fn try_current_frame(&mut self) -> Result<&mut Frame<'static>, DecodingError> { |
481 | 255 | self.current.as_mut().ok_or_else(|| DecodingError::format("bad state")) |
482 | 255 | } |
483 | | |
484 | | /// Width of the image |
485 | | #[must_use] |
486 | 10.1k | pub fn width(&self) -> u16 { |
487 | 10.1k | self.width |
488 | 10.1k | } |
489 | | |
490 | | /// Height of the image |
491 | | #[must_use] |
492 | 10.1k | pub fn height(&self) -> u16 { |
493 | 10.1k | self.height |
494 | 10.1k | } |
495 | | |
496 | | /// The version number of the GIF standard used in this image. |
497 | | /// |
498 | | /// We suppose a minimum of `V87a` compatibility. This value will be reported until we have |
499 | | /// read the version information in the magic header bytes. |
500 | | #[must_use] |
501 | 0 | pub fn version(&self) -> Version { |
502 | 0 | self.version |
503 | 0 | } |
504 | | |
505 | | #[inline] |
506 | 1.28M | fn next_state(&mut self, buf: &[u8], write_into: &mut OutputBuffer<'_>) -> Result<(usize, Decoded), DecodingError> { |
507 | | macro_rules! goto ( |
508 | | ($n:expr, $state:expr) => ({ |
509 | | self.state = $state; |
510 | | Ok(($n, Decoded::Nothing)) |
511 | | }); |
512 | | ($state:expr) => ({ |
513 | | self.state = $state; |
514 | | Ok((1, Decoded::Nothing)) |
515 | | }); |
516 | | ($n:expr, $state:expr, emit $res:expr) => ({ |
517 | | self.state = $state; |
518 | | Ok(($n, $res)) |
519 | | }); |
520 | | ($state:expr, emit $res:expr) => ({ |
521 | | self.state = $state; |
522 | | Ok((1, $res)) |
523 | | }) |
524 | | ); |
525 | | |
526 | | macro_rules! ensure_min_length_buffer ( |
527 | | ($required:expr) => ({ |
528 | | let required: usize = $required; |
529 | | if buf.len() >= required && self.unused_internal_buffer_len == 0 { |
530 | | (required, &buf[..required]) |
531 | | } else { |
532 | | let has = usize::from(self.unused_internal_buffer_len); |
533 | | let mut consumed = 0; |
534 | | if has < required { |
535 | | let to_copy = buf.len().min(required - has); |
536 | | let new_len = has + to_copy; |
537 | | self.internal_buffer[has .. new_len].copy_from_slice(&buf[..to_copy]); |
538 | | consumed += to_copy; |
539 | | if new_len < required { |
540 | | self.unused_internal_buffer_len = new_len as u8; |
541 | | return Ok((consumed, Decoded::Nothing)); |
542 | | } else { |
543 | | self.unused_internal_buffer_len = 0; |
544 | | } |
545 | | } |
546 | | (consumed, &self.internal_buffer[..required]) |
547 | | } |
548 | | }) |
549 | | ); |
550 | | |
551 | 1.28M | let b = *buf.first().ok_or(io::ErrorKind::UnexpectedEof)?; |
552 | | |
553 | 1.28M | match self.state { |
554 | | Magic => { |
555 | 2.11k | let (consumed, version) = ensure_min_length_buffer!(6); |
556 | | |
557 | 2.10k | self.version = match version { |
558 | 2.10k | b"GIF87a" => Version::V87a, |
559 | 1.25k | b"GIF89a" => Version::V89a, |
560 | 64 | _ => return Err(DecodingError::format("malformed GIF header")), |
561 | | }; |
562 | | |
563 | 2.03k | goto!(consumed, ScreenDescriptor) |
564 | | }, |
565 | | ScreenDescriptor => { |
566 | 2.03k | let (consumed, desc) = ensure_min_length_buffer!(7); |
567 | | |
568 | 2.03k | self.width = u16::from_le_bytes(desc[..2].try_into().unwrap()); |
569 | 2.03k | self.height = u16::from_le_bytes(desc[2..4].try_into().unwrap()); |
570 | 2.03k | let global_flags = desc[4]; |
571 | 2.03k | let background_color = desc[5]; |
572 | 2.03k | |
573 | 2.03k | let global_table = global_flags & 0x80 != 0; |
574 | 2.03k | let table_size = if global_table { |
575 | 1.45k | let table_size = PLTE_CHANNELS * (1 << ((global_flags & 0b111) + 1) as usize); |
576 | 1.45k | self.global_color_table.try_reserve_exact(table_size).map_err(|_| io::ErrorKind::OutOfMemory)?; |
577 | 1.45k | table_size |
578 | | } else { |
579 | 573 | 0usize |
580 | | }; |
581 | | |
582 | 2.03k | goto!( |
583 | 2.03k | consumed, |
584 | 2.03k | GlobalPalette(table_size), |
585 | 2.03k | emit Decoded::BackgroundColor(background_color) |
586 | 2.03k | ) |
587 | | }, |
588 | | ImageBlockStart => { |
589 | 1.64k | let (consumed, header) = ensure_min_length_buffer!(9); |
590 | | |
591 | 1.63k | let frame = self.current.as_mut().ok_or_else(|| DecodingError::format("bad state"))?; |
592 | 1.63k | frame.left = u16::from_le_bytes(header[..2].try_into().unwrap()); |
593 | 1.63k | frame.top = u16::from_le_bytes(header[2..4].try_into().unwrap()); |
594 | 1.63k | frame.width = u16::from_le_bytes(header[4..6].try_into().unwrap()); |
595 | 1.63k | frame.height = u16::from_le_bytes(header[6..8].try_into().unwrap()); |
596 | 1.63k | |
597 | 1.63k | let flags = header[8]; |
598 | 1.63k | frame.interlaced = (flags & 0b0100_0000) != 0; |
599 | 1.63k | |
600 | 1.63k | if self.check_frame_consistency { |
601 | | // Consistency checks. |
602 | 0 | if self.width.checked_sub(frame.width) < Some(frame.left) |
603 | 0 | || self.height.checked_sub(frame.height) < Some(frame.top) |
604 | | { |
605 | 0 | return Err(DecodingError::format("frame descriptor is out-of-bounds")); |
606 | 0 | } |
607 | 1.63k | } |
608 | | |
609 | 1.63k | let local_table = (flags & 0b1000_0000) != 0; |
610 | 1.63k | if local_table { |
611 | 256 | let table_size = flags & 0b0000_0111; |
612 | 256 | let pal_len = PLTE_CHANNELS * (1 << (table_size + 1)); |
613 | 256 | frame.palette.get_or_insert_with(Vec::new) |
614 | 256 | .try_reserve_exact(pal_len).map_err(|_| io::ErrorKind::OutOfMemory)?; |
615 | 256 | goto!(consumed, LocalPalette(pal_len)) |
616 | | } else { |
617 | 1.37k | goto!(consumed, LocalPalette(0)) |
618 | | } |
619 | | }, |
620 | 3.45k | GlobalPalette(left) => { |
621 | 3.45k | // the global_color_table is guaranteed to have the exact capacity required |
622 | 3.45k | if left > 0 { |
623 | 1.44k | let n = cmp::min(left, buf.len()); |
624 | 1.44k | if n <= self.global_color_table.capacity() - self.global_color_table.len() { |
625 | 1.44k | self.global_color_table.extend_from_slice(&buf[..n]); |
626 | 1.44k | } |
627 | 1.44k | goto!(n, GlobalPalette(left - n)) |
628 | | } else { |
629 | 2.00k | goto!(BlockStart(b), emit Decoded::GlobalPalette( |
630 | 2.00k | mem::take(&mut self.global_color_table).into_boxed_slice() |
631 | 2.00k | )) |
632 | | } |
633 | | } |
634 | 8.32k | BlockStart(type_) => { |
635 | 8.32k | if !self.header_end_reached && type_ != Block::Extension as u8 { |
636 | 1.72k | self.header_end_reached = true; |
637 | 1.72k | return goto!(0, BlockStart(type_), emit Decoded::HeaderEnd); |
638 | 6.59k | } |
639 | 6.59k | |
640 | 6.59k | match Block::from_u8(type_) { |
641 | | Some(Block::Image) => { |
642 | 1.64k | self.add_frame(); |
643 | 1.64k | goto!(0, ImageBlockStart, emit Decoded::BlockStart(Block::Image)) |
644 | | } |
645 | | Some(Block::Extension) => { |
646 | 4.88k | self.ext.data.clear(); |
647 | 4.88k | self.ext.id = AnyExtension(b); |
648 | 4.88k | if self.ext.id.into_known().is_none() { |
649 | 5 | if !self.allow_unknown_blocks { |
650 | 5 | return Err(DecodingError::format( |
651 | 5 | "unknown extension block encountered", |
652 | 5 | )); |
653 | 0 | } |
654 | 4.87k | } |
655 | 4.87k | goto!(ExtensionBlockStart, emit Decoded::BlockStart(Block::Extension)) |
656 | | } |
657 | | Some(Block::Trailer) => { |
658 | | // The `Trailer` is the final state, and isn't reachable without extraneous data after the end of file |
659 | 6 | goto!(Trailer, emit Decoded::BlockStart(Block::Trailer)) |
660 | | } |
661 | | None => { |
662 | 66 | if self.allow_unknown_blocks { |
663 | 0 | goto!(ExtensionDataBlock(b as usize)) |
664 | | } else { |
665 | 66 | Err(DecodingError::format("unknown block type encountered")) |
666 | | } |
667 | | } |
668 | | } |
669 | | }, |
670 | | BlockEnd => { |
671 | 4.61k | if b == Block::Trailer as u8 { |
672 | | // can't consume yet, because the trailer is not a real block, |
673 | | // and won't have futher data for BlockStart |
674 | 3 | goto!(0, BlockStart(b)) |
675 | | } else { |
676 | 4.61k | goto!(BlockStart(b)) |
677 | | } |
678 | | } |
679 | | ExtensionBlockStart => { |
680 | 4.85k | self.ext.data.push(b); |
681 | 4.85k | goto!(ExtensionDataBlock(b as usize)) |
682 | | } |
683 | 526k | ExtensionDataBlock(left) => { |
684 | 526k | if left > 0 { |
685 | 263k | let n = cmp::min(left, buf.len()); |
686 | 263k | self.memory_limit.check_size(self.ext.data.len() + n)?; |
687 | 263k | self.ext.data.try_reserve(n).map_err(|_| io::Error::from(io::ErrorKind::OutOfMemory))?; |
688 | 263k | self.ext.data.extend_from_slice(&buf[..n]); |
689 | 263k | goto!(n, ExtensionDataBlock(left - n)) |
690 | 263k | } else if b == 0 { |
691 | 4.70k | self.ext.is_block_end = true; |
692 | 4.70k | match self.ext.id.into_known() { |
693 | | Some(Extension::Application) => { |
694 | 2.23k | goto!(0, ApplicationExtension, emit Decoded::BlockFinished(self.ext.id)) |
695 | | } |
696 | | Some(Extension::Control) => { |
697 | 1.65k | self.read_control_extension()?; |
698 | 1.63k | goto!(BlockEnd, emit Decoded::BlockFinished(self.ext.id)) |
699 | | }, |
700 | | _ => { |
701 | 815 | goto!(BlockEnd, emit Decoded::BlockFinished(self.ext.id)) |
702 | | } |
703 | | } |
704 | | } else { |
705 | 258k | self.ext.is_block_end = false; |
706 | 258k | goto!(ExtensionDataBlock(b as usize), emit Decoded::SubBlockFinished(self.ext.id)) |
707 | | } |
708 | | } |
709 | | ApplicationExtension => { |
710 | 2.23k | debug_assert_eq!(0, b); |
711 | | // the parser removes sub-block lenghts, so app name and data are concatenated |
712 | 2.23k | if self.ext.data.len() >= 15 && &self.ext.data[1..13] == b"NETSCAPE2.0\x01" { |
713 | 776 | let repeat = &self.ext.data[13..15]; |
714 | 776 | let repeat = u16::from(repeat[0]) | u16::from(repeat[1]) << 8; |
715 | 776 | goto!(BlockEnd, emit Decoded::Repetitions(if repeat == 0 { Repeat::Infinite } else { Repeat::Finite(repeat) })) |
716 | | } else { |
717 | 1.45k | goto!(BlockEnd) |
718 | | } |
719 | | } |
720 | 1.85k | LocalPalette(left) => { |
721 | 1.85k | if left > 0 { |
722 | 255 | let n = cmp::min(left, buf.len()); |
723 | 255 | let src = &buf[..n]; |
724 | 255 | if let Some(pal) = self.try_current_frame()?.palette.as_mut() { |
725 | | // capacity has already been reserved in ImageBlockStart |
726 | 255 | if pal.capacity() - pal.len() >= src.len() { |
727 | 255 | pal.extend_from_slice(src); |
728 | 255 | } |
729 | 0 | } |
730 | 255 | goto!(n, LocalPalette(left - n)) |
731 | | } else { |
732 | 1.59k | goto!(LzwInit(b)) |
733 | | } |
734 | | } |
735 | 1.59k | LzwInit(min_code_size) => { |
736 | 1.59k | if !self.skip_frame_decoding { |
737 | | // Reset validates the min code size |
738 | 1.59k | self.lzw_reader.reset(min_code_size)?; |
739 | 1.58k | goto!(DecodeSubBlock(b as usize), emit Decoded::FrameMetadata(FrameDataType::Pixels)) |
740 | | } else { |
741 | 0 | LzwReader::check_code_size(min_code_size)?; |
742 | 0 | goto!(CopySubBlock(b as usize), emit Decoded::FrameMetadata(FrameDataType::Lzw { min_code_size })) |
743 | | } |
744 | | } |
745 | 0 | CopySubBlock(left) => { |
746 | 0 | debug_assert!(self.skip_frame_decoding); |
747 | 0 | if left > 0 { |
748 | 0 | let n = cmp::min(left, buf.len()); |
749 | 0 | let (consumed, copied) = write_into.append(&buf[..n], &self.memory_limit)?; |
750 | 0 | goto!(consumed, CopySubBlock(left - consumed), emit Decoded::LzwDataCopied(copied)) |
751 | 0 | } else if b != 0 { |
752 | 0 | goto!(CopySubBlock(b as usize)) |
753 | | } else { |
754 | 0 | goto!(0, FrameDecoded) |
755 | | } |
756 | | } |
757 | 729k | DecodeSubBlock(left) => { |
758 | 729k | debug_assert!(!self.skip_frame_decoding); |
759 | 729k | if left > 0 { |
760 | 469k | let n = cmp::min(left, buf.len()); |
761 | 469k | if self.lzw_reader.has_ended() || matches!(write_into, OutputBuffer::None) { |
762 | 9.19k | return goto!(n, DecodeSubBlock(left - n), emit Decoded::Nothing); |
763 | 460k | } |
764 | | |
765 | 459k | let (mut consumed, bytes_len, status) = |
766 | 460k | self.lzw_reader.decode_bytes(&buf[..n], write_into)?; |
767 | | |
768 | | // skip if can't make progress (decode would fail if check_for_end_code was set) |
769 | 459k | if matches!(status, LzwStatus::NoProgress) { |
770 | 441 | consumed = n; |
771 | 459k | } |
772 | | |
773 | 459k | let decoded = if let Some(bytes_len) = NonZeroUsize::new(bytes_len) { |
774 | 382k | Decoded::BytesDecoded(bytes_len) |
775 | | } else { |
776 | 77.4k | Decoded::Nothing |
777 | | }; |
778 | 459k | goto!(consumed, DecodeSubBlock(left - consumed), emit decoded) |
779 | 260k | } else if b != 0 { |
780 | | // decode next sub-block |
781 | 258k | goto!(DecodeSubBlock(b as usize)) |
782 | | } else { |
783 | 1.78k | let (_, bytes_len, status) = self.lzw_reader.decode_bytes(&[], write_into)?; |
784 | | |
785 | 1.77k | if let Some(bytes_len) = NonZeroUsize::new(bytes_len) { |
786 | 1.59k | goto!(0, DecodeSubBlock(0), emit Decoded::BytesDecoded(bytes_len)) |
787 | 178 | } else if matches!(status, LzwStatus::Ok) { |
788 | 58 | goto!(0, DecodeSubBlock(0), emit Decoded::Nothing) |
789 | 120 | } else if matches!(status, LzwStatus::Done) { |
790 | 4 | goto!(0, FrameDecoded) |
791 | | } else { |
792 | 116 | goto!(0, FrameDecoded) |
793 | | } |
794 | | } |
795 | | } |
796 | | FrameDecoded => { |
797 | | // end of image data reached |
798 | 120 | self.current = None; |
799 | 120 | debug_assert_eq!(0, b); |
800 | 120 | goto!(BlockEnd, emit Decoded::DataEnd) |
801 | | } |
802 | 0 | Trailer => goto!(0, Trailer, emit Decoded::Nothing), |
803 | | } |
804 | 1.28M | } |
805 | | |
806 | 1.65k | fn read_control_extension(&mut self) -> Result<(), DecodingError> { |
807 | 1.65k | if self.ext.data.len() != 5 { |
808 | 25 | return Err(DecodingError::format("control extension has wrong length")); |
809 | 1.63k | } |
810 | 1.63k | let control = &self.ext.data[1..]; |
811 | 1.63k | |
812 | 1.63k | let frame = self.current.get_or_insert_with(Frame::default); |
813 | 1.63k | let control_flags = control[0]; |
814 | 1.63k | frame.needs_user_input = control_flags & 0b10 != 0; |
815 | 1.63k | frame.dispose = match DisposalMethod::from_u8((control_flags & 0b11100) >> 2) { |
816 | 1.54k | Some(method) => method, |
817 | 93 | None => DisposalMethod::Any, |
818 | | }; |
819 | 1.63k | frame.delay = u16::from_le_bytes(control[1..3].try_into().unwrap()); |
820 | 1.63k | frame.transparent = (control_flags & 1 != 0).then_some(control[3]); |
821 | 1.63k | Ok(()) |
822 | 1.65k | } |
823 | | |
824 | 1.64k | fn add_frame(&mut self) { |
825 | 1.64k | if self.current.is_none() { |
826 | 1.56k | self.current = Some(Frame::default()); |
827 | 1.56k | } |
828 | 1.64k | } |
829 | | } |
830 | | |
831 | | #[test] |
832 | | fn error_cast() { |
833 | | let _ : Box<dyn error::Error> = DecodingError::format("testing").into(); |
834 | | } |