avm2: Implement `unescape`

This commit is contained in:
EmperorBale 2023-03-07 17:23:16 -08:00 committed by Bale
parent cbb2d81240
commit 683f6cc890
2 changed files with 49 additions and 0 deletions

View File

@ -502,6 +502,7 @@ pub fn load_player_globals<'gc>(
toplevel::encode_uri_component,
script,
)?;
function(activation, "", "unescape", toplevel::unescape, script)?;
avm2_system_class!(regexp, activation, regexp::create_class(activation), script);
avm2_system_class!(vector, activation, vector::create_class(activation), script);

View File

@ -8,6 +8,7 @@ use crate::avm2::value::Value;
use crate::avm2::Error;
use crate::string::{AvmString, WStr, WString};
use crate::stub::Stub;
use ruffle_wstr::Integer;
use std::borrow::Cow;
use std::fmt::Write;
@ -267,6 +268,53 @@ pub fn escape<'gc>(
Ok(AvmString::new(activation.context.gc_context, output).into())
}
pub fn unescape<'gc>(
activation: &mut Activation<'_, 'gc>,
_this: Option<Object<'gc>>,
args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
let value = match args.first() {
None => return Ok("undefined".into()),
Some(Value::Undefined) => return Ok("null".into()),
Some(value) => value.coerce_to_string(activation)?,
};
let mut output = WString::new();
let mut index = 0;
while let Some(byte) = value.get(index) {
index += 1;
if byte != b'%' as u16 {
output.push(byte);
continue;
}
let prev_index = index;
let len = match value.get(index) {
// 0x75 == 'u'
Some(0x75) => {
// increment one to consume the 'u'
index += 1;
4
}
_ => 2,
};
if let Some(x) = value
.slice(index..)
.and_then(|v| v.slice(..len))
.and_then(|v| u32::from_wstr_radix(v, 16).ok())
{
// NOTE: Yes, unpaired surrogates are allowed
output.push(x as u16);
index += len;
} else {
output.push(b'%' as u16);
index = prev_index;
}
}
Ok(AvmString::new(activation.context.gc_context, output).into())
}
pub fn encode_uri<'gc>(
activation: &mut Activation<'_, 'gc>,
_this: Option<Object<'gc>>,