Skip to content

Commit

Permalink
core: Handle empty JPEGTables tags (fix #116)
Browse files Browse the repository at this point in the history
  • Loading branch information
Herschel committed Nov 11, 2019
1 parent 1236b54 commit e3d0d90
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 23 deletions.
26 changes: 24 additions & 2 deletions core/src/backend/render.rs
Expand Up @@ -10,7 +10,7 @@ pub trait RenderBackend {
&mut self,
id: swf::CharacterId,
data: &[u8],
jpeg_tables: &[u8],
jpeg_tables: Option<&[u8]>,
) -> BitmapInfo;
fn register_bitmap_jpeg_2(&mut self, id: swf::CharacterId, data: &[u8]) -> BitmapInfo;
fn register_bitmap_jpeg_3(
Expand Down Expand Up @@ -80,7 +80,7 @@ impl RenderBackend for NullRenderer {
&mut self,
_id: swf::CharacterId,
_data: &[u8],
_jpeg_tables: &[u8],
_jpeg_tables: Option<&[u8]>,
) -> BitmapInfo {
BitmapInfo {
handle: BitmapHandle(0),
Expand Down Expand Up @@ -133,6 +133,28 @@ pub fn glue_swf_jpeg_to_tables(jpeg_tables: &[u8], jpeg_data: &[u8]) -> Vec<u8>
full_jpeg
}

/// Glues the JPEG encoding tables from a JPEGTables SWF tag to the JPEG data
/// in a DefineBits tag, producing complete JPEG data suitable for a decoder.
pub fn glue_tables_to_jpeg<'a>(
jpeg_data: &'a [u8],
jpeg_tables: Option<&'a [u8]>,
) -> std::borrow::Cow<'a, [u8]> {
if let Some(jpeg_tables) = jpeg_tables {
if jpeg_tables.len() >= 2 {
let mut full_jpeg = Vec::with_capacity(jpeg_tables.len() + jpeg_data.len());
full_jpeg.extend_from_slice(&jpeg_tables[..jpeg_tables.len() - 2]);
if jpeg_data.len() >= 2 {
full_jpeg.extend_from_slice(&jpeg_data[2..]);
}

return std::borrow::Cow::from(full_jpeg);
}
}

// No JPEG tables or not enough data; return JPEG data as is
std::borrow::Cow::Borrowed(jpeg_data)
}

/// Removes potential invalid JPEG data from SWF DefineBitsJPEG tags.
///
/// SWF19 p.138:
Expand Down
9 changes: 4 additions & 5 deletions core/src/display_object/movie_clip.rs
Expand Up @@ -886,11 +886,10 @@ impl<'gc, 'a> MovieClip<'gc> {
.get_mut()
.take(data_len as u64)
.read_to_end(&mut jpeg_data)?;
let bitmap_info = context.renderer.register_bitmap_jpeg(
id,
&jpeg_data,
context.library.jpeg_tables().unwrap(),
);
let bitmap_info =
context
.renderer
.register_bitmap_jpeg(id, &jpeg_data, context.library.jpeg_tables());
let bitmap = crate::display_object::Bitmap::new(
context,
id,
Expand Down
15 changes: 13 additions & 2 deletions core/src/library.rs
Expand Up @@ -86,8 +86,19 @@ impl<'gc> Library<'gc> {
}

pub fn set_jpeg_tables(&mut self, data: Vec<u8>) {
let data = crate::backend::render::remove_invalid_jpeg_data(&data[..]).to_vec();
self.jpeg_tables = Some(data);
if self.jpeg_tables.is_some() {
// SWF spec says there should only be one JPEGTables tag.
// TODO: What is the behavior when there are multiples?
log::warn!("SWF contains multiple JPEGTables tags");
return;
}
// Some SWFs have a JPEGTables tag with 0 length; ignore these.
// (Does this happen when there is only a single DefineBits tag?)
self.jpeg_tables = if data.is_empty() {
None
} else {
Some(crate::backend::render::remove_invalid_jpeg_data(&data[..]).to_vec())
}
}

pub fn jpeg_tables(&self) -> Option<&[u8]> {
Expand Down
12 changes: 3 additions & 9 deletions desktop/src/render.rs
Expand Up @@ -542,16 +542,10 @@ impl RenderBackend for GliumRenderBackend {
&mut self,
id: swf::CharacterId,
data: &[u8],
jpeg_tables: &[u8],
jpeg_tables: Option<&[u8]>,
) -> BitmapInfo {
if !jpeg_tables.is_empty() {
let mut full_jpeg = jpeg_tables[..jpeg_tables.len() - 2].to_vec();
full_jpeg.extend_from_slice(&data[2..]);

self.register_bitmap_jpeg_2(id, &full_jpeg[..])
} else {
self.register_bitmap_jpeg_2(id, &data[..])
}
let data = ruffle_core::backend::render::glue_tables_to_jpeg(data, jpeg_tables);
self.register_bitmap_jpeg_2(id, &data[..])
}

fn register_bitmap_jpeg_2(&mut self, id: swf::CharacterId, data: &[u8]) -> BitmapInfo {
Expand Down
8 changes: 3 additions & 5 deletions web/src/render.rs
Expand Up @@ -360,12 +360,10 @@ impl RenderBackend for WebCanvasRenderBackend {
&mut self,
id: CharacterId,
data: &[u8],
jpeg_tables: &[u8],
jpeg_tables: Option<&[u8]>,
) -> BitmapInfo {
let mut full_jpeg = jpeg_tables[..jpeg_tables.len() - 2].to_vec();
full_jpeg.extend_from_slice(&data[2..]);

self.register_bitmap_jpeg_2(id, &full_jpeg[..])
let data = ruffle_core::backend::render::glue_tables_to_jpeg(data, jpeg_tables);
self.register_bitmap_jpeg_2(id, &data[..])
}

fn register_bitmap_jpeg_2(&mut self, id: CharacterId, data: &[u8]) -> BitmapInfo {
Expand Down

0 comments on commit e3d0d90

Please sign in to comment.