avm2: use WString in QName methods

This commit is contained in:
Moulins 2021-10-03 02:33:19 +02:00 committed by kmeisthax
parent 5ca911209b
commit 053758d77c
5 changed files with 65 additions and 61 deletions

View File

@ -3,7 +3,6 @@
use crate::avm2::object::TObject; use crate::avm2::object::TObject;
use crate::avm2::QName; use crate::avm2::QName;
use crate::avm2::{Activation, Error, Object, Value}; use crate::avm2::{Activation, Error, Object, Value};
use crate::string::AvmString;
pub mod bytearray; pub mod bytearray;
pub mod compression_algorithm; pub mod compression_algorithm;
@ -42,15 +41,12 @@ pub fn get_qualified_class_name<'gc>(
}, },
}; };
Ok(AvmString::new( Ok(class
activation.context.gc_context, .inner_class_definition()
class .read()
.inner_class_definition() .name()
.read() .to_qualified_name(activation.context.gc_context)
.name() .into())
.to_qualified_name(),
)
.into())
} }
/// Implements `flash.utils.getQualifiedSuperclassName` /// Implements `flash.utils.getQualifiedSuperclassName`
@ -73,15 +69,12 @@ pub fn get_qualified_super_class_name<'gc>(
}; };
if let Some(super_class) = class.superclass_object() { if let Some(super_class) = class.superclass_object() {
Ok(AvmString::new( Ok(super_class
activation.context.gc_context, .inner_class_definition()
super_class .read()
.inner_class_definition() .name()
.read() .to_qualified_name(activation.context.gc_context)
.name() .into())
.to_qualified_name(),
)
.into())
} else { } else {
Ok(Value::Null) Ok(Value::Null)
} }
@ -98,6 +91,6 @@ pub fn get_definition_by_name<'gc>(
.get(0) .get(0)
.unwrap_or(&Value::Undefined) .unwrap_or(&Value::Undefined)
.coerce_to_string(activation)?; .coerce_to_string(activation)?;
let qname = QName::from_qualified_name(&name, activation.context.gc_context); let qname = QName::from_qualified_name(name, activation.context.gc_context);
appdomain.get_defined_value(activation, qname) appdomain.get_defined_value(activation, qname)
} }

View File

@ -4,7 +4,7 @@ use crate::avm2::activation::Activation;
use crate::avm2::script::TranslationUnit; use crate::avm2::script::TranslationUnit;
use crate::avm2::value::Value; use crate::avm2::value::Value;
use crate::avm2::Error; use crate::avm2::Error;
use crate::string::AvmString; use crate::string::{AvmString, BorrowWStr, WStr, WString};
use gc_arena::{Collect, MutationContext}; use gc_arena::{Collect, MutationContext};
use swf::avm2::types::{ use swf::avm2::types::{
AbcFile, Index, Multiname as AbcMultiname, Namespace as AbcNamespace, AbcFile, Index, Multiname as AbcMultiname, Namespace as AbcNamespace,
@ -206,32 +206,34 @@ impl<'gc> QName<'gc> {
/// NAMESPACE::LOCAL_NAME /// NAMESPACE::LOCAL_NAME
/// NAMESPACE.LOCAL_NAME (Where the LAST dot is used to split the namespace & local_name) /// NAMESPACE.LOCAL_NAME (Where the LAST dot is used to split the namespace & local_name)
/// LOCAL_NAME (Use the public namespace) /// LOCAL_NAME (Use the public namespace)
pub fn from_qualified_name(name: &str, mc: MutationContext<'gc, '_>) -> Self { pub fn from_qualified_name(name: AvmString<'gc>, mc: MutationContext<'gc, '_>) -> Self {
if let Some((package_name, local_name)) = name.rsplit_once("::") { let parts = name
.rsplit_once(WStr::from_units(b"::"))
.or_else(|| name.rsplit_once(WStr::from_units(b".")));
if let Some((package_name, local_name)) = parts {
Self { Self {
ns: Namespace::Package(AvmString::new(mc, package_name.to_string())), ns: Namespace::Package(AvmString::new_ucs2(mc, package_name.into())),
name: AvmString::new(mc, local_name.to_string()), name: AvmString::new_ucs2(mc, local_name.into()),
}
} else if let Some((package_name, local_name)) = name.rsplit_once('.') {
Self {
ns: Namespace::Package(AvmString::new(mc, package_name.to_string())),
name: AvmString::new(mc, local_name.to_string()),
} }
} else { } else {
Self { Self {
ns: Namespace::public(), ns: Namespace::public(),
name: AvmString::new(mc, name.to_string()), name,
} }
} }
} }
/// Converts this `QName` to a fully qualified name. /// Converts this `QName` to a fully qualified name.
pub fn to_qualified_name(&self) -> String { pub fn to_qualified_name(&self, mc: MutationContext<'gc, '_>) -> AvmString<'gc> {
let uri = self.namespace().as_uri(); let uri = self.namespace().as_uri();
let name = self.local_name(); let name = self.local_name();
uri.is_empty() uri.is_empty().then(|| name).unwrap_or_else(|| {
.then(|| name.to_string()) let mut buf = WString::from(uri.borrow());
.unwrap_or_else(|| format!("{}::{}", uri, name)) buf.push_str(WStr::from_units(b"::"));
buf.push_str(name.borrow());
AvmString::new_ucs2(mc, buf)
})
} }
pub fn local_name(&self) -> AvmString<'gc> { pub fn local_name(&self) -> AvmString<'gc> {
@ -244,31 +246,25 @@ impl<'gc> QName<'gc> {
/// Get the string value of this QName, including the namespace URI. /// Get the string value of this QName, including the namespace URI.
pub fn as_uri(&self, mc: MutationContext<'gc, '_>) -> AvmString<'gc> { pub fn as_uri(&self, mc: MutationContext<'gc, '_>) -> AvmString<'gc> {
match self.ns { let ns = match &self.ns {
Namespace::Namespace(s) if s != "" => { Namespace::Namespace(s) => s.borrow(),
AvmString::new(mc, format!("{}::{}", &*s, &*self.name)) Namespace::Package(s) => s.borrow(),
} Namespace::PackageInternal(s) => s.borrow(),
Namespace::Package(s) if s != "" => { Namespace::Protected(s) => s.borrow(),
AvmString::new(mc, format!("{}::{}", &*s, &*self.name)) Namespace::Explicit(s) => s.borrow(),
} Namespace::StaticProtected(s) => s.borrow(),
Namespace::PackageInternal(s) if s != "" => { Namespace::Private(s) => s.borrow(),
AvmString::new(mc, format!("{}::{}", &*s, &*self.name)) Namespace::Any => WStr::from_units(b"*"),
} };
Namespace::Protected(s) if s != "" => {
AvmString::new(mc, format!("{}::{}", &*s, &*self.name)) if ns.is_empty() {
} return self.name;
Namespace::Explicit(s) if s != "" => {
AvmString::new(mc, format!("{}::{}", &*s, &*self.name))
}
Namespace::StaticProtected(s) if s != "" => {
AvmString::new(mc, format!("{}::{}", &*s, &*self.name))
}
Namespace::Private(s) if s != "" => {
AvmString::new(mc, format!("{}::{}", &*s, &*self.name))
}
Namespace::Any => AvmString::new(mc, format!("*::{}", &*self.name)),
_ => self.name,
} }
let mut uri = WString::from(ns);
uri.push_str(WStr::from_units(b"::"));
uri.push_str(self.name.borrow());
AvmString::new_ucs2(mc, uri)
} }
} }

View File

@ -586,8 +586,9 @@ impl<'gc> MovieClip<'gc> {
for _ in 0..num_symbols { for _ in 0..num_symbols {
let id = reader.read_u16()?; let id = reader.read_u16()?;
let class_name = reader.read_str()?.to_string_lossy(reader.encoding()); let class_name = reader.read_str()?.to_string_lossy(reader.encoding());
let class_name = AvmString::new(activation.context.gc_context, class_name);
let name = Avm2QName::from_qualified_name(&class_name, activation.context.gc_context); let name = Avm2QName::from_qualified_name(class_name, activation.context.gc_context);
let library = activation let library = activation
.context .context
.library .library

View File

@ -204,13 +204,19 @@ macro_rules! impl_str_methods {
crate::string::ops::str_split($deref, separator) crate::string::ops::str_split($deref, separator)
} }
/// Analogue of [`str::split_at`] /// Analogue of [`str::split_at`].
#[inline] #[inline]
pub fn split_at($self: $receiver, index: usize) -> (crate::string::WStr<$lt>, crate::string::WStr<$lt>) { pub fn split_at($self: $receiver, index: usize) -> (crate::string::WStr<$lt>, crate::string::WStr<$lt>) {
let s = $deref; let s = $deref;
(s.slice(..index), s.slice(index..)) (s.slice(..index), s.slice(index..))
} }
/// Analogue of [`str::rsplit_once`].
#[inline]
pub fn rsplit_once<$($pat_gen)* P: crate::string::Pattern<$pat_lt>>($self: $pat_self, pattern: P) -> Option<(WStr<$pat_lt>, WStr<$pat_lt>)> {
crate::string::ops::str_rsplit_once($deref, pattern)
}
/// Analogue of [`str::trim_matches`]. /// Analogue of [`str::trim_matches`].
#[inline] #[inline]
pub fn trim_matches<$($pat_gen)* P: crate::string::Pattern<$pat_lt>>($self: $pat_self, pattern: P) -> WStr<$pat_lt> { pub fn trim_matches<$($pat_gen)* P: crate::string::Pattern<$pat_lt>>($self: $pat_self, pattern: P) -> WStr<$pat_lt> {

View File

@ -212,6 +212,14 @@ pub fn str_split<'a, P: Pattern<'a>>(string: WStr<'a>, pattern: P) -> Split<'a,
} }
} }
pub fn str_rsplit_once<'a, P: Pattern<'a>>(
string: WStr<'a>,
pattern: P,
) -> Option<(WStr<'a>, WStr<'a>)> {
let (start, end) = pattern.into_searcher(string).next_match_back()?;
Some((string.slice(..start), string.slice(end..)))
}
pub fn starts_with<'a, P: Pattern<'a>>(string: WStr<'a>, pattern: P) -> bool { pub fn starts_with<'a, P: Pattern<'a>>(string: WStr<'a>, pattern: P) -> bool {
matches!( matches!(
pattern.into_searcher(string).next(), pattern.into_searcher(string).next(),