@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.
- package/dist/avm2/amf.d.ts +1 -1
- package/dist/avm2/amf.d.ts.map +1 -1
- package/dist/avm2/amf.js +1 -1
- package/dist/avm2/amf.js.map +1 -1
- package/dist/avm2/enumeration.d.ts +1 -19
- package/dist/avm2/enumeration.d.ts.map +1 -1
- package/dist/avm2/enumeration.js +1 -51
- package/dist/avm2/enumeration.js.map +1 -1
- package/dist/avm2/errors.d.ts +2 -0
- package/dist/avm2/errors.d.ts.map +1 -1
- package/dist/avm2/errors.js +40 -2
- package/dist/avm2/errors.js.map +1 -1
- package/dist/avm2/index.d.ts +3 -1
- package/dist/avm2/index.d.ts.map +1 -1
- package/dist/avm2/index.js +3 -1
- package/dist/avm2/index.js.map +1 -1
- package/dist/avm2/natives/aliases.js +1 -1
- package/dist/avm2/natives/aliases.js.map +1 -1
- package/dist/avm2/natives/bytearray.d.ts +0 -154
- package/dist/avm2/natives/bytearray.d.ts.map +1 -1
- package/dist/avm2/natives/bytearray.js +1 -495
- package/dist/avm2/natives/bytearray.js.map +1 -1
- package/dist/avm2/natives/bytes.d.ts +141 -0
- package/dist/avm2/natives/bytes.d.ts.map +1 -0
- package/dist/avm2/natives/bytes.js +458 -0
- package/dist/avm2/natives/bytes.js.map +1 -0
- package/dist/avm2/natives/concurrent.js +1 -1
- package/dist/avm2/natives/concurrent.js.map +1 -1
- package/dist/avm2/natives/shared-bytes.d.ts +45 -0
- package/dist/avm2/natives/shared-bytes.d.ts.map +1 -0
- package/dist/avm2/natives/shared-bytes.js +52 -0
- package/dist/avm2/natives/shared-bytes.js.map +1 -0
- package/dist/avm2/natives/shell.d.ts.map +1 -1
- package/dist/avm2/natives/shell.js +3 -1
- package/dist/avm2/natives/shell.js.map +1 -1
- package/dist/avm2/options.d.ts +1 -1
- package/dist/avm2/options.d.ts.map +1 -1
- package/dist/avm2/runtime-xml.d.ts +11 -0
- package/dist/avm2/runtime-xml.d.ts.map +1 -0
- package/dist/avm2/runtime-xml.js +44 -0
- package/dist/avm2/runtime-xml.js.map +1 -0
- package/dist/avm2/runtime.d.ts +5 -13
- package/dist/avm2/runtime.d.ts.map +1 -1
- package/dist/avm2/runtime.js +17 -67
- package/dist/avm2/runtime.js.map +1 -1
- package/dist/avm2/sparse-indices.d.ts +34 -0
- package/dist/avm2/sparse-indices.d.ts.map +1 -0
- package/dist/avm2/sparse-indices.js +54 -0
- package/dist/avm2/sparse-indices.js.map +1 -0
- package/package.json +2 -2
- package/src/avm2/amf.ts +1 -1
- package/src/avm2/enumeration.ts +1 -76
- package/src/avm2/errors.ts +48 -3
- package/src/avm2/index.ts +9 -12
- package/src/avm2/natives/aliases.ts +1 -1
- package/src/avm2/natives/bytearray.ts +1 -604
- package/src/avm2/natives/bytes.ts +543 -0
- package/src/avm2/natives/concurrent.ts +1 -1
- package/src/avm2/natives/shared-bytes.ts +99 -0
- package/src/avm2/natives/shell.ts +3 -8
- package/src/avm2/options.ts +1 -1
- package/src/avm2/runtime-xml.ts +54 -0
- package/src/avm2/runtime.ts +31 -78
- 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
|
+
}
|
package/src/avm2/runtime.ts
CHANGED
|
@@ -52,7 +52,15 @@ import {
|
|
|
52
52
|
traitsAt,
|
|
53
53
|
walkless,
|
|
54
54
|
} from "./enumeration.js";
|
|
55
|
-
import {
|
|
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
|
|
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
|
-
|
|
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
|
-
/**
|
|
3532
|
+
/** See caught in errors.ts. */
|
|
3519
3533
|
caught(e: unknown): Value {
|
|
3520
|
-
|
|
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
|
-
|
|
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
|
-
/**
|
|
3701
|
+
/** See getDescendants in runtime-xml.ts. */
|
|
3725
3702
|
getDescendants(o: Value, mn: Multiname): Value {
|
|
3726
|
-
|
|
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
|
-
|
|
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
|
-
/**
|
|
3725
|
+
/** See checkFilter in runtime-xml.ts. */
|
|
3758
3726
|
checkFilter(v: Value): void {
|
|
3759
|
-
|
|
3760
|
-
throw this.error("TypeError", 1123, this.describe(v));
|
|
3761
|
-
}
|
|
3727
|
+
checkFilter(this, v);
|
|
3762
3728
|
}
|
|
3763
3729
|
|
|
3764
|
-
/**
|
|
3730
|
+
/** See escapeElement in runtime-xml.ts. */
|
|
3765
3731
|
escapeElement(v: Value): string {
|
|
3766
|
-
|
|
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
|
+
}
|