Skip to content

Commit c6f3fdd

Browse files
authored
Merge pull request #158 from kornelski/lifetime-safety
Unify Decoded events for pixels and LZW copy, check lifetimes
2 parents 42db323 + 036c998 commit c6f3fdd

File tree

2 files changed

+65
-23
lines changed

2 files changed

+65
-23
lines changed

src/reader/decoder.rs

Lines changed: 50 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,8 @@ pub enum Decoded<'a> {
145145
FrameMetadata(&'a Frame<'static>, FrameDataType),
146146
/// Decoded some data of the current frame.
147147
BytesDecoded(usize),
148-
/// Copied compressed data of the current frame.
149-
LzwData(&'a [u8]),
148+
/// Copied (or consumed and discarded) compressed data of the current frame. In bytes.
149+
LzwDataCopied(usize),
150150
/// No more data available the current frame.
151151
DataEnd,
152152
}
@@ -244,8 +244,15 @@ impl LzwReader {
244244
self.decoder.as_ref().map_or(true, |e| e.has_ended())
245245
}
246246

247-
pub fn decode_bytes(&mut self, lzw_data: &[u8], decode_buffer: &mut [u8]) -> io::Result<(usize, usize)> {
247+
pub fn decode_bytes(&mut self, lzw_data: &[u8], decode_buffer: &mut OutputBuffer<'_>) -> io::Result<(usize, usize)> {
248248
let decoder = self.decoder.as_mut().ok_or_else(|| io::ErrorKind::Unsupported)?;
249+
250+
let decode_buffer = match decode_buffer {
251+
OutputBuffer::Slice(buf) => &mut **buf,
252+
OutputBuffer::None => &mut [],
253+
OutputBuffer::Vec(_) => return Err(io::Error::from(io::ErrorKind::Unsupported)),
254+
};
255+
249256
let decoded = decoder.decode_bytes(lzw_data, decode_buffer);
250257

251258
match decoded.status {
@@ -298,6 +305,15 @@ struct ExtensionData {
298305
is_block_end: bool,
299306
}
300307

308+
pub enum OutputBuffer<'a> {
309+
/// Overwrite bytes
310+
Slice(&'a mut [u8]),
311+
/// Append LZW bytes
312+
Vec(&'a mut Vec<u8>),
313+
/// Discard bytes
314+
None,
315+
}
316+
301317
impl StreamingDecoder {
302318
/// Creates a new streaming decoder
303319
pub fn new() -> StreamingDecoder {
@@ -331,16 +347,24 @@ impl StreamingDecoder {
331347
///
332348
/// Returns the number of bytes consumed from the input buffer
333349
/// and the last decoding result.
334-
pub fn update<'a>(&'a mut self, mut buf: &[u8], mut decode_bytes_into: Option<&mut [u8]>)
350+
pub fn update<'a>(&'a mut self, mut buf: &[u8], write_into: &mut OutputBuffer<'_>)
335351
-> Result<(usize, Decoded<'a>), DecodingError> {
336352
// NOTE: Do not change the function signature without double-checking the
337353
// unsafe block!
338354
let len = buf.len();
339355
while buf.len() > 0 {
356+
// This dead code is a compile-check for lifetimes that otherwise aren't checked
357+
// due to the `mem::transmute` used later.
358+
// Keep it in sync with the other call to `next_state`.
359+
#[cfg(test)]
360+
if false {
361+
return self.next_state(buf, write_into);
362+
}
363+
340364
// It's not necessary to check here whether state is `Some`,
341365
// because `next_state` checks it anyway, and will return `DecodeError`
342366
// if the state has already been set to `None`.
343-
match self.next_state(buf, decode_bytes_into.as_deref_mut()) {
367+
match self.next_state(buf, write_into) {
344368
Ok((bytes, Decoded::Nothing)) => {
345369
buf = &buf[bytes..]
346370
}
@@ -370,7 +394,6 @@ impl StreamingDecoder {
370394
}
371395
}
372396
Ok((len-buf.len(), Decoded::Nothing))
373-
374397
}
375398

376399
/// Returns the data of the last extension that has been decoded.
@@ -417,7 +440,7 @@ impl StreamingDecoder {
417440
}
418441
}
419442

420-
fn next_state<'a>(&'a mut self, buf: &'a [u8], decode_bytes_into: Option<&mut [u8]>) -> Result<(usize, Decoded<'a>), DecodingError> {
443+
fn next_state(&mut self, buf: &[u8], write_into: &mut OutputBuffer<'_>) -> Result<(usize, Decoded<'_>), DecodingError> {
421444
macro_rules! goto (
422445
($n:expr, $state:expr) => ({
423446
self.state = Some($state);
@@ -685,9 +708,24 @@ impl StreamingDecoder {
685708
}
686709
CopySubBlock(left) => {
687710
debug_assert!(self.skip_frame_decoding);
688-
let n = cmp::min(left, buf.len());
689711
if left > 0 {
690-
goto!(n, CopySubBlock(left - n), emit Decoded::LzwData(&buf[..n]))
712+
let n = cmp::min(left, buf.len());
713+
let (consumed, copied) = match write_into {
714+
OutputBuffer::Slice(slice) => {
715+
let len = cmp::min(n, slice.len());
716+
slice[..len].copy_from_slice(&buf[..len]);
717+
(len, len)
718+
},
719+
OutputBuffer::Vec(vec) => {
720+
vec.try_reserve(n).map_err(|_| io::Error::from(io::ErrorKind::OutOfMemory))?;
721+
vec.extend_from_slice(&buf[..n]);
722+
(n, n)
723+
},
724+
// It's valid that bytes are discarded. For example,
725+
// when using next_frame_info() with skip_frame_decoding to only get metadata.
726+
OutputBuffer::None => (n, 0),
727+
};
728+
goto!(consumed, CopySubBlock(left - consumed), emit Decoded::LzwDataCopied(copied))
691729
} else if b != 0 {
692730
goto!(CopySubBlock(b as usize))
693731
} else {
@@ -700,11 +738,11 @@ impl StreamingDecoder {
700738
debug_assert!(!self.skip_frame_decoding);
701739
if left > 0 {
702740
let n = cmp::min(left, buf.len());
703-
if self.lzw_reader.has_ended() || decode_bytes_into.is_none() {
741+
if self.lzw_reader.has_ended() || matches!(write_into, OutputBuffer::None) {
704742
return goto!(n, DecodeSubBlock(0), emit Decoded::BytesDecoded(0));
705743
}
706744

707-
let (mut consumed, bytes_len) = self.lzw_reader.decode_bytes(&buf[..n], decode_bytes_into.unwrap())?;
745+
let (mut consumed, bytes_len) = self.lzw_reader.decode_bytes(&buf[..n], write_into)?;
708746

709747
// skip if can't make progress (decode would fail if check_for_end_code was set)
710748
if consumed == 0 && bytes_len == 0 {
@@ -715,7 +753,7 @@ impl StreamingDecoder {
715753
} else if b != 0 { // decode next sub-block
716754
goto!(DecodeSubBlock(b as usize))
717755
} else {
718-
let (_, bytes_len) = self.lzw_reader.decode_bytes(&[], decode_bytes_into.unwrap_or(&mut []))?;
756+
let (_, bytes_len) = self.lzw_reader.decode_bytes(&[], write_into)?;
719757

720758
if bytes_len > 0 {
721759
goto!(0, DecodeSubBlock(0), emit Decoded::BytesDecoded(bytes_len))

src/reader/mod.rs

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::common::{Block, Frame};
1111
mod decoder;
1212
pub use self::decoder::{
1313
PLTE_CHANNELS, StreamingDecoder, Decoded, DecodingError, DecodingFormatError, Extensions,
14-
Version, FrameDataType
14+
Version, FrameDataType, OutputBuffer
1515
};
1616

1717
const N_CHANNELS: usize = 4;
@@ -188,7 +188,7 @@ struct ReadDecoder<R: Read> {
188188
}
189189

190190
impl<R: Read> ReadDecoder<R> {
191-
fn decode_next(&mut self, mut decode_bytes_into: Option<&mut [u8]>) -> Result<Option<Decoded<'_>>, DecodingError> {
191+
fn decode_next(&mut self, write_into: &mut OutputBuffer<'_>) -> Result<Option<Decoded<'_>>, DecodingError> {
192192
while !self.at_eof {
193193
let (consumed, result) = {
194194
let buf = self.reader.fill_buf()?;
@@ -197,7 +197,14 @@ impl<R: Read> ReadDecoder<R> {
197197
"unexpected EOF"
198198
))
199199
}
200-
self.decoder.update(buf, decode_bytes_into.as_deref_mut())?
200+
201+
// Dead code checks the lifetimes that the later mem::transmute can't.
202+
#[cfg(test)]
203+
if false {
204+
return self.decoder.update(buf, write_into).map(|(_, res)| Some(res));
205+
}
206+
207+
self.decoder.update(buf, write_into)?
201208
};
202209
self.reader.consume(consumed);
203210
match result {
@@ -258,7 +265,7 @@ impl<R> Decoder<R> where R: Read {
258265

259266
fn init(mut self) -> Result<Self, DecodingError> {
260267
loop {
261-
match self.decoder.decode_next(None)? {
268+
match self.decoder.decode_next(&mut OutputBuffer::None)? {
262269
Some(Decoded::BackgroundColor(bg_color)) => {
263270
self.bg_color = Some(bg_color)
264271
}
@@ -292,7 +299,7 @@ impl<R> Decoder<R> where R: Read {
292299
/// Returns the next frame info
293300
pub fn next_frame_info(&mut self) -> Result<Option<&Frame<'static>>, DecodingError> {
294301
loop {
295-
match self.decoder.decode_next(None)? {
302+
match self.decoder.decode_next(&mut OutputBuffer::None)? {
296303
Some(Decoded::FrameMetadata(frame, frame_data_type)) => {
297304
self.current_frame = frame.clone();
298305
self.current_frame_data_type = frame_data_type;
@@ -379,11 +386,8 @@ impl<R> Decoder<R> where R: Read {
379386
// `write_lzw_pre_encoded_frame` smuggles `min_code_size` in the first byte.
380387
buf.push(min_code_size);
381388
loop {
382-
match self.decoder.decode_next(None)? {
383-
Some(Decoded::LzwData(data)) => {
384-
buf.try_reserve(data.len()).map_err(|_| io::Error::from(io::ErrorKind::OutOfMemory))?;
385-
buf.extend_from_slice(data);
386-
},
389+
match self.decoder.decode_next(&mut OutputBuffer::Vec(buf))? {
390+
Some(Decoded::LzwDataCopied(_len)) => {},
387391
Some(Decoded::DataEnd) => return Ok(()),
388392
_ => return Err(DecodingError::format("unexpected data")),
389393
}
@@ -415,7 +419,7 @@ impl<R> Decoder<R> where R: Read {
415419
&mut self.buffer[..buffer_size]
416420
}
417421
};
418-
match self.decoder.decode_next(Some(decode_into))? {
422+
match self.decoder.decode_next(&mut OutputBuffer::Slice(decode_into))? {
419423
Some(Decoded::BytesDecoded(bytes_decoded)) => {
420424
match self.color_output {
421425
ColorOutput::RGBA => {

0 commit comments

Comments
 (0)