Implement DefineFunction

This commit is contained in:
David Wendt 2019-09-15 23:37:15 -06:00 committed by Mike Welsh
parent 83c832ce86
commit 00b5d9ecf5
3 changed files with 81 additions and 9 deletions

View File

@ -648,13 +648,22 @@ impl<'gc> Avm1<'gc> {
fn action_define_function(
&mut self,
_context: &mut ActionContext,
_name: &str,
_params: &[&str],
_actions: &[u8],
context: &mut ActionContext<'_, 'gc, '_>,
name: &str,
params: &[&str],
actions: &[u8],
) -> Result<(), Error> {
// TODO(Herschel)
Err("Unimplemented action: DefineFunction".into())
let swf_version = self.current_stack_frame().unwrap().swf_version();
let func_data = self.current_stack_frame().unwrap().data().to_subslice(actions).unwrap();
let func = Value::Object(GcCell::allocate(context.gc_context, Object::action_function(swf_version, func_data, name, params)));
if name == "" {
self.current_stack_frame_mut().unwrap().stack_mut().push(func);
} else {
self.current_stack_frame_mut().unwrap().locals_mut().insert(name.to_string(), func);
}
Ok(())
}
fn action_define_local(&mut self, _context: &mut ActionContext) -> Result<(), Error> {

View File

@ -14,15 +14,47 @@ pub type NativeFunction<'gc> = fn(
&[Value<'gc>],
) -> Value<'gc>;
/// Represents a function defined in the AVM1 runtime.
#[derive(Clone)]
struct Avm1Function {
/// The file format version of the SWF that generated this function.
swf_version: u8,
/// A reference to the underlying SWF data.
data: SwfSlice,
/// The name of the function, if not anonymous.
name: Option<String>,
/// The names of the function parameters.
params: Vec<String>,
}
impl Avm1Function {
pub fn new(swf_version: u8, actions: SwfSlice, name: &str, params: &[&str]) -> Avm1Function {
let name = match name {
"" => None,
name => Some(name.to_string())
};
Avm1Function {
swf_version: swf_version,
data: actions,
name: name,
params: params.into_iter().map(|s| s.to_string()).collect()
}
}
}
/// Represents a function that can be defined in the Ruffle runtime or by the
/// AVM1 bytecode itself.
#[derive(Clone)]
pub enum Executable<'gc> {
enum Executable<'gc> {
/// A function provided by the Ruffle runtime and implemented in Rust.
Native(NativeFunction<'gc>),
/// ActionScript data defined by a previous action.
ActionData
Action(Avm1Function)
}
impl<'gc> Executable<'gc> {
@ -35,7 +67,7 @@ impl<'gc> Executable<'gc> {
pub fn exec(&self, avm: &mut Avm1<'gc>, ac: &mut ActionContext<'_, 'gc, '_>, this: GcCell<'gc, Object<'gc>>, args: &[Value<'gc>]) -> Option<Value<'gc>> {
match self {
Executable::Native(nf) => Some(nf(avm, ac, this, args)),
Executable::ActionData => None
Executable::Action(af) => None
}
}
}
@ -174,6 +206,15 @@ impl<'gc> Object<'gc> {
}
}
pub fn action_function(swf_version: u8, actions: SwfSlice, name: &str, params: &[&str]) -> Self {
Self {
type_of: TYPE_OF_FUNCTION,
function: Some(Executable::Action(Avm1Function::new(swf_version, actions, name, params))),
display_node: None,
values: HashMap::new()
}
}
pub fn set_display_node(&mut self, display_node: DisplayNode<'gc>) {
self.display_node = Some(display_node);
}

View File

@ -3,6 +3,7 @@ use swf::TagCode;
pub type DecodeResult = Result<(), Box<dyn std::error::Error>>;
pub type SwfStream<R> = swf::read::Reader<std::io::Cursor<R>>;
/// A shared-ownership reference to some portion of an immutable datastream.
#[derive(Debug, Clone)]
pub struct SwfSlice {
pub data: std::sync::Arc<Vec<u8>>,
@ -16,6 +17,27 @@ impl AsRef<[u8]> for SwfSlice {
}
}
impl SwfSlice {
/// Construct a new SwfSlice from a regular slice.
///
/// This function returns None if the given slice is not a subslice of the
/// current slice.
pub fn to_subslice(&self, slice: &[u8]) -> Option<SwfSlice> {
let self_pval = self.data.as_ptr() as usize;
let slice_pval = slice.as_ptr() as usize;
if (self_pval + self.start) <= slice_pval && slice_pval < (self_pval + self.end) {
Some(SwfSlice {
data: self.data.clone(),
start: slice_pval - self_pval,
end: (slice_pval - self_pval) + slice.len()
})
} else {
None
}
}
}
pub fn decode_tags<'a, R, F>(
reader: &'a mut SwfStream<R>,
mut tag_callback: F,