From 053758d77cf41e73f47ba790b29d6402eef00ef1 Mon Sep 17 00:00:00 2001 From: Moulins Date: Sun, 3 Oct 2021 02:33:19 +0200 Subject: [PATCH] avm2: use WString in QName methods --- core/src/avm2/globals/flash/utils.rs | 33 +++++------- core/src/avm2/names.rs | 74 +++++++++++++-------------- core/src/display_object/movie_clip.rs | 3 +- core/src/string/common.rs | 8 ++- core/src/string/ops.rs | 8 +++ 5 files changed, 65 insertions(+), 61 deletions(-) diff --git a/core/src/avm2/globals/flash/utils.rs b/core/src/avm2/globals/flash/utils.rs index c87e43327..a02e08334 100644 --- a/core/src/avm2/globals/flash/utils.rs +++ b/core/src/avm2/globals/flash/utils.rs @@ -3,7 +3,6 @@ use crate::avm2::object::TObject; use crate::avm2::QName; use crate::avm2::{Activation, Error, Object, Value}; -use crate::string::AvmString; pub mod bytearray; pub mod compression_algorithm; @@ -42,15 +41,12 @@ pub fn get_qualified_class_name<'gc>( }, }; - Ok(AvmString::new( - activation.context.gc_context, - class - .inner_class_definition() - .read() - .name() - .to_qualified_name(), - ) - .into()) + Ok(class + .inner_class_definition() + .read() + .name() + .to_qualified_name(activation.context.gc_context) + .into()) } /// Implements `flash.utils.getQualifiedSuperclassName` @@ -73,15 +69,12 @@ pub fn get_qualified_super_class_name<'gc>( }; if let Some(super_class) = class.superclass_object() { - Ok(AvmString::new( - activation.context.gc_context, - super_class - .inner_class_definition() - .read() - .name() - .to_qualified_name(), - ) - .into()) + Ok(super_class + .inner_class_definition() + .read() + .name() + .to_qualified_name(activation.context.gc_context) + .into()) } else { Ok(Value::Null) } @@ -98,6 +91,6 @@ pub fn get_definition_by_name<'gc>( .get(0) .unwrap_or(&Value::Undefined) .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) } diff --git a/core/src/avm2/names.rs b/core/src/avm2/names.rs index a3c3b26ee..b9d329c87 100644 --- a/core/src/avm2/names.rs +++ b/core/src/avm2/names.rs @@ -4,7 +4,7 @@ use crate::avm2::activation::Activation; use crate::avm2::script::TranslationUnit; use crate::avm2::value::Value; use crate::avm2::Error; -use crate::string::AvmString; +use crate::string::{AvmString, BorrowWStr, WStr, WString}; use gc_arena::{Collect, MutationContext}; use swf::avm2::types::{ AbcFile, Index, Multiname as AbcMultiname, Namespace as AbcNamespace, @@ -206,32 +206,34 @@ impl<'gc> QName<'gc> { /// NAMESPACE::LOCAL_NAME /// NAMESPACE.LOCAL_NAME (Where the LAST dot is used to split the namespace & local_name) /// LOCAL_NAME (Use the public namespace) - pub fn from_qualified_name(name: &str, mc: MutationContext<'gc, '_>) -> Self { - if let Some((package_name, local_name)) = name.rsplit_once("::") { + pub fn from_qualified_name(name: AvmString<'gc>, mc: MutationContext<'gc, '_>) -> Self { + 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 { - ns: Namespace::Package(AvmString::new(mc, package_name.to_string())), - name: AvmString::new(mc, local_name.to_string()), - } - } 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()), + ns: Namespace::Package(AvmString::new_ucs2(mc, package_name.into())), + name: AvmString::new_ucs2(mc, local_name.into()), } } else { Self { ns: Namespace::public(), - name: AvmString::new(mc, name.to_string()), + 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 name = self.local_name(); - uri.is_empty() - .then(|| name.to_string()) - .unwrap_or_else(|| format!("{}::{}", uri, name)) + uri.is_empty().then(|| name).unwrap_or_else(|| { + let mut buf = WString::from(uri.borrow()); + buf.push_str(WStr::from_units(b"::")); + buf.push_str(name.borrow()); + AvmString::new_ucs2(mc, buf) + }) } 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. pub fn as_uri(&self, mc: MutationContext<'gc, '_>) -> AvmString<'gc> { - match self.ns { - Namespace::Namespace(s) if s != "" => { - AvmString::new(mc, format!("{}::{}", &*s, &*self.name)) - } - Namespace::Package(s) if s != "" => { - AvmString::new(mc, format!("{}::{}", &*s, &*self.name)) - } - Namespace::PackageInternal(s) if s != "" => { - AvmString::new(mc, format!("{}::{}", &*s, &*self.name)) - } - Namespace::Protected(s) if s != "" => { - AvmString::new(mc, format!("{}::{}", &*s, &*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 ns = match &self.ns { + Namespace::Namespace(s) => s.borrow(), + Namespace::Package(s) => s.borrow(), + Namespace::PackageInternal(s) => s.borrow(), + Namespace::Protected(s) => s.borrow(), + Namespace::Explicit(s) => s.borrow(), + Namespace::StaticProtected(s) => s.borrow(), + Namespace::Private(s) => s.borrow(), + Namespace::Any => WStr::from_units(b"*"), + }; + + if ns.is_empty() { + return 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) } } diff --git a/core/src/display_object/movie_clip.rs b/core/src/display_object/movie_clip.rs index 492ab06eb..56f72a1fb 100644 --- a/core/src/display_object/movie_clip.rs +++ b/core/src/display_object/movie_clip.rs @@ -586,8 +586,9 @@ impl<'gc> MovieClip<'gc> { for _ in 0..num_symbols { let id = reader.read_u16()?; 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 .context .library diff --git a/core/src/string/common.rs b/core/src/string/common.rs index 46ad91704..f0a2be57d 100644 --- a/core/src/string/common.rs +++ b/core/src/string/common.rs @@ -204,13 +204,19 @@ macro_rules! impl_str_methods { crate::string::ops::str_split($deref, separator) } - /// Analogue of [`str::split_at`] + /// Analogue of [`str::split_at`]. #[inline] pub fn split_at($self: $receiver, index: usize) -> (crate::string::WStr<$lt>, crate::string::WStr<$lt>) { let s = $deref; (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`]. #[inline] pub fn trim_matches<$($pat_gen)* P: crate::string::Pattern<$pat_lt>>($self: $pat_self, pattern: P) -> WStr<$pat_lt> { diff --git a/core/src/string/ops.rs b/core/src/string/ops.rs index 92f9bd100..570f19fd8 100644 --- a/core/src/string/ops.rs +++ b/core/src/string/ops.rs @@ -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 { matches!( pattern.into_searcher(string).next(),