swf: Use bitflags for `PlaceFlag`

This commit is contained in:
relrelb 2022-03-17 22:49:24 +02:00 committed by Mike Welsh
parent 6d2005c2fe
commit e88c7102f5
3 changed files with 98 additions and 83 deletions

View File

@ -1918,61 +1918,68 @@ impl<'a> Reader<'a> {
place_object_version: u8,
) -> Result<PlaceObject<'a>> {
let flags = if place_object_version >= 3 {
self.read_u16()?
PlaceFlag::from_bits_truncate(self.read_u16()?)
} else {
self.read_u8()?.into()
PlaceFlag::from_bits_truncate(self.read_u8()?.into())
};
let depth = self.read_u16()?;
// PlaceObject3
let is_image = (flags & 0b10000_00000000) != 0;
// SWF19 p.40 incorrectly says class name if (HasClassNameFlag || (HasImage && HasCharacterID))
// I think this should be if (HasClassNameFlag || (HasImage && !HasCharacterID)),
// you use the class name only if a character ID isn't present.
// But what is the case where we'd have an image without either HasCharacterID or HasClassName set?
let has_character_id = (flags & 0b10) != 0;
let has_class_name = (flags & 0b1000_00000000) != 0 || (is_image && !has_character_id);
let is_image = flags.contains(PlaceFlag::IS_IMAGE);
let has_character_id = flags.contains(PlaceFlag::HAS_CHARACTER);
let has_class_name =
flags.contains(PlaceFlag::HAS_CLASS_NAME) || (is_image && !has_character_id);
let class_name = if has_class_name {
Some(self.read_str()?)
} else {
None
};
let action = match flags & 0b11 {
0b01 => PlaceObjectAction::Modify,
0b10 => PlaceObjectAction::Place(self.read_u16()?),
0b11 => PlaceObjectAction::Replace(self.read_u16()?),
let action = match (flags.contains(PlaceFlag::MOVE), has_character_id) {
(true, false) => PlaceObjectAction::Modify,
(false, true) => {
let id = self.read_u16()?;
PlaceObjectAction::Place(id)
}
(true, true) => {
let id = self.read_u16()?;
PlaceObjectAction::Replace(id)
}
_ => return Err(Error::invalid_data("Invalid PlaceObject type")),
};
let matrix = if (flags & 0b100) != 0 {
let matrix = if flags.contains(PlaceFlag::HAS_MATRIX) {
Some(self.read_matrix()?)
} else {
None
};
let color_transform = if (flags & 0b1000) != 0 {
let color_transform = if flags.contains(PlaceFlag::HAS_COLOR_TRANSFORM) {
Some(self.read_color_transform()?)
} else {
None
};
let ratio = if (flags & 0b1_0000) != 0 {
let ratio = if flags.contains(PlaceFlag::HAS_RATIO) {
Some(self.read_u16()?)
} else {
None
};
let name = if (flags & 0b10_0000) != 0 {
let name = if flags.contains(PlaceFlag::HAS_NAME) {
Some(self.read_str()?)
} else {
None
};
let clip_depth = if (flags & 0b100_0000) != 0 {
let clip_depth = if flags.contains(PlaceFlag::HAS_CLIP_DEPTH) {
Some(self.read_u16()?)
} else {
None
};
// PlaceObject3
let filters = if (flags & 0b1_00000000) != 0 {
let filters = if flags.contains(PlaceFlag::HAS_FILTER_LIST) {
let num_filters = self.read_u8()?;
let mut filters = Vec::with_capacity(num_filters as usize);
for _ in 0..num_filters {
@ -1982,37 +1989,39 @@ impl<'a> Reader<'a> {
} else {
None
};
let blend_mode = if (flags & 0b10_00000000) != 0 {
let blend_mode = if flags.contains(PlaceFlag::HAS_BLEND_MODE) {
Some(self.read_blend_mode()?)
} else {
None
};
let is_bitmap_cached = if (flags & 0b100_00000000) != 0 {
let is_bitmap_cached = if flags.contains(PlaceFlag::HAS_CACHE_AS_BITMAP) {
Some(self.read_u8()? != 0)
} else {
None
};
let is_visible = if (flags & 0b100000_00000000) != 0 {
let is_visible = if flags.contains(PlaceFlag::HAS_VISIBLE) {
Some(self.read_u8()? != 0)
} else {
None
};
let background_color = if (flags & 0b1000000_00000000) != 0 {
let background_color = if flags.contains(PlaceFlag::OPAQUE_BACKGROUND) {
Some(self.read_rgba()?)
} else {
None
};
let clip_actions = if (flags & 0b1000_0000) != 0 {
let clip_actions = if flags.contains(PlaceFlag::HAS_CLIP_ACTIONS) {
Some(self.read_clip_actions()?)
} else {
None
};
// PlaceObject4
let amf_data = if place_object_version >= 4 {
Some(self.read_slice_to_end())
} else {
None
};
Ok(PlaceObject {
version: place_object_version,
action,

View File

@ -608,6 +608,28 @@ pub struct PlaceObject<'a> {
pub amf_data: Option<&'a [u8]>,
}
bitflags! {
pub struct PlaceFlag: u16 {
const MOVE = 1 << 0;
const HAS_CHARACTER = 1 << 1;
const HAS_MATRIX = 1 << 2;
const HAS_COLOR_TRANSFORM = 1 << 3;
const HAS_RATIO = 1 << 4;
const HAS_NAME = 1 << 5;
const HAS_CLIP_DEPTH = 1 << 6;
const HAS_CLIP_ACTIONS = 1 << 7;
// PlaceObject3
const HAS_FILTER_LIST = 1 << 8;
const HAS_BLEND_MODE = 1 << 9;
const HAS_CACHE_AS_BITMAP = 1 << 10;
const HAS_CLASS_NAME = 1 << 11;
const IS_IMAGE = 1 << 12;
const HAS_VISIBLE = 1 << 13;
const OPAQUE_BACKGROUND = 1 << 14;
}
}
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum PlaceObjectAction {
Place(CharacterId),

View File

@ -1716,70 +1716,54 @@ impl<W: Write> Writer<W> {
{
// TODO: Assert version.
let mut writer = Writer::new(&mut buf, self.version);
writer.write_u8(
if place_object.clip_actions.is_some() {
0b1000_0000
} else {
0
} | if place_object.clip_depth.is_some() {
0b0100_0000
} else {
0
} | if place_object.name.is_some() {
0b0010_0000
} else {
0
} | if place_object.ratio.is_some() {
0b0001_0000
} else {
0
} | if place_object.color_transform.is_some() {
0b0000_1000
} else {
0
} | if place_object.matrix.is_some() {
0b0000_0100
} else {
0
} | match place_object.action {
PlaceObjectAction::Place(_) => 0b10,
PlaceObjectAction::Modify => 0b01,
PlaceObjectAction::Replace(_) => 0b11,
},
)?;
let mut flags = PlaceFlag::empty();
flags.set(
PlaceFlag::MOVE,
matches!(
place_object.action,
PlaceObjectAction::Modify | PlaceObjectAction::Replace(_)
),
);
flags.set(
PlaceFlag::HAS_CHARACTER,
matches!(
place_object.action,
PlaceObjectAction::Place(_) | PlaceObjectAction::Replace(_)
),
);
flags.set(PlaceFlag::HAS_MATRIX, place_object.matrix.is_some());
flags.set(
PlaceFlag::HAS_COLOR_TRANSFORM,
place_object.color_transform.is_some(),
);
flags.set(PlaceFlag::HAS_RATIO, place_object.ratio.is_some());
flags.set(PlaceFlag::HAS_NAME, place_object.name.is_some());
flags.set(PlaceFlag::HAS_CLIP_DEPTH, place_object.clip_depth.is_some());
flags.set(
PlaceFlag::HAS_CLIP_ACTIONS,
place_object.clip_actions.is_some(),
);
if place_object_version >= 3 {
writer.write_u8(
if place_object.background_color.is_some() {
0b100_0000
} else {
0
} | if place_object.is_visible.is_some() {
0b10_0000
} else {
0
} | if place_object.is_image { 0b1_0000 } else { 0 }
| if place_object.class_name.is_some() {
0b1000
} else {
0
}
| if place_object.is_bitmap_cached.is_some() {
0b100
} else {
0
}
| if place_object.blend_mode.is_some() {
0b10
} else {
0
}
| if place_object.filters.is_some() {
0b1
} else {
0
},
)?;
flags.set(PlaceFlag::HAS_FILTER_LIST, place_object.filters.is_some());
flags.set(PlaceFlag::HAS_BLEND_MODE, place_object.blend_mode.is_some());
flags.set(
PlaceFlag::HAS_CACHE_AS_BITMAP,
place_object.is_bitmap_cached.is_some(),
);
flags.set(PlaceFlag::HAS_CLASS_NAME, place_object.class_name.is_some());
flags.set(PlaceFlag::IS_IMAGE, place_object.is_image);
flags.set(PlaceFlag::HAS_VISIBLE, place_object.is_visible.is_some());
flags.set(
PlaceFlag::OPAQUE_BACKGROUND,
place_object.background_color.is_some(),
);
writer.write_u16(flags.bits())?;
} else {
writer.write_u8(flags.bits() as u8)?;
}
writer.write_u16(place_object.depth)?;
if place_object_version >= 3 {