1 | use std::borrow::Cow; |
2 | use std::cmp; |
3 | use std::error; |
4 | use std::fmt; |
5 | use std::io; |
6 | use std::mem; |
7 | use std::default::Default; |
8 | use std::num::NonZeroUsize; |
9 | |
10 | use crate::Repeat; |
11 | use crate::MemoryLimit; |
12 | use crate::common::{AnyExtension, Block, DisposalMethod, Extension, Frame}; |
13 | use crate::reader::DecodeOptions; |
14 | |
15 | use weezl::{BitOrder, decode::Decoder as LzwDecoder, 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 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
29 | fmt::Display::fmt(&*self.underlying, f:fmt) |
30 | } |
31 | } |
32 | |
33 | impl error::Error for DecodingFormatError { |
34 | #[cold ] |
35 | fn source(&self) -> Option<&(dyn error::Error + 'static)> { |
36 | Some(&*self.underlying as _) |
37 | } |
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 | pub(crate) fn format(err: &'static str) -> Self { |
52 | DecodingError::Format(DecodingFormatError { |
53 | underlying: err.into(), |
54 | }) |
55 | } |
56 | } |
57 | |
58 | impl fmt::Display for DecodingError { |
59 | #[cold ] |
60 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
61 | match *self { |
62 | DecodingError::Format(ref d: &DecodingFormatError) => d.fmt(fmt), |
63 | DecodingError::Io(ref err: &Error) => err.fmt(fmt), |
64 | } |
65 | } |
66 | } |
67 | |
68 | impl error::Error for DecodingError { |
69 | #[cold ] |
70 | fn source(&self) -> Option<&(dyn error::Error + 'static)> { |
71 | match *self { |
72 | DecodingError::Format(ref err: &DecodingFormatError) => Some(err), |
73 | DecodingError::Io(ref err: &Error) => Some(err), |
74 | } |
75 | } |
76 | } |
77 | |
78 | impl From<io::Error> for DecodingError { |
79 | #[inline ] |
80 | fn from(err: io::Error) -> Self { |
81 | DecodingError::Io(err) |
82 | } |
83 | } |
84 | |
85 | impl From<io::ErrorKind> for DecodingError { |
86 | #[cold ] |
87 | fn from(err: io::ErrorKind) -> Self { |
88 | DecodingError::Io(io::Error::from(err)) |
89 | } |
90 | } |
91 | |
92 | impl From<DecodingFormatError> for DecodingError { |
93 | #[inline ] |
94 | fn from(err: DecodingFormatError) -> Self { |
95 | DecodingError::Format(err) |
96 | } |
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(u8, [u8; 6]), |
161 | U16Byte1(U16Value, u8), |
162 | U16(U16Value), |
163 | Byte(ByteValue), |
164 | GlobalPalette(usize), |
165 | BlockStart(u8), |
166 | BlockEnd, |
167 | ExtensionBlock(AnyExtension), |
168 | /// Collects data in ext.data |
169 | ExtensionDataBlock(usize), |
170 | ApplicationExtension, |
171 | LocalPalette(usize), |
172 | LzwInit(u8), |
173 | /// Decompresses LZW |
174 | DecodeSubBlock(usize), |
175 | /// Keeps LZW compressed |
176 | CopySubBlock(usize), |
177 | FrameDecoded, |
178 | Trailer, |
179 | } |
180 | use self::State::*; |
181 | |
182 | use super::converter::PixelConverter; |
183 | |
184 | /// U16 values that may occur in a GIF image |
185 | #[derive (Debug, Copy, Clone)] |
186 | enum U16Value { |
187 | /// Logical screen descriptor width |
188 | ScreenWidth, |
189 | /// Logical screen descriptor height |
190 | ScreenHeight, |
191 | /// Delay time |
192 | Delay, |
193 | /// Left frame offset |
194 | ImageLeft, |
195 | /// Top frame offset |
196 | ImageTop, |
197 | /// Frame width |
198 | ImageWidth, |
199 | /// Frame height |
200 | ImageHeight, |
201 | } |
202 | |
203 | /// Single byte screen descriptor values |
204 | #[derive (Debug, Copy, Clone)] |
205 | enum ByteValue { |
206 | GlobalFlags, |
207 | Background { global_flags: u8 }, |
208 | AspectRatio { global_flags: u8 }, |
209 | ControlFlags, |
210 | ImageFlags, |
211 | TransparentIdx, |
212 | CodeSize, |
213 | } |
214 | |
215 | /// Decoder for `Frame::make_lzw_pre_encoded` |
216 | pub struct FrameDecoder { |
217 | lzw_reader: LzwReader, |
218 | pixel_converter: PixelConverter, |
219 | } |
220 | |
221 | impl FrameDecoder { |
222 | /// See also `set_global_palette` |
223 | #[inline ] |
224 | #[must_use ] |
225 | pub fn new(options: DecodeOptions) -> Self { |
226 | Self { |
227 | lzw_reader: LzwReader::new(options.check_for_end_code), |
228 | pixel_converter: PixelConverter::new(options.color_output, options.memory_limit), |
229 | } |
230 | } |
231 | |
232 | /// Palette used for RGBA conversion |
233 | #[inline ] |
234 | pub fn set_global_palette(&mut self, palette: Vec<u8>) { |
235 | self.pixel_converter.set_global_palette(palette); |
236 | } |
237 | |
238 | /// Converts the frame in-place, replacing its LZW buffer with pixels. |
239 | /// |
240 | /// If you get an error about invalid min code size, the buffer was probably pixels, not compressed data. |
241 | #[inline ] |
242 | pub fn decode_lzw_encoded_frame(&mut self, frame: &mut Frame<'_>) -> Result<(), DecodingError> { |
243 | let pixel_bytes = self.pixel_converter.check_buffer_size(frame)?; |
244 | let mut vec = vec![0; pixel_bytes]; |
245 | self.decode_lzw_encoded_frame_into_buffer(frame, &mut vec)?; |
246 | frame.buffer = Cow::Owned(vec); |
247 | frame.interlaced = false; |
248 | Ok(()) |
249 | } |
250 | |
251 | /// Converts into the given buffer. It must be [`buffer_size()`] bytes large. |
252 | /// |
253 | /// Pixels are always deinterlaced, so update `frame.interlaced` afterwards if you're putting the buffer back into the frame. |
254 | pub fn decode_lzw_encoded_frame_into_buffer(&mut self, frame: &Frame<'_>, buf: &mut [u8]) -> Result<(), DecodingError> { |
255 | let (&min_code_size, mut data) = frame.buffer.split_first().unwrap_or((&2, &[])); |
256 | self.lzw_reader.reset(min_code_size)?; |
257 | let lzw_reader = &mut self.lzw_reader; |
258 | self.pixel_converter.read_into_buffer(frame, buf, &mut move |out| { |
259 | loop { |
260 | let (bytes_read, bytes_written) = lzw_reader.decode_bytes(data, out)?; |
261 | data = &data.get(bytes_read..).unwrap_or_default(); |
262 | if bytes_written > 0 || bytes_read == 0 || data.is_empty() { |
263 | return Ok(bytes_written) |
264 | } |
265 | } |
266 | })?; |
267 | Ok(()) |
268 | } |
269 | |
270 | /// Number of bytes required for `decode_lzw_encoded_frame_into_buffer` |
271 | #[inline ] |
272 | #[must_use ] |
273 | pub fn buffer_size(&self, frame: &Frame<'_>) -> usize { |
274 | self.pixel_converter.buffer_size(frame).unwrap() |
275 | } |
276 | } |
277 | |
278 | struct LzwReader { |
279 | decoder: Option<LzwDecoder>, |
280 | min_code_size: u8, |
281 | check_for_end_code: bool, |
282 | } |
283 | |
284 | impl LzwReader { |
285 | pub fn new(check_for_end_code: bool) -> Self { |
286 | Self { |
287 | decoder: None, |
288 | min_code_size: 0, |
289 | check_for_end_code, |
290 | } |
291 | } |
292 | |
293 | pub fn check_code_size(min_code_size: u8) -> Result<(), DecodingError> { |
294 | // LZW spec: max 12 bits per code. This check helps catch confusion |
295 | // between LZW-compressed buffers and raw pixel data |
296 | if min_code_size > 11 || min_code_size < 1 { |
297 | return Err(DecodingError::format("invalid minimal code size" )); |
298 | } |
299 | Ok(()) |
300 | } |
301 | |
302 | pub fn reset(&mut self, min_code_size: u8) -> Result<(), DecodingError> { |
303 | Self::check_code_size(min_code_size)?; |
304 | |
305 | // The decoder can be reused if the code size stayed the same |
306 | if self.min_code_size != min_code_size || self.decoder.is_none() { |
307 | self.min_code_size = min_code_size; |
308 | self.decoder = Some(LzwDecoder::new(BitOrder::Lsb, min_code_size)); |
309 | } else { |
310 | self.decoder.as_mut().ok_or_else(|| DecodingError::format("bad state" ))?.reset(); |
311 | } |
312 | |
313 | Ok(()) |
314 | } |
315 | |
316 | pub fn has_ended(&self) -> bool { |
317 | self.decoder.as_ref().map_or(true, |e| e.has_ended()) |
318 | } |
319 | |
320 | pub fn decode_bytes(&mut self, lzw_data: &[u8], decode_buffer: &mut OutputBuffer<'_>) -> io::Result<(usize, usize)> { |
321 | let decoder = self.decoder.as_mut().ok_or(io::ErrorKind::Unsupported)?; |
322 | |
323 | let decode_buffer = match decode_buffer { |
324 | OutputBuffer::Slice(buf) => &mut **buf, |
325 | OutputBuffer::None => &mut [], |
326 | OutputBuffer::Vec(_) => return Err(io::Error::from(io::ErrorKind::Unsupported)), |
327 | }; |
328 | |
329 | let decoded = decoder.decode_bytes(lzw_data, decode_buffer); |
330 | |
331 | match decoded.status { |
332 | Ok(LzwStatus::Done | LzwStatus::Ok) => {}, |
333 | Ok(LzwStatus::NoProgress) => { |
334 | if self.check_for_end_code { |
335 | return Err(io::Error::new(io::ErrorKind::InvalidData, "no end code in lzw stream" )); |
336 | } |
337 | }, |
338 | Err(err @ LzwError::InvalidCode) => { |
339 | return Err(io::Error::new(io::ErrorKind::InvalidData, err)); |
340 | } |
341 | } |
342 | Ok((decoded.consumed_in, decoded.consumed_out)) |
343 | } |
344 | } |
345 | |
346 | /// GIF decoder which emits [low-level events](Decoded) for items in the GIF file |
347 | /// |
348 | /// To just get GIF frames, use [`crate::Decoder`] instead. |
349 | pub struct StreamingDecoder { |
350 | state: State, |
351 | lzw_reader: LzwReader, |
352 | skip_frame_decoding: bool, |
353 | check_frame_consistency: bool, |
354 | allow_unknown_blocks: bool, |
355 | memory_limit: MemoryLimit, |
356 | version: Version, |
357 | width: u16, |
358 | height: u16, |
359 | global_color_table: Vec<u8>, |
360 | background_color: [u8; 4], |
361 | /// ext buffer |
362 | ext: ExtensionData, |
363 | /// Frame data |
364 | current: Option<Frame<'static>>, |
365 | /// Needs to emit `HeaderEnd` once |
366 | header_end_reached: bool, |
367 | } |
368 | |
369 | /// One version number of the GIF standard. |
370 | #[derive (Copy, Clone, Debug, PartialEq, Eq, Hash)] |
371 | pub enum Version { |
372 | /// Version 87a, from May 1987. |
373 | V87a, |
374 | /// Version 89a, from July 1989. |
375 | V89a, |
376 | } |
377 | |
378 | struct ExtensionData { |
379 | id: AnyExtension, |
380 | data: Vec<u8>, |
381 | is_block_end: bool, |
382 | } |
383 | |
384 | /// Destination to write to for `StreamingDecoder::update` |
385 | pub enum OutputBuffer<'a> { |
386 | /// Overwrite bytes |
387 | Slice(&'a mut [u8]), |
388 | /// Append LZW bytes |
389 | Vec(&'a mut Vec<u8>), |
390 | /// Discard bytes |
391 | None, |
392 | } |
393 | |
394 | impl<'a> OutputBuffer<'a> { |
395 | fn append(&mut self, buf: &[u8], memory_limit: &MemoryLimit) -> Result<(usize, usize), DecodingError> { |
396 | let (consumed, copied) = match self { |
397 | OutputBuffer::Slice(slice) => { |
398 | let len = cmp::min(buf.len(), slice.len()); |
399 | slice[..len].copy_from_slice(&buf[..len]); |
400 | (len, len) |
401 | }, |
402 | OutputBuffer::Vec(vec) => { |
403 | let vec: &mut Vec<u8> = vec; |
404 | let len = buf.len(); |
405 | memory_limit.check_size(vec.len() + len)?; |
406 | vec.try_reserve(len).map_err(|_| io::ErrorKind::OutOfMemory)?; |
407 | if vec.capacity() - vec.len() >= len { |
408 | vec.extend_from_slice(buf); |
409 | } |
410 | (len, len) |
411 | }, |
412 | // It's valid that bytes are discarded. For example, |
413 | // when using next_frame_info() with skip_frame_decoding to only get metadata. |
414 | OutputBuffer::None => (buf.len(), 0), |
415 | }; |
416 | Ok((consumed, copied)) |
417 | } |
418 | } |
419 | |
420 | impl StreamingDecoder { |
421 | /// Creates a new streaming decoder |
422 | #[must_use ] |
423 | pub fn new() -> StreamingDecoder { |
424 | let options = DecodeOptions::new(); |
425 | Self::with_options(&options) |
426 | } |
427 | |
428 | pub(crate) fn with_options(options: &DecodeOptions) -> Self { |
429 | StreamingDecoder { |
430 | state: Magic(0, [0; 6]), |
431 | lzw_reader: LzwReader::new(options.check_for_end_code), |
432 | skip_frame_decoding: options.skip_frame_decoding, |
433 | check_frame_consistency: options.check_frame_consistency, |
434 | allow_unknown_blocks: options.allow_unknown_blocks, |
435 | memory_limit: options.memory_limit.clone(), |
436 | version: Version::V87a, |
437 | width: 0, |
438 | height: 0, |
439 | global_color_table: Vec::new(), |
440 | background_color: [0, 0, 0, 0xFF], |
441 | ext: ExtensionData { |
442 | id: AnyExtension(0), |
443 | data: Vec::with_capacity(256), // 0xFF + 1 byte length |
444 | is_block_end: true, |
445 | }, |
446 | current: None, |
447 | header_end_reached: false, |
448 | } |
449 | } |
450 | |
451 | /// Updates the internal state of the decoder. |
452 | /// |
453 | /// Returns the number of bytes consumed from the input buffer |
454 | /// and the last decoding result. |
455 | pub fn update<'a>( |
456 | &'a mut self, |
457 | mut buf: &[u8], |
458 | write_into: &mut OutputBuffer<'_>, |
459 | ) -> Result<(usize, Decoded), DecodingError> { |
460 | let len = buf.len(); |
461 | while !buf.is_empty() { |
462 | let (bytes, decoded) = self.next_state(buf, write_into)?; |
463 | buf = buf.get(bytes..).unwrap_or_default(); |
464 | match decoded { |
465 | Decoded::Nothing => {}, |
466 | result => { |
467 | return Ok((len-buf.len(), result)); |
468 | }, |
469 | }; |
470 | } |
471 | Ok((len - buf.len(), Decoded::Nothing)) |
472 | } |
473 | |
474 | /// Returns the data of the last extension that has been decoded. |
475 | #[must_use ] |
476 | pub fn last_ext(&self) -> (AnyExtension, &[u8], bool) { |
477 | (self.ext.id, &self.ext.data, self.ext.is_block_end) |
478 | } |
479 | |
480 | /// Current frame info as a mutable ref. |
481 | #[must_use ] |
482 | #[track_caller ] |
483 | pub fn current_frame_mut(&mut self) -> &mut Frame<'static> { |
484 | self.current.as_mut().unwrap() |
485 | } |
486 | |
487 | /// Current frame info as a ref. |
488 | #[track_caller ] |
489 | #[must_use ] |
490 | pub fn current_frame(&self) -> &Frame<'static> { |
491 | self.current.as_ref().unwrap() |
492 | } |
493 | |
494 | /// Current frame info as a mutable ref. |
495 | #[inline (always)] |
496 | fn try_current_frame(&mut self) -> Result<&mut Frame<'static>, DecodingError> { |
497 | self.current.as_mut().ok_or_else(|| DecodingError::format("bad state" )) |
498 | } |
499 | |
500 | /// Width of the image |
501 | #[must_use ] |
502 | pub fn width(&self) -> u16 { |
503 | self.width |
504 | } |
505 | |
506 | /// Height of the image |
507 | #[must_use ] |
508 | pub fn height(&self) -> u16 { |
509 | self.height |
510 | } |
511 | |
512 | /// The version number of the GIF standard used in this image. |
513 | /// |
514 | /// We suppose a minimum of `V87a` compatibility. This value will be reported until we have |
515 | /// read the version information in the magic header bytes. |
516 | #[must_use ] |
517 | pub fn version(&self) -> Version { |
518 | self.version |
519 | } |
520 | |
521 | #[inline ] |
522 | fn next_state(&mut self, buf: &[u8], write_into: &mut OutputBuffer<'_>) -> Result<(usize, Decoded), DecodingError> { |
523 | macro_rules! goto ( |
524 | ($n:expr, $state:expr) => ({ |
525 | self.state = $state; |
526 | Ok(($n, Decoded::Nothing)) |
527 | }); |
528 | ($state:expr) => ({ |
529 | self.state = $state; |
530 | Ok((1, Decoded::Nothing)) |
531 | }); |
532 | ($n:expr, $state:expr, emit $res:expr) => ({ |
533 | self.state = $state; |
534 | Ok(($n, $res)) |
535 | }); |
536 | ($state:expr, emit $res:expr) => ({ |
537 | self.state = $state; |
538 | Ok((1, $res)) |
539 | }) |
540 | ); |
541 | |
542 | let b = *buf.get(0).ok_or(io::ErrorKind::UnexpectedEof)?; |
543 | |
544 | match self.state { |
545 | Magic(i, mut version) => if i < 6 { |
546 | version[i as usize] = b; |
547 | goto!(Magic(i+1, version)) |
548 | } else if &version[..3] == b"GIF" { |
549 | self.version = match &version[3..] { |
550 | b"87a" => Version::V87a, |
551 | b"89a" => Version::V89a, |
552 | _ => return Err(DecodingError::format("malformed GIF header" )) |
553 | }; |
554 | goto!(U16Byte1(U16Value::ScreenWidth, b)) |
555 | } else { |
556 | Err(DecodingError::format("malformed GIF header" )) |
557 | }, |
558 | Byte(value) => { |
559 | use self::ByteValue::*; |
560 | match value { |
561 | GlobalFlags => { |
562 | goto!(Byte(Background { global_flags: b })) |
563 | }, |
564 | Background { global_flags } => { |
565 | goto!( |
566 | Byte(AspectRatio { global_flags }), |
567 | emit Decoded::BackgroundColor(b) |
568 | ) |
569 | }, |
570 | AspectRatio { global_flags } => { |
571 | let global_table = global_flags & 0x80 != 0; |
572 | let table_size = if global_table { |
573 | let table_size = PLTE_CHANNELS * (1 << ((global_flags & 0b111) + 1) as usize); |
574 | self.global_color_table.try_reserve_exact(table_size).map_err(|_| io::ErrorKind::OutOfMemory)?; |
575 | table_size |
576 | } else { |
577 | 0usize |
578 | }; |
579 | goto!(GlobalPalette(table_size)) |
580 | }, |
581 | ControlFlags => { |
582 | self.ext.data.push(b); |
583 | let frame = self.try_current_frame()?; |
584 | let control_flags = b; |
585 | if control_flags & 1 != 0 { |
586 | // Set to Some(...), gets overwritten later |
587 | frame.transparent = Some(0); |
588 | } |
589 | frame.needs_user_input = |
590 | control_flags & 0b10 != 0; |
591 | frame.dispose = match DisposalMethod::from_u8( |
592 | (control_flags & 0b11100) >> 2 |
593 | ) { |
594 | Some(method) => method, |
595 | None => DisposalMethod::Any |
596 | }; |
597 | goto!(U16(U16Value::Delay)) |
598 | } |
599 | TransparentIdx => { |
600 | self.ext.data.push(b); |
601 | if let Some(ref mut idx) = self.try_current_frame()?.transparent { |
602 | *idx = b; |
603 | } |
604 | goto!(ExtensionDataBlock(0)) |
605 | } |
606 | ImageFlags => { |
607 | let local_table = (b & 0b1000_0000) != 0; |
608 | let interlaced = (b & 0b0100_0000) != 0; |
609 | let table_size = b & 0b0000_0111; |
610 | let check_frame_consistency = self.check_frame_consistency; |
611 | let (width, height) = (self.width, self.height); |
612 | |
613 | let frame = self.try_current_frame()?; |
614 | |
615 | frame.interlaced = interlaced; |
616 | if check_frame_consistency { |
617 | // Consistency checks. |
618 | if width.checked_sub(frame.width) < Some(frame.left) |
619 | || height.checked_sub(frame.height) < Some(frame.top) |
620 | { |
621 | return Err(DecodingError::format("frame descriptor is out-of-bounds" )) |
622 | } |
623 | } |
624 | |
625 | if local_table { |
626 | let entries = PLTE_CHANNELS * (1 << (table_size + 1)); |
627 | let mut pal = Vec::new(); |
628 | pal.try_reserve_exact(entries).map_err(|_| io::ErrorKind::OutOfMemory)?; |
629 | frame.palette = Some(pal); |
630 | goto!(LocalPalette(entries)) |
631 | } else { |
632 | goto!(Byte(CodeSize)) |
633 | } |
634 | } |
635 | CodeSize => goto!(LzwInit(b)), |
636 | } |
637 | } |
638 | GlobalPalette(left) => { |
639 | let n = cmp::min(left, buf.len()); |
640 | if left > 0 { |
641 | self.global_color_table.extend_from_slice(&buf[..n]); |
642 | goto!(n, GlobalPalette(left - n)) |
643 | } else { |
644 | let idx = self.background_color[0]; |
645 | match self.global_color_table.chunks_exact(PLTE_CHANNELS).nth(idx as usize) { |
646 | Some(chunk) => self.background_color[..PLTE_CHANNELS] |
647 | .copy_from_slice(&chunk[..PLTE_CHANNELS]), |
648 | None => self.background_color[0] = 0 |
649 | } |
650 | goto!(BlockStart(b), emit Decoded::GlobalPalette( |
651 | mem::take(&mut self.global_color_table).into_boxed_slice() |
652 | )) |
653 | } |
654 | } |
655 | BlockStart(type_) => { |
656 | if !self.header_end_reached && type_ != Block::Extension as u8 { |
657 | self.header_end_reached = true; |
658 | return goto!(0, BlockStart(type_), emit Decoded::HeaderEnd); |
659 | } |
660 | |
661 | match Block::from_u8(type_) { |
662 | Some(Block::Image) => { |
663 | self.add_frame(); |
664 | goto!(U16Byte1(U16Value::ImageLeft, b), emit Decoded::BlockStart(Block::Image)) |
665 | } |
666 | Some(Block::Extension) => { |
667 | goto!(ExtensionBlock(AnyExtension(b)), emit Decoded::BlockStart(Block::Extension)) |
668 | } |
669 | Some(Block::Trailer) => { |
670 | // The `Trailer` is the final state, and isn't reachable without extraneous data after the end of file |
671 | goto!(Trailer, emit Decoded::BlockStart(Block::Trailer)) |
672 | } |
673 | None => { |
674 | if self.allow_unknown_blocks { |
675 | goto!(ExtensionDataBlock(b as usize)) |
676 | } else { |
677 | Err(DecodingError::format("unknown block type encountered" )) |
678 | } |
679 | } |
680 | } |
681 | }, |
682 | BlockEnd => { |
683 | if b == Block::Trailer as u8 { |
684 | // can't consume yet, because the trailer is not a real block, |
685 | // and won't have futher data for BlockStart |
686 | goto!(0, BlockStart(b)) |
687 | } else { |
688 | goto!(BlockStart(b)) |
689 | } |
690 | } |
691 | ExtensionBlock(id) => { |
692 | use Extension::*; |
693 | self.ext.id = id; |
694 | self.ext.data.clear(); |
695 | self.ext.data.push(b); |
696 | if let Some(ext) = Extension::from_u8(id.0) { |
697 | match ext { |
698 | Control => { |
699 | goto!(self.read_control_extension(b)?) |
700 | } |
701 | Text | Comment | Application => { |
702 | goto!(ExtensionDataBlock(b as usize)) |
703 | } |
704 | } |
705 | } else { |
706 | Err(DecodingError::format("unknown block type encountered" )) |
707 | } |
708 | } |
709 | ExtensionDataBlock(left) => { |
710 | if left > 0 { |
711 | let n = cmp::min(left, buf.len()); |
712 | self.memory_limit.check_size(self.ext.data.len() + n)?; |
713 | self.ext.data.try_reserve(n).map_err(|_| io::Error::from(io::ErrorKind::OutOfMemory))?; |
714 | self.ext.data.extend_from_slice(&buf[..n]); |
715 | goto!(n, ExtensionDataBlock(left - n)) |
716 | } else if b == 0 { |
717 | self.ext.is_block_end = true; |
718 | if self.ext.id.into_known() == Some(Extension::Application) { |
719 | goto!(0, ApplicationExtension, emit Decoded::BlockFinished(self.ext.id)) |
720 | } else { |
721 | goto!(BlockEnd, emit Decoded::BlockFinished(self.ext.id)) |
722 | } |
723 | } else { |
724 | self.ext.is_block_end = false; |
725 | goto!(ExtensionDataBlock(b as usize), emit Decoded::SubBlockFinished(self.ext.id)) |
726 | } |
727 | } |
728 | ApplicationExtension => { |
729 | debug_assert_eq!(0, b); |
730 | // the parser removes sub-block lenghts, so app name and data are concatenated |
731 | if self.ext.data.len() >= 15 && &self.ext.data[1..13] == b"NETSCAPE2.0 \x01" { |
732 | let repeat = &self.ext.data[13..15]; |
733 | let repeat = u16::from(repeat[0]) | u16::from(repeat[1]) << 8; |
734 | goto!(BlockEnd, emit Decoded::Repetitions(if repeat == 0 { Repeat::Infinite } else { Repeat::Finite(repeat) })) |
735 | } else { |
736 | goto!(BlockEnd) |
737 | } |
738 | } |
739 | LocalPalette(left) => { |
740 | let n = cmp::min(left, buf.len()); |
741 | if left > 0 { |
742 | let src = &buf[..n]; |
743 | if let Some(pal) = self.try_current_frame()?.palette.as_mut() { |
744 | // capacity has already been reserved in ImageFlags |
745 | if pal.capacity() - pal.len() >= src.len() { |
746 | pal.extend_from_slice(src); |
747 | } |
748 | } |
749 | goto!(n, LocalPalette(left - n)) |
750 | } else { |
751 | goto!(LzwInit(b)) |
752 | } |
753 | } |
754 | LzwInit(min_code_size) => { |
755 | if !self.skip_frame_decoding { |
756 | // Reset validates the min code size |
757 | self.lzw_reader.reset(min_code_size)?; |
758 | goto!(DecodeSubBlock(b as usize), emit Decoded::FrameMetadata(FrameDataType::Pixels)) |
759 | } else { |
760 | LzwReader::check_code_size(min_code_size)?; |
761 | goto!(CopySubBlock(b as usize), emit Decoded::FrameMetadata(FrameDataType::Lzw { min_code_size })) |
762 | } |
763 | } |
764 | CopySubBlock(left) => { |
765 | debug_assert!(self.skip_frame_decoding); |
766 | if left > 0 { |
767 | let n = cmp::min(left, buf.len()); |
768 | let (consumed, copied) = write_into.append(&buf[..n], &self.memory_limit)?; |
769 | goto!(consumed, CopySubBlock(left - consumed), emit Decoded::LzwDataCopied(copied)) |
770 | } else if b != 0 { |
771 | goto!(CopySubBlock(b as usize)) |
772 | } else { |
773 | goto!(0, FrameDecoded) |
774 | } |
775 | } |
776 | DecodeSubBlock(left) => { |
777 | debug_assert!(!self.skip_frame_decoding); |
778 | if left > 0 { |
779 | let n = cmp::min(left, buf.len()); |
780 | if self.lzw_reader.has_ended() || matches!(write_into, OutputBuffer::None) { |
781 | return goto!(n, DecodeSubBlock(left - n), emit Decoded::Nothing); |
782 | } |
783 | |
784 | let (mut consumed, bytes_len) = self.lzw_reader.decode_bytes(&buf[..n], write_into)?; |
785 | |
786 | // skip if can't make progress (decode would fail if check_for_end_code was set) |
787 | if consumed == 0 && bytes_len == 0 { |
788 | consumed = n; |
789 | } |
790 | |
791 | let decoded = if let Some(bytes_len) = NonZeroUsize::new(bytes_len) { |
792 | Decoded::BytesDecoded(bytes_len) |
793 | } else { |
794 | Decoded::Nothing |
795 | }; |
796 | goto!(consumed, DecodeSubBlock(left - consumed), emit decoded) |
797 | } else if b != 0 { // decode next sub-block |
798 | goto!(DecodeSubBlock(b as usize)) |
799 | } else { |
800 | let (_, bytes_len) = self.lzw_reader.decode_bytes(&[], write_into)?; |
801 | |
802 | if let Some(bytes_len) = NonZeroUsize::new(bytes_len) { |
803 | goto!(0, DecodeSubBlock(0), emit Decoded::BytesDecoded(bytes_len)) |
804 | } else { |
805 | goto!(0, FrameDecoded) |
806 | } |
807 | } |
808 | } |
809 | U16(next) => goto!(U16Byte1(next, b)), |
810 | U16Byte1(next, value) => { |
811 | goto!(self.read_second_byte(next, value, b)?) |
812 | } |
813 | FrameDecoded => { |
814 | // end of image data reached |
815 | self.current = None; |
816 | debug_assert_eq!(0, b); |
817 | goto!(BlockEnd, emit Decoded::DataEnd) |
818 | } |
819 | Trailer => goto!(0, Trailer, emit Decoded::Nothing), |
820 | } |
821 | } |
822 | |
823 | fn read_second_byte(&mut self, next: U16Value, value: u8, b: u8) -> Result<State, DecodingError> { |
824 | use self::U16Value::*; |
825 | let value = (u16::from(b) << 8) | u16::from(value); |
826 | Ok(match (next, value) { |
827 | (ScreenWidth, width) => { |
828 | self.width = width; |
829 | U16(U16Value::ScreenHeight) |
830 | }, |
831 | (ScreenHeight, height) => { |
832 | self.height = height; |
833 | Byte(ByteValue::GlobalFlags) |
834 | }, |
835 | (Delay, delay) => { |
836 | self.try_current_frame()?.delay = delay; |
837 | self.ext.data.push(value as u8); |
838 | self.ext.data.push(b); |
839 | Byte(ByteValue::TransparentIdx) |
840 | }, |
841 | (ImageLeft, left) => { |
842 | self.try_current_frame()?.left = left; |
843 | U16(U16Value::ImageTop) |
844 | }, |
845 | (ImageTop, top) => { |
846 | self.try_current_frame()?.top = top; |
847 | U16(U16Value::ImageWidth) |
848 | }, |
849 | (ImageWidth, width) => { |
850 | self.try_current_frame()?.width = width; |
851 | U16(U16Value::ImageHeight) |
852 | }, |
853 | (ImageHeight, height) => { |
854 | self.try_current_frame()?.height = height; |
855 | Byte(ByteValue::ImageFlags) |
856 | } |
857 | }) |
858 | } |
859 | |
860 | fn read_control_extension(&mut self, b: u8) -> Result<State, DecodingError> { |
861 | self.add_frame(); |
862 | self.ext.data.push(b); |
863 | if b != 4 { |
864 | return Err(DecodingError::format("control extension has wrong length" )); |
865 | } |
866 | Ok(Byte(ByteValue::ControlFlags)) |
867 | } |
868 | |
869 | fn add_frame(&mut self) { |
870 | if self.current.is_none() { |
871 | self.current = Some(Frame::default()); |
872 | } |
873 | } |
874 | } |
875 | |
876 | #[test ] |
877 | fn error_cast() { |
878 | let _ : Box<dyn error::Error> = DecodingError::format(err:"testing" ).into(); |
879 | } |
880 | |