Implement DefineFunction
This commit is contained in:
parent
83c832ce86
commit
00b5d9ecf5
|
@ -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> {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue