├── .github ├── dependabot.yml └── workflows │ └── rust.yml ├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── flash-lso ├── .gitignore ├── Cargo.toml ├── README.md ├── benches │ └── benchmarks.rs ├── src │ ├── amf0 │ │ ├── mod.rs │ │ ├── read.rs │ │ ├── type_marker.rs │ │ ├── write.rs │ │ └── writer │ │ │ ├── amf0_writer.rs │ │ │ ├── array_writer.rs │ │ │ ├── cache_key.rs │ │ │ ├── mod.rs │ │ │ ├── obj_writer.rs │ │ │ └── object_writer.rs │ ├── amf3 │ │ ├── custom_encoder.rs │ │ ├── element_cache.rs │ │ ├── length.rs │ │ ├── mod.rs │ │ ├── read.rs │ │ ├── type_marker.rs │ │ └── write.rs │ ├── errors.rs │ ├── extra │ │ ├── flex │ │ │ ├── mod.rs │ │ │ ├── read.rs │ │ │ └── write.rs │ │ └── mod.rs │ ├── lib.rs │ ├── nom_utils.rs │ ├── packet │ │ ├── mod.rs │ │ ├── read.rs │ │ └── write.rs │ ├── read.rs │ ├── types │ │ ├── amf_version.rs │ │ ├── attribute.rs │ │ ├── class_definition.rs │ │ ├── element.rs │ │ ├── lso.rs │ │ ├── lso_header.rs │ │ ├── mod.rs │ │ ├── object_id.rs │ │ ├── reference.rs │ │ └── value.rs │ └── write.rs └── tests │ ├── README.md │ ├── amf │ ├── LearnToFly3.profileData.saveString.amf │ ├── LearnToFly3.profileData.saveString.json │ ├── object-with-vec-obj-child-referencing-parent.amf │ ├── object-with-vec-obj-child-referencing-parent.json │ ├── self-referential-array.amf │ ├── self-referential-array.json │ ├── self-referential-dict.amf │ ├── self-referential-dict.json │ ├── self-referential-object.amf │ ├── self-referential-object.json │ ├── self-referential-object.txt │ ├── self-referential-vec-object.amf │ └── self-referential-vec-object.json │ ├── integration_tests.rs │ ├── packet │ ├── armorgames_auth_request.dat │ └── armorgames_auth_response.dat │ └── sol │ ├── 00000004.sol │ ├── 2.sol │ ├── AS2-Array-Demo.json │ ├── AS2-Array-Demo.sol │ ├── AS2-Boolean-Demo.json │ ├── AS2-Boolean-Demo.sol │ ├── AS2-Date-Demo.json │ ├── AS2-Date-Demo.sol │ ├── AS2-Demo.json │ ├── AS2-Demo.sol │ ├── AS2-ECMAArray-Demo.json │ ├── AS2-ECMAArray-Demo.sol │ ├── AS2-Integer-Demo.json │ ├── AS2-Integer-Demo.sol │ ├── AS2-LongString-Demo.json │ ├── AS2-LongString-Demo.sol │ ├── AS2-Null-Demo.json │ ├── AS2-Null-Demo.sol │ ├── AS2-Number-Demo.json │ ├── AS2-Number-Demo.sol │ ├── AS2-Object-Demo.json │ ├── AS2-Object-Demo.sol │ ├── AS2-String-Demo.json │ ├── AS2-String-Demo.sol │ ├── AS2-TypedObject-Demo.json │ ├── AS2-TypedObject-Demo.sol │ ├── AS2-Undefined-Demo.json │ ├── AS2-Undefined-Demo.sol │ ├── AS2-XML-Demo.json │ ├── AS2-XML-Demo.sol │ ├── AS2-half-life-2-flash.json │ ├── AS2-half-life-2-flash.sol │ ├── AS3-Array-Demo.json │ ├── AS3-Array-Demo.sol │ ├── AS3-Boolean-Demo.json │ ├── AS3-Boolean-Demo.sol │ ├── AS3-ByteArray-Demo.json │ ├── AS3-ByteArray-Demo.sol │ ├── AS3-Date-Demo.json │ ├── AS3-Date-Demo.sol │ ├── AS3-Demo.json │ ├── AS3-Demo.sol │ ├── AS3-Dictionary-Demo.json │ ├── AS3-Dictionary-Demo.sol │ ├── AS3-Integer-Demo.json │ ├── AS3-Integer-Demo.sol │ ├── AS3-Null-Demo.json │ ├── AS3-Null-Demo.sol │ ├── AS3-Number-Demo.json │ ├── AS3-Number-Demo.sol │ ├── AS3-Object-Demo.json │ ├── AS3-Object-Demo.sol │ ├── AS3-String-Demo.json │ ├── AS3-String-Demo.sol │ ├── AS3-TypedObject-Demo.json │ ├── AS3-TypedObject-Demo.sol │ ├── AS3-Undefined-Demo.json │ ├── AS3-Undefined-Demo.sol │ ├── AS3-VectorInt-Demo.json │ ├── AS3-VectorInt-Demo.sol │ ├── AS3-VectorNumber-Demo.json │ ├── AS3-VectorNumber-Demo.sol │ ├── AS3-VectorObject-Demo.json │ ├── AS3-VectorObject-Demo.sol │ ├── AS3-VectorTypedObject-Demo.json │ ├── AS3-VectorTypedObject-Demo.sol │ ├── AS3-VectorUint-Demo.json │ ├── AS3-VectorUint-Demo.sol │ ├── AS3-XML-Demo.json │ ├── AS3-XML-Demo.sol │ ├── AS3-XMLDoc-Demo.json │ ├── AS3-XMLDoc-Demo.sol │ ├── AkamaiEnterprisePlayer.userData.json │ ├── AkamaiEnterprisePlayer.userData.sol │ ├── ClarenceSave_SLOT1.json │ ├── ClarenceSave_SLOT1.sol │ ├── CoC_8.json │ ├── CoC_8.sol │ ├── HIRO_NETWORK_CAPPING_COOKIE.json │ ├── HIRO_NETWORK_CAPPING_COOKIE.sol │ ├── InfectonatorSurvivors76561198009932603.json │ ├── InfectonatorSurvivors76561198009932603.sol │ ├── JY1.json │ ├── JY1.sol │ ├── Labrat2.json │ ├── Labrat2.sol │ ├── MARDEKv3__sg_1.json │ ├── MARDEKv3__sg_1.sol │ ├── MetadataHistory.json │ ├── MetadataHistory.sol │ ├── Minimal.json │ ├── Minimal.sol │ ├── Minimalv2.json │ ├── Minimalv2.sol │ ├── Party1.json │ ├── Party1.sol │ ├── Space.json │ ├── Space.sol │ ├── StringTest.json │ ├── StringTest.sol │ ├── arenaMadnessGame2.json │ ├── arenaMadnessGame2.sol │ ├── canvas.json │ ├── canvas.sol │ ├── com.jeroenwijering.json │ ├── com.jeroenwijering.sol │ ├── cramjs.json │ ├── cramjs.sol │ ├── dolphin_show(1).json │ ├── dolphin_show(1).sol │ ├── flagstaff(1).json │ ├── flagstaff(1).sol │ ├── flagstaff.json │ ├── flagstaff.sol │ ├── flash.viewer.json │ ├── flash.viewer.sol │ ├── mediaPlayerUserSettings.json │ ├── mediaPlayerUserSettings.sol │ ├── oppDetailPrefs.json │ ├── oppDetailPrefs.sol │ ├── other │ ├── Johngame5.json │ ├── Johngame5.sol │ ├── fishtycoon.json │ ├── fishtycoon.sol │ ├── mainprofile.json │ ├── mainprofile.sol │ ├── self-referential.json │ └── self-referential.sol │ ├── previousVideo.json │ ├── previousVideo.sol │ ├── robokill.json │ ├── robokill.sol │ ├── settings.json │ ├── settings.sol │ ├── slot1.json │ ├── slot1.sol │ ├── slot1_party.json │ ├── slot1_party.sol │ ├── soundData.json │ ├── soundData.sol │ ├── soundData_level0.json │ ├── soundData_level0.sol │ ├── timeDisplayConfig.json │ ├── timeDisplayConfig.sol │ ├── user(1).json │ ├── user(1).sol │ ├── user.json │ └── user.sol ├── fuzz ├── .gitignore ├── Cargo.toml └── fuzz_targets │ ├── fuzz_amf0_body.rs │ ├── fuzz_amf0_element_array.rs │ ├── fuzz_amf0_header.rs │ ├── fuzz_amf3_body.rs │ ├── fuzz_amf3_int_signed.rs │ ├── fuzz_amf3_int_unsigned.rs │ ├── fuzz_amf3_single_element.rs │ └── fuzz_amf3_string.rs ├── lso-to-json ├── .gitignore ├── Cargo.toml └── src │ └── main.rs └── web ├── Cargo.toml ├── src ├── blob_bindgen.rs ├── component_hexview.rs ├── component_modal.rs ├── component_model.rs ├── component_number_input.rs ├── component_string_input.rs ├── component_tab.rs ├── component_tabs.rs ├── component_treenode.rs ├── jquery_bindgen.rs ├── lib.rs ├── uintarray_bindgen.rs ├── url_bindgen.rs └── web_expect.rs └── static ├── .gitignore ├── css └── bootstrap.min.css ├── icon ├── LICENSE ├── check.svg ├── database.svg ├── file-text.svg ├── file.svg ├── folder-minus.svg ├── folder-plus.svg └── x.svg ├── index.html └── script ├── bootstrap.min.js └── jquery.min.js /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | 8 | - package-ecosystem: "cargo" 9 | directory: "/" 10 | schedule: 11 | interval: "weekly" 12 | groups: 13 | yew: 14 | # Likely to need its own fixes, separate to anything else 15 | patterns: 16 | - "yew" 17 | 18 | cargo-minor: 19 | patterns: 20 | - "*" 21 | update-types: 22 | - "minor" 23 | - "patch" -------------------------------------------------------------------------------- /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | 8 | env: 9 | CARGO_TERM_COLOR: always 10 | 11 | jobs: 12 | build: 13 | 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v4 18 | - name: Build 19 | run: cargo build --verbose --all-features 20 | - name: Run tests 21 | run: cargo test --verbose --all-features 22 | - name: Run clippy 23 | run: cargo clippy --all --tests --all-features -- -D warnings 24 | - name: Check formatting 25 | run: cargo fmt -- --check 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | .idea 3 | Cargo.lock 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | members = [ 4 | "flash-lso", 5 | "lso-to-json", 6 | "web" 7 | ] 8 | 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Callum Thomson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## [flash-lso](https://crates.io/crates/flash-lso) 2 | 3 | [![GitHub license](https://img.shields.io/github/license/CUB3D/rust-sol)](https://github.com/CUB3D/rust-flash-lso/blob/master/LICENSE) 4 | [![GitHub issues](https://img.shields.io/github/issues/CUB3D/rust-sol)](https://github.com/CUB3D/rust-flash-lso/issues) 5 | 6 | A parser/encoder for Adobe Local Shared Object (LSO) file format (.sol), AMF0 and AFM3 in 100% safe rust. 7 | #### Features: 8 | - Parsing and encoding fully supported 9 | - Heavily tested and fuzzed 10 | - Circular references fully supported 11 | - Support for externalizable types (flash.utils.IExternalizable) 12 | - Support for Adobe flex types 13 | 14 | ## Example 15 | ```rust 16 | use std::fs::File; 17 | use std::io::Read; 18 | use flash_lso::read::Reader; 19 | fn main() { 20 | let mut x = File::open(path).expect("Couldn't open file"); 21 | let mut data = Vec::new(); 22 | let _ = x.read_to_end(&mut data).expect("Unable to read file"); 23 | let d = Reader::default().parse_full(&data).expect("Failed to parse lso file"); 24 | println!("{:#?}", d); 25 | } 26 | ``` 27 | 28 | ## Development / Testing 29 | To aid with development, there is a sub-project: reader, which can parse either a single file or all files in a directory and will report on which files succeeded and failed to parse 30 | 31 | In future this will be used to verify and compare the output with the official implementation 32 | 33 | ## Fuzzing 34 | This project makes use of cargo-fuzz to ensure correct handling of invalid data 35 | ``` 36 | cargo +nightly fuzz run --release fuzz_amf3_body 37 | ``` 38 | 39 | ## Web 40 | building: 41 | ``` 42 | wasm-pack build --out-name web --out-dir ./static --target web --release 43 | miniserve ./static --index index.html 44 | ``` 45 | 46 | ## License 47 | This project is licensed under MIT. 48 | 49 | Icons used in the web editor (web/static/icon) are sourced from https://feathericons.com under MIT 50 | 51 | Some test cases are covered under their own License, see [README.md](flash-lso/tests/README.md) for details 52 | -------------------------------------------------------------------------------- /flash-lso/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /flash-lso/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "flash-lso" 3 | version = "0.6.0" 4 | authors = ["CUB3D "] 5 | description = "Fast and safe SOL/AMF0/AMF3 parsing. Supports serde, Adobe flex and cyclic references" 6 | repository = "https://github.com/CUB3D/rust-sol" 7 | readme = "README.md" 8 | license = "MIT" 9 | keywords = ["sol", "amf", "parser", "serializer", "flash"] 10 | edition = "2021" 11 | categories = ["data-structures", "encoding", "parser-implementations"] 12 | 13 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 14 | 15 | [dependencies] 16 | nom = "7.1.3" 17 | enumset = "1.1.5" 18 | thiserror = "2.0.3" 19 | serde = { version = "1.0.210", optional = true, features = ["derive", "rc"] } 20 | 21 | [dev-dependencies] 22 | pretty_assertions = "1.4.0" 23 | serde_json = "1.0.128" 24 | criterion = "0.5.1" 25 | 26 | [[bench]] 27 | name = "benchmarks" 28 | harness = false 29 | 30 | [features] 31 | default = ["amf3"] 32 | flex = [] 33 | serde = ["dep:serde", "enumset/serde"] 34 | all = ["serde", "flex"] 35 | amf3 = [] 36 | 37 | [lints.rust] 38 | unexpected_cfgs = { level = "warn", check-cfg = ['cfg(fuzzing)'] } -------------------------------------------------------------------------------- /flash-lso/README.md: -------------------------------------------------------------------------------- 1 | ## [flash-lso](https://crates.io/crates/flash-lso) 2 | 3 | [![GitHub license](https://img.shields.io/github/license/CUB3D/rust-sol)](https://github.com/CUB3D/rust-flash-lso/blob/master/LICENSE) 4 | [![GitHub issues](https://img.shields.io/github/issues/CUB3D/rust-sol)](https://github.com/CUB3D/rust-flash-lso/issues) 5 | 6 | A parser and serializer for Adobe Local Shared Object (LSO) file format (.sol), AMF0 and AFM3 in 100% safe rust 7 | 8 | The primary goal of this crate is to be as safe as possible against malformed and invalid input and to fail cleanly when this is identified. 9 | 10 | ## Example 11 | ```rust 12 | use std::fs::File; 13 | use std::io::Read; 14 | use flash_lso::read::Reader; 15 | fn main() { 16 | let mut x = File::open(path).expect("Couldn't open file"); 17 | let mut data = Vec::new(); 18 | let _ = x.read_to_end(&mut data).expect("Unable to read file"); 19 | let d = Reader::default().parse_full(&data).expect("Failed to parse lso file"); 20 | println!("{:#?}", d); 21 | } 22 | ``` 23 | 24 | ## Web 25 | The ```web``` directory contains an example web viewer for LSO files using yew. To run, first build into WASM like so 26 | ```shell script 27 | cd web 28 | wasm-pack build --out-name wasm --out-dir ./static --target web --release 29 | ``` 30 | Then serve the static directory like so 31 | ```shell script 32 | # If needed install miniserve with `cargo install miniserve` 33 | miniserve ./static --index index.html 34 | ``` 35 | 36 | ## Development / Testing 37 | This project has a collection of integration tests to verify that it is able to serialize and then deserialize LSO files to produce output that is identical to it's input 38 | Also available is a lso-to-json project which allows dumping an LSO file to json for debugging and testing. 39 | 40 | ## Features 41 | To enable serde support 42 | ```toml 43 | flash-lso = { version = "0.2.0", features = ["serde"] } 44 | ``` 45 | To enable (alpha) support for flex 46 | ```toml 47 | flash-lso = { version = "0.2.0", features = ["flex"] } 48 | ``` 49 | 50 | ## Fuzzing 51 | This project makes use of cargo-fuzz to ensure correct handling of invalid data 52 | ``` 53 | cargo fuzz run --release fuzz_amf3_body 54 | ``` 55 | 56 | ## License 57 | This project is licensed under MIT 58 | -------------------------------------------------------------------------------- /flash-lso/benches/benchmarks.rs: -------------------------------------------------------------------------------- 1 | #![feature(test)] 2 | 3 | extern crate test; 4 | 5 | use flash_lso::read::Reader; 6 | 7 | use criterion::{black_box, criterion_group, criterion_main, Criterion}; 8 | 9 | criterion_group!(benches, criterion_benchmark); 10 | criterion_main!(benches); 11 | 12 | macro_rules! auto_bench { 13 | ($([$name: ident, $path: expr]),*) => { 14 | fn criterion_benchmark(c: &mut Criterion) { 15 | $( 16 | c.bench_function(concat!("parse_", $path), |b| { 17 | let input_bytes = include_bytes!(concat!("../tests/sol/", $path, ".sol")); 18 | b.iter(|| { 19 | black_box(Reader::default().parse(input_bytes).unwrap()); 20 | }) 21 | }); 22 | )* 23 | } 24 | } 25 | } 26 | 27 | auto_bench! { 28 | // AS2 29 | [bench_as2_array, "AS2-Array-Demo"], 30 | [bench_as2_boolean, "AS2-Boolean-Demo"], 31 | [bench_as2_date, "AS2-Date-Demo"], 32 | [bench_as2_demo, "AS2-Demo"], 33 | [bench_as2_ecma_array, "AS2-ECMAArray-Demo"], 34 | [bench_as2_integer, "AS2-Integer-Demo"], 35 | [bench_as2_long_string, "AS2-LongString-Demo"], 36 | [bench_as2_null, "AS2-Null-Demo"], 37 | [bench_as2_number, "AS2-Number-Demo"], 38 | [bench_as2_object, "AS2-Object-Demo"], 39 | [bench_as2_string, "AS2-String-Demo"], 40 | [bench_as2_typed_object, "AS2-TypedObject-Demo"], 41 | [bench_as2_undefined, "AS2-Undefined-Demo"], 42 | [bench_as2_xml, "AS2-XML-Demo"], 43 | // AS3 44 | [bench_as3_number, "AS3-Number-Demo"], 45 | [bench_as3_boolean, "AS3-Boolean-Demo"], 46 | [bench_as3_string, "AS3-String-Demo"], 47 | [bench_as3_object, "AS3-Object-Demo"], 48 | [bench_as3_null, "AS3-Null-Demo"], 49 | [bench_as3_undefined, "AS3-Undefined-Demo"], 50 | [bench_as3_strict_array, "AS3-Array-Demo"], 51 | [bench_as3_date, "AS3-Date-Demo"], 52 | [bench_as3_xml, "AS3-XML-Demo"], 53 | [bench_as3_xml_doc, "AS3-XMLDoc-Demo"], 54 | [bench_as3_typed_object, "AS3-TypedObject-Demo"], 55 | [bench_as3_integer, "AS3-Integer-Demo"], 56 | [bench_as3_byte_array, "AS3-ByteArray-Demo"], 57 | [bench_as3_vector_int, "AS3-VectorInt-Demo"], 58 | [bench_as3_vector_unsigned_int, "AS3-VectorUint-Demo"], 59 | [bench_as3_vector_number, "AS3-VectorNumber-Demo"], 60 | [bench_as3_vector_object, "AS3-VectorObject-Demo"], 61 | [bench_as3_vector_typed_object, "AS3-VectorTypedObject-Demo"], 62 | [bench_as3_dictionary, "AS3-Dictionary-Demo"], 63 | [bench_as3_demo, "AS3-Demo"], 64 | // Other 65 | [bench_akamai_enterprise_player, "AkamaiEnterprisePlayer.userData"], 66 | [bench_areana_madness_game_two, "arenaMadnessGame2"], 67 | [bench_canvas, "canvas"], 68 | [bench_clarence_save_slot_1, "ClarenceSave_SLOT1"], 69 | [bench_coc_8, "CoC_8"], 70 | [bench_com_jeroenwijering, "com.jeroenwijering"], 71 | [bench_cramjs, "cramjs"], 72 | [bench_dolphin_show_1, "dolphin_show(1)"], 73 | [bench_flagstaff_1, "flagstaff(1)"], 74 | [bench_flagstaff_2, "flagstaff"], 75 | [bench_flash_viewer, "flash.viewer"], 76 | [bench_hiro_network_capping_cookie, "HIRO_NETWORK_CAPPING_COOKIE"], 77 | [bench_jy1, "JY1"], 78 | [bench_labrat_2, "Labrat2"], 79 | [bench_mardek_v3_sg_1, "MARDEKv3__sg_1"], 80 | [bench_media_player_user_settings, "mediaPlayerUserSettings"], 81 | [bench_minimal, "Minimal"], 82 | [bench_minimal_2, "Minimalv2"], 83 | [bench_previous_video, "previousVideo"], 84 | [bench_robokill, "robokill"], 85 | [bench_settings, "settings"], 86 | [bench_slot_1_party, "slot1_party"], 87 | [bench_sound_data, "soundData"], 88 | [bench_sound_data_level_0, "soundData_level0"], 89 | [bench_space, "Space"], 90 | [bench_string_test, "StringTest"], 91 | [bench_time_display_config, "timeDisplayConfig"], 92 | [bench_user_1, "user(1)"], 93 | [bench_user, "user"], 94 | // Parse only 95 | [bench_infectonator_survivors_76561198009932603, "InfectonatorSurvivors76561198009932603"], 96 | [bench_slot_1, "slot1"], 97 | [bench_party_1, "Party1"], 98 | [bench_metadata_history, "MetadataHistory"] 99 | } 100 | -------------------------------------------------------------------------------- /flash-lso/src/amf0/mod.rs: -------------------------------------------------------------------------------- 1 | /// Support for reading AMF0 data 2 | pub mod read; 3 | 4 | /// AMF0 type markers 5 | mod type_marker; 6 | 7 | /// Support for writing AMF0 data 8 | pub mod write; 9 | 10 | /// High-level writer that assists in generation of self-referential amf0 data 11 | pub mod writer; 12 | -------------------------------------------------------------------------------- /flash-lso/src/amf0/type_marker.rs: -------------------------------------------------------------------------------- 1 | /// Type markers used in AMF0 2 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 3 | #[derive(Eq, PartialEq, Debug, Copy, Clone)] 4 | #[repr(u8)] 5 | pub(crate) enum TypeMarker { 6 | /// Number 7 | Number = 0x00, 8 | 9 | /// Boolean 10 | Boolean = 0x01, 11 | 12 | /// String 13 | String = 0x02, 14 | 15 | /// Object start 16 | Object = 0x03, 17 | 18 | /// MovieClip (unused) 19 | MovieClip = 0x04, 20 | 21 | /// Null 22 | Null = 0x05, 23 | 24 | /// Undefined 25 | Undefined = 0x06, 26 | 27 | /// Reference 28 | Reference = 0x07, 29 | 30 | /// Start of an ECMA array 31 | ECMAArray = 0x08, 32 | 33 | /// Object end 34 | ObjectEnd = 0x09, 35 | 36 | /// Strict array start 37 | StrictArray = 0x0A, 38 | 39 | /// Date with timezone 40 | Date = 0x0B, 41 | 42 | /// Long string (length > 65535) 43 | LongString = 0x0C, 44 | 45 | /// Unsupported 46 | Unsupported = 0x0D, 47 | 48 | /// Recordset (unused) 49 | RecordSet = 0x0E, 50 | 51 | /// XML 52 | Xml = 0x0F, 53 | 54 | /// Typed object start 55 | TypedObject = 0x10, 56 | 57 | /// Embedded AMF3 element 58 | AMF3 = 0x11, 59 | } 60 | 61 | impl TryFrom for TypeMarker { 62 | type Error = (); 63 | 64 | fn try_from(value: u8) -> Result { 65 | match value { 66 | 0 => Ok(Self::Number), 67 | 1 => Ok(Self::Boolean), 68 | 2 => Ok(Self::String), 69 | 3 => Ok(Self::Object), 70 | 4 => Ok(Self::MovieClip), 71 | 5 => Ok(Self::Null), 72 | 6 => Ok(Self::Undefined), 73 | 7 => Ok(Self::Reference), 74 | 8 => Ok(Self::ECMAArray), 75 | 9 => Ok(Self::ObjectEnd), 76 | 10 => Ok(Self::StrictArray), 77 | 11 => Ok(Self::Date), 78 | 12 => Ok(Self::LongString), 79 | 13 => Ok(Self::Unsupported), 80 | 14 => Ok(Self::RecordSet), 81 | 15 => Ok(Self::Xml), 82 | 16 => Ok(Self::TypedObject), 83 | 17 => Ok(Self::AMF3), 84 | _ => Err(()), 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /flash-lso/src/amf0/write.rs: -------------------------------------------------------------------------------- 1 | /// Support for encoding AMF0 2 | use crate::types::{Element, Reference, Value}; 3 | use crate::PADDING; 4 | use std::io::Write; 5 | 6 | use crate::amf0::type_marker::TypeMarker; 7 | use crate::nom_utils::write_string; 8 | use crate::write::WriteExt; 9 | use std::io::Result; 10 | use std::ops::Deref; 11 | use std::rc::Rc; 12 | 13 | #[cfg(feature = "amf3")] 14 | use crate::amf3::write::AMF3Encoder; 15 | 16 | fn write_type_marker<'a, 'b: 'a, W: Write + 'a>(writer: &mut W, type_: TypeMarker) -> Result<()> { 17 | writer.write_u8(type_ as u8) 18 | } 19 | 20 | fn write_reference_element<'a, 'b: 'a, W: Write + 'a>(writer: &mut W, r: &Reference) -> Result<()> { 21 | write_type_marker(writer, TypeMarker::Reference)?; 22 | writer.write_u16(r.0)?; 23 | Ok(()) 24 | } 25 | 26 | fn write_number_element<'a, 'b: 'a, W: Write + 'a>(writer: &mut W, s: f64) -> Result<()> { 27 | write_type_marker(writer, TypeMarker::Number)?; 28 | writer.write_f64(s)?; 29 | Ok(()) 30 | } 31 | 32 | fn write_bool_element<'a, 'b: 'a, W: Write + 'a>(writer: &mut W, s: bool) -> Result<()> { 33 | write_type_marker(writer, TypeMarker::Boolean)?; 34 | writer.write_u8(u8::from(s))?; 35 | Ok(()) 36 | } 37 | 38 | fn write_long_string_content<'a, 'b: 'a, W: Write + 'a>(writer: &mut W, s: &'b str) -> Result<()> { 39 | writer.write_u32(s.len() as u32)?; 40 | writer.write_all(s.as_bytes())?; 41 | Ok(()) 42 | } 43 | 44 | fn write_long_string_element<'a, 'b: 'a, W: Write + 'a>(writer: &mut W, s: &'b str) -> Result<()> { 45 | write_type_marker(writer, TypeMarker::LongString)?; 46 | write_long_string_content(writer, s)?; 47 | Ok(()) 48 | } 49 | 50 | fn write_string_element<'a, 'b: 'a, W: Write + 'a>(writer: &mut W, s: &'b str) -> Result<()> { 51 | write_type_marker(writer, TypeMarker::String)?; 52 | write_string(writer, s)?; 53 | Ok(()) 54 | } 55 | 56 | fn write_object_element<'a, 'b: 'a, W: Write + 'a>(writer: &mut W, o: &'b [Element]) -> Result<()> { 57 | write_type_marker(writer, TypeMarker::Object)?; 58 | for element in o { 59 | write_element(writer, element)?; 60 | } 61 | writer.write_u16(0)?; 62 | write_type_marker(writer, TypeMarker::ObjectEnd)?; 63 | Ok(()) 64 | } 65 | 66 | fn write_null_element<'a, 'b: 'a, W: Write + 'a>(writer: &mut W) -> Result<()> { 67 | write_type_marker(writer, TypeMarker::Null) 68 | } 69 | 70 | fn write_undefined_element<'a, 'b: 'a, W: Write + 'a>(writer: &mut W) -> Result<()> { 71 | write_type_marker(writer, TypeMarker::Undefined) 72 | } 73 | 74 | fn write_strict_array_element<'a, 'b: 'a, W: Write + 'a>( 75 | writer: &mut W, 76 | elements: &'b [Rc], 77 | ) -> Result<()> { 78 | write_type_marker(writer, TypeMarker::StrictArray)?; 79 | writer.write_u32(elements.len() as u32)?; 80 | for element in elements { 81 | write_value(writer, element)?; 82 | } 83 | Ok(()) 84 | } 85 | 86 | fn write_date_element<'a, 'b: 'a, W: Write + 'a>( 87 | writer: &mut W, 88 | date: f64, 89 | tz: Option, 90 | ) -> Result<()> { 91 | write_type_marker(writer, TypeMarker::Date)?; 92 | writer.write_f64(date)?; 93 | writer.write_u16(tz.unwrap_or(0))?; 94 | Ok(()) 95 | } 96 | 97 | fn write_unsupported_element<'a, 'b: 'a, W: Write + 'a>(writer: &mut W) -> Result<()> { 98 | write_type_marker(writer, TypeMarker::Unsupported) 99 | } 100 | 101 | fn write_xml_element<'a, 'b: 'a, W: Write + 'a>(writer: &mut W, content: &'b str) -> Result<()> { 102 | write_type_marker(writer, TypeMarker::Xml)?; 103 | write_long_string_content(writer, content)?; 104 | Ok(()) 105 | } 106 | 107 | fn write_typed_object_element<'a, 'b: 'a, W: Write + 'a>( 108 | writer: &mut W, 109 | name: &'b str, 110 | elements: &'b [Element], 111 | ) -> Result<()> { 112 | write_type_marker(writer, TypeMarker::TypedObject)?; 113 | write_string(writer, name)?; 114 | for element in elements { 115 | write_element(writer, element)?; 116 | } 117 | writer.write_u16(0)?; 118 | write_type_marker(writer, TypeMarker::ObjectEnd)?; 119 | Ok(()) 120 | } 121 | 122 | fn write_dense_element<'a, 'b: 'a, W: Write + 'a>( 123 | writer: &mut W, 124 | index: usize, 125 | element: &'b Rc, 126 | ) -> Result<()> { 127 | let index_str = index.to_string(); 128 | 129 | writer.write_u16(index_str.len() as u16)?; 130 | writer.write_all(index_str.as_bytes())?; 131 | write_value(writer, element)?; 132 | 133 | Ok(()) 134 | } 135 | 136 | fn write_ecma_array<'a, 'b: 'a, W: Write + 'a>( 137 | writer: &mut W, 138 | dense: &'b [Rc], 139 | elements: &'b [Element], 140 | length: u32, 141 | ) -> Result<()> { 142 | //TODO: what is the u16 padding 143 | //TODO: sometimes array length is ignored (u32) sometimes its: elements.len() as u32 144 | 145 | write_type_marker(writer, TypeMarker::ECMAArray)?; 146 | writer.write_u32(length)?; 147 | for (idx, value) in dense.iter().enumerate() { 148 | write_dense_element(writer, idx, value)? 149 | } 150 | for element in elements { 151 | write_element(writer, element)? 152 | } 153 | writer.write_u16(0)?; 154 | write_type_marker(writer, TypeMarker::ObjectEnd)?; 155 | Ok(()) 156 | } 157 | 158 | pub(crate) fn write_value<'a, 'b: 'a, W: Write + 'a>( 159 | writer: &mut W, 160 | element: &'b Rc, 161 | ) -> Result<()> { 162 | match element.deref() { 163 | Value::Number(n) => write_number_element(writer, *n), 164 | Value::Bool(b) => write_bool_element(writer, *b), 165 | Value::String(s) => { 166 | if s.len() > 65535 { 167 | write_long_string_element(writer, s) 168 | } else { 169 | write_string_element(writer, s) 170 | } 171 | } 172 | Value::Object(_, elements, class_def) => { 173 | if let Some(class_def) = class_def { 174 | write_typed_object_element(writer, &class_def.name, elements) 175 | } else { 176 | write_object_element(writer, elements) 177 | } 178 | } 179 | Value::Null => write_null_element(writer), 180 | Value::Undefined => write_undefined_element(writer), 181 | Value::StrictArray(_id, a) => write_strict_array_element(writer, a.as_slice()), 182 | Value::Date(d, tz) => write_date_element(writer, *d, *tz), 183 | Value::Unsupported => write_unsupported_element(writer), 184 | Value::XML(x, _string) => write_xml_element(writer, x), 185 | Value::ECMAArray(_id, dense, elems, elems_length) => { 186 | write_ecma_array(writer, dense, elems, *elems_length) 187 | } 188 | #[cfg(feature = "amf3")] 189 | Value::AMF3(e) => { 190 | write_type_marker(writer, TypeMarker::AMF3)?; 191 | let encoder = AMF3Encoder::default(); 192 | encoder.write_value_element(writer, e) 193 | } 194 | Value::Reference(r) => write_reference_element(writer, r), 195 | _ => { 196 | write_unsupported_element(writer) /* Not in amf0, TODO: use the amf3 embedding for every thing else */ 197 | } 198 | } 199 | } 200 | 201 | fn write_element<'a, 'b: 'a, W: Write + 'a>(writer: &mut W, element: &'b Element) -> Result<()> { 202 | write_string(writer, &element.name)?; 203 | write_value(writer, &element.value)?; 204 | Ok(()) 205 | } 206 | 207 | fn write_element_and_padding<'a, 'b: 'a, W: Write + 'a>( 208 | writer: &mut W, 209 | element: &'b Element, 210 | ) -> Result<()> { 211 | write_element(writer, element)?; 212 | writer.write_all(&PADDING)?; 213 | Ok(()) 214 | } 215 | 216 | pub(crate) fn write_body<'a, 'b: 'a, W: Write + 'a>( 217 | writer: &mut W, 218 | elements: &'b [Element], 219 | ) -> Result<()> { 220 | for element in elements { 221 | write_element_and_padding(writer, element)?; 222 | } 223 | Ok(()) 224 | } 225 | -------------------------------------------------------------------------------- /flash-lso/src/amf0/writer/amf0_writer.rs: -------------------------------------------------------------------------------- 1 | use std::{collections::BTreeMap, rc::Rc}; 2 | 3 | use crate::types::{AMFVersion, Element, Lso, Reference, Value}; 4 | 5 | use super::{ArrayWriter, CacheKey, ObjWriter, ObjectWriter}; 6 | 7 | /// A writer for Amf0 encoded data 8 | #[derive(Default)] 9 | pub struct Amf0Writer { 10 | /// The elements present at the root level 11 | pub(crate) elements: Vec, 12 | 13 | /// The current reference number 14 | pub(crate) ref_num: u16, 15 | 16 | /// The reference cache, allows writing self-referential data 17 | pub(crate) cache: BTreeMap, 18 | } 19 | 20 | impl<'a> ObjWriter<'a> for Amf0Writer { 21 | fn add_element(&mut self, name: &str, s: Value, inc_ref: bool) { 22 | if inc_ref { 23 | self.ref_num += 1; 24 | } 25 | 26 | self.elements.push(Element::new(name, Rc::new(s))) 27 | } 28 | 29 | fn object<'c: 'a, 'd>( 30 | &'d mut self, 31 | cache_key: CacheKey, 32 | ) -> (Option>, Reference) 33 | where 34 | 'a: 'c, 35 | 'a: 'd, 36 | { 37 | if let Some(existing_ref) = self.cache.get(&cache_key) { 38 | (None, *existing_ref) 39 | } else { 40 | // Create new object reference 41 | let r = Reference(self.ref_num); 42 | self.ref_num += 1; 43 | 44 | // Cache this new object 45 | self.cache.insert(cache_key, r); 46 | 47 | // Return the writer and the reference 48 | ( 49 | Some(ObjectWriter { 50 | elements: Vec::new(), 51 | parent: self, 52 | }), 53 | r, 54 | ) 55 | } 56 | } 57 | 58 | fn array<'c: 'a, 'd>( 59 | &'d mut self, 60 | cache_key: CacheKey, 61 | ) -> (Option>, Reference) 62 | where 63 | 'a: 'c, 64 | 'a: 'd, 65 | { 66 | if let Some(existing_ref) = self.cache.get(&cache_key) { 67 | (None, *existing_ref) 68 | } else { 69 | // Create new array reference 70 | let r = Reference(self.ref_num); 71 | self.ref_num += 1; 72 | 73 | // Cache this new array 74 | self.cache.insert(cache_key, r); 75 | 76 | // Return the writer and the reference 77 | ( 78 | Some(ArrayWriter { 79 | elements: Vec::new(), 80 | parent: self, 81 | }), 82 | r, 83 | ) 84 | } 85 | } 86 | 87 | fn make_reference(&mut self) -> Reference { 88 | let ref_num = Reference(self.ref_num); 89 | self.ref_num += 1; 90 | ref_num 91 | } 92 | 93 | fn cache_get(&mut self, cache_key: &CacheKey) -> Option { 94 | self.cache.get(cache_key).copied() 95 | } 96 | 97 | fn cache_add(&mut self, cache_key: CacheKey, reference: Reference) { 98 | self.cache.insert(cache_key, reference); 99 | } 100 | } 101 | 102 | impl Amf0Writer { 103 | /// Produce an `Lso` with the given name 104 | pub fn commit_lso(self, name: &str) -> Lso { 105 | Lso::new(self.elements, name, AMFVersion::AMF0) 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /flash-lso/src/amf0/writer/array_writer.rs: -------------------------------------------------------------------------------- 1 | use std::rc::Rc; 2 | 3 | use crate::types::{Element, ObjectId, Reference, Value}; 4 | 5 | use super::{CacheKey, ObjWriter, ObjectWriter}; 6 | 7 | /// A writer for encoding `ECMAArray` contents 8 | pub struct ArrayWriter<'a, 'b> { 9 | /// The elements in this array 10 | pub(crate) elements: Vec, 11 | 12 | /// The parent of this writer 13 | pub(crate) parent: &'a mut dyn ObjWriter<'b>, 14 | } 15 | 16 | impl<'a> ObjWriter<'a> for ArrayWriter<'a, '_> { 17 | fn add_element(&mut self, name: &str, s: Value, inc_ref: bool) { 18 | if inc_ref { 19 | self.make_reference(); 20 | } 21 | 22 | self.elements 23 | .push(Element::new(name.to_string(), Rc::new(s))); 24 | } 25 | 26 | fn object<'c: 'a, 'd>( 27 | &'d mut self, 28 | cache_key: CacheKey, 29 | ) -> (Option>, Reference) 30 | where 31 | 'a: 'c, 32 | 'a: 'd, 33 | { 34 | if let Some(existing_ref) = self.cache_get(&cache_key) { 35 | (None, existing_ref) 36 | } else { 37 | let r = self.make_reference(); 38 | 39 | // Cache this new object 40 | self.cache_add(cache_key, r); 41 | 42 | // Return the writer and the reference 43 | ( 44 | Some(ObjectWriter { 45 | elements: Vec::new(), 46 | parent: self, 47 | }), 48 | r, 49 | ) 50 | } 51 | } 52 | 53 | fn array<'c: 'a, 'd>( 54 | &'d mut self, 55 | cache_key: CacheKey, 56 | ) -> (Option>, Reference) 57 | where 58 | 'a: 'c, 59 | 'a: 'd, 60 | { 61 | if let Some(existing_ref) = self.cache_get(&cache_key) { 62 | (None, existing_ref) 63 | } else { 64 | let r = self.make_reference(); 65 | 66 | // Cache this new array 67 | self.cache_add(cache_key, r); 68 | 69 | // Return the writer and the reference 70 | ( 71 | Some(ArrayWriter { 72 | elements: Vec::new(), 73 | parent: self, 74 | }), 75 | r, 76 | ) 77 | } 78 | } 79 | 80 | fn make_reference(&mut self) -> Reference { 81 | self.parent.make_reference() 82 | } 83 | 84 | fn cache_get(&mut self, cache_key: &CacheKey) -> Option { 85 | self.parent.cache_get(cache_key) 86 | } 87 | 88 | fn cache_add(&mut self, cache_key: CacheKey, reference: Reference) { 89 | self.parent.cache_add(cache_key, reference); 90 | } 91 | } 92 | 93 | impl ArrayWriter<'_, '_> { 94 | /// Finalize this array, adding it to it's parent 95 | /// If this is not called, the array will not be added 96 | pub fn commit>(self, name: T, length: u32) { 97 | self.parent.add_element( 98 | name.as_ref(), 99 | Value::ECMAArray(ObjectId::INVALID, Vec::new(), self.elements, length), 100 | false, 101 | ); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /flash-lso/src/amf0/writer/cache_key.rs: -------------------------------------------------------------------------------- 1 | /// An identifier for a cacheable element 2 | #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 3 | pub struct CacheKey(usize); 4 | 5 | impl CacheKey { 6 | /// Create a `CacheKey` from a pointer representing an element to be serialized 7 | pub fn from_ptr(p: *const T) -> Self { 8 | Self(p as usize) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /flash-lso/src/amf0/writer/mod.rs: -------------------------------------------------------------------------------- 1 | mod amf0_writer; 2 | mod array_writer; 3 | mod cache_key; 4 | mod obj_writer; 5 | mod object_writer; 6 | 7 | pub use amf0_writer::Amf0Writer; 8 | pub use array_writer::ArrayWriter; 9 | pub use cache_key::CacheKey; 10 | pub use obj_writer::ObjWriter; 11 | pub use object_writer::ObjectWriter; 12 | 13 | #[test] 14 | fn fff() { 15 | let mut w = Amf0Writer::default(); 16 | let (aw, _) = w.object(CacheKey::from_ptr(std::ptr::null::())); 17 | let mut aw = aw.unwrap(); 18 | { 19 | aw.string("asdf", "asfd"); 20 | { 21 | let (aw2, _) = aw.object(CacheKey::from_ptr(1 as *const u8)); 22 | let mut aw2 = aw2.unwrap(); 23 | aw2.string("asf", "asdf"); 24 | aw2.commit("asf"); 25 | } 26 | } 27 | aw.commit("foo"); 28 | } 29 | -------------------------------------------------------------------------------- /flash-lso/src/amf0/writer/obj_writer.rs: -------------------------------------------------------------------------------- 1 | use crate::types::{Reference, Value}; 2 | 3 | use super::{ArrayWriter, CacheKey, ObjectWriter}; 4 | 5 | /// A trait of common functions between writers 6 | pub trait ObjWriter<'a> { 7 | /// Add an element to this object 8 | fn add_element(&mut self, name: &str, s: Value, inc_ref: bool); 9 | 10 | /// Create a writer that can serialize an object 11 | /// 12 | /// If an object with the same `cache_key` has already been written, then this will return `None` for the Writer and the existing reference 13 | /// If this key is unique, then both a Writer and a Reference will be returned 14 | fn object<'c: 'a, 'd>( 15 | &'d mut self, 16 | cache_key: CacheKey, 17 | ) -> (Option>, Reference) 18 | where 19 | 'a: 'c, 20 | 'a: 'd; 21 | 22 | /// Create a writer that can serialize an array 23 | /// 24 | /// If an object with the same `cache_key` has already been written, then this will return `None` for the Writer and the existing reference 25 | /// If this key is unique, then both a Writer and a Reference will be returned 26 | fn array<'c: 'a, 'd>( 27 | &'d mut self, 28 | cache_key: CacheKey, 29 | ) -> (Option>, Reference) 30 | where 31 | 'a: 'c, 32 | 'a: 'd; 33 | //Typed objects can also be sent cached 34 | 35 | /// Write a string 36 | fn string(&mut self, name: &str, s: &str) { 37 | self.add_element(name, Value::String(s.to_string()), true); 38 | } 39 | 40 | /// Write a number 41 | fn number(&mut self, name: &str, s: f64) { 42 | self.add_element(name, Value::Number(s), true); 43 | } 44 | 45 | /// Write a reference 46 | fn reference(&mut self, name: &str, v: Reference) { 47 | self.add_element(name, Value::Reference(v), false); 48 | } 49 | 50 | /// Write an undefined 51 | fn undefined(&mut self, name: &str) { 52 | self.add_element(name, Value::Undefined, true); 53 | } 54 | 55 | /// Write a null 56 | fn null(&mut self, name: &str) { 57 | self.add_element(name, Value::Null, true); 58 | } 59 | 60 | /// Write a bool 61 | fn bool(&mut self, name: &str, v: bool) { 62 | self.add_element(name, Value::Bool(v), true); 63 | } 64 | 65 | /// Write a date 66 | fn date(&mut self, name: &str, ms: f64, tz: Option) { 67 | self.add_element(name, Value::Date(ms, tz), true) 68 | } 69 | 70 | /// Write a XML 71 | fn xml(&mut self, name: &str, v: &str, s: bool) { 72 | self.add_element(name, Value::XML(v.to_string(), s), true); 73 | } 74 | 75 | /// Create a reference in the root 76 | fn make_reference(&mut self) -> Reference; 77 | 78 | /// Retrieve a reference from the cache 79 | fn cache_get(&mut self, cache_key: &CacheKey) -> Option; 80 | 81 | /// Add a reference to the reference cache 82 | fn cache_add(&mut self, cache_key: CacheKey, reference: Reference); 83 | } 84 | -------------------------------------------------------------------------------- /flash-lso/src/amf0/writer/object_writer.rs: -------------------------------------------------------------------------------- 1 | use std::rc::Rc; 2 | 3 | use crate::types::{Element, ObjectId, Reference, Value}; 4 | 5 | use super::{ArrayWriter, CacheKey, ObjWriter}; 6 | 7 | /// A writer for encoding the contents of a child object 8 | pub struct ObjectWriter<'a, 'b> { 9 | /// The elements of this object 10 | pub(crate) elements: Vec, 11 | 12 | /// The parent of this writer 13 | pub(crate) parent: &'a mut dyn ObjWriter<'b>, 14 | } 15 | 16 | impl<'a> ObjWriter<'a> for ObjectWriter<'a, '_> { 17 | fn add_element(&mut self, name: &str, s: Value, inc_ref: bool) { 18 | if inc_ref { 19 | self.parent.make_reference(); 20 | } 21 | 22 | self.elements.push(Element::new(name, Rc::new(s))); 23 | } 24 | 25 | fn object<'c: 'a, 'd>( 26 | &'d mut self, 27 | cache_key: CacheKey, 28 | ) -> (Option>, Reference) 29 | where 30 | 'a: 'c, 31 | 'a: 'd, 32 | { 33 | if let Some(existing_ref) = self.cache_get(&cache_key) { 34 | (None, existing_ref) 35 | } else { 36 | let r = self.make_reference(); 37 | 38 | // Cache this new object 39 | self.cache_add(cache_key, r); 40 | 41 | // Return the writer and the reference 42 | ( 43 | Some(ObjectWriter { 44 | elements: Vec::new(), 45 | parent: self, 46 | }), 47 | r, 48 | ) 49 | } 50 | } 51 | 52 | fn array<'c: 'a, 'd>( 53 | &'d mut self, 54 | cache_key: CacheKey, 55 | ) -> (Option>, Reference) 56 | where 57 | 'a: 'c, 58 | 'a: 'd, 59 | { 60 | if let Some(existing_ref) = self.cache_get(&cache_key) { 61 | (None, existing_ref) 62 | } else { 63 | let r = self.make_reference(); 64 | 65 | // Cache this new array 66 | self.cache_add(cache_key, r); 67 | 68 | // Return the writer and the reference 69 | ( 70 | Some(ArrayWriter { 71 | elements: Vec::new(), 72 | parent: self, 73 | }), 74 | r, 75 | ) 76 | } 77 | } 78 | 79 | fn make_reference(&mut self) -> Reference { 80 | self.parent.make_reference() 81 | } 82 | 83 | fn cache_get(&mut self, cache_key: &CacheKey) -> Option { 84 | self.parent.cache_get(cache_key) 85 | } 86 | 87 | fn cache_add(&mut self, cache_key: CacheKey, reference: Reference) { 88 | self.parent.cache_add(cache_key, reference); 89 | } 90 | } 91 | 92 | impl ObjectWriter<'_, '_> { 93 | /// Finalize this object, adding it to it's parent 94 | /// If this is not called, the object will not be added 95 | pub fn commit>(self, name: T) { 96 | //TODO: this doent work for multi level nesting 97 | self.parent.add_element( 98 | name.as_ref(), 99 | Value::Object(ObjectId::INVALID, self.elements, None), 100 | false, 101 | ); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /flash-lso/src/amf3/custom_encoder.rs: -------------------------------------------------------------------------------- 1 | use crate::amf3::read::AMF3Decoder; 2 | 3 | use crate::amf3::write::AMF3Encoder; 4 | 5 | use crate::types::Element; 6 | use crate::types::*; 7 | 8 | use crate::nom_utils::AMFResult; 9 | use std::rc::Rc; 10 | 11 | /// A trait to define encoding for custom types for use with Externalized objects 12 | pub trait CustomEncoder { 13 | /// This should implement the encoding of a given set of external elements for the given class definition 14 | /// Access to the AMF3Encoder is given to allow access to caches 15 | /// This implements the encoding side of externalized type support 16 | fn encode( 17 | &self, 18 | elements: &[Element], 19 | class_def: &Option, 20 | encoder: &AMF3Encoder, 21 | ) -> Vec; 22 | } 23 | 24 | //TODO: combine with trait 25 | /// Type used for specifying a custom decoder for a AMF3 external type 26 | pub type ExternalDecoderFn = 27 | Rc Fn(&'a [u8], &mut AMF3Decoder) -> AMFResult<'a, Vec>>>; 28 | -------------------------------------------------------------------------------- /flash-lso/src/amf3/element_cache.rs: -------------------------------------------------------------------------------- 1 | use crate::amf3::length::Length; 2 | use std::cell::RefCell; 3 | use std::fmt::Debug; 4 | 5 | /// Abstraction over the Amf3 caching mechanism 6 | #[derive(Clone, Debug)] 7 | pub struct ElementCache { 8 | cache: RefCell>, 9 | } 10 | 11 | impl Default for ElementCache { 12 | /// Create a new ElementCache 13 | fn default() -> Self { 14 | ElementCache { 15 | cache: RefCell::new(Vec::new()), 16 | } 17 | } 18 | } 19 | 20 | impl ElementCache { 21 | /// Check if the cache contains a given element 22 | #[inline] 23 | pub(crate) fn has(&self, val: &T) -> bool { 24 | self.cache.borrow().contains(val) 25 | } 26 | 27 | /// Add the given item to the cache, if the item already exists will do nothing 28 | #[inline] 29 | pub(crate) fn store(&self, val: T) { 30 | if !self.has(&val) { 31 | self.cache.borrow_mut().push(val); 32 | } 33 | } 34 | 35 | /// Retrieve the item at the given index from the cache 36 | #[inline] 37 | pub fn get_element(&self, index: usize) -> Option { 38 | self.cache.borrow().get(index).cloned() 39 | } 40 | 41 | /// Retrieve the index for the given value 42 | #[inline] 43 | pub(crate) fn get_index(&self, val: T) -> Option { 44 | self.cache.borrow().iter().position(|i| *i == val) 45 | } 46 | 47 | /// Get a Length reference to an item in the cache 48 | /// If the item exists, will return a `Length::Reference` to the item 49 | /// If the item does not exist, will return the given size as `Length::Size` 50 | pub(crate) fn to_length(&self, val: T, length: u32) -> Length { 51 | if let Some(i) = self.get_index(val) { 52 | Length::Reference(i) 53 | } else { 54 | Length::Size(length) 55 | } 56 | } 57 | 58 | /// See #to_length, except will store the given value via #add after retrieving the index (if it does not already exist) 59 | /// FIXME - this is currently unused, since our implementation is incorrect (we need to compare 'Rc's by pointer, 60 | /// to avoid combining two distinct objects into the same reference). 61 | #[allow(unused)] 62 | pub(crate) fn to_length_store(&self, val: T, length: u32) -> Length { 63 | let len = self.to_length(val.clone(), length); 64 | self.store(val); 65 | len 66 | } 67 | } 68 | 69 | impl ElementCache> { 70 | /// See #store, will convert slices of &\[T\] into Vec before storing 71 | #[inline] 72 | #[allow(unused)] 73 | pub(crate) fn store_slice(&self, val: &[T]) { 74 | self.store(val.to_vec()); 75 | } 76 | 77 | /// See #get_index, will convert slices of &\[T\] into Vec before retrieving 78 | #[inline] 79 | pub fn get_slice_index(&self, val: &[T]) -> Option { 80 | self.get_index(val.to_vec()) 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /flash-lso/src/amf3/length.rs: -------------------------------------------------------------------------------- 1 | use crate::amf3::write::AMF3Encoder; 2 | use std::io::Write; 3 | 4 | #[derive(Copy, Clone, Debug, Eq, Ord, PartialOrd, PartialEq)] 5 | pub(crate) enum Length { 6 | Size(u32), 7 | Reference(usize), 8 | } 9 | 10 | impl Length { 11 | pub(crate) fn is_reference(&self) -> bool { 12 | matches!(self, Length::Reference(_)) 13 | } 14 | 15 | pub(crate) fn is_size(&self) -> bool { 16 | matches!(self, Length::Size(_)) 17 | } 18 | 19 | pub(crate) fn as_position(&self) -> Option { 20 | match self { 21 | Length::Reference(x) => Some(*x), 22 | _ => None, 23 | } 24 | } 25 | 26 | pub(crate) fn write<'a, 'b: 'a, W: Write + 'a>( 27 | &self, 28 | writer: &mut W, 29 | amf3: &AMF3Encoder, 30 | ) -> std::io::Result<()> { 31 | write_length(writer, amf3, self) 32 | } 33 | } 34 | 35 | fn write_length<'a, 'b: 'a, W: Write + 'a>( 36 | writer: &mut W, 37 | amf3: &AMF3Encoder, 38 | s: &Length, 39 | ) -> std::io::Result<()> { 40 | match s { 41 | Length::Size(x) => { 42 | // With the last bit set 43 | amf3.write_int(writer, ((x << 1) | 0b1) as i32) 44 | } 45 | Length::Reference(x) => amf3.write_int(writer, (x << 1) as i32), 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /flash-lso/src/amf3/mod.rs: -------------------------------------------------------------------------------- 1 | /// Support for custom encoders / decoders 2 | pub mod custom_encoder; 3 | /// Cache pool for the 3 amf3 cache types 4 | pub mod element_cache; 5 | /// Abstraction over the AMF3 length and reference types 6 | pub mod length; 7 | /// Reading of AMF3 data 8 | pub mod read; 9 | /// AMF3 type markers 10 | mod type_marker; 11 | /// Writing of AMF3 data 12 | pub mod write; 13 | -------------------------------------------------------------------------------- /flash-lso/src/amf3/type_marker.rs: -------------------------------------------------------------------------------- 1 | /// Type markers used in AMF3 2 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 3 | #[derive(Eq, PartialEq, Debug, Copy, Clone)] 4 | #[repr(u8)] 5 | pub(crate) enum TypeMarker { 6 | /// Undefined 7 | Undefined = 0x00, 8 | /// Null 9 | Null = 0x01, 10 | /// Boolean false 11 | False = 0x02, 12 | /// Boolean true 13 | True = 0x03, 14 | /// Variable length integer 15 | Integer = 0x04, 16 | /// Floating point number 17 | Number = 0x05, 18 | /// String 19 | String = 0x06, 20 | /// XML 21 | Xml = 0x07, 22 | /// Date (always UTC) 23 | Date = 0x08, 24 | /// Array 25 | Array = 0x09, 26 | /// Object 27 | Object = 0x0A, 28 | /// XML string 29 | XmlString = 0x0B, 30 | /// Byte array 31 | ByteArray = 0x0C, 32 | /// Vector 33 | VectorInt = 0x0D, 34 | /// Vector 35 | VectorUInt = 0x0E, 36 | /// Vector 37 | VectorDouble = 0x0F, 38 | /// Vector 39 | VectorObject = 0x10, 40 | /// Dictionary 41 | Dictionary = 0x11, 42 | } 43 | 44 | impl TryFrom for TypeMarker { 45 | type Error = (); 46 | 47 | fn try_from(value: u8) -> Result { 48 | match value { 49 | 0x00 => Ok(Self::Undefined), 50 | 0x01 => Ok(Self::Null), 51 | 0x02 => Ok(Self::False), 52 | 0x03 => Ok(Self::True), 53 | 0x04 => Ok(Self::Integer), 54 | 0x05 => Ok(Self::Number), 55 | 0x06 => Ok(Self::String), 56 | 0x07 => Ok(Self::Xml), 57 | 0x08 => Ok(Self::Date), 58 | 0x09 => Ok(Self::Array), 59 | 0x0A => Ok(Self::Object), 60 | 0x0B => Ok(Self::XmlString), 61 | 0x0C => Ok(Self::ByteArray), 62 | 0x0D => Ok(Self::VectorInt), 63 | 0x0E => Ok(Self::VectorUInt), 64 | 0x0F => Ok(Self::VectorDouble), 65 | 0x10 => Ok(Self::VectorObject), 66 | 0x11 => Ok(Self::Dictionary), 67 | _ => Err(()), 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /flash-lso/src/errors.rs: -------------------------------------------------------------------------------- 1 | use nom::error::{ErrorKind, FromExternalError, ParseError}; 2 | use thiserror::Error; 3 | 4 | // Allow the Nom variant to be large 5 | #[allow(variant_size_differences)] 6 | /// Enum for representing decoding errors 7 | #[derive(Error, Debug, Clone, Eq, PartialEq)] 8 | pub enum Error<'a> { 9 | /// Out of bounds decoding 10 | #[error("Out of bounds")] 11 | OutOfBounds, 12 | 13 | /// Invalid Amf0 reference tag 14 | #[error("Invalid reference")] 15 | InvalidReference(u16), 16 | 17 | /// Invalid type marker 18 | #[error("Unsupported tag")] 19 | UnsupportedType(u8), 20 | 21 | /// A nom internal error 22 | #[error("Nom internal error")] 23 | Nom(&'a [u8], ErrorKind), 24 | 25 | /// Packet is too large (too many headers or messages) 26 | #[error("Packet has too many headers or messages")] 27 | PacketTooLarge, 28 | 29 | /// Unable to find an object in the reference table 30 | #[error("Object not in reference table")] 31 | ObjectMissingFromReferenceTable(u64), 32 | 33 | /// An unknown IO error occured 34 | #[error("IO error: {0}")] 35 | IoError(String, std::io::ErrorKind), 36 | } 37 | 38 | impl<'a> ParseError<&'a [u8]> for Error<'a> { 39 | fn from_error_kind(input: &'a [u8], kind: ErrorKind) -> Self { 40 | Error::Nom(input, kind) 41 | } 42 | 43 | fn append(_: &[u8], _: ErrorKind, other: Self) -> Self { 44 | other 45 | } 46 | } 47 | 48 | impl<'a, E> FromExternalError<&'a [u8], E> for Error<'a> { 49 | fn from_external_error(input: &'a [u8], kind: ErrorKind, _e: E) -> Self { 50 | Error::Nom(input, kind) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /flash-lso/src/extra/flex/mod.rs: -------------------------------------------------------------------------------- 1 | const NEXT_FLAG: u8 = 128; 2 | 3 | const BODY_FLAG: u8 = 1; 4 | const CLIENT_ID_FLAG: u8 = 2; 5 | const DESTINATION_ID_FLAG: u8 = 4; 6 | const HEADERS_FLAG: u8 = 8; 7 | const MESSAGE_ID_FLAG: u8 = 16; 8 | const TIMESTAMP_FLAG: u8 = 32; 9 | const TTL_FLAG: u8 = 64; 10 | 11 | const CLIENT_ID_BYTES_FLAG: u8 = 1; 12 | const MESSAGE_ID_BYTES_FLAG: u8 = 2; 13 | 14 | const CORRELATION_ID_FLAG: u8 = 1; 15 | const CORRELATION_ID_BYTES_FLAG: u8 = 2; 16 | 17 | const OPERATION_FLAG: u8 = 1; 18 | 19 | pub mod read; 20 | pub mod write; 21 | -------------------------------------------------------------------------------- /flash-lso/src/extra/mod.rs: -------------------------------------------------------------------------------- 1 | /// Reading and Writing of flex types 2 | #[cfg(feature = "flex")] 3 | pub mod flex; 4 | -------------------------------------------------------------------------------- /flash-lso/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![type_length_limit = "94603681"] 2 | //! Library for reading and writing the Adobe Flash Local Shared Object (LSO) file format and the contained AMF0/AMF3 data 3 | 4 | #![deny( 5 | anonymous_parameters, 6 | nonstandard_style, 7 | rust_2018_idioms, 8 | trivial_casts, 9 | trivial_numeric_casts, 10 | // Temporarily removed, this has a false-positive on `Reference` 11 | //unreachable_pub, 12 | unused_extern_crates, 13 | unused_qualifications, 14 | variant_size_differences, 15 | missing_docs 16 | )] 17 | 18 | const HEADER_VERSION: [u8; 2] = [0x00, 0xbf]; 19 | const HEADER_SIGNATURE: [u8; 10] = [0x54, 0x43, 0x53, 0x4f, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00]; 20 | const PADDING: [u8; 1] = [0x00]; 21 | 22 | const FORMAT_VERSION_AMF0: u8 = 0x0; 23 | 24 | #[cfg(feature = "amf3")] 25 | const FORMAT_VERSION_AMF3: u8 = 0x3; 26 | 27 | #[cfg(feature = "serde")] 28 | #[macro_use] 29 | extern crate serde; 30 | 31 | /// Reading and Writing of the AMF0 file format 32 | pub mod amf0; 33 | 34 | /// Reading and Writing of the AMF3 file format 35 | #[cfg(feature = "amf3")] 36 | pub mod amf3; 37 | 38 | /// Decoding error type 39 | pub mod errors; 40 | 41 | /// Private internal utils for reading 42 | mod nom_utils; 43 | 44 | /// Reading of the Lso container format 45 | pub mod read; 46 | 47 | /// Types used for representing Lso contents 48 | pub mod types; 49 | 50 | /// Writing of the Lso container format 51 | pub mod write; 52 | 53 | /// Extra functionality such as decoders for popular external class formats 54 | pub mod extra; 55 | 56 | /// Reading and Writing of AMF Self Contained Packets 57 | pub mod packet; 58 | -------------------------------------------------------------------------------- /flash-lso/src/nom_utils.rs: -------------------------------------------------------------------------------- 1 | use crate::errors::Error; 2 | use nom::bytes::complete::take; 3 | use nom::combinator::map_res; 4 | 5 | use crate::write::WriteExt; 6 | use nom::IResult; 7 | use std::io::Write; 8 | 9 | pub(crate) type AMFResult<'a, T> = IResult<&'a [u8], T, Error<'a>>; 10 | 11 | pub(crate) fn write_string<'a, 'b: 'a, W: Write + 'a>( 12 | writer: &mut W, 13 | s: &'b str, 14 | ) -> std::io::Result<()> { 15 | writer.write_u16(s.len() as u16)?; 16 | writer.write_all(s.as_bytes())?; 17 | Ok(()) 18 | } 19 | 20 | pub(crate) fn take_str(i: &[u8], length: u16) -> AMFResult<'_, &str> { 21 | map_res(take(length), std::str::from_utf8)(i) 22 | } 23 | -------------------------------------------------------------------------------- /flash-lso/src/packet/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::types::{AMFVersion, Value}; 2 | use std::rc::Rc; 3 | 4 | /// Reading of AMF Packets 5 | pub mod read; 6 | 7 | /// Writing of AMF Packets 8 | pub mod write; 9 | 10 | /// An AMF Packet Header 11 | #[derive(Debug, Clone)] 12 | pub struct Header { 13 | /// The name of this header. 14 | pub name: String, 15 | 16 | /// If true, the endpoint must immediately abort and error if it does not understand this header. 17 | pub must_understand: bool, 18 | 19 | /// The value of this header. 20 | pub value: Rc, 21 | } 22 | 23 | /// An AMF Packet Header 24 | #[derive(Debug, Clone)] 25 | pub struct Message { 26 | /// The target URI that this message is intended for. 27 | pub target_uri: String, 28 | 29 | /// The response URI for this message. 30 | /// 31 | /// For requests, this should be a unique identifier to represent "this message", for example `/1`. 32 | /// Responses will target this URI, suffixed with either `/onResult` or `/onStatus` (for success or failure). 33 | /// 34 | /// For responses this may be empty. 35 | pub response_uri: String, 36 | 37 | /// The contents of this message. 38 | pub contents: Rc, 39 | } 40 | 41 | /// An AMF Packet 42 | #[derive(Debug, Clone)] 43 | pub struct Packet { 44 | /// The version of this packet. Does not affect serialization. 45 | pub version: AMFVersion, 46 | 47 | /// Any headers associated with every message inside this packet. 48 | pub headers: Vec
, 49 | 50 | /// All messages included inside this packet. 51 | pub messages: Vec, 52 | } 53 | -------------------------------------------------------------------------------- /flash-lso/src/packet/read.rs: -------------------------------------------------------------------------------- 1 | use std::convert::TryInto; 2 | 3 | use nom::branch::alt; 4 | use nom::bytes::complete::tag; 5 | use nom::number::complete::{be_u16, be_u32, be_u8}; 6 | 7 | use crate::amf0; 8 | use crate::amf0::read::AMF0Decoder; 9 | use crate::errors::Error; 10 | use crate::nom_utils::AMFResult; 11 | use crate::packet::{Header, Message, Packet}; 12 | use crate::types::AMFVersion; 13 | use nom::combinator::all_consuming; 14 | use nom::multi::length_count; 15 | 16 | const FORMAT_VERSION_AMF0: u8 = 0x0; 17 | const FORMAT_VERSION_AMF3: u8 = 0x3; 18 | 19 | fn parse_header(i: &[u8]) -> AMFResult<'_, Header> { 20 | let (i, name) = amf0::read::parse_string(i)?; 21 | let (i, must_understand) = be_u8(i)?; 22 | let (i, _length) = be_u32(i)?; 23 | let (i, value) = AMF0Decoder::default().parse_single_element(i)?; 24 | 25 | Ok(( 26 | i, 27 | Header { 28 | name: name.to_string(), 29 | must_understand: must_understand != 0, 30 | value, 31 | }, 32 | )) 33 | } 34 | 35 | fn parse_message(i: &[u8]) -> AMFResult<'_, Message> { 36 | let (i, target_uri) = amf0::read::parse_string(i)?; 37 | let (i, response_uri) = amf0::read::parse_string(i)?; 38 | let (i, _length) = be_u32(i)?; 39 | let (i, contents) = AMF0Decoder::default().parse_single_element(i)?; 40 | 41 | Ok(( 42 | i, 43 | Message { 44 | target_uri: target_uri.to_string(), 45 | response_uri: response_uri.to_string(), 46 | contents, 47 | }, 48 | )) 49 | } 50 | 51 | /// Read a given buffer as a packet 52 | /// 53 | /// Unlike parse, this function will not error if the entire slice isn't consumed 54 | /// and will return the data that was not parsed 55 | pub fn parse_incomplete(i: &[u8]) -> AMFResult<'_, Packet> { 56 | let (i, _) = tag(&[0u8])(i)?; 57 | let (i, version) = alt((tag(&[FORMAT_VERSION_AMF0]), tag(&[FORMAT_VERSION_AMF3])))(i)?; 58 | // This unwrap can't fail because of the alt above 59 | let version: AMFVersion = version[0].try_into().unwrap(); 60 | 61 | let (i, headers) = length_count(be_u16, parse_header)(i)?; 62 | let (i, messages) = length_count(be_u16, parse_message)(i)?; 63 | 64 | Ok(( 65 | i, 66 | Packet { 67 | version, 68 | headers, 69 | messages, 70 | }, 71 | )) 72 | } 73 | 74 | /// Read a given slice as a packet 75 | /// 76 | /// This function will return an error if the slice could not be parsed or if the entire slice 77 | /// was not consumed 78 | pub fn parse(i: &[u8]) -> Result>> { 79 | let (_, packet) = all_consuming(|i| parse_incomplete(i))(i)?; 80 | Ok(packet) 81 | } 82 | -------------------------------------------------------------------------------- /flash-lso/src/packet/write.rs: -------------------------------------------------------------------------------- 1 | //! Handles writing of AMF packets 2 | 3 | use crate::amf0; 4 | use crate::errors::Error; 5 | use crate::packet::{Header, Message, Packet}; 6 | use crate::types::AMFVersion; 7 | 8 | fn write_header( 9 | header: &Header, 10 | out: &mut Vec, 11 | exact_lengths: bool, 12 | ) -> Result<(), Error<'static>> { 13 | // Name 14 | let name_length = u16::try_from(header.name.len()).map_err(|_| Error::PacketTooLarge)?; 15 | out.extend(name_length.to_be_bytes()); 16 | out.extend(header.name.as_bytes()); 17 | 18 | // Must understand 19 | if header.must_understand { 20 | out.push(1); 21 | } else { 22 | out.push(0); 23 | } 24 | 25 | // Value 26 | let mut value = vec![]; 27 | amf0::write::write_value(&mut value, &header.value) 28 | .map_err(|e| Error::IoError(e.to_string(), e.kind()))?; 29 | if exact_lengths { 30 | let value_length = u32::try_from(value.len()).map_err(|_| Error::PacketTooLarge)?; 31 | out.extend(value_length.to_be_bytes()); 32 | } else { 33 | out.extend(u32::MAX.to_be_bytes()); 34 | } 35 | out.append(&mut value); 36 | 37 | Ok(()) 38 | } 39 | 40 | fn write_message( 41 | message: &Message, 42 | out: &mut Vec, 43 | exact_lengths: bool, 44 | ) -> Result<(), Error<'static>> { 45 | // Target URI 46 | let target_length = 47 | u16::try_from(message.target_uri.len()).map_err(|_| Error::PacketTooLarge)?; 48 | out.extend(target_length.to_be_bytes()); 49 | out.extend(message.target_uri.as_bytes()); 50 | 51 | // Response URI 52 | let response_length = 53 | u16::try_from(message.response_uri.len()).map_err(|_| Error::PacketTooLarge)?; 54 | out.extend(response_length.to_be_bytes()); 55 | out.extend(message.response_uri.as_bytes()); 56 | 57 | // Contents 58 | let mut contents = vec![]; 59 | amf0::write::write_value(&mut contents, &message.contents) 60 | .map_err(|e| Error::IoError(e.to_string(), e.kind()))?; 61 | if exact_lengths { 62 | let contents_length = u32::try_from(contents.len()).map_err(|_| Error::PacketTooLarge)?; 63 | out.extend(contents_length.to_be_bytes()); 64 | } else { 65 | out.extend(u32::MAX.to_be_bytes()); 66 | } 67 | out.append(&mut contents); 68 | 69 | Ok(()) 70 | } 71 | 72 | /// Write a packet to a vec of bytes 73 | pub fn write_to_bytes(packet: &Packet, exact_lengths: bool) -> Result, Error<'static>> { 74 | let mut buffer = vec![]; 75 | 76 | // Version 77 | buffer.push(0); 78 | match packet.version { 79 | AMFVersion::AMF0 => buffer.push(0), 80 | #[cfg(feature = "amf3")] 81 | AMFVersion::AMF3 => buffer.push(3), 82 | } 83 | 84 | // Headers 85 | let header_count = u16::try_from(packet.headers.len()).map_err(|_| Error::PacketTooLarge)?; 86 | buffer.extend(header_count.to_be_bytes()); 87 | for header in &packet.headers { 88 | write_header(header, &mut buffer, exact_lengths)?; 89 | } 90 | 91 | // Messages 92 | let message_count = u16::try_from(packet.messages.len()).map_err(|_| Error::PacketTooLarge)?; 93 | buffer.extend(message_count.to_be_bytes()); 94 | for message in &packet.messages { 95 | write_message(message, &mut buffer, exact_lengths)?; 96 | } 97 | 98 | Ok(buffer) 99 | } 100 | -------------------------------------------------------------------------------- /flash-lso/src/read.rs: -------------------------------------------------------------------------------- 1 | use std::convert::TryInto; 2 | 3 | use nom::branch::alt; 4 | use nom::bytes::complete::tag; 5 | use nom::number::complete::be_u32; 6 | 7 | use crate::amf0; 8 | use crate::amf0::read::AMF0Decoder; 9 | #[cfg(feature = "amf3")] 10 | use crate::amf3::read::AMF3Decoder; 11 | use crate::errors::Error; 12 | use crate::nom_utils::AMFResult; 13 | use crate::types::{AMFVersion, Header, Lso}; 14 | use nom::combinator::all_consuming; 15 | 16 | const HEADER_VERSION: [u8; 2] = [0x00, 0xbf]; 17 | const HEADER_SIGNATURE: [u8; 10] = [0x54, 0x43, 0x53, 0x4f, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00]; 18 | const PADDING: [u8; 1] = [0x00]; 19 | 20 | const FORMAT_VERSION_AMF0: u8 = 0x0; 21 | 22 | #[cfg(feature = "amf3")] 23 | const FORMAT_VERSION_AMF3: u8 = 0x3; 24 | 25 | /// The main entry point of decoding an LSO file 26 | /// Example of use 27 | /// ``` 28 | /// use std::fs::File; 29 | /// use std::io::Read; 30 | /// use flash_lso::read::Reader; 31 | /// let mut x = File::open("tests/sol/AS2-Demo.sol").expect("Couldn't open file"); 32 | /// let mut data = Vec::new(); 33 | /// let _ = x.read_to_end(&mut data).expect("Unable to read file"); 34 | /// let d = Reader::default().parse(&data).expect("Failed to parse lso file"); 35 | /// println!("{:#?}", d); 36 | /// ``` 37 | /// } 38 | #[derive(Default)] 39 | pub struct Reader { 40 | #[cfg(feature = "amf3")] 41 | /// Handles reading Amf3 data 42 | pub amf3_decoder: AMF3Decoder, 43 | 44 | /// Handles reading Amf0 data 45 | pub amf0_decoder: AMF0Decoder, 46 | } 47 | 48 | impl Reader { 49 | /// Read a Lso header from the given slice 50 | pub fn parse_header<'a>(&self, i: &'a [u8]) -> AMFResult<'a, Header> { 51 | let (i, _) = tag(HEADER_VERSION)(i)?; 52 | let (i, l) = be_u32(i)?; 53 | let (i, _) = tag(HEADER_SIGNATURE)(i)?; 54 | 55 | let (i, name) = amf0::read::parse_string(i)?; 56 | 57 | let (i, _) = tag(PADDING)(i)?; 58 | let (i, _) = tag(PADDING)(i)?; 59 | let (i, _) = tag(PADDING)(i)?; 60 | 61 | let (i, version) = alt(( 62 | tag(&[FORMAT_VERSION_AMF0]), 63 | #[cfg(feature = "amf3")] 64 | tag(&[FORMAT_VERSION_AMF3]), 65 | ))(i)?; 66 | 67 | // This unwrap can't fail because of the alt above 68 | let format_version: AMFVersion = version[0].try_into().unwrap(); 69 | 70 | Ok(( 71 | i, 72 | Header { 73 | length: l, 74 | name: name.to_string(), 75 | format_version, 76 | }, 77 | )) 78 | } 79 | 80 | /// Read a given buffer as an Lso 81 | /// 82 | /// Unlike parse, this function will not error if the entire slice isn't consumed 83 | /// and will return the data that was not parsed 84 | pub fn parse_incomplete<'a>(&mut self, i: &'a [u8]) -> AMFResult<'a, Lso> { 85 | let (i, header) = self.parse_header(i)?; 86 | match header.format_version { 87 | AMFVersion::AMF0 => { 88 | let (i, body) = self.amf0_decoder.parse_body(i)?; 89 | Ok((i, Lso { header, body })) 90 | } 91 | 92 | #[cfg(feature = "amf3")] 93 | AMFVersion::AMF3 => { 94 | let (i, body) = self.amf3_decoder.parse_body(i)?; 95 | Ok((i, Lso { header, body })) 96 | } 97 | } 98 | } 99 | 100 | /// Read a given slice as an Lso 101 | /// 102 | /// This function will return an error if the slice could not be parsed or if the entire slice 103 | /// was not consumed 104 | pub fn parse<'a>(&mut self, i: &'a [u8]) -> Result>> { 105 | let (_, lso) = all_consuming(|i| self.parse_incomplete(i))(i)?; 106 | Ok(lso) 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /flash-lso/src/types/amf_version.rs: -------------------------------------------------------------------------------- 1 | use core::fmt; 2 | 3 | /// The version of AMF being used 4 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 5 | #[derive(Eq, PartialEq, Debug, Copy, Clone)] 6 | #[repr(u8)] 7 | pub enum AMFVersion { 8 | /// AMF0 9 | AMF0 = 0, 10 | 11 | #[cfg(feature = "amf3")] 12 | /// AMF3 13 | AMF3 = 3, 14 | } 15 | 16 | impl TryFrom for AMFVersion { 17 | type Error = (); 18 | 19 | fn try_from(value: u8) -> Result { 20 | match value { 21 | 0 => Ok(Self::AMF0), 22 | #[cfg(feature = "amf3")] 23 | 3 => Ok(Self::AMF3), 24 | _ => Err(()), 25 | } 26 | } 27 | } 28 | 29 | impl fmt::Display for AMFVersion { 30 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 31 | match self { 32 | AMFVersion::AMF0 => f.write_str("AMF0"), 33 | #[cfg(feature = "amf3")] 34 | AMFVersion::AMF3 => f.write_str("AMF3"), 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /flash-lso/src/types/attribute.rs: -------------------------------------------------------------------------------- 1 | use enumset::EnumSetType; 2 | 3 | /// Encodes the possible attributes that can be given to a trait 4 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 5 | #[derive(EnumSetType, Debug)] 6 | pub enum Attribute { 7 | /// If a trait is dynamic then the object it constructs may have additional properties other than the ones specified in the trait 8 | Dynamic, 9 | 10 | /// If a trait is external then it requires custom serialization and deserialization support 11 | External, 12 | } 13 | -------------------------------------------------------------------------------- /flash-lso/src/types/class_definition.rs: -------------------------------------------------------------------------------- 1 | use super::Attribute; 2 | use enumset::EnumSet; 3 | 4 | /// A class definition (trait) used in AMF3 5 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 6 | #[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] 7 | pub struct ClassDefinition { 8 | /// The name of the class definition 9 | pub name: String, 10 | 11 | /// The attributes on this trait 12 | pub attributes: EnumSet, 13 | 14 | /// The name of the static properties defined in this definition 15 | pub static_properties: Vec, 16 | } 17 | 18 | impl Default for ClassDefinition { 19 | fn default() -> Self { 20 | Self { 21 | name: "Object".to_string(), 22 | attributes: EnumSet::empty(), 23 | static_properties: Vec::new(), 24 | } 25 | } 26 | } 27 | 28 | impl ClassDefinition { 29 | /// Creates a new ClassDefinition with the given name, and no attributes or properties 30 | pub fn default_with_name(name: String) -> Self { 31 | Self { 32 | name, 33 | attributes: EnumSet::empty(), 34 | static_properties: Vec::new(), 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /flash-lso/src/types/element.rs: -------------------------------------------------------------------------------- 1 | use super::Value; 2 | use core::ops::Deref; 3 | use std::rc::Rc; 4 | 5 | /// Represent a named element 6 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 7 | #[derive(Clone, Debug, PartialEq)] 8 | pub struct Element { 9 | /// The name of the element 10 | pub name: String, 11 | 12 | /// The value of the element 13 | pub value: Rc, 14 | } 15 | 16 | impl Element { 17 | /// Create a new Element 18 | #[inline] 19 | pub fn new(name: impl Into, value: Rc) -> Self { 20 | Self { 21 | name: name.into(), 22 | value, 23 | } 24 | } 25 | 26 | /// Get the Value of this element 27 | pub fn value(&self) -> &Value { 28 | self.value.deref() 29 | } 30 | 31 | /// Get the name of this element 32 | pub fn name(&self) -> &str { 33 | self.name.as_str() 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /flash-lso/src/types/lso.rs: -------------------------------------------------------------------------------- 1 | use super::{AMFVersion, Element, Header}; 2 | 3 | /// A container for lso files 4 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 5 | #[derive(Debug, PartialEq, Clone)] 6 | pub struct Lso { 7 | /// The header of this lso 8 | pub header: Header, 9 | 10 | /// The elements at the root level of this lso 11 | pub body: Vec, 12 | } 13 | 14 | impl Lso { 15 | /// Create a new Lso with a header with the given name and version and an empty body 16 | #[inline] 17 | pub fn new_empty(name: impl Into, version: AMFVersion) -> Self { 18 | Self::new(Vec::new(), name, version) 19 | } 20 | 21 | /// Crate a new Lso with a header with the given name, version and body 22 | #[inline] 23 | pub fn new(body: Vec, name: impl Into, version: AMFVersion) -> Self { 24 | Self { 25 | header: Header::new(name, version), 26 | body, 27 | } 28 | } 29 | } 30 | 31 | impl IntoIterator for Lso { 32 | type Item = Element; 33 | type IntoIter = std::vec::IntoIter; 34 | 35 | fn into_iter(self) -> Self::IntoIter { 36 | self.body.into_iter() 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /flash-lso/src/types/lso_header.rs: -------------------------------------------------------------------------------- 1 | use super::AMFVersion; 2 | 3 | /// The header of a lso file 4 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 5 | #[derive(Debug, PartialEq, Eq, Clone)] 6 | pub struct Header { 7 | /// The length of the lso in bytes 8 | pub length: u32, 9 | 10 | /// The name of the lso file 11 | pub name: String, 12 | 13 | /// The version of AMF used to encode the data 14 | pub format_version: AMFVersion, 15 | } 16 | 17 | impl Header { 18 | /// Create a new header with the given name and version, will have a size of 0 by default 19 | #[inline] 20 | pub fn new(name: impl Into, version: AMFVersion) -> Self { 21 | Self { 22 | length: 0, 23 | name: name.into(), 24 | format_version: version, 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /flash-lso/src/types/mod.rs: -------------------------------------------------------------------------------- 1 | mod amf_version; 2 | mod attribute; 3 | mod class_definition; 4 | mod element; 5 | mod lso; 6 | mod lso_header; 7 | mod reference; 8 | mod value; 9 | 10 | mod object_id; 11 | 12 | pub use amf_version::AMFVersion; 13 | pub use attribute::Attribute; 14 | pub use class_definition::ClassDefinition; 15 | pub use element::Element; 16 | pub use lso::Lso; 17 | pub use lso_header::Header; 18 | pub use object_id::ObjectId; 19 | pub use reference::Reference; 20 | pub use value::Value; 21 | -------------------------------------------------------------------------------- /flash-lso/src/types/object_id.rs: -------------------------------------------------------------------------------- 1 | /// A locally unique identifier for an Amf3 object 2 | /// 3 | /// See the comment on `Value::Amf3ObjectReference` for details 4 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 5 | #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] 6 | pub struct ObjectId(pub i64); 7 | 8 | impl ObjectId { 9 | /// An invalid object id 10 | /// 11 | /// Use this when the id of an object can't be known or will never need to be referenced (e.g. amf0) 12 | /// Unlike valid object id's, multiple objects with an `INVALID` id are explicitly allowed 13 | /// Attempting to write a reference to an invalid object id is illegal and may error 14 | /// Attempting to write an object with an invalid object id is allowed, but it cannot be referenced later 15 | pub const INVALID: Self = ObjectId(-1); 16 | } 17 | -------------------------------------------------------------------------------- /flash-lso/src/types/reference.rs: -------------------------------------------------------------------------------- 1 | /// A reference to an existing value 2 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 3 | #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] 4 | pub struct Reference(pub(crate) u16); 5 | -------------------------------------------------------------------------------- /flash-lso/src/types/value.rs: -------------------------------------------------------------------------------- 1 | use super::{ClassDefinition, Element, ObjectId, Reference}; 2 | use std::rc::Rc; 3 | 4 | //TODO: should amf3 assoc arrays be their own type with a dense and assoc section 5 | /// A single or compound value 6 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 7 | #[derive(Debug, Clone, PartialEq)] 8 | pub enum Value { 9 | /// Represent the type number (amf0) and double (amf3) 10 | Number(f64), 11 | 12 | /// Represents the type boolean (amf0) and both the true/false type (amf3) 13 | Bool(bool), 14 | 15 | /// Represent both the string (amf0/3) and long string type (amf0) 16 | String(String), 17 | 18 | /// Represents the object type in both amf0 and amf3, class definition are only available with amf3 19 | Object(ObjectId, Vec, Option), 20 | 21 | /// Represent the null type 22 | Null, 23 | 24 | /// Represent the undefined type 25 | Undefined, 26 | 27 | /// Represent ECMA-Arrays (amf0) and associative arrays (amf3, even if they contain a dense part) 28 | /// Final value represents the length of the array in amf0, this can differ from the actual number of elements 29 | ECMAArray(ObjectId, Vec>, Vec, u32), 30 | 31 | /// Represent a strict array (amf0) or a dense array (amf3) 32 | StrictArray(ObjectId, Vec>), 33 | 34 | /// Represent a timezone in the format (seconds since epoch, timezone or UTC if missing (amf3) ) 35 | Date(f64, Option), 36 | 37 | /// Represent the unsupported type 38 | Unsupported, 39 | 40 | /// Represent the XML type, (value, is_string) 41 | XML(String, bool), 42 | 43 | #[cfg(feature = "amf3")] 44 | /// Represent an amf3 element embedded in an AMF0 file 45 | AMF3(Rc), 46 | 47 | // AMF3 48 | /// Represent the integer type (u29) (amf3) 49 | Integer(i32), 50 | 51 | /// Represent the bytearray type (amf3) 52 | ByteArray(Vec), 53 | 54 | /// Represent the int vector type (amf3) 55 | /// Format is (values, is_fixed_length) 56 | VectorInt(Vec, bool), 57 | 58 | /// Represent the unsigned int vector type (amf3) 59 | /// Format is (values, is_fixed_length) 60 | VectorUInt(Vec, bool), 61 | 62 | /// Represent the double vector type (amf3) 63 | /// Format is (values, is_fixed_length) 64 | VectorDouble(Vec, bool), 65 | 66 | /// Represent the object vector type (amf3) 67 | /// Format is (values, is_fixed_length) 68 | VectorObject(ObjectId, Vec>, String, bool), 69 | 70 | /// Represent the dictionary type (amf3) 71 | /// Format is ((key, value), has_weak_keys) 72 | Dictionary(ObjectId, Vec<(Rc, Rc)>, bool), 73 | 74 | /// Represent a external object, such as from flex 75 | /// (custom_elements, regular elements, class def) 76 | Custom(Vec, Vec, Option), 77 | 78 | /// Represent an existing value, stored by reference, the value here should be considered opaque 79 | Reference(Reference), 80 | 81 | /// A reference to a previously parsed element 82 | /// 83 | /// While traversing `Value`s you should maintain a mapping of `ObjectId` to your internal 84 | /// representation of a value and consider this a reference to the exact same value. 85 | /// 86 | /// As `Value` graphs can contain cycles which are best handled by garbage collected structures 87 | /// we leave the handling of this to the user, sorry 88 | Amf3ObjectReference(ObjectId), 89 | } 90 | 91 | impl FromIterator for Vec> { 92 | fn from_iter>(iter: T) -> Self { 93 | iter.into_iter().map(Rc::new).collect() 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /flash-lso/src/write.rs: -------------------------------------------------------------------------------- 1 | //! Handles writing of LSO files 2 | use std::io::Write; 3 | 4 | #[cfg(feature = "amf3")] 5 | use crate::amf3::write::AMF3Encoder; 6 | use crate::errors::Error; 7 | use crate::nom_utils::write_string; 8 | use crate::types::{AMFVersion, Header, Lso}; 9 | #[cfg(feature = "amf3")] 10 | use crate::FORMAT_VERSION_AMF3; 11 | use crate::{FORMAT_VERSION_AMF0, HEADER_SIGNATURE, HEADER_VERSION, PADDING}; 12 | 13 | /// Handles writing a given LSO 14 | #[derive(Default)] 15 | pub struct Writer { 16 | /// The encoder used for writing Value::AMF3() wrapped types 17 | #[cfg(feature = "amf3")] 18 | pub amf3_encoder: AMF3Encoder, 19 | } 20 | 21 | impl Writer { 22 | /// Write a given LSO 23 | pub fn write_full<'a, 'b: 'a, W: Write + 'a>( 24 | &'a mut self, 25 | writer: &mut W, 26 | lso: &'b mut Lso, 27 | ) -> std::io::Result<()> { 28 | let mut buffer = vec![]; 29 | if lso.header.format_version == AMFVersion::AMF0 { 30 | crate::amf0::write::write_body(&mut buffer, &lso.body)?; 31 | } else { 32 | #[cfg(feature = "amf3")] 33 | self.amf3_encoder.write_body(&mut buffer, &lso.body)?; 34 | } 35 | 36 | lso.header.length = buffer.len() as u32 + header_length(&lso.header) as u32; 37 | 38 | write_header(writer, &lso.header)?; 39 | writer.write_all(&buffer)?; 40 | Ok(()) 41 | } 42 | } 43 | 44 | fn write_header<'a, 'b: 'a, W: Write + 'a>( 45 | writer: &mut W, 46 | header: &'b Header, 47 | ) -> std::io::Result<()> { 48 | writer.write_all(&HEADER_VERSION)?; 49 | writer.write_u32(header.length)?; 50 | writer.write_all(&HEADER_SIGNATURE)?; 51 | write_string(writer, &header.name)?; 52 | writer.write_all(&PADDING)?; 53 | writer.write_all(&PADDING)?; 54 | writer.write_all(&PADDING)?; 55 | match header.format_version { 56 | AMFVersion::AMF0 => writer.write_all(&[FORMAT_VERSION_AMF0])?, 57 | #[cfg(feature = "amf3")] 58 | AMFVersion::AMF3 => writer.write_all(&[FORMAT_VERSION_AMF3])?, 59 | }; 60 | Ok(()) 61 | } 62 | 63 | /// Get the serialized length of the header in bytes, this does not include the size of the header length field or the lso version marker 64 | pub fn header_length(header: &Header) -> usize { 65 | // signature + (name size u16 + name_len) + 3*padding + amf_version_marker 66 | 10 + (2 + header.name.len() + 3 + 1) 67 | } 68 | 69 | /// Write a LSO to a vec of bytes 70 | pub fn write_to_bytes<'a>(lso: &mut Lso) -> Result, Error<'a>> { 71 | let mut v = vec![]; 72 | 73 | let mut s = Writer::default(); 74 | s.write_full(&mut v, lso) 75 | .map_err(|e| Error::IoError(e.to_string(), e.kind()))?; 76 | Ok(v) 77 | } 78 | 79 | pub(crate) trait WriteExt { 80 | fn write_u8(&mut self, value: u8) -> std::io::Result<()>; 81 | fn write_u16(&mut self, value: u16) -> std::io::Result<()>; 82 | fn write_u32(&mut self, value: u32) -> std::io::Result<()>; 83 | fn write_i32(&mut self, value: i32) -> std::io::Result<()>; 84 | fn write_f64(&mut self, value: f64) -> std::io::Result<()>; 85 | } 86 | 87 | impl WriteExt for T 88 | where 89 | T: Write, 90 | { 91 | fn write_u8(&mut self, value: u8) -> std::io::Result<()> { 92 | self.write_all(&[value]) 93 | } 94 | 95 | fn write_u16(&mut self, value: u16) -> std::io::Result<()> { 96 | self.write_all(&value.to_be_bytes()) 97 | } 98 | 99 | fn write_u32(&mut self, value: u32) -> std::io::Result<()> { 100 | self.write_all(&value.to_be_bytes()) 101 | } 102 | 103 | fn write_i32(&mut self, value: i32) -> std::io::Result<()> { 104 | self.write_all(&value.to_be_bytes()) 105 | } 106 | 107 | fn write_f64(&mut self, value: f64) -> std::io::Result<()> { 108 | self.write_all(&value.to_be_bytes()) 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /flash-lso/tests/README.md: -------------------------------------------------------------------------------- 1 | The following files in ./sol/ are sourced from minerva and are covered under their own license, see https://github.com/gmariani/minerva for details 2 | 3 | 00000004.sol 4 | 2.sol 5 | AkamaiEnterprisePlayer.userData.sol 6 | arenaMadnessGame2.sol 7 | AS2-Array-Demo.sol 8 | AS2-Boolean-Demo.sol 9 | AS2-Date-Demo.sol 10 | AS2-Demo.sol 11 | AS2-ECMAArray-Demo.sol 12 | AS2-Integer-Demo.sol 13 | AS2-LongString-Demo.sol 14 | AS2-Null-Demo.sol 15 | AS2-Number-Demo.sol 16 | AS2-Object-Demo.sol 17 | AS2-String-Demo.sol 18 | AS2-TypedObject-Demo.sol 19 | AS2-Undefined-Demo.sol 20 | AS2-XML-Demo.sol 21 | AS3-Array-Demo.sol 22 | AS3-Boolean-Demo.sol 23 | AS3-ByteArray-Demo.sol 24 | AS3-Date-Demo.sol 25 | AS3-Demo.sol 26 | AS3-Dictionary-Demo.sol 27 | AS3-Integer-Demo.sol 28 | AS3-Null-Demo.sol 29 | AS3-Number-Demo.sol 30 | AS3-Object-Demo.sol 31 | AS3-String-Demo.sol 32 | AS3-TypedObject-Demo.sol 33 | AS3-Undefined-Demo.sol 34 | AS3-VectorInt-Demo.sol 35 | AS3-VectorNumber-Demo.sol 36 | AS3-VectorObject-Demo.sol 37 | AS3-VectorTypedObject-Demo.sol 38 | AS3-VectorUint-Demo.sol 39 | AS3-XML-Demo.sol 40 | AS3-XMLDoc-Demo.sol 41 | canvas.sol 42 | ClarenceSave_SLOT1.sol 43 | CoC_8.sol 44 | com.jeroenwijering.sol 45 | cramjs.sol 46 | dolphin_show(1).sol 47 | flagstaff(1).sol 48 | flagstaff.sol 49 | flash.viewer.sol 50 | HIRO_NETWORK_CAPPING_COOKIE.sol 51 | InfectonatorSurvivors76561198009932603.sol 52 | JY1.sol 53 | Labrat2.sol 54 | MARDEKv3__sg_1.sol 55 | mediaPlayerUserSettings.sol 56 | MetadataHistory.sol 57 | Minimal.sol 58 | Minimalv2.sol 59 | oppDetailPrefs.sol 60 | Party1.sol 61 | previousVideo.sol 62 | robokill.sol 63 | settings.sol 64 | slot1.sol 65 | slot1_party.sol 66 | soundData.sol 67 | soundData_level0.sol 68 | Space.sol 69 | StringTest.sol 70 | timeDisplayConfig.sol 71 | user(1).sol 72 | user.sol 73 | -------------------------------------------------------------------------------- /flash-lso/tests/amf/LearnToFly3.profileData.saveString.amf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/amf/LearnToFly3.profileData.saveString.amf -------------------------------------------------------------------------------- /flash-lso/tests/amf/object-with-vec-obj-child-referencing-parent.amf: -------------------------------------------------------------------------------- 1 | 2 |  3 | -------------------------------------------------------------------------------- /flash-lso/tests/amf/object-with-vec-obj-child-referencing-parent.json: -------------------------------------------------------------------------------- 1 | {"Object":[1,[{"name":"","value":{"Amf3ObjectReference":1}}],{"name":"","attributes":0,"static_properties":[""]}]} -------------------------------------------------------------------------------- /flash-lso/tests/amf/self-referential-array.amf: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /flash-lso/tests/amf/self-referential-array.json: -------------------------------------------------------------------------------- 1 | {"StrictArray":[1,[{"Amf3ObjectReference":1}]]} -------------------------------------------------------------------------------- /flash-lso/tests/amf/self-referential-dict.amf: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /flash-lso/tests/amf/self-referential-dict.json: -------------------------------------------------------------------------------- 1 | {"Dictionary":[1,[["Undefined",{"Amf3ObjectReference":1}]],false]} -------------------------------------------------------------------------------- /flash-lso/tests/amf/self-referential-object.amf: -------------------------------------------------------------------------------- 1 | 2 |  AAAA 3 | -------------------------------------------------------------------------------- /flash-lso/tests/amf/self-referential-object.json: -------------------------------------------------------------------------------- 1 | {"Object":[1,[{"name":"AAAA","value":{"Amf3ObjectReference":1}}],{"name":"","attributes":0,"static_properties":["AAAA"]}]} -------------------------------------------------------------------------------- /flash-lso/tests/amf/self-referential-object.txt: -------------------------------------------------------------------------------- 1 | This file was generated with the following: 2 | 3 | let mut v = vec![]; 4 | let r = Rc::new(Value::Object(0, Vec::new().into(), Some(ClassDefinition { 5 | name: "".to_string(), 6 | attributes: Default::default(), 7 | static_properties: vec![], 8 | }))); 9 | 10 | let o = Value::Object(0, vec![ 11 | Element::new("AAAA", Rc::clone(&r)) 12 | ].into(), Some(ClassDefinition { 13 | name: "".to_string(), 14 | attributes: Default::default(), 15 | static_properties: vec!["AAAA".to_string()], 16 | })); 17 | let oo = Rc::new(o); 18 | 19 | AMF3Encoder::default().write_value(&mut v, oo.as_ref()).unwrap(); 20 | v[9] = 0; 21 | v.pop(); -------------------------------------------------------------------------------- /flash-lso/tests/amf/self-referential-vec-object.amf: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /flash-lso/tests/amf/self-referential-vec-object.json: -------------------------------------------------------------------------------- 1 | {"VectorObject":[1,["Null","Null",{"Amf3ObjectReference":1}],"",true]} -------------------------------------------------------------------------------- /flash-lso/tests/packet/armorgames_auth_request.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/packet/armorgames_auth_request.dat -------------------------------------------------------------------------------- /flash-lso/tests/packet/armorgames_auth_response.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/packet/armorgames_auth_response.dat -------------------------------------------------------------------------------- /flash-lso/tests/sol/00000004.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/00000004.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/2.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/2.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS2-Array-Demo.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":87,"name":"AS2-Array-Demo","format_version":"AMF0"},"body":[{"name":"myIntArray","value":{"ECMAArray":[-1,[],[{"name":"0","value":{"Number":1.0}},{"name":"1","value":{"Number":2.0}},{"name":"2","value":{"Number":3.0}}],3]}}]} -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS2-Array-Demo.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/AS2-Array-Demo.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS2-Boolean-Demo.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":43,"name":"AS2-Boolean-Demo","format_version":"AMF0"},"body":[{"name":"myBool","value":{"Bool":true}}]} 2 | -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS2-Boolean-Demo.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/AS2-Boolean-Demo.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS2-Date-Demo.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":49,"name":"AS2-Date-Demo","format_version":"AMF0"},"body":[{"name":"myDate","value":{"Date":[1409653383774.0,240]}}]} 2 | -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS2-Date-Demo.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/AS2-Date-Demo.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS2-Demo.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/AS2-Demo.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS2-ECMAArray-Demo.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":261,"name":"AS2-ECMAArray-Demo","format_version":"AMF0"},"body":[{"name":"holeyArray","value":{"ECMAArray":[-1,[],[],15]}},{"name":"emptyArray","value":{"ECMAArray":[-1,[],[],0]}},{"name":"holeyArray2","value":{"ECMAArray":[-1,[],[{"name":"1","value":{"String":"one"}}],2]}},{"name":"mixedArray","value":{"ECMAArray":[-1,[],[{"name":"0","value":{"String":"first"}},{"name":"1","value":{"String":"second"}},{"name":"propertyA","value":{"String":"aaaa"}}],2]}},{"name":"myStringArray","value":{"ECMAArray":[-1,[],[{"name":"one","value":{"String":"eins"}},{"name":"two","value":{"String":"zwei"}}],0]}},{"name":"denseArray","value":{"ECMAArray":[-1,[],[{"name":"0","value":{"String":"first"}},{"name":"1","value":{"String":"second"}}],2]}}]} -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS2-ECMAArray-Demo.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/AS2-ECMAArray-Demo.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS2-Integer-Demo.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":49,"name":"AS2-Integer-Demo","format_version":"AMF0"},"body":[{"name":"myInt","value":{"Number":7.0}}]} 2 | -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS2-Integer-Demo.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/AS2-Integer-Demo.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS2-LongString-Demo.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/AS2-LongString-Demo.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS2-Null-Demo.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":39,"name":"AS2-Null-Demo","format_version":"AMF0"},"body":[{"name":"myNull","value":"Null"}]} 2 | -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS2-Null-Demo.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/AS2-Null-Demo.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS2-Number-Demo.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":50,"name":"AS2-Number-Demo","format_version":"AMF0"},"body":[{"name":"myFloat","value":{"Number":3.141592653589793}}]} 2 | -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS2-Number-Demo.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/AS2-Number-Demo.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS2-Object-Demo.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":72,"name":"AS2-Object-Demo","format_version":"AMF0"},"body":[{"name":"myObject2","value":{"Object":[-1,[{"name":"p4","value":{"Number":8.0}},{"name":"p3","value":{"String":"hallo"}}],null]}}]} 2 | -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS2-Object-Demo.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/AS2-Object-Demo.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS2-String-Demo.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":50,"name":"AS2-String-Demo","format_version":"AMF0"},"body":[{"name":"myString","value":{"String":"ralle"}}]} 2 | -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS2-String-Demo.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/AS2-String-Demo.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS2-TypedObject-Demo.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":93,"name":"AS2-TypedObject-Demo","format_version":"AMF0"},"body":[{"name":"myTypedObject","value":{"Object":[-1,[{"name":"foo","value":{"String":"changed prop"}}],{"name":"AS2SolTestClass","attributes":0,"static_properties":[]}]}}]} 2 | -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS2-TypedObject-Demo.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/AS2-TypedObject-Demo.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS2-Undefined-Demo.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":49,"name":"AS2-Undefined-Demo","format_version":"AMF0"},"body":[{"name":"myUndefined","value":"Undefined"}]} 2 | -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS2-Undefined-Demo.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/AS2-Undefined-Demo.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS2-XML-Demo.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":79,"name":"AS2-XML-Demo","format_version":"AMF0"},"body":[{"name":"myXML","value":{"XML":["

test

test2

",true]}}]} 2 | -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS2-XML-Demo.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/AS2-XML-Demo.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS2-half-life-2-flash.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":873,"name":"HLF","format_version":"AMF0"},"body":[{"name":"LAST_LV","value":{"Number":5.0}},{"name":"LAST_GUNS","value":{"ECMAArray":[-1,[],[{"name":"0","value":{"ECMAArray":[-1,[],[{"name":"0","value":{"Object":[-1,[{"name":"alt_clip","value":{"Number":0.0}},{"name":"TYPE","value":{"String":"crowbar"}},{"name":"SUBTYPE","value":{"String":"crowbar"}},{"name":"link","value":{"String":"Crowbar"}},{"name":"TYPER","value":{"String":"crowbar"}},{"name":"plus","value":{"Number":0.0}},{"name":"cal","value":{"String":"None"}},{"name":"kickback","value":{"Number":0.0}},{"name":"fire_rate","value":{"Number":11.0}},{"name":"damage","value":{"Number":8.0}},{"name":"clip","value":{"Number":0.0001}},{"name":"ammo","value":{"Number":0.0}},{"name":"max_ammo","value":{"Number":0.0}},{"name":"max_clip","value":{"Number":1.0}},{"name":"treat","value":{"Number":0.0}},{"name":"range","value":{"Number":20.0}},{"name":"alternate","value":{"Bool":false}},{"name":"description","value":{"String":"Монтировка"}}],null]}}],1]}},{"name":"1","value":{"ECMAArray":[-1,[],[],0]}},{"name":"2","value":{"ECMAArray":[-1,[],[],0]}},{"name":"3","value":{"ECMAArray":[-1,[],[],0]}},{"name":"4","value":{"ECMAArray":[-1,[],[],0]}},{"name":"5","value":{"ECMAArray":[-1,[],[],0]}}],6]}},{"name":"LAST_HP","value":{"Number":100.0}},{"name":"LAST_AC","value":{"Number":0.0}},{"name":"LAST_CURR","value":{"Reference":3}},{"name":"MAX_EPISODE","value":{"Number":2.0}},{"name":"BLOOD","value":{"Bool":true}},{"name":"SHELLS","value":{"Bool":true}},{"name":"CORPSES","value":{"Bool":true}},{"name":"DIFFICULTLY","value":{"Number":2.0}},{"name":"OLD_BULLETS","value":{"Bool":false}},{"name":"OLD_SHELLS","value":{"Bool":false}},{"name":"SAVED_QUALITY","value":{"String":"MEDIUM"}},{"name":"SMALL_OBJECTS","value":{"Bool":true}},{"name":"BLOOD_LEVEL","value":{"Number":0.0}},{"name":"SONG_VOLIME","value":{"Number":32.0}},{"name":"CO_LEFT","value":{"Number":65.0}},{"name":"CO_RIGHT","value":{"Number":68.0}},{"name":"CO_RUN","value":{"Number":16.0}},{"name":"CO_JUMP","value":{"Number":87.0}},{"name":"CO_DUCK","value":{"Number":17.0}},{"name":"CO_ALT","value":{"Number":32.0}},{"name":"CO_USE","value":{"Number":69.0}},{"name":"CO_RELOAD","value":{"Number":82.0}},{"name":"CO_DROP","value":{"Number":71.0}}]} -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS2-half-life-2-flash.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/AS2-half-life-2-flash.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS3-Array-Demo.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":51,"name":"AS3-Array-Demo","format_version":"AMF3"},"body":[{"name":"myIntArray","value":{"StrictArray":[1,[{"Integer":1},{"Integer":2},{"Integer":3}]]}}]} -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS3-Array-Demo.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/AS3-Array-Demo.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS3-Boolean-Demo.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":41,"name":"AS3-Boolean-Demo","format_version":"AMF3"},"body":[{"name":"myBool","value":{"Bool":true}}]} 2 | -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS3-Boolean-Demo.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/AS3-Boolean-Demo.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS3-ByteArray-Demo.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":63,"name":"AS3-ByteArray-Demo","format_version":"AMF3"},"body":[{"name":"myByteArray","value":{"ByteArray":[0,12,72,101,108,108,111,32,87,111,114,108,100,33]}}]} 2 | -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS3-ByteArray-Demo.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/AS3-ByteArray-Demo.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS3-Date-Demo.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":47,"name":"AS3-Date-Demo","format_version":"AMF3"},"body":[{"name":"myDate","value":{"Date":[1409660827254.0,null]}}]} 2 | -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS3-Date-Demo.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/AS3-Date-Demo.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS3-Demo.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":1082,"name":"AS3-Demo","format_version":"AMF3"},"body":[{"name":"myTypedObject","value":{"Object":[1,[{"name":"foo","value":{"Integer":6}}],{"name":"com.AS3SolTestClass","attributes":0,"static_properties":["foo"]}]}},{"name":"myBA_comp_ZLIB","value":{"ByteArray":[120,218,99,224,241,72,205,201,201,87,8,207,47,202,73,81,4,0,28,231,4,74]}},{"name":"myXML","value":{"XML":["\n

test

\n

test2

\n
",true]}},{"name":"mcXMLDoc","value":{"XML":["

test_doc

test2_doc

",false]}},{"name":"myBA_comp_Deflate","value":{"ByteArray":[99,224,241,72,205,201,201,87,8,207,47,202,73,81,4,0]}},{"name":"myUndefined","value":"Undefined"},{"name":"myNull","value":"Null"},{"name":"myBA_LZMA","value":{"ByteArray":[93,0,0,16,0,14,0,0,0,0,0,0,0,0,0,3,120,142,192,161,229,6,25,88,24,102,118,133,42,102,121,128]}},{"name":"myByteArray","value":{"ByteArray":[0,12,72,101,108,108,111,32,87,111,114,108,100,33]}},{"name":"myBool","value":{"Bool":true}},{"name":"myBA_Deflate","value":{"ByteArray":[99,224,241,72,205,201,201,87,8,207,47,202,73,81,4,0]}},{"name":"myVectorNumber","value":{"VectorDouble":[[1.1,-1.1,1.79769313486231e308,5e-324,null,null,null],false]}},{"name":"myDate","value":{"Date":[1406680830523.0,null]}},{"name":"myIntArray","value":{"StrictArray":[2,[{"Integer":1},{"Integer":2},{"Integer":3}]]}},{"name":"myDictionary","value":{"Object":[3,[{"name":"0","value":{"Object":[4,[{"name":"foo","value":{"String":"value0"}}],{"name":"","attributes":1,"static_properties":[]}]}},{"name":"[object Object]","value":{"String":"value3"}},{"name":"Tue Jul 29 20:40:30 GMT-0400 2014","value":{"String":"value6"}},{"name":"\u0000\fHello World!","value":{"String":"value5"}},{"name":"\n testing\n","value":{"String":"value4"}},{"name":"key1","value":{"Object":[5,[{"name":"foo","value":{"String":"what"}}],{"name":"","attributes":1,"static_properties":[]}]}},{"name":"[com.AS3SolTestClass - foo=7]","value":{"String":"value2"}}],{"name":"","attributes":1,"static_properties":[]}]}},{"name":"myStringArray","value":{"StrictArray":[6,[{"String":"eins"},{"String":"zwei"}]]}},{"name":"dictItem","value":{"Object":[7,[{"name":"Lol","value":{"String":"Wat"}},{"name":"herp","value":{"String":"Derp"}}],{"name":"","attributes":1,"static_properties":[]}]}},{"name":"myInt","value":{"Integer":7}},{"name":"myVectorInt","value":{"VectorInt":[[2,2000,2147483647,-2147483648],false]}},{"name":"myFloat","value":{"Number":3.141592653589793}},{"name":"myObject","value":{"Object":[8,[{"name":"p4","value":{"Object":[9,[{"name":"prop","value":{"String":"val"}}],{"name":"","attributes":1,"static_properties":[]}]}},{"name":"p1","value":{"Integer":5}},{"name":"p5","value":{"Date":[1406680830523.0,null]}},{"name":"p3","value":{"Number":3.141592653589793}},{"name":"p2","value":{"String":"hallo"}}],{"name":"","attributes":1,"static_properties":[]}]}},{"name":"myVectorTypedObject","value":{"VectorObject":[10,[{"Object":[11,[{"name":"foo","value":{"Integer":1}}],{"name":"com.AS3SolTestClass","attributes":0,"static_properties":["foo"]}]},{"Object":[12,[{"name":"foo","value":{"Integer":2}}],{"name":"com.AS3SolTestClass","attributes":0,"static_properties":["foo"]}]},{"Object":[13,[{"name":"foo","value":{"Integer":3}}],{"name":"com.AS3SolTestClass","attributes":0,"static_properties":["foo"]}]}],"com.AS3SolTestClass",true]}},{"name":"myVectorUInt","value":{"VectorUInt":[[2,2000,4294967295,0],false]}},{"name":"myString","value":{"String":"ralle"}},{"name":"myVectorIntFixed","value":{"VectorInt":[[2,2000,2147483647,-2147483648],true]}},{"name":"myVectorObject","value":{"VectorObject":[14,[{"Number":4.1},{"Integer":3},{"String":"aaa"}],"",false]}}]} -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS3-Demo.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/AS3-Demo.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS3-Dictionary-Demo.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":197,"name":"AS3-Dictionary-Demo","format_version":"AMF3"},"body":[{"name":"myDictionary","value":{"Dictionary":[1,[[{"String":"0"},{"Object":[2,[{"name":"foo","value":{"String":"value0"}}],{"name":"","attributes":1,"static_properties":[]}]}],[{"String":"key1"},{"Object":[3,[{"name":"foo","value":{"String":"what"}}],{"name":"","attributes":1,"static_properties":[]}]}],[{"XML":["\n testing\n",true]},{"String":"value4"}],[{"Object":[4,[{"name":"foo","value":{"Integer":7}}],{"name":"com.AS3SolTestClass","attributes":0,"static_properties":["foo"]}]},{"String":"value2"}],[{"Object":[5,[{"name":"this_is","value":{"String":" a test"}}],{"name":"","attributes":1,"static_properties":[]}]},{"String":"value3"}]],false]}}]} -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS3-Dictionary-Demo.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/AS3-Dictionary-Demo.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS3-Integer-Demo.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":41,"name":"AS3-Integer-Demo","format_version":"AMF3"},"body":[{"name":"myInt","value":{"Integer":7}}]} 2 | -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS3-Integer-Demo.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/AS3-Integer-Demo.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS3-Null-Demo.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":38,"name":"AS3-Null-Demo","format_version":"AMF3"},"body":[{"name":"myNull","value":"Null"}]} 2 | -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS3-Null-Demo.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/AS3-Null-Demo.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS3-Number-Demo.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":49,"name":"AS3-Number-Demo","format_version":"AMF3"},"body":[{"name":"myFloat","value":{"Number":3.141592653589793}}]} 2 | -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS3-Number-Demo.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/AS3-Number-Demo.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS3-Object-Demo.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":101,"name":"AS3-Object-Demo","format_version":"AMF3"},"body":[{"name":"myObject","value":{"Object":[1,[{"name":"p5","value":{"Date":[1409704396759.0,null]}},{"name":"p3","value":{"Number":3.141592653589793}},{"name":"p4","value":{"Object":[2,[{"name":"prop","value":{"String":"val"}}],{"name":"","attributes":1,"static_properties":[]}]}},{"name":"p1","value":{"Integer":5}},{"name":"p2","value":{"String":"hallo"}}],{"name":"","attributes":1,"static_properties":[]}]}}]} 2 | -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS3-Object-Demo.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/AS3-Object-Demo.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS3-String-Demo.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":48,"name":"AS3-String-Demo","format_version":"AMF3"},"body":[{"name":"myString","value":{"String":"ralle"}}]} 2 | -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS3-String-Demo.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/AS3-String-Demo.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS3-TypedObject-Demo.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":79,"name":"AS3-TypedObject-Demo","format_version":"AMF3"},"body":[{"name":"myTypedObject","value":{"Object":[1,[{"name":"foo","value":{"Integer":6}}],{"name":"com.AS3SolTestClass","attributes":0,"static_properties":["foo"]}]}}]} 2 | -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS3-TypedObject-Demo.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/AS3-TypedObject-Demo.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS3-Undefined-Demo.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":48,"name":"AS3-Undefined-Demo","format_version":"AMF3"},"body":[{"name":"myUndefined","value":"Undefined"}]} 2 | -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS3-Undefined-Demo.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/AS3-Undefined-Demo.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS3-VectorInt-Demo.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":71,"name":"AS3-VectorInt-Demo","format_version":"AMF3"},"body":[{"name":"myVectorIntFixed","value":{"VectorInt":[[2,2000,2147483647,-2147483648],true]}}]} 2 | -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS3-VectorInt-Demo.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/AS3-VectorInt-Demo.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS3-VectorNumber-Demo.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":112,"name":"AS3-VectorNumber-Demo","format_version":"AMF3"},"body":[{"name":"myVectorNumber","value":{"VectorDouble":[[1.1,-1.1,1.79769313486231e308,5e-324,null,null,null],false]}}]} 2 | -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS3-VectorNumber-Demo.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/AS3-VectorNumber-Demo.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS3-VectorObject-Demo.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":73,"name":"AS3-VectorObject-Demo","format_version":"AMF3"},"body":[{"name":"myVectorObject","value":{"VectorObject":[1,[{"Number":4.1},{"Integer":3},{"String":"aaa"}],"",false]}}]} -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS3-VectorObject-Demo.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/AS3-VectorObject-Demo.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS3-VectorTypedObject-Demo.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":103,"name":"AS3-VectorTypedObject-Demo","format_version":"AMF3"},"body":[{"name":"myVectorTypedObject","value":{"VectorObject":[1,[{"Object":[2,[{"name":"foo","value":{"Integer":1}}],{"name":"com.AS3SolTestClass","attributes":0,"static_properties":["foo"]}]},{"Object":[3,[{"name":"foo","value":{"Integer":2}}],{"name":"com.AS3SolTestClass","attributes":0,"static_properties":["foo"]}]},{"Object":[4,[{"name":"foo","value":{"Integer":3}}],{"name":"com.AS3SolTestClass","attributes":0,"static_properties":["foo"]}]}],"com.AS3SolTestClass",true]}}]} -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS3-VectorTypedObject-Demo.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/AS3-VectorTypedObject-Demo.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS3-VectorUint-Demo.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":68,"name":"AS3-VectorUint-Demo","format_version":"AMF3"},"body":[{"name":"myVectorUInt","value":{"VectorUInt":[[2,2000,4294967295,0],false]}}]} 2 | -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS3-VectorUint-Demo.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/AS3-VectorUint-Demo.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS3-XML-Demo.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":82,"name":"AS3-XML-Demo","format_version":"AMF3"},"body":[{"name":"myXML","value":{"XML":["\n

test

\n

test2

\n
",true]}}]} 2 | -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS3-XML-Demo.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/AS3-XML-Demo.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS3-XMLDoc-Demo.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":89,"name":"AS3-XMLDoc-Demo","format_version":"AMF3"},"body":[{"name":"mcXMLDoc","value":{"XML":["

test_doc

test2_doc

",false]}}]} 2 | -------------------------------------------------------------------------------- /flash-lso/tests/sol/AS3-XMLDoc-Demo.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/AS3-XMLDoc-Demo.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/AkamaiEnterprisePlayer.userData.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":160,"name":"AkamaiEnterprisePlayer.userData","format_version":"AMF3"},"body":[{"name":"lsoCaptionSettings","value":{"Bool":false}},{"name":"lsoPlaybackKbpsPerSecond","value":{"Integer":503}},{"name":"lsoLastRenderedMbrBitrate","value":{"Integer":1186}},{"name":"lsoVolume","value":{"Integer":0}},{"name":"lsoCurrentVolume","value":{"Integer":1}}]} 2 | -------------------------------------------------------------------------------- /flash-lso/tests/sol/AkamaiEnterprisePlayer.userData.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/AkamaiEnterprisePlayer.userData.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/ClarenceSave_SLOT1.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":634,"name":"ClarenceSave_SLOT1","format_version":"AMF3"},"body":[{"name":"SAVEDATA","value":{"Object":[1,[{"name":"girlfriend","value":{"StrictArray":[2,[{"StrictArray":[3,[{"Integer":1},{"Integer":-1},{"Integer":0}]]},{"StrictArray":[4,[{"Integer":1},{"Integer":0},{"Integer":-1}]]},{"StrictArray":[5,[{"Integer":0},{"Integer":1},{"Integer":-1}]]},{"StrictArray":[6,[{"Integer":0},{"Integer":1},{"Integer":-1}]]},{"StrictArray":[7,[{"Integer":1},{"Integer":-1},{"Integer":0}]]},{"StrictArray":[8,[{"Integer":1},{"Integer":0},{"Integer":-1}]]},{"StrictArray":[9,[{"Integer":1},{"Integer":-1},{"Integer":0}]]},{"StrictArray":[10,[{"Integer":-1},{"Integer":0},{"Integer":1}]]},{"StrictArray":[11,[{"Integer":1},{"Integer":0},{"Integer":-1}]]},{"StrictArray":[12,[{"Integer":-1},{"Integer":0},{"Integer":1}]]},{"StrictArray":[13,[{"Integer":-1},{"Integer":0},{"Integer":1}]]},{"StrictArray":[14,[{"Integer":-1},{"Integer":1},{"Integer":0}]]},{"StrictArray":[15,[{"Integer":1},{"Integer":-1},{"Integer":0}]]},{"StrictArray":[16,[{"Integer":1},{"Integer":-1},{"Integer":0}]]},{"StrictArray":[17,[{"Integer":-1},{"Integer":1},{"Integer":0}]]},{"StrictArray":[18,[{"Integer":1},{"Integer":0},{"Integer":-1}]]}]]}},{"name":"computerTips","value":{"StrictArray":[19,[]]}},{"name":"tipsOrder","value":{"StrictArray":[20,[{"Integer":8},{"Integer":9},{"Integer":4},{"Integer":10},{"Integer":14},{"Integer":2},{"Integer":11},{"Integer":13},{"Integer":0},{"Integer":3},{"Integer":5},{"Integer":12},{"Integer":6},{"Integer":15},{"Integer":1},{"Integer":7}]]}},{"name":"advice","value":{"StrictArray":[21,[]]}},{"name":"vehicleLocation","value":"Null"},{"name":"tasksCleared","value":{"StrictArray":[22,[{"StrictArray":[23,[]]},{"StrictArray":[24,[]]},{"StrictArray":[25,[]]},{"StrictArray":[26,[]]},{"StrictArray":[27,[]]},{"StrictArray":[28,[]]},{"StrictArray":[29,[]]},{"StrictArray":[30,[]]},{"StrictArray":[31,[]]},{"StrictArray":[32,[]]}]]}},{"name":"tasksUnlocked","value":{"StrictArray":[33,[]]}},{"name":"online","value":{"Bool":false}},{"name":"shopsDone","value":{"StrictArray":[34,[]]}},{"name":"timer","value":{"Integer":-1}},{"name":"job","value":{"Integer":1}},{"name":"deaths","value":{"Integer":0}},{"name":"explored","value":{"Object":[35,[],{"name":"","attributes":1,"static_properties":[]}]}},{"name":"room","value":{"String":"111"}},{"name":"completions","value":{"Integer":0}},{"name":"SpawnPoint","value":{"StrictArray":[36,[{"Integer":3},{"Integer":13}]]}},{"name":"dimdoors","value":{"Object":[37,[],{"name":"","attributes":1,"static_properties":[]}]}},{"name":"coins","value":{"Integer":0}},{"name":"wagesEarned","value":{"Integer":0}},{"name":"coinsCollected","value":{"StrictArray":[38,[{"Integer":0},{"Integer":0},{"Integer":0},{"Integer":0}]]}},{"name":"keys","value":{"StrictArray":[39,[{"Integer":0},{"Integer":0},{"Integer":0},{"Integer":0}]]}},{"name":"PCHP","value":{"Integer":4}},{"name":"playtime","value":{"Integer":0}},{"name":"collection","value":{"StrictArray":[40,[]]}},{"name":"cleared","value":{"Object":[41,[],{"name":"","attributes":1,"static_properties":[]}]}}],{"name":"SaveData","attributes":0,"static_properties":["girlfriend","computerTips","tipsOrder","advice","vehicleLocation","tasksCleared","tasksUnlocked","online","shopsDone","timer","job","deaths","explored","room","completions","SpawnPoint","dimdoors","coins","wagesEarned","coinsCollected","keys","PCHP","playtime","collection","cleared"]}]}}]} -------------------------------------------------------------------------------- /flash-lso/tests/sol/ClarenceSave_SLOT1.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/ClarenceSave_SLOT1.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/CoC_8.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/CoC_8.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/HIRO_NETWORK_CAPPING_COOKIE.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/HIRO_NETWORK_CAPPING_COOKIE.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/InfectonatorSurvivors76561198009932603.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/InfectonatorSurvivors76561198009932603.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/JY1.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/JY1.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/Labrat2.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/Labrat2.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/MARDEKv3__sg_1.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/MARDEKv3__sg_1.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/MetadataHistory.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/MetadataHistory.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/Minimal.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":56,"name":"Minimal","format_version":"AMF3"},"body":[{"name":"dictItem","value":{"Dictionary":[1,[],true]}},{"name":"exists","value":{"Bool":true}},{"name":"version","value":{"Integer":1}}]} -------------------------------------------------------------------------------- /flash-lso/tests/sol/Minimal.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/Minimal.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/Minimalv2.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":80,"name":"Minimalv2","format_version":"AMF3"},"body":[{"name":"dictItem","value":{"Dictionary":[1,[[{"String":"Lol"},{"String":"Wat"}],[{"String":"herp"},{"String":"Derp"}]],false]}},{"name":"version","value":{"Integer":1}},{"name":"exists","value":{"Bool":true}}]} -------------------------------------------------------------------------------- /flash-lso/tests/sol/Minimalv2.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/Minimalv2.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/Party1.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/Party1.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/Space.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":52,"name":"Space","format_version":"AMF3"},"body":[{"name":"objSpacing","value":{"Integer":0}},{"name":"selectedIndex","value":{"Integer":0}}]} 2 | -------------------------------------------------------------------------------- /flash-lso/tests/sol/Space.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/Space.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/StringTest.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":265,"name":"StringTest","format_version":"AMF3"},"body":[{"name":"exists","value":{"Bool":true}},{"name":"testForThirdItem","value":{"String":"This is the third item"}},{"name":"dictItem","value":{"Dictionary":[1,[[{"String":"testForFirstItem"},{"String":"This is the first item"}]],false]}},{"name":"arrayItem","value":{"StrictArray":[2,[{"String":"This is the first item"},{"String":"This is the second item"},{"String":"This is the third item"},{"String":"This is the first item"},{"String":"This is the second item"},{"String":"This is the third item"},{"String":"This is the first item"},{"String":"This is the second item"},{"String":"This is the third item"},{"String":"This is the first item"},{"String":"This is the second item"},{"String":"This is the third item"},{"String":"This is the first item"},{"String":"This is the second item"},{"String":"This is the third item"},{"String":"This is the first item"},{"String":"This is the second item"},{"String":"This is the third item"},{"String":"This is the first item"},{"String":"This is the second item"},{"String":"This is the third item"},{"String":"This is the first item"},{"String":"This is the second item"},{"String":"This is the third item"},{"String":"This is the first item"},{"String":"This is the second item"},{"String":"This is the third item"},{"String":"This is the first item"},{"String":"This is the second item"},{"String":"This is the third item"}]]}},{"name":"objectItem","value":{"Object":[3,[{"name":"testForSecondItem","value":{"String":"This is the second item"}}],{"name":"","attributes":1,"static_properties":[]}]}}]} -------------------------------------------------------------------------------- /flash-lso/tests/sol/StringTest.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/StringTest.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/arenaMadnessGame2.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":3827,"name":"arenaMadnessGame2","format_version":"AMF0"},"body":[{"name":"haveSaved","value":{"Bool":true}},{"name":"dataTester","value":{"String":"FILE INTEGRITY INTACT"}},{"name":"myCash","value":{"Number":999999999.0}},{"name":"teamLeader","value":{"Object":[-1,[{"name":"perkShotgunROF2","value":{"Bool":false}},{"name":"perkKnockdown1","value":{"Bool":false}},{"name":"myHat","value":{"ECMAArray":[-1,[],[{"name":"0","value":"Undefined"}],1]}},{"name":"perkBlockBreak","value":{"Bool":false}},{"name":"traitBravery","value":{"Number":1.0}},{"name":"myMouth","value":{"ECMAArray":[-1,[],[{"name":"0","value":"Undefined"}],1]}},{"name":"perkMeleePistolWhip","value":{"Bool":false}},{"name":"perkShotgunDamage","value":{"Bool":false}},{"name":"myMask","value":{"ECMAArray":[-1,[],[{"name":"0","value":"Undefined"}],1]}},{"name":"fastDeteriorate","value":{"Bool":false}},{"name":"fastDeath","value":{"Bool":false}},{"name":"perkMeleeMoves2","value":{"Bool":false}},{"name":"traitTriggerFinger","value":{"Number":1.0}},{"name":"perkSidearm1","value":{"Bool":false}},{"name":"mySlowMo","value":{"Number":0.0}},{"name":"slamGrab","value":{"Bool":false}},{"name":"perkKnockdown2","value":{"Bool":false}},{"name":"perkMeleeDisarm","value":{"Bool":false}},{"name":"traitAwareness","value":{"Number":4.0}},{"name":"myShirt","value":{"ECMAArray":[-1,[],[{"name":"0","value":"Undefined"}],1]}},{"name":"perkMeleeMoves3","value":{"Bool":false}},{"name":"myDash","value":{"Number":1.3}},{"name":"perkStunDash1","value":{"Bool":false}},{"name":"perkDodge1","value":{"Bool":false}},{"name":"grabBreaker","value":{"Bool":false}},{"name":"weakToDash","value":{"Bool":false}},{"name":"perkUnarmedMoves1","value":{"Bool":false}},{"name":"perkBulletTime2","value":{"Bool":false}},{"name":"perkRifleAccuracy","value":{"Bool":false}},{"name":"myWidth","value":{"Number":50.0}},{"name":"strongGrip","value":{"Bool":false}},{"name":"perkMeleeMoves4","value":{"Bool":false}},{"name":"noRange","value":{"Bool":false}},{"name":"statEND","value":{"Number":0.0}},{"name":"perkDodge2","value":{"Bool":false}},{"name":"perkArmorPierce","value":{"Bool":false}},{"name":"perkReload1","value":{"Bool":false}},{"name":"perkBlock2","value":{"Bool":false}},{"name":"perkMeleeMoves1","value":{"Bool":false}},{"name":"myReload","value":{"Number":96.0}},{"name":"traitCombatSkill","value":{"Number":1.0}},{"name":"perkRifleReload","value":{"Bool":false}},{"name":"hitStopAttack","value":{"Bool":false}},{"name":"bodyType","value":{"String":"civ"}},{"name":"perkUnarmedMoves3","value":{"Bool":false}},{"name":"perkTacBar1","value":{"Bool":false}},{"name":"statSTR","value":{"Number":0.0}},{"name":"perkLowAcc1","value":{"Bool":false}},{"name":"amZombie","value":{"Bool":false}},{"name":"statDEX","value":{"Number":0.0}},{"name":"myUnarmed","value":{"Object":[-1,[{"name":"twoHand","value":{"Bool":false}},{"name":"myRange","value":{"Number":95.0}},{"name":"myType","value":{"String":"unarmed"}},{"name":"myPiercing","value":{"Number":0.0}},{"name":"melee","value":{"Bool":true}},{"name":"myDamage","value":{"Number":2.0}},{"name":"myShots","value":{"Number":1.0}},{"name":"myCat","value":{"String":"melee"}},{"name":"myDamageType","value":{"String":"punch"}},{"name":"myName","value":{"String":"Unarmed"}},{"name":"myROF","value":{"Number":30.0}},{"name":"myAmmo","value":{"Number":1.0}},{"name":"myTag","value":{"String":"Unarmed"}},{"name":"myCasing","value":{"String":"spark1"}},{"name":"mySpread","value":{"Number":3.0}}],null]}},{"name":"perkLowAcc2","value":{"Bool":false}},{"name":"perkShotgunShots1","value":{"Bool":false}},{"name":"noHeadshots","value":{"Bool":false}},{"name":"perkPistolReload","value":{"Bool":false}},{"name":"perkBlock1","value":{"Bool":false}},{"name":"perkUnarmedMoves2","value":{"Bool":false}},{"name":"perkPistolROF1","value":{"Bool":false}},{"name":"perkCoverShoot","value":{"Bool":false}},{"name":"noDodge","value":{"Bool":false}},{"name":"traitDistracted","value":{"Number":8.0}},{"name":"perkDodge3","value":{"Bool":false}},{"name":"autoDash","value":{"Bool":false}},{"name":"headType","value":{"String":"civ"}},{"name":"perkUnarmedSpeed1","value":{"Bool":false}},{"name":"autoAware","value":{"Bool":false}},{"name":"bodyWounds","value":{"ECMAArray":[-1,[],[],0]}},{"name":"myHeight","value":{"Number":94.0}},{"name":"perkUnarmedSpeed2","value":{"Bool":false}},{"name":"myCharacter","value":{"String":"civ"}},{"name":"perkArmor2","value":{"Bool":false}},{"name":"skillMelee","value":{"Number":0.0}},{"name":"noWieldGuns","value":{"Bool":false}},{"name":"amAbom","value":{"Bool":false}},{"name":"skillPistol","value":{"Number":0.0}},{"name":"statLEAD","value":{"Number":0.0}},{"name":"perkPistolAccuracy2","value":{"Bool":false}},{"name":"skillRevolver","value":{"Number":0.0}},{"name":"weaponArray","value":{"ECMAArray":[-1,[],[{"name":"0","value":{"String":"ppk"}},{"name":"1","value":{"String":"beretta"}},{"name":"2","value":{"String":"glock20"}}],3]}},{"name":"traitCover","value":{"Number":1.0}},{"name":"statAWR","value":{"Number":0.0}},{"name":"perkStunDash2","value":{"Bool":false}},{"name":"statTAC","value":{"Number":0.0}},{"name":"perkPistolROF2","value":{"Bool":false}},{"name":"perkUnarmedSpeed3","value":{"Bool":false}},{"name":"perkPistolEffectiveness","value":{"Bool":false}},{"name":"perkTacBar2","value":{"Bool":false}},{"name":"perkSMGAim1","value":{"Bool":false}},{"name":"perkArmor1","value":{"Bool":false}},{"name":"amInvincible","value":{"Bool":false}},{"name":"skillSMG","value":{"Number":0.0}},{"name":"noZombie","value":{"Bool":false}},{"name":"skillShotgun","value":{"Number":0.0}},{"name":"headWounds","value":{"ECMAArray":[-1,[],[],0]}},{"name":"myDepth","value":{"Number":16.0}},{"name":"skillUnarmed","value":{"Number":0.0}},{"name":"myIconPos","value":{"Number":1.0}},{"name":"myShootHeight","value":{"Number":50.0}},{"name":"noHands","value":{"Bool":false}},{"name":"freakOut","value":{"Bool":false}},{"name":"myScale","value":{"Number":1.0}},{"name":"myNaturalArmorHead","value":{"Number":0.0}},{"name":"noCollide","value":{"Bool":false}},{"name":"myNaturalArmorBody","value":{"Number":0.0}},{"name":"meleeHealth","value":{"Number":3.0}},{"name":"perkStunProof1","value":{"Bool":false}},{"name":"myName","value":{"String":"Ace"}},{"name":"amSlow","value":{"Bool":false}},{"name":"modHurtTactics","value":{"Number":1.0}},{"name":"amEvader","value":{"Bool":false}},{"name":"bulletEater","value":{"Bool":false}},{"name":"perkArmor3","value":{"Bool":false}},{"name":"skillRifle","value":{"Number":0.0}},{"name":"perkSMGReload","value":{"Bool":false}},{"name":"improvedChump","value":{"Bool":false}},{"name":"myXP","value":{"Number":0.0}},{"name":"skillHeavy","value":{"Number":0.0}},{"name":"standStill","value":{"Bool":false}},{"name":"myBoss","value":{"String":""}},{"name":"perkImmuneLowDmg","value":{"Bool":false}},{"name":"perkFearMonger1","value":{"Bool":false}},{"name":"perkSMGTacDamage","value":{"Bool":false}},{"name":"perkStunProof2","value":{"Bool":false}},{"name":"perkTeamBonus2","value":{"Bool":false}},{"name":"myKills","value":{"Number":0.0}},{"name":"myHeadHeight","value":{"Number":50.0}},{"name":"skillPoints","value":{"Number":0.0}},{"name":"myWaves","value":{"Number":0.0}},{"name":"perkFearMonger3","value":{"Bool":false}},{"name":"modRecharge","value":{"Number":1.0}},{"name":"perkFearMonger2","value":{"Bool":false}},{"name":"modSpeed","value":{"Number":1.0}},{"name":"perkTeamBonus3","value":{"Bool":false}},{"name":"perkTeamBonus1","value":{"Bool":false}},{"name":"perkSMGAim2","value":{"Bool":false}},{"name":"amSpecial","value":{"Bool":true}},{"name":"knockdownDash","value":{"Bool":false}},{"name":"modDmg","value":{"Number":1.0}},{"name":"perkRifleTacDamage","value":{"Bool":false}},{"name":"thrownBlock","value":{"Bool":false}},{"name":"statPoints","value":{"Number":0.0}},{"name":"weaponStealer","value":{"Bool":false}},{"name":"myHealth","value":{"Number":17.0}},{"name":"headGearResurrect","value":{"Bool":false}},{"name":"perkRifleRange1","value":{"Bool":false}},{"name":"perkHeadshotCrits","value":{"Bool":false}},{"name":"myAccel","value":{"Number":1.25}},{"name":"modAllySmart","value":{"Number":1.0}},{"name":"mySpeed","value":{"Number":4.8}},{"name":"selfShoot","value":{"Bool":false}},{"name":"myBlood","value":{"String":"red"}},{"name":"modArmor","value":{"Number":1.0}},{"name":"perkBulletTime1","value":{"Bool":false}},{"name":"perkSMGRange","value":{"Bool":false}},{"name":"perkRifleRange2","value":{"Bool":false}},{"name":"perkBulletTime3","value":{"Bool":false}},{"name":"myHealthMax","value":{"Number":17.0}},{"name":"perkBulletTime4","value":{"Bool":false}},{"name":"autoHit","value":{"Bool":false}},{"name":"perkPistolAccuracy1","value":{"Bool":false}},{"name":"myTacticsMax","value":{"Number":0.0}},{"name":"footType","value":{"String":"civ"}},{"name":"perkLowAcc3","value":{"Bool":false}},{"name":"handType","value":{"String":"civ"}},{"name":"mySlowMoMax","value":{"Number":400.0}},{"name":"perkShotgunROF1","value":{"Bool":false}},{"name":"noPaint","value":{"Bool":false}},{"name":"noAimShots","value":{"Bool":false}},{"name":"perkRifleEffectiveness","value":{"Bool":false}},{"name":"myTactics","value":{"Number":0.0}},{"name":"perkShotgunReload","value":{"Bool":false}},{"name":"modRange","value":{"Number":0.0}},{"name":"myWeapons","value":{"ECMAArray":[-1,[],[{"name":"0","value":"Undefined"},{"name":"1","value":"Undefined"}],2]}},{"name":"perkShotgunShots2","value":{"Bool":false}},{"name":"attackNeutrals","value":{"Bool":false}},{"name":"meleeShy","value":{"Bool":false}},{"name":"disarmHelm","value":{"Bool":false}},{"name":"myLevel","value":{"Number":1.0}}],null]}},{"name":"myActiveMembers","value":{"ECMAArray":[-1,[],[],0]}},{"name":"currentWave","value":{"Number":1.0}},{"name":"myWeaponsList","value":{"ECMAArray":[-1,[],[],0]}},{"name":"myInactiveMembers","value":{"ECMAArray":[-1,[],[],0]}},{"name":"arenaWaves","value":{"Number":0.0}},{"name":"arenaKills","value":{"Number":0.0}},{"name":"newArena","value":{"Bool":true}},{"name":"myArmorList","value":{"ECMAArray":[-1,[],[],0]}}]} -------------------------------------------------------------------------------- /flash-lso/tests/sol/arenaMadnessGame2.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/arenaMadnessGame2.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/canvas.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":33,"name":"canvas","format_version":"AMF3"},"body":[{"name":"toCanvas","value":{"Bool":true}}]} 2 | -------------------------------------------------------------------------------- /flash-lso/tests/sol/canvas.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/canvas.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/com.jeroenwijering.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":48,"name":"com.jeroenwijering","format_version":"AMF3"},"body":[{"name":"bandwidth","value":{"Integer":4059}}]} 2 | -------------------------------------------------------------------------------- /flash-lso/tests/sol/com.jeroenwijering.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/com.jeroenwijering.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/cramjs.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":188,"name":"cramjs","format_version":"AMF3"},"body":[{"name":"currentVersion","value":{"String":"%229dae4e93be0af4977e467a62d80f5b90ab17ad43%22"}},{"name":"versionChangedTime","value":{"String":"1406582987132"}},{"name":"userWatchedHistory_1361030","value":{"String":"%5B60394281%5D"}},{"name":"userHistory_1361030","value":{"String":"%5B60394281%5D"}}]} 2 | -------------------------------------------------------------------------------- /flash-lso/tests/sol/cramjs.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/cramjs.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/dolphin_show(1).json: -------------------------------------------------------------------------------- 1 | {"header":{"length":179,"name":"dolphin_show","format_version":"AMF3"},"body":[{"name":"userData","value":{"Object":[1,[{"name":"userName","value":{"String":"user"}},{"name":"playerMoney","value":{"Integer":49275}},{"name":"showTimeLastPlayed","value":{"Integer":0}},{"name":"dolphinScins","value":{"StrictArray":[2,[{"Integer":1},{"Integer":2}]]}},{"name":"currentDolphinScin","value":{"Integer":1}},{"name":"points","value":{"Integer":0}},{"name":"musicMute","value":{"Bool":false}},{"name":"soundMute","value":{"Bool":false}},{"name":"effectsMute","value":{"Bool":false}}],{"name":"","attributes":0,"static_properties":["userName","playerMoney","showTimeLastPlayed","dolphinScins","currentDolphinScin","points","musicMute","soundMute","effectsMute"]}]}}]} -------------------------------------------------------------------------------- /flash-lso/tests/sol/dolphin_show(1).sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/dolphin_show(1).sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/flagstaff(1).json: -------------------------------------------------------------------------------- 1 | {"header":{"length":555,"name":"flagstaff","format_version":"AMF3"},"body":[{"name":"chapter1UserData","value":{"Object":[1,[{"name":"campaigns","value":{"VectorObject":[2,[{"Object":[3,[{"name":"currentMissionIndex","value":{"Integer":5}},{"name":"slot","value":{"Integer":0}},{"name":"partyExperience","value":{"Integer":24}},{"name":"numPartyDeaths","value":{"Integer":0}},{"name":"upgradePoints","value":{"Integer":0}},{"name":"playerTeam","value":{"VectorObject":[4,[{"Object":[5,[{"name":"enabledUpgrades","value":{"StrictArray":[6,[{"String":"Sword Attack"},{"String":"Spin Attack"},{"String":"Increase Health"},{"String":"Increase Speed"},{"String":"Dual Abilities"}]]}}],{"name":"com.joelesler.flagstaff.model.tactical.world.character.SavedCharacterVO","attributes":0,"static_properties":["enabledUpgrades"]}]},{"Object":[7,[{"name":"enabledUpgrades","value":{"StrictArray":[8,[{"String":"Heal"},{"String":"Smite"},{"String":"Heal All"},{"String":"Dual Abilities"}]]}}],{"name":"com.joelesler.flagstaff.model.tactical.world.character.SavedCharacterVO","attributes":0,"static_properties":["enabledUpgrades"]}]},{"Object":[9,[{"name":"enabledUpgrades","value":{"StrictArray":[10,[{"String":"Bow Attack"},{"String":"Point Blank Arrow"},{"String":"Rain of Arrows"},{"String":"Increase Speed"},{"String":"Dual Abilities"}]]}}],{"name":"com.joelesler.flagstaff.model.tactical.world.character.SavedCharacterVO","attributes":0,"static_properties":["enabledUpgrades"]}]},{"Object":[11,[{"name":"enabledUpgrades","value":{"StrictArray":[12,[{"String":"Fireball"},{"String":"Sleep"},{"String":"Dual Abilities"}]]}}],{"name":"com.joelesler.flagstaff.model.tactical.world.character.SavedCharacterVO","attributes":0,"static_properties":["enabledUpgrades"]}]}],"com.joelesler.flagstaff.model.tactical.world.character.SavedCharacterVO",false]}},{"name":"partyLevel","value":{"Integer":14}}],{"name":"com.joelesler.flagstaff.model.campaign.SavedCampaignVO","attributes":0,"static_properties":["currentMissionIndex","slot","partyExperience","numPartyDeaths","upgradePoints","playerTeam","partyLevel"]}]}],"com.joelesler.flagstaff.model.campaign.SavedCampaignVO",false]}}],{"name":"com.joelesler.flagstaff.model.campaign.SavedUserVO","attributes":0,"static_properties":["campaigns"]}]}}]} -------------------------------------------------------------------------------- /flash-lso/tests/sol/flagstaff(1).sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/flagstaff(1).sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/flagstaff.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/flagstaff.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/flash.viewer.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/flash.viewer.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/mediaPlayerUserSettings.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":88,"name":"mediaPlayerUserSettings","format_version":"AMF0"},"body":[{"name":"volume","value":{"Number":1.0}},{"name":"smoothing","value":{"Bool":false}},{"name":"sizeMode","value":{"String":"fit"}}]} 2 | -------------------------------------------------------------------------------- /flash-lso/tests/sol/mediaPlayerUserSettings.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/mediaPlayerUserSettings.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/oppDetailPrefs.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":935,"name":"oppDetailPrefs","format_version":"AMF3"},"body":[{"name":"oppDetailPrefs","value":{"Custom":[[{"name":"data","value":{"StrictArray":[2,[{"Custom":[[{"name":"object","value":{"Object":[4,[{"name":"name","value":{"String":"SummaryBox"}},{"name":"indexCompare","value":"Undefined"},{"name":"visibleCompare","value":"Undefined"},{"name":"visibleSingleView","value":{"Bool":true}},{"name":"title","value":{"String":"Status"}},{"name":"indexSingleView","value":{"Integer":1}}],{"name":"","attributes":1,"static_properties":[]}]}}],[],{"name":"flex.messaging.io.ObjectProxy","attributes":3,"static_properties":[]}]},{"Custom":[[{"name":"object","value":{"Object":[6,[{"name":"name","value":{"String":"LocationBox"}},{"name":"indexCompare","value":"Undefined"},{"name":"visibleCompare","value":"Undefined"},{"name":"visibleSingleView","value":{"Bool":true}},{"name":"title","value":{"String":"Location"}},{"name":"indexSingleView","value":{"Integer":2}}],{"name":"","attributes":1,"static_properties":[]}]}}],[],{"name":"flex.messaging.io.ObjectProxy","attributes":3,"static_properties":[]}]},{"Custom":[[{"name":"object","value":{"Object":[8,[{"name":"name","value":{"String":"PropertyDetailsBox"}},{"name":"indexCompare","value":"Undefined"},{"name":"visibleCompare","value":"Undefined"},{"name":"visibleSingleView","value":{"Bool":true}},{"name":"title","value":{"String":"Property Details"}},{"name":"indexSingleView","value":{"Integer":3}}],{"name":"","attributes":1,"static_properties":[]}]}}],[],{"name":"flex.messaging.io.ObjectProxy","attributes":3,"static_properties":[]}]},{"Custom":[[{"name":"object","value":{"Object":[10,[{"name":"name","value":{"String":"OwnerBox"}},{"name":"indexCompare","value":"Undefined"},{"name":"visibleCompare","value":"Undefined"},{"name":"visibleSingleView","value":{"Bool":true}},{"name":"title","value":{"String":"Current Owner Name & Mailing Address"}},{"name":"indexSingleView","value":{"Integer":4}}],{"name":"","attributes":1,"static_properties":[]}]}}],[],{"name":"flex.messaging.io.ObjectProxy","attributes":3,"static_properties":[]}]},{"Custom":[[{"name":"object","value":{"Object":[12,[{"name":"name","value":{"String":"FinancialsBox"}},{"name":"indexCompare","value":"Undefined"},{"name":"visibleCompare","value":"Undefined"},{"name":"visibleSingleView","value":{"Bool":true}},{"name":"title","value":{"String":"Financial Analysis"}},{"name":"indexSingleView","value":{"Integer":5}}],{"name":"","attributes":1,"static_properties":[]}]}}],[],{"name":"flex.messaging.io.ObjectProxy","attributes":3,"static_properties":[]}]},{"Custom":[[{"name":"object","value":{"Object":[14,[{"name":"name","value":{"String":"DocumentsBox"}},{"name":"indexCompare","value":"Undefined"},{"name":"visibleCompare","value":"Undefined"},{"name":"visibleSingleView","value":{"Bool":true}},{"name":"title","value":{"String":"Transaction History"}},{"name":"indexSingleView","value":{"Integer":6}}],{"name":"","attributes":1,"static_properties":[]}]}}],[],{"name":"flex.messaging.io.ObjectProxy","attributes":3,"static_properties":[]}]},{"Custom":[[{"name":"object","value":{"Object":[16,[{"name":"name","value":{"String":"ValueEquityBox"}},{"name":"indexCompare","value":"Undefined"},{"name":"visibleCompare","value":"Undefined"},{"name":"visibleSingleView","value":{"Bool":true}},{"name":"title","value":{"String":"Value & Equity (Estimated)"}},{"name":"indexSingleView","value":{"Integer":7}}],{"name":"","attributes":1,"static_properties":[]}]}}],[],{"name":"flex.messaging.io.ObjectProxy","attributes":3,"static_properties":[]}]},{"Custom":[[{"name":"object","value":{"Object":[18,[{"name":"name","value":{"String":"TaxBox"}},{"name":"indexCompare","value":"Undefined"},{"name":"visibleCompare","value":"Undefined"},{"name":"visibleSingleView","value":{"Bool":true}},{"name":"title","value":{"String":"Tax Assessment"}},{"name":"indexSingleView","value":{"Integer":8}}],{"name":"","attributes":1,"static_properties":[]}]}}],[],{"name":"flex.messaging.io.ObjectProxy","attributes":3,"static_properties":[]}]},{"Custom":[[{"name":"object","value":{"Object":[20,[{"name":"name","value":{"String":"ListingBox"}},{"name":"indexCompare","value":"Undefined"},{"name":"visibleCompare","value":"Undefined"},{"name":"visibleSingleView","value":{"Bool":true}},{"name":"title","value":{"String":"Listing Details"}},{"name":"indexSingleView","value":{"Integer":9}}],{"name":"","attributes":1,"static_properties":[]}]}}],[],{"name":"flex.messaging.io.ObjectProxy","attributes":3,"static_properties":[]}]},{"Custom":[[{"name":"object","value":{"Object":[22,[{"name":"name","value":{"String":"LinksBox"}},{"name":"indexCompare","value":"Undefined"},{"name":"visibleCompare","value":"Undefined"},{"name":"visibleSingleView","value":{"Bool":true}},{"name":"title","value":{"String":"Links"}},{"name":"indexSingleView","value":{"Integer":10}}],{"name":"","attributes":1,"static_properties":[]}]}}],[],{"name":"flex.messaging.io.ObjectProxy","attributes":3,"static_properties":[]}]},{"Custom":[[{"name":"object","value":{"Object":[24,[{"name":"name","value":{"String":"NotesBox"}},{"name":"indexCompare","value":"Undefined"},{"name":"visibleCompare","value":"Undefined"},{"name":"visibleSingleView","value":{"Bool":true}},{"name":"title","value":{"String":"Notes"}},{"name":"indexSingleView","value":{"Integer":11}}],{"name":"","attributes":1,"static_properties":[]}]}}],[],{"name":"flex.messaging.io.ObjectProxy","attributes":3,"static_properties":[]}]},{"Custom":[[{"name":"object","value":{"Object":[26,[{"name":"name","value":{"String":"FilesBox"}},{"name":"indexCompare","value":"Undefined"},{"name":"visibleCompare","value":"Undefined"},{"name":"visibleSingleView","value":{"Bool":true}},{"name":"title","value":{"String":"Files"}},{"name":"indexSingleView","value":{"Integer":12}}],{"name":"","attributes":1,"static_properties":[]}]}}],[],{"name":"flex.messaging.io.ObjectProxy","attributes":3,"static_properties":[]}]},{"Custom":[[{"name":"object","value":{"Object":[28,[{"name":"name","value":{"String":"BirdsEyeBox"}},{"name":"indexCompare","value":"Undefined"},{"name":"visibleCompare","value":"Undefined"},{"name":"visibleSingleView","value":{"Bool":true}},{"name":"title","value":{"String":"Bird's Eye View"}},{"name":"indexSingleView","value":{"Integer":2}}],{"name":"","attributes":1,"static_properties":[]}]}}],[],{"name":"flex.messaging.io.ObjectProxy","attributes":3,"static_properties":[]}]},{"Custom":[[{"name":"object","value":{"Object":[30,[{"name":"name","value":{"String":"PhotosBox"}},{"name":"indexCompare","value":"Undefined"},{"name":"visibleCompare","value":"Undefined"},{"name":"visibleSingleView","value":{"Bool":true}},{"name":"title","value":{"String":"My Photos"}},{"name":"indexSingleView","value":{"Integer":3}}],{"name":"","attributes":1,"static_properties":[]}]}}],[],{"name":"flex.messaging.io.ObjectProxy","attributes":3,"static_properties":[]}]},{"Custom":[[{"name":"object","value":{"Object":[32,[{"name":"visibleSingleView","value":{"Bool":true}},{"name":"container","value":{"String":"Media"}},{"name":"name","value":{"String":"AerialBox"}},{"name":"title","value":{"String":"Aerial View"}},{"name":"indexSingleView","value":{"Integer":3}}],{"name":"","attributes":1,"static_properties":[]}]}}],[],{"name":"flex.messaging.io.ObjectProxy","attributes":3,"static_properties":[]}]},{"Custom":[[{"name":"object","value":{"Object":[34,[{"name":"name","value":{"String":"MapBox"}},{"name":"indexCompare","value":"Undefined"},{"name":"visibleCompare","value":"Undefined"},{"name":"visibleSingleView","value":{"Bool":true}},{"name":"title","value":{"String":"Map"}},{"name":"indexSingleView","value":{"Integer":12}}],{"name":"","attributes":1,"static_properties":[]}]}}],[],{"name":"flex.messaging.io.ObjectProxy","attributes":3,"static_properties":[]}]},{"Custom":[[{"name":"object","value":{"Object":[36,[{"name":"visibleSingleView","value":{"Bool":true}},{"name":"container","value":{"String":"Media"}},{"name":"name","value":{"String":"SharedPhotosBox"}},{"name":"title","value":{"String":"Public Photos"}},{"name":"indexSingleView","value":{"Integer":5}}],{"name":"","attributes":1,"static_properties":[]}]}}],[],{"name":"flex.messaging.io.ObjectProxy","attributes":3,"static_properties":[]}]}]]}}],[],{"name":"flex.messaging.io.ArrayCollection","attributes":2,"static_properties":[]}]}}]} -------------------------------------------------------------------------------- /flash-lso/tests/sol/oppDetailPrefs.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/oppDetailPrefs.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/other/Johngame5.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":340,"name":"Johngame5","format_version":"AMF3"},"body":[{"name":"Save","value":{"Object":[1,[{"name":"medalArray","value":{"ECMAArray":[2,[],[{"name":"1","value":{"Bool":true}},{"name":"2","value":{"Bool":true}},{"name":"3","value":{"Bool":true}},{"name":"4","value":{"Bool":true}},{"name":"6","value":{"Bool":true}},{"name":"8","value":{"Bool":true}}],6]}},{"name":"gameComplete","value":{"Bool":true}},{"name":"upgradeArray","value":{"StrictArray":[{"Integer":4},{"Integer":1},{"Integer":1},{"Integer":4},{"Integer":4},{"Integer":4},{"Integer":3},{"Integer":1},{"Integer":20},{"Integer":1},{"Integer":1},{"Integer":0},{"Integer":1},{"Integer":0},{"Integer":1},{"Integer":5},{"Integer":1}]}},{"name":"checkMade","value":{"Bool":true}},{"name":"gameTimer","value":{"Integer":30849}},{"name":"shipCode","value":{"StrictArray":[{"Integer":2},{"Integer":32},{"Integer":-1},{"Integer":0},{"Integer":0},{"Integer":5},{"Integer":2},{"Integer":-33},{"Integer":-6},{"Integer":0},{"Integer":0},{"Integer":5},{"Integer":6},{"Integer":-3},{"Integer":34},{"Integer":0},{"Integer":0},{"Integer":5},{"Integer":5},{"Integer":27},{"Integer":34},{"Integer":0},{"Integer":0},{"Integer":3},{"Integer":4},{"Integer":-33},{"Integer":34},{"Integer":0},{"Integer":0},{"Integer":2},{"Integer":2},{"Integer":67},{"Integer":4},{"Integer":0},{"Integer":0},{"Integer":5},{"Integer":2},{"Integer":-58},{"Integer":-1},{"Integer":0},{"Integer":0},{"Integer":4},{"Integer":3},{"Integer":47},{"Integer":4},{"Integer":0},{"Integer":0},{"Integer":4},{"Integer":2},{"Integer":92},{"Integer":4},{"Integer":0},{"Integer":0},{"Integer":5},{"Integer":2},{"Integer":-88},{"Integer":-6},{"Integer":0},{"Integer":0},{"Integer":3},{"Integer":6},{"Integer":-67},{"Integer":29},{"Integer":0},{"Integer":0},{"Integer":5}]}},{"name":"money","value":{"Integer":7503}}],{"name":"","attributes":1,"static_properties":[]}]}}]} -------------------------------------------------------------------------------- /flash-lso/tests/sol/other/Johngame5.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/other/Johngame5.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/other/fishtycoon.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/other/fishtycoon.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/other/mainprofile.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":4881,"name":"mainprofile","format_version":"AMF0"},"body":[{"name":"profileState","value":{"Object":[-1,[{"name":"bestDaysForClassic","value":{"Number":9999.0}},{"name":"bestDaysForStory","value":{"Number":9999.0}},{"name":"enableTutorials","value":{"Bool":true}},{"name":"enableTransitions","value":{"Bool":true}},{"name":"enableAnimations","value":{"Bool":true}},{"name":"controlMode","value":{"String":"classic"}},{"name":"controlSet","value":{"String":"basic"}},{"name":"modesUnlocked","value":{"Bool":false}},{"name":"mute","value":{"Number":1.0}},{"name":"sfxVolume","value":{"Number":85.0}},{"name":"bgmVolume","value":{"Number":85.0}},{"name":"quality","value":{"String":"MEDIUM"}},{"name":"bgm_flight1","value":{"String":"basic1"}},{"name":"bgm_flight2","value":{"String":"basic2"}},{"name":"bgm_flight3","value":{"String":"basic3"}},{"name":"bgm_shop","value":{"String":"basic_theme2"}},{"name":"test_player_points","value":{"Number":0.0}},{"name":"bonusItemOwn","value":{"String":"0,0,0,0,0,0,0,0,0,0,0,0"}},{"name":"musicOwn","value":{"String":"2,0,0,0,0,0,0,0,0,0,0"}},{"name":"RAMP_ANGLE_SLIDER_Y","value":{"Number":-1.0}},{"name":"RAMP_JUMP_ANGLE","value":{"Number":-40.0}},{"name":"RAMP_JUMP_ANGLE_OVER","value":{"Number":1.0}},{"name":"movieUnlocked","value":{"String":"true,true,false,false,false"}},{"name":"tutorialsDone","value":{"String":"true,true,false,true,false,false,false,false"}},{"name":"obstacleDestroyedTotal","value":{"Number":0.0}},{"name":"seaBouncesTotal","value":{"Number":0.0}},{"name":"daysTotal","value":{"Number":4.0}},{"name":"distanceTotal","value":{"Number":110.0}},{"name":"durationTotal","value":{"Number":17.535000000000032}},{"name":"bonusPointsTotal","value":{"Number":0.0}},{"name":"reverseTotal","value":{"Number":0.0}},{"name":"diveTotal","value":{"Number":2.8}},{"name":"bestAltitude","value":{"Number":16.0}},{"name":"bestSpeed","value":{"Number":37.8}},{"name":"bestObstacleInADay","value":{"Number":0.0}},{"name":"bestStoryChallenges","value":{"Number":2.0}},{"name":"bestClassicChallenges","value":{"Number":0.0}},{"name":"bestCash","value":{"Number":121.0}},{"name":"bestPacifistDays","value":{"Number":4.0}},{"name":"bestCrash","value":{"Number":8.933139943752506}},{"name":"medalBool","value":{"String":"false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false"}},{"name":"arcadeScore1","value":{"Number":0.0}},{"name":"arcadeScore2","value":{"Number":0.0}},{"name":"arcadeScore3","value":{"Number":0.0}},{"name":"keyLeft","value":{"Number":37.0}},{"name":"keyRight","value":{"Number":39.0}},{"name":"keyBoost","value":{"Number":32.0}},{"name":"useHandCursor","value":{"Bool":false}},{"name":"tabEnabled","value":{"Bool":false}}],null]}},{"name":"saveState0","value":{"Object":[-1,[{"name":"GAME_ID","value":{"Number":81.0}},{"name":"game_mode","value":{"String":"story"}},{"name":"save_date","value":{"String":"20 July 2020 1:11"}},{"name":"day","value":{"Number":5.0}},{"name":"pacifistDays","value":{"Number":4.0}},{"name":"old_dis","value":{"Number":33.0}},{"name":"old_alt","value":{"Number":16.0}},{"name":"old_dur","value":{"Number":7.000000000000019}},{"name":"old_spe","value":{"Number":37.8}},{"name":"old_des","value":{"Number":0.0}},{"name":"player_cash","value":{"Number":121.0}},{"name":"player_length","value":{"Number":2.0}},{"name":"player_height","value":{"Number":1.0}},{"name":"player_fuel","value":{"Number":0.0}},{"name":"upg_sleigh","value":{"String":"1,2,0,0,0,0,0,0,0,0"}},{"name":"upg_glider","value":{"String":"1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0"}},{"name":"upg_boost","value":{"String":"2,0,0,0,0,0,0,0,0,0,0,0,0,0,0"}},{"name":"upg_payload","value":{"String":"2,0,0,0,0,0,0,0,0"}},{"name":"obstacle_health_left","value":{"String":"0,60,250,750,2000,7000"}},{"name":"obstacleDestroyedCount","value":{"String":"0,0,0,0,0,0"}},{"name":"classicModeGoalBool","value":{"String":"false"}},{"name":"challengeBool","value":{"String":"false,false,false,false,false,true,false,false,false,false,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false"}},{"name":"useHandCursor","value":{"Bool":false}},{"name":"tabEnabled","value":{"Bool":false}}],null]}},{"name":"saveState1","value":{"Object":[-1,[{"name":"GAME_ID","value":{"Number":81.0}},{"name":"game_mode","value":{"String":"story"}},{"name":"save_date","value":{"String":"20 July 2020 1:11"}},{"name":"day","value":{"Number":5.0}},{"name":"pacifistDays","value":{"Number":4.0}},{"name":"old_dis","value":{"Number":33.0}},{"name":"old_alt","value":{"Number":16.0}},{"name":"old_dur","value":{"Number":7.000000000000019}},{"name":"old_spe","value":{"Number":37.8}},{"name":"old_des","value":{"Number":0.0}},{"name":"player_cash","value":{"Number":71.0}},{"name":"player_length","value":{"Number":2.0}},{"name":"player_height","value":{"Number":2.0}},{"name":"player_fuel","value":{"Number":0.0}},{"name":"upg_sleigh","value":{"String":"1,2,0,0,0,0,0,0,0,0"}},{"name":"upg_glider","value":{"String":"1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0"}},{"name":"upg_boost","value":{"String":"2,0,0,0,0,0,0,0,0,0,0,0,0,0,0"}},{"name":"upg_payload","value":{"String":"2,0,0,0,0,0,0,0,0"}},{"name":"obstacle_health_left","value":{"String":"0,60,250,750,2000,7000"}},{"name":"obstacleDestroyedCount","value":{"String":"0,0,0,0,0,0"}},{"name":"classicModeGoalBool","value":{"String":"false"}},{"name":"challengeBool","value":{"String":"false,false,false,false,false,true,false,false,false,false,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false"}},{"name":"useHandCursor","value":{"Bool":false}},{"name":"tabEnabled","value":{"Bool":false}}],null]}},{"name":"saveState2","value":{"Object":[-1,[{"name":"GAME_ID","value":{"Number":-1.0}},{"name":"game_mode","value":{"String":" Empty"}},{"name":"save_date","value":{"String":"Click to save on this file"}},{"name":"day","value":{"Number":-1.0}},{"name":"pacifistDays","value":{"Number":0.0}},{"name":"old_dis","value":{"Number":0.0}},{"name":"old_alt","value":{"Number":0.0}},{"name":"old_dur","value":{"Number":0.0}},{"name":"old_spe","value":{"Number":0.0}},{"name":"old_des","value":{"Number":0.0}},{"name":"player_cash","value":{"Number":0.0}},{"name":"player_length","value":{"Number":0.0}},{"name":"player_height","value":{"Number":0.0}},{"name":"player_fuel","value":{"Number":0.0}},{"name":"upg_sleigh","value":{"String":"2,0,0,0,0,0,0,0,0,0"}},{"name":"upg_glider","value":{"String":"2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0"}},{"name":"upg_boost","value":{"String":"2,0,0,0,0,0,0,0,0,0,0,0,0,0,0"}},{"name":"upg_payload","value":{"String":"2,0,0,0,0,0,0,0,0"}},{"name":"obstacle_health_left","value":{"String":"0,0,0,0,0,0"}},{"name":"obstacleDestroyedCount","value":{"String":"0,0,0,0,0,0"}},{"name":"classicModeGoalBool","value":{"String":"false"}},{"name":"challengeBool","value":{"String":"false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false"}},{"name":"useHandCursor","value":{"Bool":false}},{"name":"tabEnabled","value":{"Bool":false}}],null]}},{"name":"saveState3","value":{"Object":[-1,[{"name":"GAME_ID","value":{"Number":-1.0}},{"name":"game_mode","value":{"String":" Empty"}},{"name":"save_date","value":{"String":"Click to save on this file"}},{"name":"day","value":{"Number":-1.0}},{"name":"pacifistDays","value":{"Number":0.0}},{"name":"old_dis","value":{"Number":0.0}},{"name":"old_alt","value":{"Number":0.0}},{"name":"old_dur","value":{"Number":0.0}},{"name":"old_spe","value":{"Number":0.0}},{"name":"old_des","value":{"Number":0.0}},{"name":"player_cash","value":{"Number":0.0}},{"name":"player_length","value":{"Number":0.0}},{"name":"player_height","value":{"Number":0.0}},{"name":"player_fuel","value":{"Number":0.0}},{"name":"upg_sleigh","value":{"String":"2,0,0,0,0,0,0,0,0,0"}},{"name":"upg_glider","value":{"String":"2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0"}},{"name":"upg_boost","value":{"String":"2,0,0,0,0,0,0,0,0,0,0,0,0,0,0"}},{"name":"upg_payload","value":{"String":"2,0,0,0,0,0,0,0,0"}},{"name":"obstacle_health_left","value":{"String":"0,0,0,0,0,0"}},{"name":"obstacleDestroyedCount","value":{"String":"0,0,0,0,0,0"}},{"name":"classicModeGoalBool","value":{"String":"false"}},{"name":"challengeBool","value":{"String":"false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false"}},{"name":"useHandCursor","value":{"Bool":false}},{"name":"tabEnabled","value":{"Bool":false}}],null]}}]} -------------------------------------------------------------------------------- /flash-lso/tests/sol/other/mainprofile.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/other/mainprofile.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/other/self-referential.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":57,"name":"asdf","format_version":"AMF0"},"body":[{"name":"asdfsadf","value":{"String":"Hello"}},{"name":"foo","value":{"Object":[-1,[{"name":"foo","value":{"Reference":1}}],null]}}]} -------------------------------------------------------------------------------- /flash-lso/tests/sol/other/self-referential.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/other/self-referential.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/previousVideo.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":2584,"name":"previousVideo","format_version":"AMF3"},"body":[{"name":"abandonedVideo","value":{"Object":[1,[{"name":"videoStillURL","value":{"String":"http://brightcove.vo.llnwd.net/d21/unsecured/media/624246174001/201406/1549/624246174001_3600111511001_5966c9cead62398e66ede926709ddc10-538b5436.jpg?pubId=624246174001"}},{"name":"FLVFullSize","value":{"Integer":23976385}},{"name":"publishedDate","value":{"Date":[1401641061469.0,null]}},{"name":"FLVFullLengthURL","value":{"String":"rtmp://brightcove.fcod.llnwd.net/a500/d15/&mp4:media/624246174001/201406/3429/624246174001_3600152980001_d6348f1b54b5be87c0f30c68711d4871-538b543b.mp4&1402088400000&59fd6bc50ef031215d8d3d7a58a27565"}},{"name":"renditions","value":{"StrictArray":[2,[{"Object":[3,[{"name":"frameHeight","value":{"Integer":224}},{"name":"encodingRate","value":{"Integer":336910}},{"name":"size","value":{"Integer":4258272}},{"name":"frameWidth","value":{"Integer":400}},{"name":"defaultURL","value":{"String":"rtmp://brightcove.fcod.llnwd.net/a500/d15/&mp4:media/624246174001/201406/3429/624246174001_3600145291001_d6348f1b54b5be87c0f30c68711d4871-538b543b.mp4&1402088400000&59fd6bc50ef031215d8d3d7a58a27565"}}],{"name":"","attributes":0,"static_properties":["frameHeight","encodingRate","size","frameWidth","defaultURL"]}]},{"Object":[4,[{"name":"frameHeight","value":{"Integer":268}},{"name":"encodingRate","value":{"Integer":532871}},{"name":"size","value":{"Integer":6673643}},{"name":"frameWidth","value":{"Integer":480}},{"name":"defaultURL","value":{"String":"rtmp://brightcove.fcod.llnwd.net/a500/d15/&mp4:media/624246174001/201406/3429/624246174001_3600145290001_d6348f1b54b5be87c0f30c68711d4871-538b543b.mp4&1402088400000&59fd6bc50ef031215d8d3d7a58a27565"}}],{"name":"","attributes":0,"static_properties":["frameHeight","encodingRate","size","frameWidth","defaultURL"]}]},{"Object":[5,[{"name":"frameHeight","value":{"Integer":404}},{"name":"encodingRate","value":{"Integer":1260700}},{"name":"size","value":{"Integer":15772274}},{"name":"frameWidth","value":{"Integer":720}},{"name":"defaultURL","value":{"String":"rtmp://brightcove.fcod.llnwd.net/a500/d15/&mp4:media/624246174001/201406/3429/624246174001_3600152992001_d6348f1b54b5be87c0f30c68711d4871-538b543b.mp4&1402088400000&59fd6bc50ef031215d8d3d7a58a27565"}}],{"name":"","attributes":0,"static_properties":["frameHeight","encodingRate","size","frameWidth","defaultURL"]}]},{"Object":[6,[{"name":"frameHeight","value":{"Integer":360}},{"name":"encodingRate","value":{"Integer":852469}},{"name":"size","value":{"Integer":10691439}},{"name":"frameWidth","value":{"Integer":640}},{"name":"defaultURL","value":{"String":"rtmp://brightcove.fcod.llnwd.net/a500/d15/&mp4:media/624246174001/201406/3429/624246174001_3600145297001_d6348f1b54b5be87c0f30c68711d4871-538b543b.mp4&1402088400000&59fd6bc50ef031215d8d3d7a58a27565"}}],{"name":"","attributes":0,"static_properties":["frameHeight","encodingRate","size","frameWidth","defaultURL"]}]},{"Object":[7,[{"name":"frameHeight","value":{"Integer":720}},{"name":"encodingRate","value":{"Integer":1920027}},{"name":"size","value":{"Integer":23976385}},{"name":"frameWidth","value":{"Integer":1280}},{"name":"defaultURL","value":{"String":"rtmp://brightcove.fcod.llnwd.net/a500/d15/&mp4:media/624246174001/201406/3429/624246174001_3600152980001_d6348f1b54b5be87c0f30c68711d4871-538b543b.mp4&1402088400000&59fd6bc50ef031215d8d3d7a58a27565"}}],{"name":"","attributes":0,"static_properties":["frameHeight","encodingRate","size","frameWidth","defaultURL"]}]},{"Object":[8,[{"name":"frameHeight","value":{"Integer":224}},{"name":"encodingRate","value":{"Integer":134612}},{"name":"size","value":{"Integer":1717898}},{"name":"frameWidth","value":{"Integer":400}},{"name":"defaultURL","value":{"String":"rtmp://brightcove.fcod.llnwd.net/a500/d15/&mp4:media/624246174001/201406/3429/624246174001_3600145289001_d6348f1b54b5be87c0f30c68711d4871-538b543b.mp4&1402088400000&59fd6bc50ef031215d8d3d7a58a27565"}}],{"name":"","attributes":0,"static_properties":["frameHeight","encodingRate","size","frameWidth","defaultURL"]}]}]]}},{"name":"FLVFullLengthStreamed","value":{"Bool":true}},{"name":"FLVFullCodec","value":{"Integer":3}},{"name":"endDate","value":{"Object":[9,[{"name":"minutes","value":{"Integer":40}},{"name":"hour","value":{"Integer":11}},{"name":"seconds","value":{"Integer":0}},{"name":"meridian","value":{"String":"AM"}},{"name":"milliseconds","value":{"Integer":0}},{"name":"month","value":{"Integer":5}},{"name":"timezone","value":{"String":"America/New_York"}},{"name":"day","value":{"Integer":1}},{"name":"year","value":{"Integer":2114}}],{"name":"","attributes":0,"static_properties":["minutes","hour","seconds","meridian","milliseconds","month","timezone","day","year"]}]}},{"name":"linkURL","value":"Null"},{"name":"economics","value":{"Integer":1}},{"name":"displayName","value":{"String":"Corruption allegations against Qatar 2022"}},{"name":"tags","value":{"StrictArray":[10,[{"String":"Rightster"},{"String":"3924"},{"String":"502"},{"String":"01z04v7o"},{"String":"sports"},{"String":"t5m networks"},{"String":"sportshub"},{"String":"sntv"}]]}},{"name":"shortDescription","value":{"String":"A former member of FIFA's executive committee was accused on Sunday (1st June) of making payments totaling $5 million (US dollars) to senior football officials, in return for support for Qatar's successful bid for the FIFA World Cup in 202"}},{"name":"publisherId","value":{"Number":624246174001.0}},{"name":"referenceId","value":{"String":"SNTV_01z04v7o_SNTV-2014-World-Cup-Service-Produced"}},{"name":"adKeys","value":{"String":"rightster=1;rstrVideoId=01z04v7o;rstrRightsOwner=SNTV;rstrProjectId=3924;rstrAccountId=502;rstrCategory=t5m networks,sports"}},{"name":"id","value":{"Number":3600092188001.0}},{"name":"allowViralSyndication","value":{"Bool":true}},{"name":"forceAds","value":{"Bool":false}},{"name":"longDescription","value":"Null"},{"name":"startDate","value":"Null"},{"name":"thumbnailURL","value":{"String":"http://brightcove.vo.llnwd.net/d21/unsecured/media/624246174001/201406/1549/624246174001_3600111511001_5966c9cead62398e66ede926709ddc10-538b5436.jpg?pubId=624246174001"}},{"name":"lineupId","value":{"Integer":0}},{"name":"length","value":{"Integer":99614}},{"name":"customFields","value":{"Object":[11,[],{"name":"","attributes":1,"static_properties":[]}]}},{"name":"linkText","value":"Null"}],{"name":"","attributes":0,"static_properties":["videoStillURL","FLVFullSize","publishedDate","FLVFullLengthURL","renditions","FLVFullLengthStreamed","FLVFullCodec","endDate","linkURL","economics","displayName","tags","shortDescription","publisherId","referenceId","adKeys","id","allowViralSyndication","forceAds","longDescription","startDate","thumbnailURL","lineupId","length","customFields","linkText"]}]}}]} -------------------------------------------------------------------------------- /flash-lso/tests/sol/previousVideo.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/previousVideo.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/robokill.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/robokill.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/settings.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/settings.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/slot1.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/slot1.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/slot1_party.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":371,"name":"slot1_party","format_version":"AMF3"},"body":[{"name":"battle","value":{"Bool":false}},{"name":"pc_party","value":{"Object":[1,[{"name":"version","value":{"String":"1.86"}},{"name":"campaign","value":{"Integer":1}},{"name":"difficulty","value":{"Integer":2}},{"name":"difficultyMods","value":{"Integer":0}},{"name":"sneaking","value":{"Integer":0}},{"name":"gold","value":{"Integer":0}},{"name":"stat_member_deaths","value":{"Integer":0}},{"name":"stat_shrines_used","value":{"Integer":2}},{"name":"stat_party_defeats","value":{"Integer":0}},{"name":"stat_hordes_defeated","value":{"Integer":14}},{"name":"stat_leaders_defeated","value":{"Integer":2}},{"name":"stat_rooms_total","value":{"Integer":88}},{"name":"stat_rooms_explored","value":{"Integer":71}},{"name":"invFilter","value":{"Integer":1}},{"name":"invSort","value":{"Integer":1}},{"name":"lootSettings","value":{"Integer":1023}},{"name":"sortAscending","value":{"Bool":false}},{"name":"level","value":{"Integer":2}},{"name":"usedTeleportItemThisLevel","value":{"Bool":false}}],{"name":"PartyAlias","attributes":0,"static_properties":["version","campaign","difficulty","difficultyMods","sneaking","gold","stat_member_deaths","stat_shrines_used","stat_party_defeats","stat_hordes_defeated","stat_leaders_defeated","stat_rooms_total","stat_rooms_explored","invFilter","invSort","lootSettings","sortAscending","level","usedTeleportItemThisLevel"]}]}}]} 2 | -------------------------------------------------------------------------------- /flash-lso/tests/sol/slot1_party.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/slot1_party.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/soundData.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":43,"name":"soundData","format_version":"AMF0"},"body":[{"name":"volume","value":{"Number":31.360000000000003}}]} 2 | -------------------------------------------------------------------------------- /flash-lso/tests/sol/soundData.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/soundData.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/soundData_level0.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":59,"name":"soundData_level0","format_version":"AMF0"},"body":[{"name":"volume","value":{"Number":100.0}},{"name":"mute","value":{"Bool":false}}]} 2 | -------------------------------------------------------------------------------- /flash-lso/tests/sol/soundData_level0.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/soundData_level0.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/timeDisplayConfig.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":75,"name":"timeDisplayConfig","format_version":"AMF0"},"body":[{"name":"modeDefaultSet","value":{"Bool":true}},{"name":"displayMode","value":{"String":"played"}}]} 2 | -------------------------------------------------------------------------------- /flash-lso/tests/sol/timeDisplayConfig.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/timeDisplayConfig.sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/user(1).json: -------------------------------------------------------------------------------- 1 | {"header":{"length":840,"name":"p2p/user","format_version":"AMF3"},"body":[{"name":"user","value":{"Object":[1,[{"name":"filt","value":{"Integer":1}},{"name":"gender","value":{"Integer":1}},{"name":"blockdate","value":{"Number":null}},{"name":"freeisover","value":{"Bool":true}},{"name":"notify_messages","value":{"Integer":1}},{"name":"volume","value":{"Number":0.5}},{"name":"firstgift","value":{"Bool":true}},{"name":"adult","value":{"Integer":0}},{"name":"isuser","value":{"Bool":true}},{"name":"guest_key","value":{"Integer":0}},{"name":"email","value":{"String":"mssail@cv.ru"}},{"name":"sf","value":{"Integer":0}},{"name":"pass","value":{"String":"9ff8176c4b5613971a628ededcfccf2f"}},{"name":"sv","value":{"Integer":0}},{"name":"getuser","value":{"Integer":0}},{"name":"st","value":{"Integer":0}},{"name":"age","value":{"Integer":21}},{"name":"sl","value":{"Integer":0}},{"name":"bdate","value":{"String":"02.02.1991"}},{"name":"active_video","value":{"Integer":0}},{"name":"video","value":{"StrictArray":[2,[]]}},{"name":"area","value":{"Integer":2949}},{"name":"id","value":{"Integer":1463339}},{"name":"areaname","value":{"String":"Краснодарский край"}},{"name":"city","value":{"Integer":1164003}},{"name":"view_video","value":{"Integer":0}},{"name":"lookfor","value":{"Integer":2}},{"name":"nofreechat","value":{"Bool":false}},{"name":"lookagemin","value":{"Integer":19}},{"name":"ban","value":{"Bool":false}},{"name":"auto","value":{"Bool":true}},{"name":"lookagemax","value":{"Integer":99}},{"name":"banned_till","value":{"Integer":-8145}},{"name":"money","value":{"Integer":0}},{"name":"check","value":{"Integer":0}},{"name":"gifts","value":{"Integer":0}},{"name":"vids","value":{"Integer":0}},{"name":"ID","value":{"Integer":0}},{"name":"nextview","value":{"Date":[1329777054281.0,null]}},{"name":"username","value":{"String":"ssMailss"}},{"name":"abuse","value":{"Integer":0}},{"name":"total_video","value":{"Integer":0}},{"name":"dating_purpose","value":{"Integer":3}},{"name":"invite","value":{"StrictArray":[3,[]]}},{"name":"freeday","value":{"Bool":false}},{"name":"real","value":{"StrictArray":[4,[]]}},{"name":"cityname","value":{"String":"Краснодар"}},{"name":"spam","value":{"String":""}},{"name":"anket","value":{"Object":[5,[{"name":"dontlike","value":{"Integer":0}},{"name":"country","value":{"Integer":0}},{"name":"area","value":{"Integer":0}},{"name":"love","value":{"Integer":0}},{"name":"city","value":{"Integer":0}},{"name":"melike","value":{"Integer":0}},{"name":"ilike","value":{"Integer":0}}],{"name":"","attributes":1,"static_properties":[]}]}},{"name":"paygirl","value":{"Bool":true}},{"name":"hasphoto","value":{"Bool":false}},{"name":"lang","value":{"Integer":0}},{"name":"country","value":{"String":"230"}},{"name":"viewhint","value":{"Bool":true}},{"name":"noise","value":{"Integer":1}},{"name":"blocknum","value":{"Integer":1}},{"name":"friend","value":{"Integer":0}},{"name":"mute","value":{"Bool":false}},{"name":"hash","value":{"String":"ck77pnhc07uhrjrqaea1momrv1"}},{"name":"video_volume","value":{"Number":0.5}},{"name":"time","value":{"Number":null}}],{"name":"userData","attributes":0,"static_properties":["filt","gender","blockdate","freeisover","notify_messages","volume","firstgift","adult","isuser","guest_key","email","sf","pass","sv","getuser","st","age","sl","bdate","active_video","video","area","id","areaname","city","view_video","lookfor","nofreechat","lookagemin","ban","auto","lookagemax","banned_till","money","check","gifts","vids","ID","nextview","username","abuse","total_video","dating_purpose","invite","freeday","real","cityname","spam","anket","paygirl","hasphoto","lang","country","viewhint","noise","blocknum","friend","mute","hash","video_volume","time"]}]}}]} -------------------------------------------------------------------------------- /flash-lso/tests/sol/user(1).sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/user(1).sol -------------------------------------------------------------------------------- /flash-lso/tests/sol/user.json: -------------------------------------------------------------------------------- 1 | {"header":{"length":840,"name":"p2p/user","format_version":"AMF3"},"body":[{"name":"user","value":{"Object":[1,[{"name":"filt","value":{"Integer":1}},{"name":"gender","value":{"Integer":1}},{"name":"blockdate","value":{"Number":null}},{"name":"freeisover","value":{"Bool":true}},{"name":"notify_messages","value":{"Integer":1}},{"name":"volume","value":{"Number":0.5}},{"name":"firstgift","value":{"Bool":true}},{"name":"adult","value":{"Integer":0}},{"name":"isuser","value":{"Bool":true}},{"name":"guest_key","value":{"Integer":0}},{"name":"email","value":{"String":"mssail@cv.ru"}},{"name":"sf","value":{"Integer":0}},{"name":"pass","value":{"String":"9ff8176c4b5613971a628ededcfccf2f"}},{"name":"sv","value":{"Integer":0}},{"name":"getuser","value":{"Integer":0}},{"name":"st","value":{"Integer":0}},{"name":"age","value":{"Integer":21}},{"name":"sl","value":{"Integer":0}},{"name":"bdate","value":{"String":"02.02.1991"}},{"name":"active_video","value":{"Integer":0}},{"name":"video","value":{"StrictArray":[2,[]]}},{"name":"area","value":{"Integer":2949}},{"name":"id","value":{"Integer":1463339}},{"name":"areaname","value":{"String":"Краснодарский край"}},{"name":"city","value":{"Integer":1164003}},{"name":"view_video","value":{"Integer":0}},{"name":"lookfor","value":{"Integer":2}},{"name":"nofreechat","value":{"Bool":false}},{"name":"lookagemin","value":{"Integer":19}},{"name":"ban","value":{"Bool":false}},{"name":"auto","value":{"Bool":true}},{"name":"lookagemax","value":{"Integer":99}},{"name":"banned_till","value":{"Integer":-8145}},{"name":"money","value":{"Integer":0}},{"name":"check","value":{"Integer":0}},{"name":"gifts","value":{"Integer":0}},{"name":"vids","value":{"Integer":0}},{"name":"ID","value":{"Integer":0}},{"name":"nextview","value":{"Date":[1329777054281.0,null]}},{"name":"username","value":{"String":"ssMailss"}},{"name":"abuse","value":{"Integer":0}},{"name":"total_video","value":{"Integer":0}},{"name":"dating_purpose","value":{"Integer":3}},{"name":"invite","value":{"StrictArray":[3,[]]}},{"name":"freeday","value":{"Bool":false}},{"name":"real","value":{"StrictArray":[4,[]]}},{"name":"cityname","value":{"String":"Краснодар"}},{"name":"spam","value":{"String":""}},{"name":"anket","value":{"Object":[5,[{"name":"dontlike","value":{"Integer":0}},{"name":"country","value":{"Integer":0}},{"name":"area","value":{"Integer":0}},{"name":"love","value":{"Integer":0}},{"name":"city","value":{"Integer":0}},{"name":"melike","value":{"Integer":0}},{"name":"ilike","value":{"Integer":0}}],{"name":"","attributes":1,"static_properties":[]}]}},{"name":"paygirl","value":{"Bool":true}},{"name":"hasphoto","value":{"Bool":false}},{"name":"lang","value":{"Integer":0}},{"name":"country","value":{"String":"230"}},{"name":"viewhint","value":{"Bool":true}},{"name":"noise","value":{"Integer":1}},{"name":"blocknum","value":{"Integer":1}},{"name":"friend","value":{"Integer":0}},{"name":"mute","value":{"Bool":false}},{"name":"hash","value":{"String":"ck77pnhc07uhrjrqaea1momrv1"}},{"name":"video_volume","value":{"Number":0.5}},{"name":"time","value":{"Number":null}}],{"name":"userData","attributes":0,"static_properties":["filt","gender","blockdate","freeisover","notify_messages","volume","firstgift","adult","isuser","guest_key","email","sf","pass","sv","getuser","st","age","sl","bdate","active_video","video","area","id","areaname","city","view_video","lookfor","nofreechat","lookagemin","ban","auto","lookagemax","banned_till","money","check","gifts","vids","ID","nextview","username","abuse","total_video","dating_purpose","invite","freeday","real","cityname","spam","anket","paygirl","hasphoto","lang","country","viewhint","noise","blocknum","friend","mute","hash","video_volume","time"]}]}}]} -------------------------------------------------------------------------------- /flash-lso/tests/sol/user.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffle-rs/rust-flash-lso/998f47c926b9986aabd518fbb7394ff56936d0b0/flash-lso/tests/sol/user.sol -------------------------------------------------------------------------------- /fuzz/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | target 3 | corpus 4 | artifacts 5 | -------------------------------------------------------------------------------- /fuzz/Cargo.toml: -------------------------------------------------------------------------------- 1 | 2 | [package] 3 | name = "flash-lso-fuzz" 4 | version = "0.0.0" 5 | authors = ["Automatically generated"] 6 | publish = false 7 | edition = "2021" 8 | 9 | [package.metadata] 10 | cargo-fuzz = true 11 | 12 | [dependencies] 13 | libfuzzer-sys = "0.4.7" 14 | flash-lso = { path = "../flash-lso", default-features = false, features = ["amf3"]} 15 | 16 | # Prevent this from interfering with workspaces 17 | [workspace] 18 | members = ["."] 19 | 20 | 21 | [[bin]] 22 | name = "fuzz_amf0_body" 23 | path = "fuzz_targets/fuzz_amf0_body.rs" 24 | 25 | [[bin]] 26 | name = "fuzz_amf0_element_array" 27 | path = "fuzz_targets/fuzz_amf0_element_array.rs" 28 | 29 | [[bin]] 30 | name = "fuzz_amf0_header" 31 | path = "fuzz_targets/fuzz_amf0_header.rs" 32 | 33 | [[bin]] 34 | name = "fuzz_amf3_int_signed" 35 | path = "fuzz_targets/fuzz_amf3_int_signed.rs" 36 | 37 | [[bin]] 38 | name = "fuzz_amf3_int_unsigned" 39 | path = "fuzz_targets/fuzz_amf3_int_unsigned.rs" 40 | 41 | [[bin]] 42 | name = "fuzz_amf3_string" 43 | path = "fuzz_targets/fuzz_amf3_string.rs" 44 | 45 | [[bin]] 46 | name = "fuzz_amf3_body" 47 | path = "fuzz_targets/fuzz_amf3_body.rs" 48 | 49 | [[bin]] 50 | name = "fuzz_amf3_single_element" 51 | path = "fuzz_targets/fuzz_amf3_single_element.rs" 52 | -------------------------------------------------------------------------------- /fuzz/fuzz_targets/fuzz_amf0_body.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | use libfuzzer_sys::fuzz_target; 3 | 4 | use flash_lso::amf0::read::AMF0Decoder; 5 | 6 | fuzz_target!(|data: &[u8]| { 7 | let _ = AMF0Decoder::default().parse_body(data); 8 | }); 9 | -------------------------------------------------------------------------------- /fuzz/fuzz_targets/fuzz_amf0_element_array.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | use libfuzzer_sys::fuzz_target; 3 | 4 | use flash_lso::amf0::read::AMF0Decoder; 5 | 6 | fuzz_target!(|data: &[u8]| { 7 | let _ = AMF0Decoder::default().fuzz_parse_element_array(data); 8 | }); 9 | -------------------------------------------------------------------------------- /fuzz/fuzz_targets/fuzz_amf0_header.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | use libfuzzer_sys::fuzz_target; 3 | 4 | use flash_lso::read::Reader; 5 | 6 | fuzz_target!(|data: &[u8]| { 7 | let _ = Reader::default().parse_header(data); 8 | }); 9 | -------------------------------------------------------------------------------- /fuzz/fuzz_targets/fuzz_amf3_body.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | use libfuzzer_sys::fuzz_target; 3 | 4 | use flash_lso::amf3; 5 | 6 | fuzz_target!(|data: &[u8]| { 7 | let _ = amf3::read::AMF3Decoder::default().parse_body(data); 8 | }); 9 | -------------------------------------------------------------------------------- /fuzz/fuzz_targets/fuzz_amf3_int_signed.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | use libfuzzer_sys::fuzz_target; 3 | 4 | use flash_lso::amf3::read::fuzz_read_int_signed; 5 | 6 | fuzz_target!(|data: &[u8]| { 7 | let _ = fuzz_read_int_signed(data); 8 | }); 9 | -------------------------------------------------------------------------------- /fuzz/fuzz_targets/fuzz_amf3_int_unsigned.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | use libfuzzer_sys::fuzz_target; 3 | 4 | use flash_lso::amf3::read::fuzz_read_int; 5 | 6 | fuzz_target!(|data: &[u8]| { 7 | let _ = fuzz_read_int(data); 8 | }); 9 | -------------------------------------------------------------------------------- /fuzz/fuzz_targets/fuzz_amf3_single_element.rs: -------------------------------------------------------------------------------- 1 | //! This specifically tests the `parse_single_element` function used for 2 | //! `ByteArray.readObject` in Ruffle among other places 3 | #![no_main] 4 | use libfuzzer_sys::fuzz_target; 5 | 6 | use flash_lso::amf3; 7 | 8 | fuzz_target!(|data: &[u8]| { 9 | let _ = amf3::read::AMF3Decoder::default().parse_single_element(data); 10 | }); 11 | -------------------------------------------------------------------------------- /fuzz/fuzz_targets/fuzz_amf3_string.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | use libfuzzer_sys::fuzz_target; 3 | 4 | use flash_lso::amf3; 5 | 6 | fuzz_target!(|data: &[u8]| { 7 | let _ = amf3::read::AMF3Decoder::default().fuzz_parse_string(data); 8 | }); 9 | -------------------------------------------------------------------------------- /lso-to-json/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /lso-to-json/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lso-to-json" 3 | version = "0.1.0" 4 | authors = ["CUB3D "] 5 | edition = "2021" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | flash-lso = { path = "../flash-lso", features = ["serde", "flex"] } 11 | env_logger = "0.11.3" 12 | clap = "4.5.8" 13 | serde_json = "1.0.120" 14 | -------------------------------------------------------------------------------- /lso-to-json/src/main.rs: -------------------------------------------------------------------------------- 1 | //! This tool allows converting a given Flash Local Shared Object file (Lso) to a JSON document for 2 | //! easy previewing, as well as the creation of test cases for the flash-lso library 3 | 4 | #![deny(missing_docs, clippy::missing_docs_in_private_items)] 5 | 6 | use clap::{Arg, Command}; 7 | use flash_lso::amf3::read::AMF3Decoder; 8 | use flash_lso::extra::*; 9 | use flash_lso::read::Reader; 10 | use flash_lso::types::Lso; 11 | use std::path::PathBuf; 12 | 13 | fn main() -> Result<(), Box> { 14 | env_logger::init(); 15 | 16 | let matched = Command::new("Lso -> json converter") 17 | .version("1.0") 18 | .author("CUB3D ") 19 | .subcommand(Command::new("file").arg(Arg::new("INPUT").help("").required(true))) 20 | .subcommand(Command::new("object-amf3").arg(Arg::new("INPUT").help("").required(true))) 21 | .subcommand(Command::new("regen").arg(Arg::new("INPUT").help("").required(true))) 22 | .subcommand_required(true) 23 | .get_matches(); 24 | 25 | let (cmd, args) = matched.subcommand().unwrap(); 26 | 27 | let file_name: &String = args.get_one("INPUT").unwrap(); 28 | 29 | match cmd { 30 | "file" => { 31 | let data = std::fs::read(PathBuf::from(file_name))?; 32 | match parse_file(&data) { 33 | Ok(lso) => { 34 | let json = serde_json::to_string(&lso).expect("Unable to encode lso as json"); 35 | println!("{}", json); 36 | } 37 | Err(e) => { 38 | eprintln!("Couldn't read lso file, maybe open a issue on github at https://github.com/CUB3D/rust-flash-lso"); 39 | eprintln!("Error = {:?}", e); 40 | } 41 | }; 42 | } 43 | "regen" => { 44 | for f in std::fs::read_dir(file_name)? { 45 | let f = f?; 46 | 47 | if !f.file_type()?.is_file() { 48 | continue; 49 | } 50 | let name = f.file_name().to_string_lossy().to_string(); 51 | 52 | if name.ends_with(".sol") { 53 | let data = std::fs::read(f.path())?; 54 | 55 | let out = f 56 | .path() 57 | .parent() 58 | .unwrap() 59 | .join(f.file_name().to_string_lossy().replace(".sol", ".json")); 60 | 61 | match parse_file(&data) { 62 | Ok(lso) => { 63 | let json = 64 | serde_json::to_string(&lso).expect("Unable to encode lso as json"); 65 | std::fs::write(out, format!("{}\n", json)) 66 | .expect("Unable to write file"); 67 | } 68 | Err(e) => { 69 | eprintln!("Couldn't read lso file, maybe open a issue on github at https://github.com/CUB3D/rust-flash-lso"); 70 | eprintln!("Error = {:?}", e); 71 | } 72 | }; 73 | } else if name.ends_with(".amf") { 74 | let data = std::fs::read(f.path())?; 75 | 76 | let out = f 77 | .path() 78 | .parent() 79 | .unwrap() 80 | .join(f.file_name().to_string_lossy().replace(".amf", ".json")); 81 | 82 | match AMF3Decoder::default().parse_single_element(&data) { 83 | Ok((_, amf)) => { 84 | let json = 85 | serde_json::to_string(&amf).expect("Unable to encode amf as json"); 86 | std::fs::write(out, json).expect("Unable to write file"); 87 | } 88 | Err(e) => { 89 | eprintln!("Couldn't read amf file, maybe open a issue on github at https://github.com/CUB3D/rust-flash-lso"); 90 | eprintln!("Error = {:?}", e); 91 | } 92 | }; 93 | } 94 | } 95 | } 96 | "object-amf3" => { 97 | let data = std::fs::read(PathBuf::from(file_name))?; 98 | let (_, obj) = AMF3Decoder::default() 99 | .parse_single_element(&data) 100 | .expect("Failed to parse object"); 101 | let json = serde_json::to_string(&obj).expect("Unable to encode lso as json"); 102 | println!("{}", json); 103 | } 104 | _ => { 105 | println!("Unknown command"); 106 | } 107 | } 108 | 109 | Ok(()) 110 | } 111 | 112 | /// Parse a given slice into an Lso 113 | fn parse_file(data: &[u8]) -> Result> { 114 | let mut d = Reader::default(); 115 | flex::read::register_decoders(&mut d.amf3_decoder); 116 | let lso = d.parse(data)?; 117 | Ok(lso) 118 | } 119 | -------------------------------------------------------------------------------- /web/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "web" 3 | version = "0.1.0" 4 | authors = ["CUB3D "] 5 | edition = "2021" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [lib] 10 | crate-type = ["cdylib", "rlib"] 11 | 12 | [dependencies] 13 | yew = { version = "0.20.0", features = ["csr"] } 14 | yewtil = "0.4.0" 15 | web-sys = "0.3.59" 16 | wasm-bindgen = "0.2.81" 17 | js-sys = "0.3.58" 18 | log = "0.4.17" 19 | wasm-logger = "0.2.0" 20 | flash-lso = { path = "../flash-lso", features = ["serde", "flex"] } 21 | gloo-file = "0.3.0" 22 | -------------------------------------------------------------------------------- /web/src/blob_bindgen.rs: -------------------------------------------------------------------------------- 1 | use js_sys::Array; 2 | use wasm_bindgen::prelude::*; 3 | 4 | #[wasm_bindgen] 5 | extern "C" { 6 | pub type Blob; 7 | 8 | #[wasm_bindgen(constructor)] 9 | pub fn new(text: Array, options: JsValue) -> Blob; 10 | } 11 | -------------------------------------------------------------------------------- /web/src/component_hexview.rs: -------------------------------------------------------------------------------- 1 | use crate::component_number_input::NumberInput; 2 | use crate::web_expect::WebSafeExpect; 3 | use yew::prelude::*; 4 | use yew::{Component, Html, Properties}; 5 | 6 | pub struct HexView { 7 | selected: Option, 8 | } 9 | 10 | #[derive(PartialEq, Properties, Clone)] 11 | pub struct Props { 12 | pub bytes: Vec, 13 | pub onchange: Callback>, 14 | 15 | pub onadd: Callback<()>, 16 | pub onremove: Callback, 17 | } 18 | 19 | pub enum Msg { 20 | Edit(u8, usize), 21 | Focus(usize), 22 | Blur, 23 | Remove, 24 | Add, 25 | } 26 | 27 | impl Component for HexView { 28 | type Message = Msg; 29 | type Properties = Props; 30 | 31 | fn create(_ctx: &Context) -> Self { 32 | Self { selected: None } 33 | } 34 | 35 | fn update(&mut self, ctx: &Context, msg: Self::Message) -> bool { 36 | match msg { 37 | Msg::Edit(data, index) => { 38 | let mut new_data = ctx.props().bytes.clone(); 39 | new_data[index] = data; 40 | ctx.props().onchange.emit(new_data); 41 | true 42 | } 43 | Msg::Focus(index) => { 44 | self.selected = Some(index); 45 | true 46 | } 47 | Msg::Blur => { 48 | // self.selected = None; 49 | true 50 | } 51 | Msg::Remove => { 52 | ctx.props() 53 | .onremove 54 | .emit(self.selected.web_expect("Nothing selected")); 55 | true 56 | } 57 | Msg::Add => { 58 | ctx.props().onadd.emit(()); 59 | true 60 | } 61 | } 62 | } 63 | 64 | fn view(&self, ctx: &Context) -> Html { 65 | html! { 66 | <> 67 | 68 | 69 | { self.table_body(ctx) } 70 | 71 |
72 | {"Add"} 73 | {self.remove_button(ctx)} 74 | 75 | } 76 | } 77 | } 78 | 79 | const CHUNK_SIZE: usize = 8; 80 | 81 | impl HexView { 82 | fn remove_button(&self, ctx: &Context) -> Html { 83 | if self.selected.is_some() { 84 | html! { 85 | {"Remove"} 86 | } 87 | } else { 88 | html! {} 89 | } 90 | } 91 | 92 | fn table_body(&self, ctx: &Context) -> Html { 93 | let chunks: Vec<&[u8]> = ctx.props().bytes.chunks(CHUNK_SIZE).collect(); 94 | 95 | html! { 96 | <> 97 | {for chunks.iter().enumerate().map(|(chunk_index, chunk)| html! { 98 | 99 | { for chunk.iter().enumerate().map(move |(subchunk_index, v)| html! { 100 | 101 | 102 | value={*v} 103 | onchange={ctx.link().callback(move |data| Msg::Edit(data, chunk_index*CHUNK_SIZE + subchunk_index))} 104 | onfocus={ctx.link().callback(move |_| Msg::Focus(chunk_index*CHUNK_SIZE + subchunk_index))} 105 | onblur={ctx.link().callback(move |_| Msg::Blur)}/> 106 | 107 | })} 108 | 109 | })} 110 | 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /web/src/component_modal.rs: -------------------------------------------------------------------------------- 1 | use crate::jquery_bindgen::jquery; 2 | use wasm_bindgen::JsValue; 3 | use yew::prelude::*; 4 | 5 | pub struct ModalContainer {} 6 | 7 | #[derive(PartialEq, Properties, Clone)] 8 | pub struct Props { 9 | pub children: ChildrenWithProps, 10 | pub onclose: Callback, 11 | } 12 | 13 | pub enum Msg { 14 | Close(usize), 15 | } 16 | 17 | impl Component for ModalContainer { 18 | type Message = Msg; 19 | type Properties = Props; 20 | 21 | fn create(_ctx: &Context) -> Self { 22 | Self {} 23 | } 24 | 25 | fn update(&mut self, ctx: &Context, msg: Self::Message) -> bool { 26 | match msg { 27 | //TODO: should this be passed to host as well, to be able to remove dismissed messages 28 | Msg::Close(index) => { 29 | let id = format!("#modal-{}", index); 30 | jquery(&id).modal(&JsValue::from("hide")); 31 | ctx.props().onclose.emit(index); 32 | } 33 | } 34 | false 35 | } 36 | 37 | fn view(&self, ctx: &Context) -> Html { 38 | html! { 39 | <> 40 | { for ctx.props().children.iter().enumerate().map(|(i, modal)| { 41 | *modal.props.id.borrow_mut() = format!("modal-{}", i); 42 | *modal.props.onclosed.borrow_mut() = Some(ctx.link().callback(move |_| { 43 | Msg::Close(i) 44 | })); 45 | modal 46 | })} 47 | 48 | } 49 | } 50 | 51 | /// When a is rendered it displays all of its child modals 52 | fn rendered(&mut self, ctx: &Context, _first_render: bool) { 53 | let ids = ctx 54 | .props() 55 | .children 56 | .iter() 57 | .enumerate() 58 | .map(|(i, _)| format!("#modal-{}", i)); 59 | 60 | for id in ids { 61 | let o: js_sys::Object = js_sys::Object::new(); 62 | jquery(&id).modal(&o); 63 | } 64 | } 65 | } 66 | 67 | pub mod modal { 68 | use std::cell::RefCell; 69 | use std::ops::Deref; 70 | use yew::prelude::*; 71 | 72 | pub enum Msg { 73 | Closed, 74 | } 75 | 76 | #[derive(Default)] 77 | pub struct Modal; 78 | 79 | #[derive(Properties, Clone, PartialEq)] 80 | pub struct Props { 81 | pub content: String, 82 | pub title: String, 83 | 84 | // Props filled by container 85 | #[prop_or(RefCell::>>::new(None))] 86 | pub onclosed: RefCell>>, 87 | #[prop_or(RefCell::::new("".to_string()))] 88 | pub id: RefCell, 89 | } 90 | 91 | impl Component for Modal { 92 | type Message = Msg; 93 | type Properties = Props; 94 | 95 | fn create(_ctx: &Context) -> Self { 96 | Self 97 | } 98 | 99 | fn update(&mut self, ctx: &Context, msg: Self::Message) -> bool { 100 | match msg { 101 | Msg::Closed => { 102 | if let Some(callback) = ctx.props().onclosed.borrow().deref() { 103 | callback.emit(()) 104 | } 105 | } 106 | } 107 | false 108 | } 109 | 110 | //TODO: currently dismissing using anything other than the close button will cause the modal to re-appear when a new one is created 111 | //TODO: only fix seems to be to not use a js modal but rather a custom one 112 | fn view(&self, ctx: &Context) -> Html { 113 | html! { 114 | 132 | } 133 | } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /web/src/component_number_input.rs: -------------------------------------------------------------------------------- 1 | use crate::component_string_input::StringInput; 2 | use std::fmt::Display; 3 | use std::marker::PhantomData; 4 | use std::str::FromStr; 5 | use yew::prelude::*; 6 | use yew::{Component, Html, Properties}; 7 | 8 | pub struct NumberInput { 9 | pd: PhantomData, 10 | } 11 | 12 | #[derive(PartialEq, Clone, Properties)] 13 | pub struct Props { 14 | pub onchange: Callback, 15 | pub value: T, 16 | 17 | #[prop_or(None)] 18 | pub onfocus: Option>, 19 | #[prop_or(None)] 20 | pub onblur: Option>, 21 | } 22 | 23 | pub enum Msg { 24 | Value(String), 25 | Focus, 26 | UnFocus, 27 | } 28 | 29 | impl Component for NumberInput { 30 | type Message = Msg; 31 | type Properties = Props; 32 | 33 | fn create(_ctx: &Context) -> Self { 34 | Self { 35 | pd: Default::default(), 36 | } 37 | } 38 | 39 | fn update(&mut self, ctx: &Context, msg: Self::Message) -> bool { 40 | match msg { 41 | Msg::Value(s) => { 42 | if let Ok(f) = s.parse::() { 43 | ctx.props().onchange.emit(f); 44 | } 45 | true 46 | } 47 | Msg::Focus => { 48 | if let Some(onfocus) = &ctx.props().onfocus { 49 | onfocus.emit(()); 50 | } 51 | true 52 | } 53 | Msg::UnFocus => { 54 | if let Some(onblur) = &ctx.props().onblur { 55 | onblur.emit(()); 56 | } 57 | true 58 | } 59 | } 60 | } 61 | 62 | fn view(&self, ctx: &Context) -> Html { 63 | html! { 64 | 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /web/src/component_string_input.rs: -------------------------------------------------------------------------------- 1 | use wasm_bindgen::JsCast; 2 | use web_sys::{EventTarget, HtmlInputElement}; 3 | use yew::{events::Event, html, Callback, Component, Context, Html, Properties}; 4 | 5 | pub struct StringInput {} 6 | 7 | #[derive(PartialEq, Properties)] 8 | pub struct Props { 9 | pub onchange: Callback, 10 | pub value: String, 11 | 12 | #[prop_or("".to_string())] 13 | pub placeholder: String, 14 | 15 | #[prop_or("".to_string())] 16 | pub class: String, 17 | 18 | #[prop_or(None)] 19 | pub onfocus: Option>, 20 | #[prop_or(None)] 21 | pub onblur: Option>, 22 | } 23 | 24 | pub enum Msg { 25 | Value(String), 26 | Focus, 27 | UnFocus, 28 | } 29 | 30 | impl Component for StringInput { 31 | type Message = Msg; 32 | type Properties = Props; 33 | 34 | fn create(_ctx: &Context) -> Self { 35 | StringInput {} 36 | } 37 | 38 | fn update(&mut self, ctx: &Context, msg: Self::Message) -> bool { 39 | match msg { 40 | Msg::Value(s) => { 41 | ctx.props().onchange.emit(s); 42 | true 43 | } 44 | Msg::Focus => { 45 | if let Some(onfocus) = &ctx.props().onfocus { 46 | onfocus.emit(()); 47 | } 48 | true 49 | } 50 | Msg::UnFocus => { 51 | if let Some(onblur) = &ctx.props().onblur { 52 | onblur.emit(()); 53 | } 54 | true 55 | } 56 | } 57 | } 58 | 59 | fn view(&self, ctx: &Context) -> Html { 60 | html! { 61 | = e.target(); 64 | let input = target.and_then(|t| t.dyn_into::().ok()); 65 | 66 | input.map(|input| Msg::Value(input.value())) 67 | })} 68 | placeholder={ctx.props().placeholder.clone()} 69 | onblur={ctx.link().callback(move |_fe| Msg::UnFocus)} 70 | onfocus={ctx.link().callback(move |_fe| Msg::Focus)} 71 | value={ctx.props().value.clone()} 72 | class={format!("form-control {}", ctx.props().class)}/> 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /web/src/component_tab.rs: -------------------------------------------------------------------------------- 1 | use yew::prelude::*; 2 | use yew::{Children, Component, Html, Properties}; 3 | 4 | pub struct Tab {} 5 | 6 | #[derive(Properties, Clone, PartialEq)] 7 | pub struct Props { 8 | pub label: String, 9 | pub loading: bool, 10 | pub children: Children, 11 | } 12 | 13 | impl Component for Tab { 14 | type Message = (); 15 | type Properties = Props; 16 | 17 | fn create(_ctx: &Context) -> Self { 18 | Self {} 19 | } 20 | 21 | fn update(&mut self, _ctx: &Context, _msg: Self::Message) -> bool { 22 | false 23 | } 24 | 25 | fn view(&self, ctx: &Context) -> Html { 26 | html! { 27 | <> 28 | { for ctx.props().children.iter()} 29 | 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /web/src/component_tabs.rs: -------------------------------------------------------------------------------- 1 | use crate::component_tab::Tab; 2 | use yew::prelude::*; 3 | use yew::virtual_dom::VChild; 4 | use yew::{ChildrenWithProps, Component, Html, Properties}; 5 | 6 | pub struct Tabs {} 7 | 8 | #[derive(Properties, Clone, PartialEq)] 9 | pub struct Props { 10 | pub ontabselect: Callback, 11 | pub ontabremove: Callback, 12 | pub children: ChildrenWithProps, 13 | pub selected: Option, 14 | } 15 | 16 | #[derive(Debug)] 17 | pub enum Msg { 18 | Selected(usize), 19 | Removed(usize), 20 | } 21 | 22 | impl Component for Tabs { 23 | type Message = Msg; 24 | type Properties = Props; 25 | 26 | fn create(_ctx: &Context) -> Self { 27 | Self {} 28 | } 29 | 30 | fn update(&mut self, ctx: &Context, msg: Self::Message) -> bool { 31 | log::info!("TAB msg={:?}", msg); 32 | match msg { 33 | Msg::Selected(pos) => { 34 | ctx.props().ontabselect.emit(pos); 35 | true 36 | } 37 | Msg::Removed(pos) => { 38 | ctx.props().ontabremove.emit(pos); 39 | true 40 | } 41 | } 42 | } 43 | 44 | fn view(&self, ctx: &Context) -> Html { 45 | html! { 46 | <> 47 | 56 | 57 |
58 | { for ctx.props().children.iter().enumerate().map(|(i, e)| html! { 59 |
60 | {e} 61 |
62 | })} 63 |
64 | 65 | } 66 | } 67 | } 68 | 69 | impl Tabs { 70 | fn tab_details(&self, ctx: &Context, tab: VChild, index: usize) -> Html { 71 | if tab.props.loading { 72 | self.loading_spinner() 73 | } else { 74 | self.remove_button(ctx, index) 75 | } 76 | } 77 | 78 | fn remove_button(&self, ctx: &Context, index: usize) -> Html { 79 | html! { 80 | {"Close"} 81 | } 82 | } 83 | 84 | fn loading_spinner(&self) -> Html { 85 | html! { 86 | {"Loading"} 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /web/src/jquery_bindgen.rs: -------------------------------------------------------------------------------- 1 | use wasm_bindgen::prelude::*; 2 | 3 | #[wasm_bindgen] 4 | extern "C" { 5 | pub type JQueryValue; 6 | 7 | #[wasm_bindgen(js_name = "$")] 8 | pub fn jquery(name: &str) -> JQueryValue; 9 | 10 | #[wasm_bindgen(method)] 11 | pub fn modal(this: &JQueryValue, options: &JsValue); 12 | } 13 | -------------------------------------------------------------------------------- /web/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![recursion_limit = "1024"] 2 | 3 | use wasm_bindgen::prelude::*; 4 | use yew::prelude::*; 5 | 6 | use flash_lso::types::Value; 7 | 8 | pub(crate) mod blob_bindgen; 9 | pub(crate) mod component_hexview; 10 | pub(crate) mod component_modal; 11 | pub(crate) mod component_model; 12 | pub(crate) mod component_number_input; 13 | pub(crate) mod component_string_input; 14 | pub(crate) mod component_tab; 15 | pub(crate) mod component_tabs; 16 | pub(crate) mod component_treenode; 17 | pub(crate) mod jquery_bindgen; 18 | pub(crate) mod uintarray_bindgen; 19 | pub(crate) mod url_bindgen; 20 | pub(crate) mod web_expect; 21 | 22 | use crate::component_model::Model; 23 | 24 | #[derive(Clone, Debug, PartialEq)] 25 | pub struct EditableValue { 26 | pub value: Value, 27 | pub callback: Callback, 28 | pub path: TreeNodePath, 29 | } 30 | 31 | #[derive(Clone, Debug, PartialEq, Eq)] 32 | pub struct TreeNodePath(Vec); 33 | impl TreeNodePath { 34 | pub fn root() -> Self { 35 | Self(vec!["/".to_string()]) 36 | } 37 | 38 | #[must_use] 39 | pub fn join(&self, child: String) -> Self { 40 | Self(self.0.iter().chain(&[child]).cloned().collect()) 41 | } 42 | 43 | pub fn contains(&self, other: Self) -> bool { 44 | if other.0.len() > self.0.len() { 45 | return false; 46 | } 47 | 48 | self.0[..other.0.len()] == other.0[..] 49 | } 50 | 51 | pub fn string(&self) -> String { 52 | self.0.join("::") 53 | } 54 | } 55 | 56 | #[wasm_bindgen(start)] 57 | pub fn run_app() { 58 | wasm_logger::init(wasm_logger::Config::default()); 59 | yew::Renderer::::new().render(); 60 | } 61 | 62 | //TODO fix saving 63 | -------------------------------------------------------------------------------- /web/src/uintarray_bindgen.rs: -------------------------------------------------------------------------------- 1 | use wasm_bindgen::prelude::*; 2 | 3 | #[wasm_bindgen] 4 | extern "C" { 5 | pub type Uint8Array; 6 | 7 | #[wasm_bindgen(constructor)] 8 | pub fn new(length: u32) -> Uint8Array; 9 | 10 | #[wasm_bindgen(method, structural, indexing_setter)] 11 | pub fn set(this: &Uint8Array, prop: u32, val: u32); 12 | } 13 | -------------------------------------------------------------------------------- /web/src/url_bindgen.rs: -------------------------------------------------------------------------------- 1 | use crate::blob_bindgen::Blob; 2 | use wasm_bindgen::prelude::*; 3 | 4 | #[wasm_bindgen] 5 | extern "C" { 6 | pub type URL; 7 | 8 | #[wasm_bindgen(static_method_of=URL)] 9 | pub fn createObjectURL(blob: &Blob) -> String; 10 | } 11 | -------------------------------------------------------------------------------- /web/src/web_expect.rs: -------------------------------------------------------------------------------- 1 | pub trait WebSafeExpect { 2 | fn web_expect(self, msg: &str) -> T; 3 | } 4 | 5 | impl WebSafeExpect for Option { 6 | fn web_expect(self, msg: &str) -> T { 7 | match self { 8 | Some(val) => val, 9 | None => { 10 | log::error!("{}", msg); 11 | log::logger().flush(); 12 | panic!() 13 | } 14 | } 15 | } 16 | } 17 | 18 | impl WebSafeExpect for Result { 19 | fn web_expect(self, msg: &str) -> T { 20 | match self { 21 | Ok(val) => val, 22 | Err(e) => { 23 | log::error!("{} - {:?}", msg, e); 24 | log::logger().flush(); 25 | panic!() 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /web/static/.gitignore: -------------------------------------------------------------------------------- 1 | * -------------------------------------------------------------------------------- /web/static/icon/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013-2017 Cole Bemis 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /web/static/icon/check.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /web/static/icon/database.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /web/static/icon/file-text.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /web/static/icon/file.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /web/static/icon/folder-minus.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /web/static/icon/folder-plus.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /web/static/icon/x.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /web/static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | LSO Editor 6 | 7 | 8 | 9 | 10 | 11 | 21 | 25 | 26 | 27 | 28 | --------------------------------------------------------------------------------