Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extract next_state bits into functions #181

Merged
merged 3 commits into from
Jan 15, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 82 additions & 61 deletions src/reader/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ impl LzwReader {
self.min_code_size = min_code_size;
self.decoder = Some(LzwDecoder::new(BitOrder::Lsb, min_code_size));
} else {
self.decoder.as_mut().unwrap().reset();
self.decoder.as_mut().ok_or_else(|| DecodingError::format("bad state"))?.reset();
}

Ok(())
Expand Down Expand Up @@ -386,6 +386,32 @@ pub enum OutputBuffer<'a> {
None,
}

impl<'a> OutputBuffer<'a> {
fn append(&mut self, buf: &[u8], memory_limit: &MemoryLimit) -> Result<(usize, usize), DecodingError> {
let (consumed, copied) = match self {
OutputBuffer::Slice(slice) => {
let len = cmp::min(buf.len(), slice.len());
slice[..len].copy_from_slice(&buf[..len]);
(len, len)
},
OutputBuffer::Vec(vec) => {
let vec: &mut Vec<u8> = vec;
let len = buf.len();
memory_limit.check_size(vec.len() + len)?;
vec.try_reserve(len).map_err(|_| io::ErrorKind::OutOfMemory)?;
if vec.capacity() - vec.len() >= len {
vec.extend_from_slice(buf);
}
(len, len)
},
// It's valid that bytes are discarded. For example,
// when using next_frame_info() with skip_frame_decoding to only get metadata.
OutputBuffer::None => (buf.len(), 0),
};
Ok((consumed, copied))
}
}

impl StreamingDecoder {
/// Creates a new streaming decoder
#[must_use]
Expand Down Expand Up @@ -429,7 +455,7 @@ impl StreamingDecoder {
let len = buf.len();
while !buf.is_empty() {
let (bytes, decoded) = self.next_state(buf, write_into)?;
buf = &buf[bytes..];
buf = buf.get(bytes..).unwrap_or_default();
match decoded {
Decoded::Nothing => {},
result => {
Expand All @@ -446,20 +472,26 @@ impl StreamingDecoder {
(self.ext.id, &self.ext.data, self.ext.is_block_end)
}

#[inline(always)]
/// Current frame info as a mutable ref.
#[must_use]
#[track_caller]
pub fn current_frame_mut(&mut self) -> &mut Frame<'static> {
self.current.as_mut().unwrap()
}

/// Current frame info as a ref.
#[inline(always)]
#[track_caller]
#[must_use]
pub fn current_frame(&self) -> &Frame<'static> {
self.current.as_ref().unwrap()
}

/// Current frame info as a mutable ref.
#[inline(always)]
fn try_current_frame(&mut self) -> Result<&mut Frame<'static>, DecodingError> {
self.current.as_mut().ok_or_else(|| DecodingError::format("bad state"))
}

/// Width of the image
#[must_use]
pub fn width(&self) -> u16 {
Expand Down Expand Up @@ -518,43 +550,6 @@ impl StreamingDecoder {
} else {
Err(DecodingError::format("malformed GIF header"))
},
U16(next) => goto!(U16Byte1(next, b)),
U16Byte1(next, value) => {
use self::U16Value::*;
let value = (u16::from(b) << 8) | u16::from(value);
match (next, value) {
(ScreenWidth, width) => {
self.width = width;
goto!(U16(U16Value::ScreenHeight))
},
(ScreenHeight, height) => {
self.height = height;
goto!(Byte(ByteValue::GlobalFlags))
},
(Delay, delay) => {
self.current_frame_mut().delay = delay;
self.ext.data.push(value as u8);
self.ext.data.push(b);
goto!(Byte(ByteValue::TransparentIdx))
},
(ImageLeft, left) => {
self.current_frame_mut().left = left;
goto!(U16(U16Value::ImageTop))
},
(ImageTop, top) => {
self.current_frame_mut().top = top;
goto!(U16(U16Value::ImageWidth))
},
(ImageWidth, width) => {
self.current_frame_mut().width = width;
goto!(U16(U16Value::ImageHeight))
},
(ImageHeight, height) => {
self.current_frame_mut().height = height;
goto!(Byte(ByteValue::ImageFlags))
}
}
}
Byte(value) => {
use self::ByteValue::*;
match value {
Expand All @@ -580,7 +575,7 @@ impl StreamingDecoder {
},
ControlFlags => {
self.ext.data.push(b);
let frame = self.current_frame_mut();
let frame = self.try_current_frame()?;
let control_flags = b;
if control_flags & 1 != 0 {
// Set to Some(...), gets overwritten later
Expand All @@ -598,7 +593,7 @@ impl StreamingDecoder {
}
TransparentIdx => {
self.ext.data.push(b);
if let Some(ref mut idx) = self.current_frame_mut().transparent {
if let Some(ref mut idx) = self.try_current_frame()?.transparent {
*idx = b;
}
goto!(ExtensionDataBlock(0))
Expand All @@ -610,7 +605,7 @@ impl StreamingDecoder {
let check_frame_consistency = self.check_frame_consistency;
let (width, height) = (self.width, self.height);

let frame = self.current_frame_mut();
let frame = self.try_current_frame()?;

frame.interlaced = interlaced;
if check_frame_consistency {
Expand Down Expand Up @@ -740,7 +735,7 @@ impl StreamingDecoder {
let n = cmp::min(left, buf.len());
if left > 0 {
let src = &buf[..n];
if let Some(pal) = self.current_frame_mut().palette.as_mut() {
if let Some(pal) = self.try_current_frame()?.palette.as_mut() {
// capacity has already been reserved in ImageFlags
if pal.capacity() - pal.len() >= src.len() {
pal.extend_from_slice(src);
Expand All @@ -764,22 +759,7 @@ impl StreamingDecoder {
debug_assert!(self.skip_frame_decoding);
if left > 0 {
let n = cmp::min(left, buf.len());
let (consumed, copied) = match write_into {
OutputBuffer::Slice(slice) => {
let len = cmp::min(n, slice.len());
slice[..len].copy_from_slice(&buf[..len]);
(len, len)
},
OutputBuffer::Vec(vec) => {
self.memory_limit.check_size(vec.len() + n)?;
vec.try_reserve(n).map_err(|_| io::ErrorKind::OutOfMemory)?;
vec.extend_from_slice(&buf[..n]);
(n, n)
},
// It's valid that bytes are discarded. For example,
// when using next_frame_info() with skip_frame_decoding to only get metadata.
OutputBuffer::None => (n, 0),
};
let (consumed, copied) = write_into.append(&buf[..n], &self.memory_limit)?;
goto!(consumed, CopySubBlock(left - consumed), emit Decoded::LzwDataCopied(copied))
} else if b != 0 {
goto!(CopySubBlock(b as usize))
Expand Down Expand Up @@ -820,6 +800,10 @@ impl StreamingDecoder {
}
}
}
U16(next) => goto!(U16Byte1(next, b)),
U16Byte1(next, value) => {
goto!(self.read_second_byte(next, value, b)?)
}
FrameDecoded => {
// end of image data reached
self.current = None;
Expand All @@ -830,6 +814,43 @@ impl StreamingDecoder {
}
}

fn read_second_byte(&mut self, next: U16Value, value: u8, b: u8) -> Result<State, DecodingError> {
use self::U16Value::*;
let value = (u16::from(b) << 8) | u16::from(value);
Ok(match (next, value) {
(ScreenWidth, width) => {
self.width = width;
U16(U16Value::ScreenHeight)
},
(ScreenHeight, height) => {
self.height = height;
Byte(ByteValue::GlobalFlags)
},
(Delay, delay) => {
self.try_current_frame()?.delay = delay;
self.ext.data.push(value as u8);
self.ext.data.push(b);
Byte(ByteValue::TransparentIdx)
},
(ImageLeft, left) => {
self.try_current_frame()?.left = left;
U16(U16Value::ImageTop)
},
(ImageTop, top) => {
self.try_current_frame()?.top = top;
U16(U16Value::ImageWidth)
},
(ImageWidth, width) => {
self.try_current_frame()?.width = width;
U16(U16Value::ImageHeight)
},
(ImageHeight, height) => {
self.try_current_frame()?.height = height;
Byte(ByteValue::ImageFlags)
}
})
}

fn read_control_extension(&mut self, b: u8) -> Result<State, DecodingError> {
self.add_frame();
self.ext.data.push(b);
Expand Down
Loading