diff --git a/core/src/avm2/names.rs b/core/src/avm2/names.rs index 117652c2f..b1a2cc10c 100644 --- a/core/src/avm2/names.rs +++ b/core/src/avm2/names.rs @@ -1,5 +1,6 @@ //! AVM2 names & namespacing +use crate::avm2::Avm2; use gc_arena::Collect; use swf::avm2::types::{AbcFile, Index, Multiname as AbcMultiname, Namespace as AbcNamespace}; @@ -70,3 +71,59 @@ pub struct QName { ns: Namespace, name: String, } + +/// A `Multiname` consists of a name which could be resolved in one or more +/// potential namespaces. +/// +/// All unresolved names are of the form `Multiname`, and the name resolution +/// process consists of searching each name space for a given name. +pub struct Multiname { + ns: Vec, + name: String, +} + +impl Multiname { + /// Read a multiname from the ABC constant pool, copying it into the most + /// general form of multiname. + /// + /// This does not yet support late-bound or runtime multinames. + pub fn from_abc_multiname( + file: &AbcFile, + multiname_index: Index, + avm: &mut Avm2<'_>, + ) -> Option { + Some( + match file + .constant_pool + .multinames + .get(multiname_index.0 as usize)? + { + AbcMultiname::QName { namespace, name } + | AbcMultiname::QNameA { namespace, name } => Self { + ns: vec![Namespace::from_abc_namespace(file, namespace.clone())?], + name: file.constant_pool.strings.get(name.0 as usize)?.clone(), + }, + AbcMultiname::Multiname { + namespace_set, + name, + } + | AbcMultiname::MultinameA { + namespace_set, + name, + } => Self { + ns: file + .constant_pool + .namespace_sets + .get(namespace_set.0 as usize)? + .iter() + .map(|ns| Namespace::from_abc_namespace(file, ns.clone())) + .filter(|ns| ns.is_some()) + .map(|ns| ns.unwrap()) + .collect(), + name: file.constant_pool.strings.get(name.0 as usize)?.clone(), + }, + _ => return None, + }, + ) + } +}