Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

avm1+avm2: Implement SharedObject.size/getSize #12081

Merged
merged 2 commits into from
Jul 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 33 additions & 18 deletions core/src/avm1/globals/shared_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,18 @@ fn deserialize_lso<'gc>(
Ok(obj.into())
}

fn new_lso<'gc>(activation: &mut Activation<'_, 'gc>, name: &str, data: Object<'gc>) -> Lso {
let mut w = Amf0Writer::default();
recursive_serialize(activation, data, &mut w);
w.commit_lso(
&name
.split('/')
.last()
.map(|e| e.to_string())
.unwrap_or_else(|| "<unknown>".to_string()),
)
}

pub fn get_local<'gc>(
activation: &mut Activation<'_, 'gc>,
_this: Object<'gc>,
Expand Down Expand Up @@ -510,32 +522,35 @@ pub fn flush<'gc>(
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
let data = this.get("data", activation)?.coerce_to_object(activation);

let this_obj = this.as_shared_object().unwrap();
let name = this_obj.get_name();

let mut w = Amf0Writer::default();
recursive_serialize(activation, data, &mut w);
let mut lso = w.commit_lso(
&name
.split('/')
.last()
.map(|e| e.to_string())
.unwrap_or_else(|| "<unknown>".to_string()),
);

let bytes = flash_lso::write::write_to_bytes(&mut lso).unwrap_or_default();

Ok(activation.context.storage.put(&name, &bytes).into())
let mut lso = new_lso(activation, &name, data);
flash_lso::write::write_to_bytes(&mut lso).unwrap_or_default();
// Flash does not write empty LSOs to disk
if lso.body.is_empty() {
Ok(true.into())
} else {
let bytes = flash_lso::write::write_to_bytes(&mut lso).unwrap_or_default();
Ok(activation.context.storage.put(&name, &bytes).into())
}
}

pub fn get_size<'gc>(
activation: &mut Activation<'_, 'gc>,
_this: Object<'gc>,
this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
avm1_stub!(activation, "SharedObject", "getSize");
Ok(Value::Undefined)
let data = this.get("data", activation)?.coerce_to_object(activation);
let this_obj = this.as_shared_object().unwrap();
let name = this_obj.get_name();
let mut lso = new_lso(activation, &name, data);
// Flash returns 0 for empty LSOs, but the actual number of bytes (including the header) otherwise
if lso.body.is_empty() {
Ok(0.into())
} else {
let bytes = flash_lso::write::write_to_bytes(&mut lso).unwrap_or_default();
Ok(bytes.len().into())
}
}

pub fn send<'gc>(
Expand Down
5 changes: 2 additions & 3 deletions core/src/avm2/globals/flash/net/SharedObject.as
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ package flash.net

native public static function getLocal(name:String, localPath:String = null, secure:Boolean = false): SharedObject;

native public function get size() : uint;

native public function flush(minDiskSpace:int = 0) : String;
native public function close() : void;
native public function clear() : void;
Expand All @@ -29,9 +31,6 @@ package flash.net

// note: this is supposed to be a read-only property
public var data: Object;

// note: this is supposed to be a read-only property
public var size: uint;

ruffle var _ruffleName: String;
}
Expand Down
63 changes: 51 additions & 12 deletions core/src/avm2/globals/flash/net/shared_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,23 @@ use crate::string::AvmString;
use flash_lso::types::{AMFVersion, Lso};
use std::borrow::Cow;

fn new_lso<'gc>(
activation: &mut Activation<'_, 'gc>,
name: &str,
data: Object<'gc>,
) -> Result<Lso, Error<'gc>> {
let mut elements = Vec::new();
crate::avm2::amf::recursive_serialize(activation, data, &mut elements, AMFVersion::AMF3)?;
Ok(Lso::new(
elements,
name.split('/')
.last()
.map(|e| e.to_string())
.unwrap_or_else(|| "<unknown>".to_string()),
AMFVersion::AMF3,
))
}

pub fn get_local<'gc>(
activation: &mut Activation<'_, 'gc>,
this: Object<'gc>,
Expand Down Expand Up @@ -193,20 +210,42 @@ pub fn flush<'gc>(
.coerce_to_string(activation)?;
let name = name.to_utf8_lossy();

let mut elements = Vec::new();
crate::avm2::amf::recursive_serialize(activation, data, &mut elements, AMFVersion::AMF3)?;
let mut lso = Lso::new(
elements,
name.split('/')
.last()
.map(|e| e.to_string())
.unwrap_or_else(|| "<unknown>".to_string()),
AMFVersion::AMF3,
);
let mut lso = new_lso(activation, &name, data)?;
// Flash does not write empty LSOs to disk
if lso.body.is_empty() {
Ok(true.into())
} else {
let bytes = flash_lso::write::write_to_bytes(&mut lso).unwrap_or_default();
Ok(activation.context.storage.put(&name, &bytes).into())
}
}

pub fn get_size<'gc>(
activation: &mut Activation<'_, 'gc>,
this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
let data = this
.get_public_property("data", activation)?
.coerce_to_object(activation)?;

let bytes = flash_lso::write::write_to_bytes(&mut lso).unwrap_or_default();
let ruffle_name = Multiname::new(
Namespace::package("__ruffle__", &mut activation.borrow_gc()),
"_ruffleName",
);
let name = this
.get_property(&ruffle_name, activation)?
.coerce_to_string(activation)?;
let name = name.to_utf8_lossy();

Ok(activation.context.storage.put(&name, &bytes).into())
let mut lso = new_lso(activation, &name, data)?;
// Flash returns 0 for empty LSOs, but the actual number of bytes (including the header) otherwise
if lso.body.is_empty() {
Ok(0.into())
} else {
let bytes = flash_lso::write::write_to_bytes(&mut lso).unwrap_or_default();
Ok(bytes.len().into())
}
}

pub fn close<'gc>(
Expand Down
3 changes: 3 additions & 0 deletions tests/tests/swfs/avm1/shared_object/output1.txt
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
No data found. Initializing...
size: 0
size: 279
size: 279
1 change: 1 addition & 0 deletions tests/tests/swfs/avm1/shared_object/output2.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ o.b: b
delete
false
saved: true
size: 279
6 changes: 6 additions & 0 deletions tests/tests/swfs/avm1/shared_object/test.as
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ class test {

if(obj.data.saved === undefined) {
trace("No data found. Initializing...");
trace("size: " + obj.getSize());
obj.data.saved = true;
obj.data.num = 10;
obj.data.str = "hello";
Expand All @@ -23,7 +24,10 @@ class test {
obj.data.testxml = new XML("<test>Test</test>");

obj.data.o = {a: "a", b: "b"};

trace("size: " + obj.getSize());
obj.flush();
trace("size: " + obj.getSize());
} else {
trace("saved: " + obj.data.saved);
trace("num: " + obj.data.num);
Expand All @@ -44,9 +48,11 @@ class test {

trace("o.a: " + obj.data.o.a);
trace("o.b: " + obj.data.o.b);

trace("delete");
trace(delete obj.data);
trace("saved: " + obj.data.saved);
trace("size: " + obj.getSize());
}
}
}
Binary file modified tests/tests/swfs/avm1/shared_object/test.fla
Binary file not shown.
Binary file modified tests/tests/swfs/avm1/shared_object/test.swf
Binary file not shown.
11 changes: 9 additions & 2 deletions tests/tests/swfs/avm2/shared_object/Test.as
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@

if(obj.data.props === undefined) {
trace("No data found. Initializing...");
trace("sizes: obj = " + obj.size + ", otherObj = " + otherObj.size);

storeData(obj.data)
storeData(otherObj.data)
Expand All @@ -74,8 +75,10 @@
trace("otherObj.data.props:")
dump(otherObj.data.props);

trace("sizes: obj = " + obj.size + ", otherObj = " + otherObj.size);
obj.flush();
otherObj.flush();
trace("sizes: obj = " + obj.size + ", otherObj = " + otherObj.size);
} else {
trace("obj.data.hidden: " + obj.data.hidden);
trace("otherObj.data.hidden: " + otherObj.data.hidden);
Expand All @@ -87,6 +90,9 @@
trace()
trace("otherObj dump:")
dump(otherObj.data.props)

trace();
trace("sizes: obj = " + obj.size + ", otherObj = " + otherObj.size);

// Test SharedObject.clear()
trace();
Expand All @@ -98,6 +104,9 @@
trace();
trace("obj dump:");
dump(obj.data);

trace();
trace("sizes: obj = " + obj.size + ", otherObj = " + otherObj.size);

trace();
trace("obj dump again:");
Expand Down Expand Up @@ -132,5 +141,3 @@ function dump(obj:Object) {

}
}

test.main();
3 changes: 3 additions & 0 deletions tests/tests/swfs/avm2/shared_object/output1.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
typeof obj =object
typeof otherObj =object
No data found. Initializing...
sizes: obj = 0, otherObj = 0
otherObj.data.props:
0 = true type boolean
1 = hello type string
Expand All @@ -13,3 +14,5 @@ otherObj.data.props:
8 = type object
val.aPropertyThatIsNotANumber: strange property
9 = (UTC) Sun Jan 25 20:31:23 1970 UTC
sizes: obj = 299, otherObj = 330
sizes: obj = 299, otherObj = 330
4 changes: 4 additions & 0 deletions tests/tests/swfs/avm2/shared_object/output2.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,13 @@ otherObj dump:
val.aPropertyThatIsNotANumber: strange property
9 = (UTC) Sun Jan 25 20:31:23 1970 UTC

sizes: obj = 299, otherObj = 330

obj.clear()
obj == previousData: false

obj dump:

sizes: obj = 0, otherObj = 330

obj dump again:
Binary file modified tests/tests/swfs/avm2/shared_object/test.swf
Binary file not shown.