@swf2es/runtime 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/LICENSE.third-party +422 -0
- package/README.md +29 -2
- package/dist/avm1/activation.d.ts +108 -0
- package/dist/avm1/activation.d.ts.map +1 -0
- package/dist/avm1/activation.js +90 -0
- package/dist/avm1/activation.js.map +1 -0
- package/dist/avm1/case.d.ts +3 -0
- package/dist/avm1/case.d.ts.map +1 -0
- package/dist/avm1/case.js +250 -0
- package/dist/avm1/case.js.map +1 -0
- package/dist/avm1/clips.d.ts +68 -0
- package/dist/avm1/clips.d.ts.map +1 -0
- package/dist/avm1/clips.js +335 -0
- package/dist/avm1/clips.js.map +1 -0
- package/dist/avm1/control.d.ts +54 -0
- package/dist/avm1/control.d.ts.map +1 -0
- package/dist/avm1/control.js +281 -0
- package/dist/avm1/control.js.map +1 -0
- package/dist/avm1/errors.d.ts +49 -0
- package/dist/avm1/errors.d.ts.map +1 -0
- package/dist/avm1/errors.js +51 -0
- package/dist/avm1/errors.js.map +1 -0
- package/dist/avm1/functions.d.ts +94 -0
- package/dist/avm1/functions.d.ts.map +1 -0
- package/dist/avm1/functions.js +250 -0
- package/dist/avm1/functions.js.map +1 -0
- package/dist/avm1/globals/array.d.ts +8 -0
- package/dist/avm1/globals/array.d.ts.map +1 -0
- package/dist/avm1/globals/array.js +550 -0
- package/dist/avm1/globals/array.js.map +1 -0
- package/dist/avm1/globals/broadcaster.d.ts +22 -0
- package/dist/avm1/globals/broadcaster.d.ts.map +1 -0
- package/dist/avm1/globals/broadcaster.js +132 -0
- package/dist/avm1/globals/broadcaster.js.map +1 -0
- package/dist/avm1/globals/date.d.ts +10 -0
- package/dist/avm1/globals/date.d.ts.map +1 -0
- package/dist/avm1/globals/date.js +437 -0
- package/dist/avm1/globals/date.js.map +1 -0
- package/dist/avm1/globals/global.d.ts +23 -0
- package/dist/avm1/globals/global.d.ts.map +1 -0
- package/dist/avm1/globals/global.js +345 -0
- package/dist/avm1/globals/global.js.map +1 -0
- package/dist/avm1/globals/math.d.ts +7 -0
- package/dist/avm1/globals/math.d.ts.map +1 -0
- package/dist/avm1/globals/math.js +140 -0
- package/dist/avm1/globals/math.js.map +1 -0
- package/dist/avm1/globals/number.d.ts +11 -0
- package/dist/avm1/globals/number.d.ts.map +1 -0
- package/dist/avm1/globals/number.js +94 -0
- package/dist/avm1/globals/number.js.map +1 -0
- package/dist/avm1/globals/string.d.ts +8 -0
- package/dist/avm1/globals/string.d.ts.map +1 -0
- package/dist/avm1/globals/string.js +202 -0
- package/dist/avm1/globals/string.js.map +1 -0
- package/dist/avm1/globals/timers.d.ts +49 -0
- package/dist/avm1/globals/timers.d.ts.map +1 -0
- package/dist/avm1/globals/timers.js +130 -0
- package/dist/avm1/globals/timers.js.map +1 -0
- package/dist/avm1/host.d.ts +146 -0
- package/dist/avm1/host.d.ts.map +1 -0
- package/dist/avm1/host.js +6 -0
- package/dist/avm1/host.js.map +1 -0
- package/dist/avm1/index.d.ts +15 -0
- package/dist/avm1/index.d.ts.map +1 -0
- package/dist/avm1/index.js +15 -0
- package/dist/avm1/index.js.map +1 -0
- package/dist/avm1/inheritance.d.ts +25 -0
- package/dist/avm1/inheritance.d.ts.map +1 -0
- package/dist/avm1/inheritance.js +133 -0
- package/dist/avm1/inheritance.js.map +1 -0
- package/dist/avm1/numbers.d.ts +21 -0
- package/dist/avm1/numbers.d.ts.map +1 -0
- package/dist/avm1/numbers.js +299 -0
- package/dist/avm1/numbers.js.map +1 -0
- package/dist/avm1/objects.d.ts +245 -0
- package/dist/avm1/objects.d.ts.map +1 -0
- package/dist/avm1/objects.js +897 -0
- package/dist/avm1/objects.js.map +1 -0
- package/dist/avm1/operators.d.ts +45 -0
- package/dist/avm1/operators.d.ts.map +1 -0
- package/dist/avm1/operators.js +171 -0
- package/dist/avm1/operators.js.map +1 -0
- package/dist/avm1/realm.d.ts +126 -0
- package/dist/avm1/realm.d.ts.map +1 -0
- package/dist/avm1/realm.js +530 -0
- package/dist/avm1/realm.js.map +1 -0
- package/dist/avm1/runtime.d.ts +294 -0
- package/dist/avm1/runtime.d.ts.map +1 -0
- package/dist/avm1/runtime.js +883 -0
- package/dist/avm1/runtime.js.map +1 -0
- package/dist/avm1/scope.d.ts +77 -0
- package/dist/avm1/scope.d.ts.map +1 -0
- package/dist/avm1/scope.js +386 -0
- package/dist/avm1/scope.js.map +1 -0
- package/dist/avm1/urls.d.ts +25 -0
- package/dist/avm1/urls.d.ts.map +1 -0
- package/dist/avm1/urls.js +181 -0
- package/dist/avm1/urls.js.map +1 -0
- package/dist/avm1/values.d.ts +52 -0
- package/dist/avm1/values.d.ts.map +1 -0
- package/dist/avm1/values.js +98 -0
- package/dist/avm1/values.js.map +1 -0
- package/dist/avm2/amf-classes.d.ts +28 -0
- package/dist/avm2/amf-classes.d.ts.map +1 -0
- package/dist/avm2/amf-classes.js +67 -0
- package/dist/avm2/amf-classes.js.map +1 -0
- package/dist/avm2/amf.d.ts +96 -0
- package/dist/avm2/amf.d.ts.map +1 -0
- package/dist/avm2/amf.js +802 -0
- package/dist/avm2/amf.js.map +1 -0
- package/dist/avm2/array-conversion.d.ts +31 -0
- package/dist/avm2/array-conversion.d.ts.map +1 -0
- package/dist/avm2/array-conversion.js +101 -0
- package/dist/avm2/array-conversion.js.map +1 -0
- package/dist/avm2/builtin-library.d.ts +2 -0
- package/dist/avm2/builtin-library.d.ts.map +1 -0
- package/dist/avm2/builtin-library.js +22 -0
- package/dist/avm2/builtin-library.js.map +1 -0
- package/dist/avm2/cache-fill.d.ts +14 -0
- package/dist/avm2/cache-fill.d.ts.map +1 -0
- package/dist/avm2/cache-fill.js +87 -0
- package/dist/avm2/cache-fill.js.map +1 -0
- package/dist/avm2/classes.d.ts +17 -0
- package/dist/avm2/classes.d.ts.map +1 -0
- package/dist/avm2/classes.js +212 -0
- package/dist/avm2/classes.js.map +1 -0
- package/dist/avm2/definitions.d.ts +28 -0
- package/dist/avm2/definitions.d.ts.map +1 -0
- package/dist/avm2/definitions.js +70 -0
- package/dist/avm2/definitions.js.map +1 -0
- package/dist/avm2/descriptors.d.ts +118 -0
- package/dist/avm2/descriptors.d.ts.map +1 -0
- package/dist/avm2/descriptors.js +6 -0
- package/dist/avm2/descriptors.js.map +1 -0
- package/dist/avm2/dictionary-keys.d.ts +73 -0
- package/dist/avm2/dictionary-keys.d.ts.map +1 -0
- package/dist/avm2/dictionary-keys.js +296 -0
- package/dist/avm2/dictionary-keys.js.map +1 -0
- package/dist/avm2/domain-memory.d.ts +23 -0
- package/dist/avm2/domain-memory.d.ts.map +1 -0
- package/dist/avm2/domain-memory.js +76 -0
- package/dist/avm2/domain-memory.js.map +1 -0
- package/dist/avm2/domain.d.ts +108 -0
- package/dist/avm2/domain.d.ts.map +1 -0
- package/dist/avm2/domain.js +281 -0
- package/dist/avm2/domain.js.map +1 -0
- package/dist/avm2/dynamic-properties.d.ts +62 -0
- package/dist/avm2/dynamic-properties.d.ts.map +1 -0
- package/dist/avm2/dynamic-properties.js +183 -0
- package/dist/avm2/dynamic-properties.js.map +1 -0
- package/dist/avm2/enumeration.d.ts +75 -0
- package/dist/avm2/enumeration.d.ts.map +1 -0
- package/dist/avm2/enumeration.js +394 -0
- package/dist/avm2/enumeration.js.map +1 -0
- package/dist/avm2/errors.d.ts +20 -0
- package/dist/avm2/errors.d.ts.map +1 -0
- package/dist/avm2/errors.js +46 -0
- package/dist/avm2/errors.js.map +1 -0
- package/dist/avm2/float-library.d.ts +2 -0
- package/dist/avm2/float-library.d.ts.map +1 -0
- package/dist/avm2/float-library.js +67 -0
- package/dist/avm2/float-library.js.map +1 -0
- package/dist/avm2/float.d.ts +9 -0
- package/dist/avm2/float.d.ts.map +1 -0
- package/dist/avm2/float.js +27 -0
- package/dist/avm2/float.js.map +1 -0
- package/dist/avm2/hooks.d.ts +77 -0
- package/dist/avm2/hooks.d.ts.map +1 -0
- package/dist/avm2/hooks.js +20 -0
- package/dist/avm2/hooks.js.map +1 -0
- package/dist/avm2/index.d.ts +32 -0
- package/dist/avm2/index.d.ts.map +1 -0
- package/dist/avm2/index.js +39 -0
- package/dist/avm2/index.js.map +1 -0
- package/dist/avm2/messages.d.ts +2 -0
- package/dist/avm2/messages.d.ts.map +1 -0
- package/dist/avm2/messages.js +178 -0
- package/dist/avm2/messages.js.map +1 -0
- package/dist/avm2/method-factories.d.ts +35 -0
- package/dist/avm2/method-factories.d.ts.map +1 -0
- package/dist/avm2/method-factories.js +96 -0
- package/dist/avm2/method-factories.js.map +1 -0
- package/dist/avm2/modules.d.ts +40 -0
- package/dist/avm2/modules.d.ts.map +1 -0
- package/dist/avm2/modules.js +106 -0
- package/dist/avm2/modules.js.map +1 -0
- package/dist/avm2/names.d.ts +143 -0
- package/dist/avm2/names.d.ts.map +1 -0
- package/dist/avm2/names.js +249 -0
- package/dist/avm2/names.js.map +1 -0
- package/dist/avm2/natives/aliases.d.ts +3 -0
- package/dist/avm2/natives/aliases.d.ts.map +1 -0
- package/dist/avm2/natives/aliases.js +48 -0
- package/dist/avm2/natives/aliases.js.map +1 -0
- package/dist/avm2/natives/array.d.ts +5 -0
- package/dist/avm2/natives/array.d.ts.map +1 -0
- package/dist/avm2/natives/array.js +391 -0
- package/dist/avm2/natives/array.js.map +1 -0
- package/dist/avm2/natives/bytearray.d.ts +180 -0
- package/dist/avm2/natives/bytearray.d.ts.map +1 -0
- package/dist/avm2/natives/bytearray.js +1228 -0
- package/dist/avm2/natives/bytearray.js.map +1 -0
- package/dist/avm2/natives/case.d.ts +5 -0
- package/dist/avm2/natives/case.d.ts.map +1 -0
- package/dist/avm2/natives/case.js +89 -0
- package/dist/avm2/natives/case.js.map +1 -0
- package/dist/avm2/natives/concurrent.d.ts +24 -0
- package/dist/avm2/natives/concurrent.d.ts.map +1 -0
- package/dist/avm2/natives/concurrent.js +200 -0
- package/dist/avm2/natives/concurrent.js.map +1 -0
- package/dist/avm2/natives/date.d.ts +5 -0
- package/dist/avm2/natives/date.d.ts.map +1 -0
- package/dist/avm2/natives/date.js +582 -0
- package/dist/avm2/natives/date.js.map +1 -0
- package/dist/avm2/natives/define.d.ts +58 -0
- package/dist/avm2/natives/define.d.ts.map +1 -0
- package/dist/avm2/natives/define.js +131 -0
- package/dist/avm2/natives/define.js.map +1 -0
- package/dist/avm2/natives/describe.d.ts +3 -0
- package/dist/avm2/natives/describe.d.ts.map +1 -0
- package/dist/avm2/natives/describe.js +352 -0
- package/dist/avm2/natives/describe.js.map +1 -0
- package/dist/avm2/natives/dictionary.d.ts +3 -0
- package/dist/avm2/natives/dictionary.d.ts.map +1 -0
- package/dist/avm2/natives/dictionary.js +13 -0
- package/dist/avm2/natives/dictionary.js.map +1 -0
- package/dist/avm2/natives/float-vector.d.ts +20 -0
- package/dist/avm2/natives/float-vector.d.ts.map +1 -0
- package/dist/avm2/natives/float-vector.js +82 -0
- package/dist/avm2/natives/float-vector.js.map +1 -0
- package/dist/avm2/natives/float.d.ts +5 -0
- package/dist/avm2/natives/float.d.ts.map +1 -0
- package/dist/avm2/natives/float.js +97 -0
- package/dist/avm2/natives/float.js.map +1 -0
- package/dist/avm2/natives/index.d.ts +7 -0
- package/dist/avm2/natives/index.d.ts.map +1 -0
- package/dist/avm2/natives/index.js +65 -0
- package/dist/avm2/natives/index.js.map +1 -0
- package/dist/avm2/natives/json.d.ts +3 -0
- package/dist/avm2/natives/json.d.ts.map +1 -0
- package/dist/avm2/natives/json.js +515 -0
- package/dist/avm2/natives/json.js.map +1 -0
- package/dist/avm2/natives/number.d.ts +15 -0
- package/dist/avm2/natives/number.d.ts.map +1 -0
- package/dist/avm2/natives/number.js +163 -0
- package/dist/avm2/natives/number.js.map +1 -0
- package/dist/avm2/natives/object.d.ts +8 -0
- package/dist/avm2/natives/object.d.ts.map +1 -0
- package/dist/avm2/natives/object.js +238 -0
- package/dist/avm2/natives/object.js.map +1 -0
- package/dist/avm2/natives/proxy.d.ts +5 -0
- package/dist/avm2/natives/proxy.d.ts.map +1 -0
- package/dist/avm2/natives/proxy.js +76 -0
- package/dist/avm2/natives/proxy.js.map +1 -0
- package/dist/avm2/natives/regexp.d.ts +21 -0
- package/dist/avm2/natives/regexp.d.ts.map +1 -0
- package/dist/avm2/natives/regexp.js +486 -0
- package/dist/avm2/natives/regexp.js.map +1 -0
- package/dist/avm2/natives/shell-workers.d.ts +140 -0
- package/dist/avm2/natives/shell-workers.d.ts.map +1 -0
- package/dist/avm2/natives/shell-workers.js +405 -0
- package/dist/avm2/natives/shell-workers.js.map +1 -0
- package/dist/avm2/natives/shell.d.ts +12 -0
- package/dist/avm2/natives/shell.d.ts.map +1 -0
- package/dist/avm2/natives/shell.js +558 -0
- package/dist/avm2/natives/shell.js.map +1 -0
- package/dist/avm2/natives/sort.d.ts +7 -0
- package/dist/avm2/natives/sort.d.ts.map +1 -0
- package/dist/avm2/natives/sort.js +378 -0
- package/dist/avm2/natives/sort.js.map +1 -0
- package/dist/avm2/natives/string.d.ts +5 -0
- package/dist/avm2/natives/string.d.ts.map +1 -0
- package/dist/avm2/natives/string.js +133 -0
- package/dist/avm2/natives/string.js.map +1 -0
- package/dist/avm2/natives/sync.d.ts +215 -0
- package/dist/avm2/natives/sync.d.ts.map +1 -0
- package/dist/avm2/natives/sync.js +822 -0
- package/dist/avm2/natives/sync.js.map +1 -0
- package/dist/avm2/natives/toplevel.d.ts +5 -0
- package/dist/avm2/natives/toplevel.d.ts.map +1 -0
- package/dist/avm2/natives/toplevel.js +140 -0
- package/dist/avm2/natives/toplevel.js.map +1 -0
- package/dist/avm2/natives/vector-elements.d.ts +10 -0
- package/dist/avm2/natives/vector-elements.d.ts.map +1 -0
- package/dist/avm2/natives/vector-elements.js +47 -0
- package/dist/avm2/natives/vector-elements.js.map +1 -0
- package/dist/avm2/natives/vector.d.ts +5 -0
- package/dist/avm2/natives/vector.d.ts.map +1 -0
- package/dist/avm2/natives/vector.js +407 -0
- package/dist/avm2/natives/vector.js.map +1 -0
- package/dist/avm2/natives/xml/access.d.ts +34 -0
- package/dist/avm2/natives/xml/access.d.ts.map +1 -0
- package/dist/avm2/natives/xml/access.js +634 -0
- package/dist/avm2/natives/xml/access.js.map +1 -0
- package/dist/avm2/natives/xml/build.d.ts +11 -0
- package/dist/avm2/natives/xml/build.d.ts.map +1 -0
- package/dist/avm2/natives/xml/build.js +292 -0
- package/dist/avm2/natives/xml/build.js.map +1 -0
- package/dist/avm2/natives/xml/chars.d.ts +9 -0
- package/dist/avm2/natives/xml/chars.d.ts.map +1 -0
- package/dist/avm2/natives/xml/chars.js +113 -0
- package/dist/avm2/natives/xml/chars.js.map +1 -0
- package/dist/avm2/natives/xml/escape.d.ts +5 -0
- package/dist/avm2/natives/xml/escape.d.ts.map +1 -0
- package/dist/avm2/natives/xml/escape.js +39 -0
- package/dist/avm2/natives/xml/escape.js.map +1 -0
- package/dist/avm2/natives/xml/names.d.ts +46 -0
- package/dist/avm2/natives/xml/names.d.ts.map +1 -0
- package/dist/avm2/natives/xml/names.js +205 -0
- package/dist/avm2/natives/xml/names.js.map +1 -0
- package/dist/avm2/natives/xml/node.d.ts +94 -0
- package/dist/avm2/natives/xml/node.d.ts.map +1 -0
- package/dist/avm2/natives/xml/node.js +273 -0
- package/dist/avm2/natives/xml/node.js.map +1 -0
- package/dist/avm2/natives/xml/operators.d.ts +7 -0
- package/dist/avm2/natives/xml/operators.d.ts.map +1 -0
- package/dist/avm2/natives/xml/operators.js +70 -0
- package/dist/avm2/natives/xml/operators.js.map +1 -0
- package/dist/avm2/natives/xml/parser.d.ts +51 -0
- package/dist/avm2/natives/xml/parser.d.ts.map +1 -0
- package/dist/avm2/natives/xml/parser.js +357 -0
- package/dist/avm2/natives/xml/parser.js.map +1 -0
- package/dist/avm2/natives/xml/strings.d.ts +10 -0
- package/dist/avm2/natives/xml/strings.d.ts.map +1 -0
- package/dist/avm2/natives/xml/strings.js +192 -0
- package/dist/avm2/natives/xml/strings.js.map +1 -0
- package/dist/avm2/natives/xml/values.d.ts +48 -0
- package/dist/avm2/natives/xml/values.d.ts.map +1 -0
- package/dist/avm2/natives/xml/values.js +123 -0
- package/dist/avm2/natives/xml/values.js.map +1 -0
- package/dist/avm2/natives/xml/xml.d.ts +5 -0
- package/dist/avm2/natives/xml/xml.d.ts.map +1 -0
- package/dist/avm2/natives/xml/xml.js +646 -0
- package/dist/avm2/natives/xml/xml.js.map +1 -0
- package/dist/avm2/number-strings.d.ts +28 -0
- package/dist/avm2/number-strings.d.ts.map +1 -0
- package/dist/avm2/number-strings.js +111 -0
- package/dist/avm2/number-strings.js.map +1 -0
- package/dist/avm2/numbers.d.ts +12 -0
- package/dist/avm2/numbers.d.ts.map +1 -0
- package/dist/avm2/numbers.js +559 -0
- package/dist/avm2/numbers.js.map +1 -0
- package/dist/avm2/options.d.ts +105 -0
- package/dist/avm2/options.d.ts.map +1 -0
- package/dist/avm2/options.js +17 -0
- package/dist/avm2/options.js.map +1 -0
- package/dist/avm2/player-messages.d.ts +3 -0
- package/dist/avm2/player-messages.d.ts.map +1 -0
- package/dist/avm2/player-messages.js +551 -0
- package/dist/avm2/player-messages.js.map +1 -0
- package/dist/avm2/property-cache.d.ts +61 -0
- package/dist/avm2/property-cache.d.ts.map +1 -0
- package/dist/avm2/property-cache.js +136 -0
- package/dist/avm2/property-cache.js.map +1 -0
- package/dist/avm2/runtime.d.ts +588 -0
- package/dist/avm2/runtime.d.ts.map +1 -0
- package/dist/avm2/runtime.js +2645 -0
- package/dist/avm2/runtime.js.map +1 -0
- package/dist/avm2/traits.d.ts +233 -0
- package/dist/avm2/traits.d.ts.map +1 -0
- package/dist/avm2/traits.js +510 -0
- package/dist/avm2/traits.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/package.json +43 -3
- package/src/avm1/activation.ts +114 -0
- package/src/avm1/case.ts +257 -0
- package/src/avm1/clips.ts +440 -0
- package/src/avm1/control.ts +339 -0
- package/src/avm1/errors.ts +60 -0
- package/src/avm1/functions.ts +271 -0
- package/src/avm1/globals/array.ts +676 -0
- package/src/avm1/globals/broadcaster.ts +185 -0
- package/src/avm1/globals/date.ts +548 -0
- package/src/avm1/globals/global.ts +420 -0
- package/src/avm1/globals/math.ts +152 -0
- package/src/avm1/globals/number.ts +122 -0
- package/src/avm1/globals/string.ts +254 -0
- package/src/avm1/globals/timers.ts +144 -0
- package/src/avm1/host.ts +155 -0
- package/src/avm1/index.ts +69 -0
- package/src/avm1/inheritance.ts +159 -0
- package/src/avm1/numbers.ts +348 -0
- package/src/avm1/objects.ts +1080 -0
- package/src/avm1/operators.ts +229 -0
- package/src/avm1/realm.ts +704 -0
- package/src/avm1/runtime.ts +1291 -0
- package/src/avm1/scope.ts +482 -0
- package/src/avm1/urls.ts +226 -0
- package/src/avm1/values.ts +145 -0
- package/src/avm2/amf-classes.ts +80 -0
- package/src/avm2/amf.ts +913 -0
- package/src/avm2/array-conversion.ts +117 -0
- package/src/avm2/builtin-library.ts +28 -0
- package/src/avm2/cache-fill.ts +124 -0
- package/src/avm2/classes.ts +235 -0
- package/src/avm2/definitions.ts +93 -0
- package/src/avm2/descriptors.ts +137 -0
- package/src/avm2/dictionary-keys.ts +345 -0
- package/src/avm2/domain-memory.ts +95 -0
- package/src/avm2/domain.ts +335 -0
- package/src/avm2/dynamic-properties.ts +209 -0
- package/src/avm2/enumeration.ts +506 -0
- package/src/avm2/errors.ts +54 -0
- package/src/avm2/float-library.ts +66 -0
- package/src/avm2/float.ts +31 -0
- package/src/avm2/hooks.ts +97 -0
- package/src/avm2/index.ts +84 -0
- package/src/avm2/messages.ts +178 -0
- package/src/avm2/method-factories.ts +130 -0
- package/src/avm2/modules.ts +120 -0
- package/src/avm2/names.ts +292 -0
- package/src/avm2/natives/aliases.ts +59 -0
- package/src/avm2/natives/array.ts +482 -0
- package/src/avm2/natives/bytearray.ts +1474 -0
- package/src/avm2/natives/case.ts +98 -0
- package/src/avm2/natives/concurrent.ts +268 -0
- package/src/avm2/natives/date.ts +678 -0
- package/src/avm2/natives/define.ts +176 -0
- package/src/avm2/natives/describe.ts +426 -0
- package/src/avm2/natives/dictionary.ts +18 -0
- package/src/avm2/natives/float-vector.ts +99 -0
- package/src/avm2/natives/float.ts +116 -0
- package/src/avm2/natives/index.ts +70 -0
- package/src/avm2/natives/json.ts +600 -0
- package/src/avm2/natives/number.ts +194 -0
- package/src/avm2/natives/object.ts +272 -0
- package/src/avm2/natives/proxy.ts +98 -0
- package/src/avm2/natives/regexp.ts +580 -0
- package/src/avm2/natives/shell-workers.ts +474 -0
- package/src/avm2/natives/shell.ts +707 -0
- package/src/avm2/natives/sort.ts +438 -0
- package/src/avm2/natives/string.ts +158 -0
- package/src/avm2/natives/sync.ts +964 -0
- package/src/avm2/natives/toplevel.ts +163 -0
- package/src/avm2/natives/vector-elements.ts +61 -0
- package/src/avm2/natives/vector.ts +511 -0
- package/src/avm2/natives/xml/access.ts +767 -0
- package/src/avm2/natives/xml/build.ts +381 -0
- package/src/avm2/natives/xml/chars.ts +127 -0
- package/src/avm2/natives/xml/escape.ts +46 -0
- package/src/avm2/natives/xml/names.ts +256 -0
- package/src/avm2/natives/xml/node.ts +339 -0
- package/src/avm2/natives/xml/operators.ts +90 -0
- package/src/avm2/natives/xml/parser.ts +414 -0
- package/src/avm2/natives/xml/strings.ts +241 -0
- package/src/avm2/natives/xml/values.ts +162 -0
- package/src/avm2/natives/xml/xml.ts +829 -0
- package/src/avm2/number-strings.ts +127 -0
- package/src/avm2/numbers.ts +605 -0
- package/src/avm2/options.ts +125 -0
- package/src/avm2/player-messages.ts +552 -0
- package/src/avm2/property-cache.ts +160 -0
- package/src/avm2/runtime.ts +3274 -0
- package/src/avm2/traits.ts +584 -0
- package/src/index.ts +8 -0
|
@@ -0,0 +1,1291 @@
|
|
|
1
|
+
// What a SWF's AVM1 module calls (docs/avm1.md, "Compiling"): its factory
|
|
2
|
+
// takes the runtime, asks it for the operations of the SWF's version,
|
|
3
|
+
// `V`, once, and each region of each block takes its activation, `cx`.
|
|
4
|
+
import { Activation, type Blocks, type Region, type Units } from "./activation.js";
|
|
5
|
+
import {
|
|
6
|
+
callFrame,
|
|
7
|
+
cloneSprite,
|
|
8
|
+
frameLoaded,
|
|
9
|
+
frameLoaded2,
|
|
10
|
+
getProperty,
|
|
11
|
+
gotoFrame,
|
|
12
|
+
gotoFrame2,
|
|
13
|
+
gotoLabel,
|
|
14
|
+
nextFrame,
|
|
15
|
+
prevFrame,
|
|
16
|
+
removeSprite,
|
|
17
|
+
setProperty,
|
|
18
|
+
setTarget,
|
|
19
|
+
setTarget2,
|
|
20
|
+
startDrag,
|
|
21
|
+
targetPathOf,
|
|
22
|
+
} from "./clips.js";
|
|
23
|
+
import { caught, enterTry, enterWith, leave, returned, scopes } from "./control.js";
|
|
24
|
+
import { Avm1Throw, BASE_REMOVED, Disabled, Halt, NotYet, TimedOut } from "./errors.js";
|
|
25
|
+
import { Avm1Super, argumentsOf, ScriptFunction, superOf } from "./functions.js";
|
|
26
|
+
import type { Host, Target } from "./host.js";
|
|
27
|
+
import { extend, implementsOp, instanceOf } from "./inheritance.js";
|
|
28
|
+
import {
|
|
29
|
+
Avm1Function,
|
|
30
|
+
Avm1Object,
|
|
31
|
+
foundDepth,
|
|
32
|
+
get,
|
|
33
|
+
invoke,
|
|
34
|
+
keys,
|
|
35
|
+
nameOf,
|
|
36
|
+
READ_ONLY,
|
|
37
|
+
removeOwn,
|
|
38
|
+
set,
|
|
39
|
+
VERSION_BITS,
|
|
40
|
+
} from "./objects.js";
|
|
41
|
+
import {
|
|
42
|
+
add2,
|
|
43
|
+
charOf,
|
|
44
|
+
extract,
|
|
45
|
+
firstCode,
|
|
46
|
+
lessThan,
|
|
47
|
+
looselyEquals,
|
|
48
|
+
strictlyEquals,
|
|
49
|
+
toInt32,
|
|
50
|
+
wellFormed,
|
|
51
|
+
} from "./operators.js";
|
|
52
|
+
import { BUDGET, Realm } from "./realm.js";
|
|
53
|
+
import {
|
|
54
|
+
defineLocal,
|
|
55
|
+
defineLocal2,
|
|
56
|
+
deleteVariable,
|
|
57
|
+
foundLocal,
|
|
58
|
+
foundOn,
|
|
59
|
+
getVariable,
|
|
60
|
+
resolve,
|
|
61
|
+
resolveCallable,
|
|
62
|
+
SCOPE_Target,
|
|
63
|
+
Scope,
|
|
64
|
+
setVariable,
|
|
65
|
+
} from "./scope.js";
|
|
66
|
+
import { getUrl, getUrl2 } from "./urls.js";
|
|
67
|
+
import {
|
|
68
|
+
isPrimitive,
|
|
69
|
+
type Primitive,
|
|
70
|
+
stringOf,
|
|
71
|
+
toBoolean,
|
|
72
|
+
toNumber,
|
|
73
|
+
typeOf,
|
|
74
|
+
type Value,
|
|
75
|
+
} from "./values.js";
|
|
76
|
+
|
|
77
|
+
export {
|
|
78
|
+
Activation,
|
|
79
|
+
Avm1Throw,
|
|
80
|
+
type Blocks,
|
|
81
|
+
Disabled,
|
|
82
|
+
Halt,
|
|
83
|
+
NotYet,
|
|
84
|
+
type Region,
|
|
85
|
+
TimedOut,
|
|
86
|
+
type Units,
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
/** The most timers a pass fires, as Ruffle's MAX_TICKS: a timer far behind catches up over frames. */
|
|
90
|
+
const MAX_TICKS = 10;
|
|
91
|
+
|
|
92
|
+
/** A module's default export. */
|
|
93
|
+
export type Factory = (rt: Runtime) => Blocks;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* The operations of a version, `V`: the module's code calls these, never
|
|
97
|
+
* testing its version. A binary action's operands come as the code pops
|
|
98
|
+
* them, the top of the stack, `a`, first: `Subtract` is `b - a`.
|
|
99
|
+
*/
|
|
100
|
+
export interface Operations {
|
|
101
|
+
readonly version: number;
|
|
102
|
+
/** ConstantPool: the activation's pool from here on, which a frame's later blocks start with. */
|
|
103
|
+
constantPool(cx: Activation, pool: Value[]): void;
|
|
104
|
+
trace(cx: Activation, value: Value): void;
|
|
105
|
+
toBoolean(value: Value): boolean;
|
|
106
|
+
/** ToString, and how every action that takes a string converts a value. */
|
|
107
|
+
toString(value: Value): string;
|
|
108
|
+
/** ToNumber, and how every arithmetic action converts a value. */
|
|
109
|
+
toNumber(value: Value): number;
|
|
110
|
+
/** ToInteger: ToInt32 of the number. */
|
|
111
|
+
toInteger(value: Value): number;
|
|
112
|
+
typeOf(value: Value): string;
|
|
113
|
+
/** SWF 4's Add: numbers, whatever the operands. */
|
|
114
|
+
add(a: Value, b: Value): number;
|
|
115
|
+
add2(a: Value, b: Value): Value;
|
|
116
|
+
subtract(a: Value, b: Value): number;
|
|
117
|
+
multiply(a: Value, b: Value): number;
|
|
118
|
+
/** "#ERROR#" for a division by zero up to SWF 4. */
|
|
119
|
+
divide(a: Value, b: Value): Value;
|
|
120
|
+
modulo(a: Value, b: Value): number;
|
|
121
|
+
increment(a: Value): number;
|
|
122
|
+
decrement(a: Value): number;
|
|
123
|
+
/** SWF 4's Equals: as numbers. */
|
|
124
|
+
equals(a: Value, b: Value): boolean;
|
|
125
|
+
equals2(a: Value, b: Value): boolean;
|
|
126
|
+
strictEquals(a: Value, b: Value): boolean;
|
|
127
|
+
/** SWF 4's Less: as numbers, false for NaN. */
|
|
128
|
+
less(a: Value, b: Value): boolean;
|
|
129
|
+
/** `b < a`: undefined where a number is NaN. */
|
|
130
|
+
less2(a: Value, b: Value): boolean | undefined;
|
|
131
|
+
/** `b > a`: undefined where a number is NaN. */
|
|
132
|
+
greater(a: Value, b: Value): boolean | undefined;
|
|
133
|
+
and(a: Value, b: Value): boolean;
|
|
134
|
+
or(a: Value, b: Value): boolean;
|
|
135
|
+
not(a: Value): boolean;
|
|
136
|
+
bitAnd(a: Value, b: Value): number;
|
|
137
|
+
bitOr(a: Value, b: Value): number;
|
|
138
|
+
bitXor(a: Value, b: Value): number;
|
|
139
|
+
bitLShift(a: Value, b: Value): number;
|
|
140
|
+
bitRShift(a: Value, b: Value): number;
|
|
141
|
+
/** Unsigned, but signed in SWF 8 and 9. */
|
|
142
|
+
bitURShift(a: Value, b: Value): number;
|
|
143
|
+
stringAdd(a: Value, b: Value): string;
|
|
144
|
+
stringEquals(a: Value, b: Value): boolean;
|
|
145
|
+
stringLess(a: Value, b: Value): boolean;
|
|
146
|
+
stringGreater(a: Value, b: Value): boolean;
|
|
147
|
+
stringLength(a: Value): number;
|
|
148
|
+
mbStringLength(a: Value): number;
|
|
149
|
+
/** StringExtract: `count` characters of `s` from the 1-based `index`. */
|
|
150
|
+
stringExtract(count: Value, index: Value, s: Value): string;
|
|
151
|
+
mbStringExtract(count: Value, index: Value, s: Value): string;
|
|
152
|
+
charToAscii(a: Value): number;
|
|
153
|
+
asciiToChar(a: Value): string;
|
|
154
|
+
mbCharToAscii(a: Value): number;
|
|
155
|
+
mbAsciiToChar(a: Value): string;
|
|
156
|
+
/** GetVariable of `name`, a path or not. */
|
|
157
|
+
getVariable(cx: Activation, name: Value): Value;
|
|
158
|
+
setVariable(cx: Activation, value: Value, name: Value): void;
|
|
159
|
+
defineLocal(cx: Activation, value: Value, name: Value): void;
|
|
160
|
+
defineLocal2(cx: Activation, name: Value): void;
|
|
161
|
+
/** `object[name]`. */
|
|
162
|
+
getMember(cx: Activation, name: Value, object: Value): Value;
|
|
163
|
+
setMember(cx: Activation, value: Value, name: Value, object: Value): void;
|
|
164
|
+
/** Delete: whether `object[name]` went. */
|
|
165
|
+
deleteMember(cx: Activation, name: Value, object: Value): boolean;
|
|
166
|
+
/** Delete2: whether the variable went. */
|
|
167
|
+
deleteVariable(cx: Activation, name: Value): boolean;
|
|
168
|
+
/** InitObject and InitArray, which pop their counts and their values themselves. */
|
|
169
|
+
initObject(cx: Activation): void;
|
|
170
|
+
initArray(cx: Activation): void;
|
|
171
|
+
/** Enumerate: a terminator, then the names of the variable's object, the first to visit on top. */
|
|
172
|
+
enumerate(cx: Activation, name: Value): void;
|
|
173
|
+
enumerate2(cx: Activation, object: Value): void;
|
|
174
|
+
/** CallFunction, CallMethod, NewObject and NewMethod, which pop their operands themselves. */
|
|
175
|
+
callFunction(cx: Activation): void;
|
|
176
|
+
callMethod(cx: Activation): void;
|
|
177
|
+
newObject(cx: Activation): void;
|
|
178
|
+
newMethod(cx: Activation): void;
|
|
179
|
+
/**
|
|
180
|
+
* DefineFunction: the function of region `region` of the activation's
|
|
181
|
+
* block, defined as a local variable, or pushed where it has no name;
|
|
182
|
+
* `params` its parameters' names.
|
|
183
|
+
*/
|
|
184
|
+
defineFunction(cx: Activation, region: number, name: Value, params: string[]): void;
|
|
185
|
+
/** DefineFunction2: as DefineFunction, null for a parameter in a register, and its flags. */
|
|
186
|
+
defineFunction2(
|
|
187
|
+
cx: Activation,
|
|
188
|
+
region: number,
|
|
189
|
+
name: Value,
|
|
190
|
+
params: (string | null)[],
|
|
191
|
+
flags: number,
|
|
192
|
+
): void;
|
|
193
|
+
/** Extends: the subclass's `prototype` made one whose prototype is the superclass's. */
|
|
194
|
+
extends(cx: Activation, superclass: Value, subclass: Value): void;
|
|
195
|
+
/** InstanceOf: `object instanceof constr`. */
|
|
196
|
+
instanceOf(cx: Activation, constr: Value, object: Value): boolean;
|
|
197
|
+
/** CastOp: the object where it is an instance of the constructor, else null. */
|
|
198
|
+
castOp(cx: Activation, object: Value, constr: Value): Value;
|
|
199
|
+
/** ImplementsOp, which pops its operands itself. */
|
|
200
|
+
implementsOp(cx: Activation): void;
|
|
201
|
+
/** RandomNumber: an int from 0 below `max`, 0 for a max below 1. */
|
|
202
|
+
randomNumber(max: Value): number;
|
|
203
|
+
/** What DefineFunction2 preloads: its `arguments`, its `super`, `_root` and `_parent`, undefined for none. */
|
|
204
|
+
argumentsOf(cx: Activation, args: Value[]): Value;
|
|
205
|
+
superOf(cx: Activation, self: Value): Value;
|
|
206
|
+
root(cx: Activation): Value;
|
|
207
|
+
parentOf(cx: Activation): Value;
|
|
208
|
+
/**
|
|
209
|
+
* With: `object` on the scope chain over the blocks of its body, from
|
|
210
|
+
* `from` to `to`; false where the body is skipped.
|
|
211
|
+
*/
|
|
212
|
+
with(cx: Activation, object: Value, from: number, to: number): boolean;
|
|
213
|
+
/**
|
|
214
|
+
* Try: its handlers over its try and catch bodies, the blocks from
|
|
215
|
+
* `from` to `finallyFrom`, the catch's from `catchFrom`; a throw lands at
|
|
216
|
+
* block `catchAt` (-1 for the exit, -2 for no catch), its value into the
|
|
217
|
+
* variable or the register `into`, or at the finally's blocks, from
|
|
218
|
+
* `finallyFrom` to `finallyTo`.
|
|
219
|
+
*/
|
|
220
|
+
try(
|
|
221
|
+
cx: Activation,
|
|
222
|
+
from: number,
|
|
223
|
+
catchFrom: number,
|
|
224
|
+
finallyFrom: number,
|
|
225
|
+
finallyTo: number,
|
|
226
|
+
catchAt: number,
|
|
227
|
+
into: string | number,
|
|
228
|
+
): void;
|
|
229
|
+
throw(value: Value): never;
|
|
230
|
+
/**
|
|
231
|
+
* Where control goes after `error` was thrown in block `at`: a block, -1
|
|
232
|
+
* for the exit; a register catch's value is `cx.thrown`, into `cx.into`.
|
|
233
|
+
*/
|
|
234
|
+
caught(cx: Activation, error: unknown, at: number): number;
|
|
235
|
+
/**
|
|
236
|
+
* Where control goes on its way to block `to` (-1: the exit) out of a
|
|
237
|
+
* Try's, a finally's or a scope's body.
|
|
238
|
+
*/
|
|
239
|
+
leave(cx: Activation, to: number): number;
|
|
240
|
+
/** After the first action of block `at`, reached from a body: the scopes that do not hold over it come off. */
|
|
241
|
+
scopes(cx: Activation, at: number): void;
|
|
242
|
+
/** Return of the value on top of the stack: where control goes first, a finally's block, or -1 to return `cx.ret`. */
|
|
243
|
+
ret(cx: Activation): number;
|
|
244
|
+
play(cx: Activation): void;
|
|
245
|
+
stop(cx: Activation): void;
|
|
246
|
+
/** SetTarget: the clip `name` names the target, "" the code's own. */
|
|
247
|
+
setTarget(cx: Activation, name: string): void;
|
|
248
|
+
setTarget2(cx: Activation, target: Value): void;
|
|
249
|
+
/** GetProperty: property `index` of the clip `path` names. */
|
|
250
|
+
getProperty(cx: Activation, index: Value, path: Value): Value;
|
|
251
|
+
setProperty(cx: Activation, value: Value, index: Value, path: Value): void;
|
|
252
|
+
/** GotoFrame: frame `frame`, 0 the first, of the target. */
|
|
253
|
+
gotoFrame(cx: Activation, frame: number): void;
|
|
254
|
+
gotoLabel(cx: Activation, label: string): void;
|
|
255
|
+
/** GotoFrame2: the frame the value names, `bias` frames on, played or stopped. */
|
|
256
|
+
gotoFrame2(cx: Activation, frame: Value, play: boolean, bias: number): void;
|
|
257
|
+
nextFrame(cx: Activation): void;
|
|
258
|
+
prevFrame(cx: Activation): void;
|
|
259
|
+
/** WaitForFrame: whether frame `frame`, 0 the first, is loaded. */
|
|
260
|
+
frameLoaded(cx: Activation, frame: number): boolean;
|
|
261
|
+
/** WaitForFrame2: whether the frame the value names, 1 the first, is loaded. */
|
|
262
|
+
frameLoaded2(cx: Activation, frame: Value): boolean;
|
|
263
|
+
/** TargetPath: a clip's path, undefined for anything else. */
|
|
264
|
+
targetPath(cx: Activation, value: Value): Value;
|
|
265
|
+
/** CallFrame: the actions of the frame the value names run now. */
|
|
266
|
+
callFrame(cx: Activation, frame: Value): void;
|
|
267
|
+
stopSounds(cx: Activation): void;
|
|
268
|
+
toggleQuality(cx: Activation): void;
|
|
269
|
+
/** GetTime: ms since the movie started, on the player's clock. */
|
|
270
|
+
getTime(cx: Activation): number;
|
|
271
|
+
/** CloneSprite: the clip `source` names duplicated as `name` at timeline depth `depth`. */
|
|
272
|
+
cloneSprite(cx: Activation, depth: Value, name: Value, source: Value): void;
|
|
273
|
+
/** RemoveSprite: the clip `target` names removed, where a script may remove it. */
|
|
274
|
+
removeSprite(cx: Activation, target: Value): void;
|
|
275
|
+
/** StartDrag: the clip on the stack dragged, its lock and bounds below it. */
|
|
276
|
+
startDrag(cx: Activation): void;
|
|
277
|
+
/** EndDrag: the drag ends. */
|
|
278
|
+
stopDrag(cx: Activation): void;
|
|
279
|
+
/** GetURL: fscommand, a load into a level, or a page to open. */
|
|
280
|
+
getUrl(cx: Activation, url: string, target: string): void;
|
|
281
|
+
/** GetURL2 of the target and the URL on the stack, the target on top, by its flags. */
|
|
282
|
+
getUrl2(cx: Activation, target: Value, url: Value, flags: number): void;
|
|
283
|
+
/**
|
|
284
|
+
* What a jump back counts down, shared by every activation of the
|
|
285
|
+
* version: as it runs out, `timeout` reads the clock.
|
|
286
|
+
*/
|
|
287
|
+
budget: number;
|
|
288
|
+
/** The budget ran out: past the script timeout, the movie's actions are disabled. */
|
|
289
|
+
timeout(cx: Activation): void;
|
|
290
|
+
/**
|
|
291
|
+
* Control going on at `at` in the SWF, outside the home the region
|
|
292
|
+
* running was compiled within, in units until it leaves the region, which
|
|
293
|
+
* ends at `end`, its actions' bytes at `bound`, `five` if it runs as a
|
|
294
|
+
* SWF 5's function: what the region returns.
|
|
295
|
+
*/
|
|
296
|
+
far(cx: Activation, at: number, end: number, bound: number, five: boolean): Value;
|
|
297
|
+
/** An action Flash cannot read: the SWF stops there. */
|
|
298
|
+
halt(cx: Activation): never;
|
|
299
|
+
/** A block larger than the compiler takes. */
|
|
300
|
+
tooLarge(): never;
|
|
301
|
+
/** An action the runtime does not do yet. */
|
|
302
|
+
notYet(name: string): never;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function operations(version: number): Operations {
|
|
306
|
+
/** Whether strings are bytes, up to SWF 5, which the MB actions read as a single-byte locale's. */
|
|
307
|
+
const bytes = version < 6;
|
|
308
|
+
// Flash's log writes half a surrogate pair as U+FFFD (adl a low half followed by more as three).
|
|
309
|
+
const written = bytes ? bytesAsUtf8 : wellFormed;
|
|
310
|
+
const byZero = version < 5 ? () => "#ERROR#" : divideByZero;
|
|
311
|
+
const stringLength = (a: Value) => stringOf(a, version).length;
|
|
312
|
+
const stringExtract = (count: Value, index: Value, s: Value) => {
|
|
313
|
+
const n = toInt32(count, version);
|
|
314
|
+
const i = toInt32(index, version);
|
|
315
|
+
const text = extract(stringOf(s, version), i, n);
|
|
316
|
+
return bytes ? text : wellFormed(text);
|
|
317
|
+
};
|
|
318
|
+
/**
|
|
319
|
+
* A member's name, as GetMember, SetMember and Delete take it: in a SWF
|
|
320
|
+
* 7, a NaN names element 0 ("0"), as Windows' Flash Player and AIR read,
|
|
321
|
+
* write and delete it (avm1-nan-names-swf7); SWF 6's and 8's, and any
|
|
322
|
+
* name a method converts (hasOwnProperty's), name it "NaN".
|
|
323
|
+
*/
|
|
324
|
+
const memberName =
|
|
325
|
+
version === 7
|
|
326
|
+
? (name: Value) =>
|
|
327
|
+
typeof name === "number" && Number.isNaN(name) ? "0" : nameOf(name, version)
|
|
328
|
+
: (name: Value) => nameOf(name, version);
|
|
329
|
+
|
|
330
|
+
return {
|
|
331
|
+
version,
|
|
332
|
+
constantPool(cx, pool) {
|
|
333
|
+
cx.pool = pool;
|
|
334
|
+
},
|
|
335
|
+
// undefined traces as "undefined" whatever the version, which converts it to "" up to SWF 6;
|
|
336
|
+
// a SWF 5 string's bytes are UTF-8, as Flash's log writes them.
|
|
337
|
+
// A toString that throws gives what an object without one does, and
|
|
338
|
+
// the value is thrown once the trace is written (adl).
|
|
339
|
+
trace(cx, value) {
|
|
340
|
+
let text: string;
|
|
341
|
+
try {
|
|
342
|
+
text = value === undefined ? "undefined" : stringOf(value, version);
|
|
343
|
+
} catch (error) {
|
|
344
|
+
if (!(error instanceof Avm1Throw)) {
|
|
345
|
+
throw error;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
cx.host.trace(value instanceof Avm1Function ? "[type Function]" : "[type Object]");
|
|
349
|
+
throw error;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
cx.host.trace(written(text));
|
|
353
|
+
},
|
|
354
|
+
toBoolean: (value) => toBoolean(value, version),
|
|
355
|
+
toString: (value) => stringOf(value, version),
|
|
356
|
+
toNumber: (value) => toNumber(value, version),
|
|
357
|
+
toInteger: (value) => toInt32(value, version),
|
|
358
|
+
typeOf,
|
|
359
|
+
add: (a, b) => toNumber(b, version) + toNumber(a, version),
|
|
360
|
+
add2: (a, b) => add2(a, b, version),
|
|
361
|
+
subtract(a, b) {
|
|
362
|
+
const x = toNumber(a, version);
|
|
363
|
+
return toNumber(b, version) - x;
|
|
364
|
+
},
|
|
365
|
+
multiply: (a, b) => toNumber(b, version) * toNumber(a, version),
|
|
366
|
+
divide(a, b) {
|
|
367
|
+
const x = toNumber(a, version);
|
|
368
|
+
const y = toNumber(b, version);
|
|
369
|
+
return x === 0 ? byZero(y) : y / x;
|
|
370
|
+
},
|
|
371
|
+
modulo(a, b) {
|
|
372
|
+
const x = toNumber(a, version);
|
|
373
|
+
return toNumber(b, version) % x;
|
|
374
|
+
},
|
|
375
|
+
increment: (a) => toNumber(a, version) + 1,
|
|
376
|
+
decrement: (a) => toNumber(a, version) - 1,
|
|
377
|
+
equals(a, b) {
|
|
378
|
+
const x = toNumber(a, version);
|
|
379
|
+
return toNumber(b, version) === x;
|
|
380
|
+
},
|
|
381
|
+
equals2: (a, b) => looselyEquals(b, a, version),
|
|
382
|
+
strictEquals: strictlyEquals,
|
|
383
|
+
less(a, b) {
|
|
384
|
+
return toNumber(b, version) < toNumber(a, version);
|
|
385
|
+
},
|
|
386
|
+
less2: (a, b) => lessThan(b, a, version),
|
|
387
|
+
greater: (a, b) => lessThan(a, b, version),
|
|
388
|
+
and(a, b) {
|
|
389
|
+
return toBoolean(b, version) && toBoolean(a, version);
|
|
390
|
+
},
|
|
391
|
+
or(a, b) {
|
|
392
|
+
return toBoolean(b, version) || toBoolean(a, version);
|
|
393
|
+
},
|
|
394
|
+
not: (a) => !toBoolean(a, version),
|
|
395
|
+
bitAnd: (a, b) => toInt32(a, version) & toInt32(b, version),
|
|
396
|
+
bitOr: (a, b) => toInt32(a, version) | toInt32(b, version),
|
|
397
|
+
bitXor: (a, b) => toInt32(a, version) ^ toInt32(b, version),
|
|
398
|
+
bitLShift(a, b) {
|
|
399
|
+
const n = toInt32(a, version);
|
|
400
|
+
return toInt32(b, version) << n;
|
|
401
|
+
},
|
|
402
|
+
bitRShift(a, b) {
|
|
403
|
+
const n = toInt32(a, version);
|
|
404
|
+
return toInt32(b, version) >> n;
|
|
405
|
+
},
|
|
406
|
+
bitURShift:
|
|
407
|
+
version === 8 || version === 9
|
|
408
|
+
? (a, b) => {
|
|
409
|
+
const n = toInt32(a, version);
|
|
410
|
+
return (toInt32(b, version) >>> n) | 0;
|
|
411
|
+
}
|
|
412
|
+
: (a, b) => {
|
|
413
|
+
const n = toInt32(a, version);
|
|
414
|
+
return toInt32(b, version) >>> n;
|
|
415
|
+
},
|
|
416
|
+
stringAdd(a, b) {
|
|
417
|
+
const x = stringOf(a, version);
|
|
418
|
+
return stringOf(b, version) + x;
|
|
419
|
+
},
|
|
420
|
+
stringEquals(a, b) {
|
|
421
|
+
const x = stringOf(a, version);
|
|
422
|
+
return stringOf(b, version) === x;
|
|
423
|
+
},
|
|
424
|
+
stringLess(a, b) {
|
|
425
|
+
const x = stringOf(a, version);
|
|
426
|
+
const y = stringOf(b, version);
|
|
427
|
+
return bytes && againstHighByte(y, x) ? false : y < x;
|
|
428
|
+
},
|
|
429
|
+
stringGreater(a, b) {
|
|
430
|
+
const x = stringOf(a, version);
|
|
431
|
+
const y = stringOf(b, version);
|
|
432
|
+
return bytes && againstHighByte(y, x) ? true : y > x;
|
|
433
|
+
},
|
|
434
|
+
stringLength,
|
|
435
|
+
mbStringLength: stringLength,
|
|
436
|
+
stringExtract,
|
|
437
|
+
mbStringExtract: stringExtract,
|
|
438
|
+
charToAscii: (a) => firstCode(stringOf(a, version)),
|
|
439
|
+
// Up to SWF 5 a string is bytes: AsciiToChar takes the code's low
|
|
440
|
+
// byte, MBAsciiToChar writes a code past 0xFF as two, high first, and
|
|
441
|
+
// the MB actions read one, as in a single-byte locale such as adl's.
|
|
442
|
+
asciiToChar: bytes
|
|
443
|
+
? (a) => charOf(toInt32(a, version) & 0xff, false)
|
|
444
|
+
: (a) => charOf(toInt32(a, version) & 0xffff, true),
|
|
445
|
+
mbCharToAscii: bytes
|
|
446
|
+
? (a) => stringOf(a, version).charCodeAt(0) & 0xff
|
|
447
|
+
: (a) => firstCode(stringOf(a, version)),
|
|
448
|
+
mbAsciiToChar: bytes
|
|
449
|
+
? (a) => {
|
|
450
|
+
const code = toInt32(a, version) & 0xffff;
|
|
451
|
+
return code > 0xff
|
|
452
|
+
? charOf(code >> 8, false) + charOf(code & 0xff, false)
|
|
453
|
+
: charOf(code, false);
|
|
454
|
+
}
|
|
455
|
+
: (a) => charOf(toInt32(a, version) & 0xffff, true),
|
|
456
|
+
// A SWF 4's variables hold no display objects (Ruffle's as_swf4_variable).
|
|
457
|
+
getVariable:
|
|
458
|
+
version <= 4
|
|
459
|
+
? (cx, name) => {
|
|
460
|
+
const value = getVariable(cx, nameOf(name, version), version);
|
|
461
|
+
return value instanceof Avm1Object && value.display !== null ? undefined : value;
|
|
462
|
+
}
|
|
463
|
+
: (cx, name) => getVariable(cx, nameOf(name, version), version),
|
|
464
|
+
setVariable(cx, value, name) {
|
|
465
|
+
setVariable(cx, nameOf(name, version), value, version);
|
|
466
|
+
},
|
|
467
|
+
defineLocal(cx, value, name) {
|
|
468
|
+
defineLocal(cx, nameOf(name, version), value, version);
|
|
469
|
+
},
|
|
470
|
+
defineLocal2(cx, name) {
|
|
471
|
+
defineLocal2(cx, nameOf(name, version), version);
|
|
472
|
+
},
|
|
473
|
+
getMember(cx, name, object) {
|
|
474
|
+
// An array's element by its number, as loops read them: no name made.
|
|
475
|
+
if (typeof name === "number" && object instanceof Avm1Object && object.elems !== null) {
|
|
476
|
+
const p = name >= 0 && name < object.elems.length ? object.elems[name] : undefined;
|
|
477
|
+
if (p !== undefined && p.get === null && (p.flags & VERSION_BITS) === 0) {
|
|
478
|
+
return p.value;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
const key = memberName(name);
|
|
483
|
+
if (object instanceof Avm1Super) {
|
|
484
|
+
return get(object, key, version, object.self);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
if (object instanceof Avm1Object) {
|
|
488
|
+
const live = object.display === null ? object : object.display.live();
|
|
489
|
+
return live === null ? undefined : get(live, key, version);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
return object === undefined || object === null
|
|
493
|
+
? undefined
|
|
494
|
+
: cx.realm.primitiveMember(object as Primitive, key, version);
|
|
495
|
+
},
|
|
496
|
+
setMember(cx, value, name, object) {
|
|
497
|
+
if (
|
|
498
|
+
typeof name === "number" &&
|
|
499
|
+
object instanceof Avm1Object &&
|
|
500
|
+
object.elems !== null &&
|
|
501
|
+
object.watchers === null
|
|
502
|
+
) {
|
|
503
|
+
const p = name >= 0 && name < object.elems.length ? object.elems[name] : undefined;
|
|
504
|
+
if (p !== undefined && p.get === null && (p.flags & (READ_ONLY | VERSION_BITS)) === 0) {
|
|
505
|
+
p.value = value;
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
const key = memberName(name);
|
|
511
|
+
if (object instanceof Avm1Super) {
|
|
512
|
+
set(object.self, key, value, version);
|
|
513
|
+
} else if (object instanceof Avm1Object) {
|
|
514
|
+
const live = object.display === null ? object : object.display.live();
|
|
515
|
+
if (live !== null) {
|
|
516
|
+
set(live, key, value, version);
|
|
517
|
+
}
|
|
518
|
+
} else if (object !== undefined && object !== null) {
|
|
519
|
+
set(cx.realm.box(object, version), key, value, version);
|
|
520
|
+
}
|
|
521
|
+
},
|
|
522
|
+
deleteMember(_, name, object) {
|
|
523
|
+
const key = memberName(name);
|
|
524
|
+
const o = live(object);
|
|
525
|
+
return o instanceof Avm1Object && removeOwn(o, key, version);
|
|
526
|
+
},
|
|
527
|
+
deleteVariable: (cx, name) => deleteVariable(cx, nameOf(name, version), version),
|
|
528
|
+
initObject(cx) {
|
|
529
|
+
const st = cx.st;
|
|
530
|
+
const n = countOf(st.pop(), version);
|
|
531
|
+
if (n < 0) {
|
|
532
|
+
st.push(undefined);
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// Pairs past the stack's are all undefined, which set the same name each time: one does.
|
|
537
|
+
const object = cx.realm.newObject(version);
|
|
538
|
+
const pairs = Math.min(n, (st.length >> 1) + 2);
|
|
539
|
+
for (let i = 0; i < pairs; i++) {
|
|
540
|
+
const value = st.pop();
|
|
541
|
+
set(object, nameOf(st.pop(), version), value, version);
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
st.push(object);
|
|
545
|
+
},
|
|
546
|
+
initArray(cx) {
|
|
547
|
+
const st = cx.st;
|
|
548
|
+
const n = countOf(st.pop(), version);
|
|
549
|
+
if (n < 0) {
|
|
550
|
+
st.push(undefined);
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
// Past the stack's values, undefined ones; a count far past it is cut short, as no
|
|
555
|
+
// compiler writes one and Flash would make billions of elements.
|
|
556
|
+
const count = Math.min(n, st.length + 0x10000);
|
|
557
|
+
const elements: Value[] = new Array(count);
|
|
558
|
+
for (let i = 0; i < count; i++) {
|
|
559
|
+
elements[i] = st.pop();
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
st.push(cx.realm.newArray(elements, version));
|
|
563
|
+
},
|
|
564
|
+
enumerate(cx, name) {
|
|
565
|
+
enumerate(cx, getVariable(cx, nameOf(name, version), version), version);
|
|
566
|
+
},
|
|
567
|
+
enumerate2(cx, object) {
|
|
568
|
+
enumerate(cx, live(object), version);
|
|
569
|
+
},
|
|
570
|
+
callFunction(cx) {
|
|
571
|
+
const st = cx.st;
|
|
572
|
+
const name = nameOf(st.pop(), version);
|
|
573
|
+
const args = popArgs(st, version);
|
|
574
|
+
const fn = resolveCallable(cx, name, version);
|
|
575
|
+
// `this` is what had the name, a function's activation object too,
|
|
576
|
+
// but in a SWF 5, which takes the target's clip for it (adl).
|
|
577
|
+
const self = foundOn === undefined || (version < 6 && foundLocal) ? cx.clip : foundOn;
|
|
578
|
+
// `super(...)` called by name runs the class above's constructor, as CallMethod of it does.
|
|
579
|
+
st.push(
|
|
580
|
+
fn instanceof Avm1Super
|
|
581
|
+
? superCall(fn, "", args, version)
|
|
582
|
+
: invoke(fn, self, args, version),
|
|
583
|
+
);
|
|
584
|
+
if (fn instanceof ScriptFunction) {
|
|
585
|
+
cx.host.returned?.();
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
returnIfRemoved(cx);
|
|
589
|
+
},
|
|
590
|
+
callMethod(cx) {
|
|
591
|
+
// A method of undefined or null is no call: its code goes on (Ruffle).
|
|
592
|
+
if (callMethod(cx, version)) {
|
|
593
|
+
returnIfRemoved(cx);
|
|
594
|
+
}
|
|
595
|
+
},
|
|
596
|
+
newObject(cx) {
|
|
597
|
+
const st = cx.st;
|
|
598
|
+
const name = nameOf(st.pop(), version);
|
|
599
|
+
const args = popArgs(st, version);
|
|
600
|
+
st.push(cx.realm.construct(resolve(cx, name, version), args, version));
|
|
601
|
+
returnIfRemoved(cx);
|
|
602
|
+
},
|
|
603
|
+
newMethod(cx) {
|
|
604
|
+
if (newMethod(cx, version)) {
|
|
605
|
+
returnIfRemoved(cx);
|
|
606
|
+
}
|
|
607
|
+
},
|
|
608
|
+
defineFunction(cx, region, name, params) {
|
|
609
|
+
defineFunction(cx, region, name, params, 0, version);
|
|
610
|
+
},
|
|
611
|
+
defineFunction2(cx, region, name, params, flags) {
|
|
612
|
+
defineFunction(cx, region, name, params, flags, version);
|
|
613
|
+
},
|
|
614
|
+
extends(cx, superclass, subclass) {
|
|
615
|
+
extend(cx, superclass, subclass, version);
|
|
616
|
+
},
|
|
617
|
+
instanceOf: (cx, constr, object) => instanceOf(cx.realm, object, constr, version),
|
|
618
|
+
castOp(cx, object, constr) {
|
|
619
|
+
// Flash boxes a primitive first, for nothing: a class replaced on _global sees it.
|
|
620
|
+
if (object !== undefined && object !== null && isPrimitive(object)) {
|
|
621
|
+
cx.realm.box(object, version);
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
return instanceOf(cx.realm, object, constr, version) ? object : null;
|
|
625
|
+
},
|
|
626
|
+
implementsOp(cx) {
|
|
627
|
+
implementsOp(cx, version);
|
|
628
|
+
},
|
|
629
|
+
randomNumber(max) {
|
|
630
|
+
// Rust's cast of the max: saturated, NaN 0.
|
|
631
|
+
const n = toNumber(max, version);
|
|
632
|
+
const m = Number.isNaN(n) ? 0 : Math.trunc(Math.min(Math.max(n, -2147483648), 2147483647));
|
|
633
|
+
return m > 0 ? Math.floor(Math.random() * 0x80000000) % m : 0;
|
|
634
|
+
},
|
|
635
|
+
argumentsOf: (cx, args) => argumentsOf(cx, args, version),
|
|
636
|
+
superOf: (cx, self) => superOf(cx, self, version),
|
|
637
|
+
root: (cx) => cx.host.root?.(cx.base),
|
|
638
|
+
parentOf: (cx) => cx.host.parent?.(cx.clip),
|
|
639
|
+
with: (cx, object, from, to) => enterWith(cx, object, from, to, version),
|
|
640
|
+
try: enterTry,
|
|
641
|
+
throw(value) {
|
|
642
|
+
throw new Avm1Throw(value);
|
|
643
|
+
},
|
|
644
|
+
caught,
|
|
645
|
+
leave,
|
|
646
|
+
scopes,
|
|
647
|
+
ret: returned,
|
|
648
|
+
play(cx) {
|
|
649
|
+
if (cx.target !== null) {
|
|
650
|
+
cx.host.play(cx.target);
|
|
651
|
+
}
|
|
652
|
+
},
|
|
653
|
+
stop(cx) {
|
|
654
|
+
if (cx.target !== null) {
|
|
655
|
+
cx.host.stop(cx.target);
|
|
656
|
+
}
|
|
657
|
+
},
|
|
658
|
+
setTarget(cx, name) {
|
|
659
|
+
setTarget(cx, name, version);
|
|
660
|
+
},
|
|
661
|
+
setTarget2(cx, target) {
|
|
662
|
+
setTarget2(cx, target, version);
|
|
663
|
+
},
|
|
664
|
+
getProperty: (cx, index, path) => getProperty(cx, index, path, version),
|
|
665
|
+
setProperty(cx, value, index, path) {
|
|
666
|
+
setProperty(cx, value, index, path, version);
|
|
667
|
+
},
|
|
668
|
+
gotoFrame,
|
|
669
|
+
gotoLabel,
|
|
670
|
+
gotoFrame2(cx, frame, play, bias) {
|
|
671
|
+
gotoFrame2(cx, frame, play, bias, version);
|
|
672
|
+
},
|
|
673
|
+
nextFrame,
|
|
674
|
+
prevFrame,
|
|
675
|
+
frameLoaded: (_, frame) => frameLoaded(frame),
|
|
676
|
+
frameLoaded2: (_, frame) => frameLoaded2(frame, version),
|
|
677
|
+
targetPath: (_, value) => targetPathOf(value),
|
|
678
|
+
callFrame(cx, frame) {
|
|
679
|
+
callFrame(cx, frame, version);
|
|
680
|
+
returnIfRemoved(cx);
|
|
681
|
+
},
|
|
682
|
+
stopSounds(cx) {
|
|
683
|
+
cx.host.stopSounds?.();
|
|
684
|
+
},
|
|
685
|
+
toggleQuality(cx) {
|
|
686
|
+
cx.host.toggleQuality?.();
|
|
687
|
+
},
|
|
688
|
+
getTime: (cx) => cx.host.time?.() ?? 0,
|
|
689
|
+
cloneSprite(cx, depth, name, source) {
|
|
690
|
+
cloneSprite(cx, depth, name, source, version);
|
|
691
|
+
},
|
|
692
|
+
removeSprite(cx, target) {
|
|
693
|
+
removeSprite(cx, target, version);
|
|
694
|
+
},
|
|
695
|
+
startDrag(cx) {
|
|
696
|
+
startDrag(cx, version);
|
|
697
|
+
},
|
|
698
|
+
stopDrag(cx) {
|
|
699
|
+
cx.host.stopDrag?.();
|
|
700
|
+
},
|
|
701
|
+
getUrl,
|
|
702
|
+
getUrl2(cx, target, url, flags) {
|
|
703
|
+
getUrl2(cx, target, url, flags, version);
|
|
704
|
+
},
|
|
705
|
+
budget: BUDGET,
|
|
706
|
+
timeout(cx) {
|
|
707
|
+
this.budget = BUDGET;
|
|
708
|
+
cx.realm.timeout();
|
|
709
|
+
},
|
|
710
|
+
far(cx, at, end, bound, five) {
|
|
711
|
+
const code = cx.code;
|
|
712
|
+
const units = cx.realm.units.get(code);
|
|
713
|
+
if (units === undefined) {
|
|
714
|
+
throw new Error("swf2es: AVM1 code whose SWF has no units");
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
try {
|
|
718
|
+
for (;;) {
|
|
719
|
+
// Each unit may be where a loop goes round.
|
|
720
|
+
if (--this.budget < 0) {
|
|
721
|
+
this.timeout(cx);
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
const unit = units.unit(at, end, bound, five);
|
|
725
|
+
cx.code = unit;
|
|
726
|
+
const next = unit[0](cx) as number;
|
|
727
|
+
if (next < 0) {
|
|
728
|
+
return next === -2 ? cx.ret : undefined;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
if (next >= end) {
|
|
732
|
+
return undefined;
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
at = next;
|
|
736
|
+
}
|
|
737
|
+
} finally {
|
|
738
|
+
cx.code = code;
|
|
739
|
+
}
|
|
740
|
+
},
|
|
741
|
+
halt(cx) {
|
|
742
|
+
cx.host.halt();
|
|
743
|
+
throw new Halt("the SWF stopped at an action Flash cannot read");
|
|
744
|
+
},
|
|
745
|
+
tooLarge() {
|
|
746
|
+
throw new Error("an AVM1 block too large to compile");
|
|
747
|
+
},
|
|
748
|
+
notYet(name) {
|
|
749
|
+
throw new NotYet(name);
|
|
750
|
+
},
|
|
751
|
+
};
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
/**
|
|
755
|
+
* CallMethod, which pops its operands and pushes what the method gives:
|
|
756
|
+
* false where there was no object to call it on.
|
|
757
|
+
*/
|
|
758
|
+
function callMethod(cx: Activation, version: number): boolean {
|
|
759
|
+
const st = cx.st;
|
|
760
|
+
const name = st.pop();
|
|
761
|
+
const object = live(st.pop());
|
|
762
|
+
const args = popArgs(st, version);
|
|
763
|
+
if (object === undefined || object === null) {
|
|
764
|
+
st.push(undefined);
|
|
765
|
+
return false;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
const key = name === undefined ? "" : nameOf(name, version);
|
|
769
|
+
if (object instanceof Avm1Super) {
|
|
770
|
+
st.push(superCall(object, key, args, version));
|
|
771
|
+
} else if (key === "") {
|
|
772
|
+
st.push(invoke(object, undefined, args, version));
|
|
773
|
+
} else if (!(object instanceof Avm1Object)) {
|
|
774
|
+
const method = cx.realm.primitiveMember(object as Primitive, key, version);
|
|
775
|
+
st.push(invoke(method, object, args, version, 1));
|
|
776
|
+
} else {
|
|
777
|
+
// A method found on the object itself is called as if found on its
|
|
778
|
+
// prototype; up to SWF 6 wherever it was found (adl).
|
|
779
|
+
const method = get(object, key, version);
|
|
780
|
+
st.push(invoke(method, object, args, version, version < 7 ? 1 : Math.max(foundDepth, 1)));
|
|
781
|
+
if (method instanceof ScriptFunction) {
|
|
782
|
+
cx.host.returned?.();
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
return true;
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
/** NewMethod: `new object[name](args)`, `new object(args)` for an empty name; false for no object. */
|
|
790
|
+
function newMethod(cx: Activation, version: number): boolean {
|
|
791
|
+
const st = cx.st;
|
|
792
|
+
const name = st.pop();
|
|
793
|
+
const object = st.pop();
|
|
794
|
+
const args = popArgs(st, version);
|
|
795
|
+
if (object === undefined || object === null) {
|
|
796
|
+
st.push(undefined);
|
|
797
|
+
return false;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
const key = name === undefined ? "" : nameOf(name, version);
|
|
801
|
+
const boxed = cx.realm.box(object, version);
|
|
802
|
+
const constr = key === "" ? boxed : get(boxed, key, version);
|
|
803
|
+
st.push(cx.realm.construct(constr, args, version));
|
|
804
|
+
return true;
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
/**
|
|
808
|
+
* After a call: where it removed the clip whose code made it, that code
|
|
809
|
+
* returns, as Flash's does. The clip is looked at only where a clip was
|
|
810
|
+
* removed since the code last looked.
|
|
811
|
+
*/
|
|
812
|
+
function returnIfRemoved(cx: Activation): void {
|
|
813
|
+
const removals = cx.realm.removals;
|
|
814
|
+
if (removals !== cx.removals) {
|
|
815
|
+
cx.removals = removals;
|
|
816
|
+
if (cx.host.removed?.(cx.base)) {
|
|
817
|
+
throw BASE_REMOVED;
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
/** A value as a reference reaches it now: a clip's AVM1 object the one at its path, undefined for none. */
|
|
823
|
+
function live(value: Value): Value {
|
|
824
|
+
if (value instanceof Avm1Object && value.display !== null) {
|
|
825
|
+
return value.display.live() ?? undefined;
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
return value;
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
/**
|
|
832
|
+
* Whether one of two SWF 5 strings is empty and the other starts with a
|
|
833
|
+
* byte from 0x80: adl's StringLess has neither less than the other, and
|
|
834
|
+
* its StringGreater each greater.
|
|
835
|
+
*/
|
|
836
|
+
function againstHighByte(x: string, y: string): boolean {
|
|
837
|
+
return (x === "" && y.charCodeAt(0) >= 0x80) || (y === "" && x.charCodeAt(0) >= 0x80);
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
/**
|
|
841
|
+
* A division by zero from SWF 5, whose sign the zero does not change, as
|
|
842
|
+
* adl divides: 1 / -0 is Infinity.
|
|
843
|
+
*/
|
|
844
|
+
function divideByZero(n: number): number {
|
|
845
|
+
if (n > 0) {
|
|
846
|
+
return Number.POSITIVE_INFINITY;
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
return n < 0 ? Number.NEGATIVE_INFINITY : Number.NaN;
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
// The web's and node's alike, though not ECMAScript's.
|
|
853
|
+
declare const TextEncoder: new () => { encode(s: string): Uint8Array };
|
|
854
|
+
declare const TextDecoder: new (
|
|
855
|
+
label: string,
|
|
856
|
+
options: { ignoreBOM: boolean },
|
|
857
|
+
) => { decode(bytes: Uint8Array): string };
|
|
858
|
+
|
|
859
|
+
/** Text that is the same as bytes and as UTF-8, as most is. */
|
|
860
|
+
const ascii = /^[ -~\t\n\r]*$/;
|
|
861
|
+
const encoder = new TextEncoder();
|
|
862
|
+
const decoder = new TextDecoder("utf-8", { ignoreBOM: true });
|
|
863
|
+
|
|
864
|
+
/**
|
|
865
|
+
* A SWF 5 string, its bytes, as Flash's log writes it: read as UTF-8, what
|
|
866
|
+
* is not UTF-8 as U+FFFD, as the encoding standard's decoder has it (adl's
|
|
867
|
+
* replacements agree). A character past a byte, from code of a later
|
|
868
|
+
* version, is its UTF-8.
|
|
869
|
+
*/
|
|
870
|
+
function bytesAsUtf8(text: string): string {
|
|
871
|
+
if (ascii.test(text)) {
|
|
872
|
+
return text;
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
const bytes: number[] = [];
|
|
876
|
+
for (const c of text) {
|
|
877
|
+
const code = c.codePointAt(0) as number;
|
|
878
|
+
if (code <= 0xff) {
|
|
879
|
+
bytes.push(code);
|
|
880
|
+
} else {
|
|
881
|
+
bytes.push(...encoder.encode(c));
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
return decoder.decode(new Uint8Array(bytes));
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
/** InitObject's and InitArray's count: truncated, then -1 where it is not an int from 0 (adl). */
|
|
889
|
+
function countOf(value: Value, version: number): number {
|
|
890
|
+
const n = Math.trunc(toNumber(value, version));
|
|
891
|
+
return n >= 0 && n <= 0x7fffffff ? n : -1;
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
/**
|
|
895
|
+
* A call's arguments, their count on top and the first argument under it:
|
|
896
|
+
* as many as the stack has, the count taken as a u32.
|
|
897
|
+
*/
|
|
898
|
+
function popArgs(st: Value[], version: number): Value[] {
|
|
899
|
+
const n = Math.min(toNumber(st.pop(), version) >>> 0, st.length);
|
|
900
|
+
const args: Value[] = new Array(n);
|
|
901
|
+
for (let i = 0; i < n; i++) {
|
|
902
|
+
args[i] = st.pop();
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
return args;
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
function defineFunction(
|
|
909
|
+
cx: Activation,
|
|
910
|
+
region: number,
|
|
911
|
+
name: Value,
|
|
912
|
+
params: (string | null)[],
|
|
913
|
+
flags: number,
|
|
914
|
+
version: number,
|
|
915
|
+
): void {
|
|
916
|
+
const fn = cx.realm.newFunction(cx, cx.code[region], params, flags, version);
|
|
917
|
+
const key = nameOf(name, version);
|
|
918
|
+
if (key === "") {
|
|
919
|
+
cx.st.push(fn);
|
|
920
|
+
return;
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
// A SWF 5 function's named function is its clip's, not a local variable (adl).
|
|
924
|
+
if (version < 6 && cx.callee !== null) {
|
|
925
|
+
let s: Scope | null = cx.scope;
|
|
926
|
+
while (s !== null && s.kind !== SCOPE_Target) {
|
|
927
|
+
s = s.parent;
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
if (s !== null) {
|
|
931
|
+
set(s.object, key, fn, version);
|
|
932
|
+
return;
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
defineLocal(cx, key, fn, version);
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
/**
|
|
940
|
+
* CallMethod of `super`: `super()` its prototype's `__constructor__` on
|
|
941
|
+
* `this`, `super.name()` the method above the one running, with its `this`.
|
|
942
|
+
*/
|
|
943
|
+
function superCall(zuper: Avm1Super, key: string, args: Value[], version: number): Value {
|
|
944
|
+
if (key === "") {
|
|
945
|
+
let base: Value = zuper.self;
|
|
946
|
+
for (let i = 0; i < zuper.depth && base instanceof Avm1Object; i++) {
|
|
947
|
+
base = base.protoFor(version);
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
if (!(base instanceof Avm1Object)) {
|
|
951
|
+
return undefined;
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
const constr = get(base, "__constructor__", version, base, false);
|
|
955
|
+
if (constr instanceof Avm1Function) {
|
|
956
|
+
return constr.callConstructor(zuper.self, args, version, zuper.depth + 1);
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
return undefined;
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
const proto = zuper.proto;
|
|
963
|
+
if (!(proto instanceof Avm1Object)) {
|
|
964
|
+
return undefined;
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
const method = get(proto, key, version, zuper.self);
|
|
968
|
+
// Up to SWF 6 the method's `super` is one above this one's, wherever it was found (adl).
|
|
969
|
+
const depth = zuper.depth + (version < 7 ? 0 : foundDepth) + 1;
|
|
970
|
+
return invoke(method, zuper.self, args, version, depth);
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
/** Enumerate's and Enumerate2's pushes: a terminator, then the names, the first to visit on top. */
|
|
974
|
+
function enumerate(cx: Activation, object: Value, version: number): void {
|
|
975
|
+
const st = cx.st;
|
|
976
|
+
st.push(undefined);
|
|
977
|
+
if (object instanceof Avm1Object) {
|
|
978
|
+
const names = keys(object, version);
|
|
979
|
+
for (let i = names.length - 1; i >= 0; i--) {
|
|
980
|
+
st.push(names[i]);
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
/**
|
|
986
|
+
* Whether `error` is the engine's own stack running out: V8's and
|
|
987
|
+
* JavaScriptCore's RangeError, SpiderMonkey's InternalError. Any other
|
|
988
|
+
* RangeError, such as a string grown past the engine's longest, is an
|
|
989
|
+
* error like the rest.
|
|
990
|
+
*/
|
|
991
|
+
function stackOverflow(error: unknown): boolean {
|
|
992
|
+
return (
|
|
993
|
+
error instanceof Error &&
|
|
994
|
+
(error.name === "RangeError" || error.name === "InternalError") &&
|
|
995
|
+
/call stack|recursion/i.test(error.message)
|
|
996
|
+
);
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
/** Units of a region alone, by the numbers V.far is called with. */
|
|
1000
|
+
export class OwnUnits<T> {
|
|
1001
|
+
private readonly byEnd = new Map<number, Map<number, Map<number, T>>>();
|
|
1002
|
+
|
|
1003
|
+
get(at: number, end: number, bound: number, five: boolean): T | undefined {
|
|
1004
|
+
return this.byEnd
|
|
1005
|
+
.get(end)
|
|
1006
|
+
?.get(bound)
|
|
1007
|
+
?.get(at * 2 + (five ? 1 : 0));
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
set(at: number, end: number, bound: number, five: boolean, unit: T): void {
|
|
1011
|
+
let byBound = this.byEnd.get(end);
|
|
1012
|
+
if (byBound === undefined) {
|
|
1013
|
+
byBound = new Map();
|
|
1014
|
+
this.byEnd.set(end, byBound);
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
let byAt = byBound.get(bound);
|
|
1018
|
+
if (byAt === undefined) {
|
|
1019
|
+
byAt = new Map();
|
|
1020
|
+
byBound.set(bound, byAt);
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
byAt.set(at * 2 + (five ? 1 : 0), unit);
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
/**
|
|
1028
|
+
* What a module's `units` export gives: by key, a unit's regions and how
|
|
1029
|
+
* far a region's end and its bytes' end must reach for it to run for that
|
|
1030
|
+
* region, -1 for only the one its key names (codegen's emit/module.ts).
|
|
1031
|
+
*/
|
|
1032
|
+
export type UnitTable = Record<string, [Region[], number, number]>;
|
|
1033
|
+
|
|
1034
|
+
/** The operations of each version asked for, made once and shared by every runtime. */
|
|
1035
|
+
const versions = new Map<number, Operations>();
|
|
1036
|
+
|
|
1037
|
+
/** A player's AVM1 runtime, which its SWFs' modules are loaded into. */
|
|
1038
|
+
export class Runtime {
|
|
1039
|
+
/** The builtins and `_global`, which every SWF the player runs shares. */
|
|
1040
|
+
readonly realm = new Realm();
|
|
1041
|
+
/**
|
|
1042
|
+
* Whether the movie's actions are disabled, as Flash disables them past
|
|
1043
|
+
* its recursion limit: no action of it runs again, its timelines play on.
|
|
1044
|
+
*/
|
|
1045
|
+
disabled = false;
|
|
1046
|
+
/** Whether that was the script timeout's doing. */
|
|
1047
|
+
timedOut = false;
|
|
1048
|
+
|
|
1049
|
+
/** How deep function calls may go: a SWF's ScriptLimits sets it (Flash's default 1000, adl's). */
|
|
1050
|
+
get maxRecursion(): number {
|
|
1051
|
+
return this.realm.maxCalls;
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
set maxRecursion(depth: number) {
|
|
1055
|
+
this.realm.maxCalls = depth;
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
/**
|
|
1059
|
+
* How long, in seconds, a frame's actions may run before Flash offers to
|
|
1060
|
+
* stop them: a SWF's ScriptLimits sets it (Flash's default 15). Past
|
|
1061
|
+
* it, the movie's actions are disabled, as Flash's are once stopped.
|
|
1062
|
+
*/
|
|
1063
|
+
get scriptTimeout(): number {
|
|
1064
|
+
return this.timeout;
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
/**
|
|
1068
|
+
* Set while scripts run, as a ScriptLimits their gotos reach is, it
|
|
1069
|
+
* counts from when they began, not from now: gotos that enter its
|
|
1070
|
+
* frame again and again still run into it.
|
|
1071
|
+
*/
|
|
1072
|
+
set scriptTimeout(seconds: number) {
|
|
1073
|
+
this.timeout = seconds;
|
|
1074
|
+
if (this.realm.deadline !== Number.POSITIVE_INFINITY) {
|
|
1075
|
+
this.realm.deadline = this.began + seconds * 1000;
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
private timeout = 15;
|
|
1080
|
+
/** When the scripts running began, on the player's clock. */
|
|
1081
|
+
private began = 0;
|
|
1082
|
+
|
|
1083
|
+
/**
|
|
1084
|
+
* The player starts running scripts, a frame's or its timers', at `now`
|
|
1085
|
+
* on its clock, `clock`: they have the script timeout from there.
|
|
1086
|
+
*/
|
|
1087
|
+
begin(now: number, clock: () => number): void {
|
|
1088
|
+
this.began = now;
|
|
1089
|
+
this.realm.clock = clock;
|
|
1090
|
+
this.realm.deadline = now + this.timeout * 1000;
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
/** The player's scripts are done until it begins again. */
|
|
1094
|
+
end(): void {
|
|
1095
|
+
this.realm.deadline = Number.POSITIVE_INFINITY;
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
/**
|
|
1099
|
+
* A module's blocks, as its default export gave them, and the units its
|
|
1100
|
+
* `units` export gave, if it has them: V.far finds their units there.
|
|
1101
|
+
*/
|
|
1102
|
+
adoptUnits(blocks: Blocks, table: UnitTable): void {
|
|
1103
|
+
// By numbers, as V.far asks, not by the keys' text.
|
|
1104
|
+
const first = new Map<number, [Region[], number, number]>();
|
|
1105
|
+
const own = new OwnUnits<Region[]>();
|
|
1106
|
+
const known = this.realm.units;
|
|
1107
|
+
for (const key in table) {
|
|
1108
|
+
const entry = table[key];
|
|
1109
|
+
const [at, a, b, c] = key.split(",").map(Number);
|
|
1110
|
+
if (b === undefined) {
|
|
1111
|
+
first.set(at * 2 + a, entry);
|
|
1112
|
+
} else {
|
|
1113
|
+
own.set(at, a, b, c !== 0, entry[0]);
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
const units: Units = {
|
|
1118
|
+
blocks,
|
|
1119
|
+
unit(at, end, bound, five) {
|
|
1120
|
+
const entry = first.get(at * 2 + (five ? 1 : 0));
|
|
1121
|
+
if (entry !== undefined && entry[1] >= 0 && entry[1] <= end && entry[2] <= bound) {
|
|
1122
|
+
return entry[0];
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
const regions = own.get(at, end, bound, five);
|
|
1126
|
+
if (regions === undefined) {
|
|
1127
|
+
throw new Error(`swf2es: no AVM1 unit at ${at}`);
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
return regions;
|
|
1131
|
+
},
|
|
1132
|
+
};
|
|
1133
|
+
for (const regions of blocks) {
|
|
1134
|
+
known.set(regions, units);
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
for (const key in table) {
|
|
1138
|
+
known.set(table[key][0], units);
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
/**
|
|
1143
|
+
* Run a block's own region, `regions[0]`, in `cx`. A value thrown and
|
|
1144
|
+
* not caught ends the block, as Flash ends it, writing nothing. Past the
|
|
1145
|
+
* recursion limit or the script timeout, or where JavaScript's own stack
|
|
1146
|
+
* runs out first, the movie's actions are disabled from there.
|
|
1147
|
+
*/
|
|
1148
|
+
run(regions: Region[], cx: Activation): void {
|
|
1149
|
+
if (regions.length === 0) {
|
|
1150
|
+
return;
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
cx.code = regions;
|
|
1154
|
+
this.call(cx, () => regions[0](cx));
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
/**
|
|
1158
|
+
* Run `body` in `cx`, as a block runs: what the player calls into AVM1
|
|
1159
|
+
* other than a block, an event's method, a class's constructor, a
|
|
1160
|
+
* timer's callback, which the limits and an uncaught throw end alike.
|
|
1161
|
+
*/
|
|
1162
|
+
call(cx: Activation, body: () => void): void {
|
|
1163
|
+
if (this.disabled) {
|
|
1164
|
+
return;
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
// The block is a level of the limit itself: a depth of 1 or 0 runs nothing (adl).
|
|
1168
|
+
const realm = this.realm;
|
|
1169
|
+
if (realm.maxCalls <= 1) {
|
|
1170
|
+
this.disabled = true;
|
|
1171
|
+
return;
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
const outer = realm.current;
|
|
1175
|
+
const calls = realm.calls;
|
|
1176
|
+
realm.current = cx;
|
|
1177
|
+
try {
|
|
1178
|
+
body();
|
|
1179
|
+
} catch (error) {
|
|
1180
|
+
if (error instanceof Avm1Throw || error === BASE_REMOVED) {
|
|
1181
|
+
return;
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
if (!(error instanceof Disabled || stackOverflow(error))) {
|
|
1185
|
+
throw error;
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
this.disabled = true;
|
|
1189
|
+
this.timedOut ||= error instanceof TimedOut;
|
|
1190
|
+
} finally {
|
|
1191
|
+
realm.current = outer;
|
|
1192
|
+
realm.calls = calls;
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
/**
|
|
1197
|
+
* `object`'s method `name` called with `args`, as Flash calls an event's
|
|
1198
|
+
* (`onEnterFrame`...) and a timer's: found without `__resolve`, nothing
|
|
1199
|
+
* where it is no function.
|
|
1200
|
+
*/
|
|
1201
|
+
callMethod(
|
|
1202
|
+
cx: Activation,
|
|
1203
|
+
object: Avm1Object,
|
|
1204
|
+
name: string,
|
|
1205
|
+
args: Value[],
|
|
1206
|
+
version: number,
|
|
1207
|
+
): void {
|
|
1208
|
+
this.call(cx, () => {
|
|
1209
|
+
const method = get(object, name, version, object, false);
|
|
1210
|
+
invoke(method, object, args, version, Math.max(foundDepth, 1));
|
|
1211
|
+
});
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
/**
|
|
1215
|
+
* Fire the timers due by `time` on the player's clock, the earliest
|
|
1216
|
+
* first, at most `MAX_TICKS` of them, each in the activation `cx` gives
|
|
1217
|
+
* (the root's), `after` running what each queued; while one runs, the
|
|
1218
|
+
* clock reads its time.
|
|
1219
|
+
*/
|
|
1220
|
+
fireTimers(
|
|
1221
|
+
time: number,
|
|
1222
|
+
version: number,
|
|
1223
|
+
cx: () => Activation | null,
|
|
1224
|
+
after: () => void,
|
|
1225
|
+
removed: (object: Avm1Object) => boolean,
|
|
1226
|
+
): void {
|
|
1227
|
+
const timers = this.realm.timers;
|
|
1228
|
+
for (let ticks = 0; ticks < MAX_TICKS && !this.disabled; ticks++) {
|
|
1229
|
+
const timer = timers.due(time);
|
|
1230
|
+
if (timer === null) {
|
|
1231
|
+
break;
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
timers.now = timer.due;
|
|
1235
|
+
timers.fired(timer);
|
|
1236
|
+
// A method's object a removed clip: the timer stops, as Ruffle has it.
|
|
1237
|
+
if (timer.method !== null && removed(timer.callback)) {
|
|
1238
|
+
timers.remove(timer.id);
|
|
1239
|
+
continue;
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
const activation = cx();
|
|
1243
|
+
if (activation !== null) {
|
|
1244
|
+
if (timer.method === null) {
|
|
1245
|
+
this.call(activation, () => {
|
|
1246
|
+
invoke(timer.callback, undefined, timer.args, version);
|
|
1247
|
+
});
|
|
1248
|
+
} else {
|
|
1249
|
+
this.callMethod(activation, timer.callback, timer.method, timer.args, version);
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
after();
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
timers.now = time;
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
/** A new object, as `{}` makes one: what the player gives a clip until clips have their class. */
|
|
1260
|
+
newObject(): Avm1Object {
|
|
1261
|
+
return new Avm1Object(this.realm.objectProto);
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
/**
|
|
1265
|
+
* An activation of a timeline's code: `clip`, the target's AVM1 object,
|
|
1266
|
+
* above `_global` on the scope chain, and `this`.
|
|
1267
|
+
*/
|
|
1268
|
+
activation(st: Value[], pool: Value[], target: Target, clip: Avm1Object, host: Host): Activation {
|
|
1269
|
+
return new Activation(
|
|
1270
|
+
st,
|
|
1271
|
+
pool,
|
|
1272
|
+
target,
|
|
1273
|
+
host,
|
|
1274
|
+
this.realm,
|
|
1275
|
+
new Scope(this.realm.globalScope, SCOPE_Target, clip),
|
|
1276
|
+
clip,
|
|
1277
|
+
clip,
|
|
1278
|
+
);
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
/** The operations of SWF version `version`. */
|
|
1282
|
+
version(version: number): Operations {
|
|
1283
|
+
let ops = versions.get(version);
|
|
1284
|
+
if (!ops) {
|
|
1285
|
+
ops = operations(version);
|
|
1286
|
+
versions.set(version, ops);
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
return ops;
|
|
1290
|
+
}
|
|
1291
|
+
}
|