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