@swf2es/runtime 0.1.19 → 0.1.21

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.
Files changed (64) hide show
  1. package/dist/avm2/amf.d.ts +1 -1
  2. package/dist/avm2/amf.d.ts.map +1 -1
  3. package/dist/avm2/amf.js +1 -1
  4. package/dist/avm2/amf.js.map +1 -1
  5. package/dist/avm2/enumeration.d.ts +1 -19
  6. package/dist/avm2/enumeration.d.ts.map +1 -1
  7. package/dist/avm2/enumeration.js +1 -51
  8. package/dist/avm2/enumeration.js.map +1 -1
  9. package/dist/avm2/errors.d.ts +2 -0
  10. package/dist/avm2/errors.d.ts.map +1 -1
  11. package/dist/avm2/errors.js +40 -2
  12. package/dist/avm2/errors.js.map +1 -1
  13. package/dist/avm2/index.d.ts +3 -1
  14. package/dist/avm2/index.d.ts.map +1 -1
  15. package/dist/avm2/index.js +3 -1
  16. package/dist/avm2/index.js.map +1 -1
  17. package/dist/avm2/natives/aliases.js +1 -1
  18. package/dist/avm2/natives/aliases.js.map +1 -1
  19. package/dist/avm2/natives/bytearray.d.ts +0 -154
  20. package/dist/avm2/natives/bytearray.d.ts.map +1 -1
  21. package/dist/avm2/natives/bytearray.js +1 -495
  22. package/dist/avm2/natives/bytearray.js.map +1 -1
  23. package/dist/avm2/natives/bytes.d.ts +141 -0
  24. package/dist/avm2/natives/bytes.d.ts.map +1 -0
  25. package/dist/avm2/natives/bytes.js +458 -0
  26. package/dist/avm2/natives/bytes.js.map +1 -0
  27. package/dist/avm2/natives/concurrent.js +1 -1
  28. package/dist/avm2/natives/concurrent.js.map +1 -1
  29. package/dist/avm2/natives/shared-bytes.d.ts +45 -0
  30. package/dist/avm2/natives/shared-bytes.d.ts.map +1 -0
  31. package/dist/avm2/natives/shared-bytes.js +52 -0
  32. package/dist/avm2/natives/shared-bytes.js.map +1 -0
  33. package/dist/avm2/natives/shell.d.ts.map +1 -1
  34. package/dist/avm2/natives/shell.js +3 -1
  35. package/dist/avm2/natives/shell.js.map +1 -1
  36. package/dist/avm2/options.d.ts +1 -1
  37. package/dist/avm2/options.d.ts.map +1 -1
  38. package/dist/avm2/runtime-xml.d.ts +11 -0
  39. package/dist/avm2/runtime-xml.d.ts.map +1 -0
  40. package/dist/avm2/runtime-xml.js +44 -0
  41. package/dist/avm2/runtime-xml.js.map +1 -0
  42. package/dist/avm2/runtime.d.ts +5 -13
  43. package/dist/avm2/runtime.d.ts.map +1 -1
  44. package/dist/avm2/runtime.js +17 -67
  45. package/dist/avm2/runtime.js.map +1 -1
  46. package/dist/avm2/sparse-indices.d.ts +34 -0
  47. package/dist/avm2/sparse-indices.d.ts.map +1 -0
  48. package/dist/avm2/sparse-indices.js +54 -0
  49. package/dist/avm2/sparse-indices.js.map +1 -0
  50. package/package.json +2 -2
  51. package/src/avm2/amf.ts +1 -1
  52. package/src/avm2/enumeration.ts +1 -76
  53. package/src/avm2/errors.ts +48 -3
  54. package/src/avm2/index.ts +9 -12
  55. package/src/avm2/natives/aliases.ts +1 -1
  56. package/src/avm2/natives/bytearray.ts +1 -604
  57. package/src/avm2/natives/bytes.ts +543 -0
  58. package/src/avm2/natives/concurrent.ts +1 -1
  59. package/src/avm2/natives/shared-bytes.ts +99 -0
  60. package/src/avm2/natives/shell.ts +3 -8
  61. package/src/avm2/options.ts +1 -1
  62. package/src/avm2/runtime-xml.ts +54 -0
  63. package/src/avm2/runtime.ts +31 -78
  64. package/src/avm2/sparse-indices.ts +80 -0
@@ -0,0 +1,54 @@
1
+ // What E4X's opcodes ask of the runtime: getdescendants, dxns and
2
+ // dxnslate, checkfilter and esc_xelem, the bodies of Runtime's
3
+ // getDescendants, setDefaultXmlNamespace, checkFilter and escapeElement.
4
+ // XML and XMLList answer through their property hook (natives/xml).
5
+
6
+ import type { Value } from "./descriptors.js";
7
+ import type { PropertyHook } from "./hooks.js";
8
+ import { type Multiname, Namespace, prefixedNamespace } from "./names.js";
9
+ import { escapeElementValue } from "./natives/xml/escape.js";
10
+ import type { Runtime } from "./runtime.js";
11
+
12
+ /** getdescendants: x..name, on XML or XMLList; anything else, as avmplus, TypeError 1016. */
13
+ export function getDescendants(rt: Runtime, o: Value, mn: Multiname): Value {
14
+ const properties: PropertyHook | null | undefined = o?.$traits?.properties;
15
+ if (!properties) {
16
+ throw rt.error("TypeError", 1016, rt.describe(o));
17
+ }
18
+
19
+ return properties.descendants(rt, o, mn);
20
+ }
21
+
22
+ export function setDefaultXmlNamespace(rt: Runtime, ns: Value): void {
23
+ if (ns instanceof Namespace) {
24
+ rt.defaultXmlNamespace = ns;
25
+ } else {
26
+ const uri = rt.toString(ns);
27
+ rt.defaultXmlNamespace = prefixedNamespace(uri === "" ? "" : undefined, uri);
28
+ }
29
+ }
30
+
31
+ /** checkfilter: x.(...) filters XML and XMLList only, else TypeError 1123. */
32
+ export function checkFilter(rt: Runtime, v: Value): void {
33
+ if (!v?.$traits?.properties) {
34
+ throw rt.error("TypeError", 1123, rt.describe(v));
35
+ }
36
+ }
37
+
38
+ /** esc_xelem, as AvmCore::ToXMLString: XML's own XML, else a string escaped and trimmed. */
39
+ export function escapeElement(rt: Runtime, v: Value): string {
40
+ if (typeof v === "string") {
41
+ return escapeElementValue(v, true);
42
+ }
43
+
44
+ if (typeof v !== "object" || v === null) {
45
+ return rt.toString(v);
46
+ }
47
+
48
+ const properties: PropertyHook | null | undefined = v.$traits?.properties;
49
+ if (properties) {
50
+ return properties.toXMLString(rt, v);
51
+ }
52
+
53
+ return escapeElementValue(rt.toString(v), true);
54
+ }
@@ -52,7 +52,15 @@ import {
52
52
  traitsAt,
53
53
  walkless,
54
54
  } from "./enumeration.js";
55
- import { AsError, describe, detailOf, errorMessage, stackOf, UnsupportedError } from "./errors.js";
55
+ import {
56
+ AsError,
57
+ caught,
58
+ describe,
59
+ detailOf,
60
+ errorMessage,
61
+ stackOf,
62
+ UnsupportedError,
63
+ } from "./errors.js";
56
64
  import { FloatValue, floatValue } from "./float.js";
57
65
  import { type ClassHook, hookedBinding, type NativesProvider, type PropertyHook } from "./hooks.js";
58
66
  import {
@@ -82,7 +90,6 @@ import {
82
90
  NS_Private,
83
91
  NS_Public,
84
92
  namespace,
85
- prefixedNamespace,
86
93
  prefixOf,
87
94
  publicNs,
88
95
  publicQname,
@@ -97,7 +104,7 @@ import {
97
104
  storeInt,
98
105
  storeObject,
99
106
  } from "./natives/vector-elements.js";
100
- import { escapeAttributeValue, escapeElementValue } from "./natives/xml/escape.js";
107
+ import { escapeAttributeValue } from "./natives/xml/escape.js";
101
108
  import { numberToString, stringToNumber } from "./number-strings.js";
102
109
  import {
103
110
  defaultPrint,
@@ -123,6 +130,12 @@ import {
123
130
  ScopeFinds,
124
131
  UNFILLED,
125
132
  } from "./property-cache.js";
133
+ import {
134
+ checkFilter,
135
+ escapeElement,
136
+ getDescendants,
137
+ setDefaultXmlNamespace,
138
+ } from "./runtime-xml.js";
126
139
  import {
127
140
  BIND_Const,
128
141
  BIND_Get,
@@ -201,7 +214,8 @@ function dynamicValue(o: AsObject, name: string): Value {
201
214
  export class Runtime {
202
215
  readonly print: (line: string) => void;
203
216
  readonly debugger: boolean;
204
- private readonly onUnsupported: ((message: string) => void) | undefined;
217
+ /** @internal */
218
+ readonly onUnsupported: ((message: string) => void) | undefined;
205
219
  readonly compileAbc:
206
220
  | ((abc: Uint8Array, unit: CompileUnit) => ((rt: Runtime) => Abc) | number)
207
221
  | null;
@@ -3515,51 +3529,14 @@ export class Runtime {
3515
3529
  return describe(this, v);
3516
3530
  }
3517
3531
 
3518
- /** An exception as AS3 catches it: a stack overflow is an AS3 Error; the runtime's own errors are not caught. */
3532
+ /** See caught in errors.ts. */
3519
3533
  caught(e: unknown): Value {
3520
- if (e instanceof RangeError && /call stack/.test(e.message)) {
3521
- return this.error("Error", 1023);
3522
- }
3523
-
3524
- // Domain memory's, in the handler's own method (see memoryError).
3525
- if (isViewRangeError(e)) {
3526
- return this.error("RangeError", 1506);
3527
- }
3528
-
3529
- if (e instanceof UnsupportedError) {
3530
- return this.unsupportedCaught(e);
3531
- }
3532
-
3533
- if (e instanceof Error && !(e instanceof AsError)) {
3534
- throw e;
3535
- }
3536
-
3537
- return e;
3534
+ return caught(this, e);
3538
3535
  }
3539
3536
 
3540
- /** What a catch was told of already (unsupportedCaught). */
3541
- private readonly unsupportedTold = new Set<string>();
3542
-
3543
- /**
3544
- * What is not supported as the AS3 error a catch gets: an
3545
- * IllegalOperationError with its message, or an Error where the player's
3546
- * classes are not loaded; said once to the host, as the code may say nothing.
3547
- */
3548
- private unsupportedCaught(e: UnsupportedError): Value {
3549
- if (!this.unsupportedTold.has(e.message)) {
3550
- this.unsupportedTold.add(e.message);
3551
- this.onUnsupported?.(e.message);
3552
- }
3553
-
3554
- let cls: AsObject;
3555
- try {
3556
- cls = this.resolve(this.cls(namespace(NS_Public, "flash.errors"), "IllegalOperationError"));
3557
- } catch {
3558
- cls = this.builtinClass("Error");
3559
- }
3560
-
3561
- return this.constructClass(cls, [e.message, 0]);
3562
- }
3537
+ /** What a catch was told of already (unsupportedCaught in errors.ts). */
3538
+ /** @internal */
3539
+ readonly unsupportedTold = new Set<string>();
3563
3540
 
3564
3541
  catches(e: Value, type: TypeRef): boolean {
3565
3542
  return this.isInstanceOf(e, this.traitsOfType(type));
@@ -3721,14 +3698,9 @@ export class Runtime {
3721
3698
 
3722
3699
  // E4X.
3723
3700
 
3724
- /** getdescendants: x..name, on XML or XMLList; anything else, as avmplus, TypeError 1016. */
3701
+ /** See getDescendants in runtime-xml.ts. */
3725
3702
  getDescendants(o: Value, mn: Multiname): Value {
3726
- const properties: PropertyHook | null | undefined = o?.$traits?.properties;
3727
- if (!properties) {
3728
- throw this.error("TypeError", 1016, this.describe(o));
3729
- }
3730
-
3731
- return properties.descendants(this, o, mn);
3703
+ return getDescendants(this, o, mn);
3732
3704
  }
3733
3705
 
3734
3706
  /**
@@ -3745,38 +3717,19 @@ export class Runtime {
3745
3717
  return this.defaultXmlNamespace;
3746
3718
  }
3747
3719
 
3720
+ /** See setDefaultXmlNamespace in runtime-xml.ts. */
3748
3721
  setDefaultXmlNamespace(ns: Value): void {
3749
- if (ns instanceof Namespace) {
3750
- this.defaultXmlNamespace = ns;
3751
- } else {
3752
- const uri = this.toString(ns);
3753
- this.defaultXmlNamespace = prefixedNamespace(uri === "" ? "" : undefined, uri);
3754
- }
3722
+ setDefaultXmlNamespace(this, ns);
3755
3723
  }
3756
3724
 
3757
- /** checkfilter: x.(...) filters XML and XMLList only, else TypeError 1123. */
3725
+ /** See checkFilter in runtime-xml.ts. */
3758
3726
  checkFilter(v: Value): void {
3759
- if (!v?.$traits?.properties) {
3760
- throw this.error("TypeError", 1123, this.describe(v));
3761
- }
3727
+ checkFilter(this, v);
3762
3728
  }
3763
3729
 
3764
- /** esc_xelem, as AvmCore::ToXMLString: XML's own XML, else a string escaped and trimmed. */
3730
+ /** See escapeElement in runtime-xml.ts. */
3765
3731
  escapeElement(v: Value): string {
3766
- if (typeof v === "string") {
3767
- return escapeElementValue(v, true);
3768
- }
3769
-
3770
- if (typeof v !== "object" || v === null) {
3771
- return this.toString(v);
3772
- }
3773
-
3774
- const properties: PropertyHook | null | undefined = v.$traits?.properties;
3775
- if (properties) {
3776
- return properties.toXMLString(this, v);
3777
- }
3778
-
3779
- return escapeElementValue(this.toString(v), true);
3732
+ return escapeElement(this, v);
3780
3733
  }
3781
3734
 
3782
3735
  escapeAttribute(v: Value): string {
@@ -0,0 +1,80 @@
1
+ // A sparse Array's indices, in order, which a for-in over it crosses each
2
+ // gap by (enumeration.ts): the list, and how it is taken and searched.
3
+
4
+ import type { Value } from "./descriptors.js";
5
+
6
+ /**
7
+ * The indices of a sparse Array, in order, taken when a for-in first meets
8
+ * a run of holes too long to step through, so that it crosses each gap by
9
+ * them, and dropped when the for-in ends or another starts.
10
+ */
11
+ export interface SparseIndices {
12
+ indices: number[];
13
+ /** The Array's length when they were last brought up to it. */
14
+ length: number;
15
+ /** Where in them the index last given is, and that index, so that the next step goes on from there. */
16
+ at: number;
17
+ given: number;
18
+ /** How many were given since they were taken, and whether they were taken again since this for-in met them. */
19
+ sinceTaken: number;
20
+ retaken: boolean;
21
+ /** Whether avmplus holds the Array's elements in its hashtable (see hashed). */
22
+ hashed: boolean;
23
+ }
24
+
25
+ /** Take a sparse Array's indices again. */
26
+ export function retake(a: Value[], sparse: SparseIndices): void {
27
+ sparse.indices = indicesOf(a, 0);
28
+ sparse.length = a.length;
29
+ sparse.at = -1;
30
+ sparse.given = -1;
31
+ sparse.sinceTaken = 0;
32
+ // An Array in avmplus' hashtable never leaves it.
33
+ sparse.hashed ||= hashed(sparse.indices);
34
+ }
35
+
36
+ /**
37
+ * Whether avmplus holds an Array with these elements in its hashtable, as
38
+ * it must when they span more than 32 slots and more than four times one
39
+ * more than their count (ArrayObject's shouldBeSparse): its dense part
40
+ * never holds so few over so many. Else avmplus may hold them dense,
41
+ * walking them by index, as the for-in here does.
42
+ */
43
+ export function hashed(indices: number[]): boolean {
44
+ const n = indices.length;
45
+ if (n === 0) {
46
+ return false;
47
+ }
48
+
49
+ const span = indices[n - 1] - indices[0] + 1;
50
+ return span > 32 && span > (n + 1) * 4;
51
+ }
52
+
53
+ /** An Array's indices from `from` on, in order, as Object.keys gives them, appended to `indices`. */
54
+ export function indicesOf(a: Value[], from: number, indices: number[] = []): number[] {
55
+ const keys = Object.keys(a);
56
+ for (let k = 0; k < keys.length; k++) {
57
+ const i = Number(keys[k]);
58
+ if (i >= from) {
59
+ indices.push(i);
60
+ }
61
+ }
62
+
63
+ return indices;
64
+ }
65
+
66
+ /** Where in `indices`, in order, the first at or after `from` is. */
67
+ export function firstAtOrAfter(indices: number[], from: number): number {
68
+ let low = 0;
69
+ let high = indices.length;
70
+ while (low < high) {
71
+ const mid = (low + high) >>> 1;
72
+ if (indices[mid] < from) {
73
+ low = mid + 1;
74
+ } else {
75
+ high = mid;
76
+ }
77
+ }
78
+
79
+ return low;
80
+ }