@swf2es/player-hosts 0.1.4 → 0.1.6
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/thread/format/bitmap.js +13 -14
- package/dist/thread/format/index.js +1 -1
- package/dist/thread/format/swf.js +11 -1
- package/dist/thread/player/avm1/globals/BitmapData.js +2 -1
- package/dist/thread/player/bitmap/composite.js +767 -0
- package/dist/thread/player/bitmap/draw.js +3 -3
- package/dist/thread/player/bitmap/filters.js +32 -32
- package/dist/thread/player/bitmap/ops.js +2 -766
- package/dist/thread/player/bitmap/pixel-bender.js +4 -1
- package/dist/thread/player/display/bounds.js +105 -0
- package/dist/thread/player/display/displayobject.js +1 -1
- package/dist/thread/player/display/drawing.js +25 -10
- package/dist/thread/player/display/instantiate.js +28 -29
- package/dist/thread/player/display/shapes.js +72 -54
- package/dist/thread/player/display/textobjects.js +34 -1
- package/dist/thread/player/player.js +4 -3
- package/dist/thread/player/playerglobal/flash/desktop/NativeApplication.js +1 -1
- package/dist/thread/player/playerglobal/flash/display/BitmapData.js +3 -2
- package/dist/thread/player/playerglobal/flash/display/DisplayObject.js +2 -2
- package/dist/thread/player/playerglobal/flash/display/SimpleButton.js +12 -11
- package/dist/thread/player/playerglobal/flash/display/Stage.js +2 -8
- package/dist/thread/player/playerglobal/flash/display/shaders.js +1 -1
- package/dist/thread/player/playerglobal/flash/filesystem/paths.js +1 -1
- package/dist/thread/player/playerglobal/flash/filesystem/writes.js +1 -1
- package/dist/thread/player/playerglobal/flash/globalization/locale.js +1 -1
- package/dist/thread/player/scripting/events.js +2 -2
- package/dist/thread/player/scripting/lifecycle.js +39 -19
- package/dist/thread/player/scripting/symbols.js +24 -30
- package/dist/thread/player/scripting.js +5 -9
- package/dist/thread/runtime/avm1/errors.js +1 -1
- package/dist/thread/runtime/avm1/numbers.js +7 -8
- package/dist/thread/runtime/avm2/amf.js +2 -1
- package/dist/thread/runtime/avm2/names.js +0 -4
- package/dist/thread/runtime/avm2/natives/bytearray.js +6 -166
- package/dist/thread/runtime/avm2/natives/regexp.js +68 -64
- package/dist/thread/runtime/avm2/natives/shell-workers.js +1 -1
- package/dist/thread/runtime/avm2/natives/shell.js +2 -1
- package/dist/thread/runtime/avm2/natives/xml/parser.js +2 -2
- package/dist/thread/runtime/avm2/numbers.js +1 -1
- package/dist/thread/runtime/avm2/runtime.js +10 -8
- package/dist/thread/runtime/avm2/traits.js +1 -1
- package/dist/thread/runtime/avm2/utf8.js +167 -0
- package/package.json +2 -2
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import { avm2 } from "../../../../runtime/index.js";
|
|
8
8
|
import { NativePaths } from "./paths.js";
|
|
9
9
|
/** "Error #id: message", as an IOErrorEvent's text begins. */
|
|
10
|
-
|
|
10
|
+
function errorText(id) {
|
|
11
11
|
return `Error #${id}: ${avm2.errorMessages[id]}`;
|
|
12
12
|
}
|
|
13
13
|
/** Throws adl's SecurityError where `at` is in the application's directory by its app: URL. */
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// LastOperationStatus's values.
|
|
2
2
|
export const NO_ERROR = "noError";
|
|
3
3
|
export const USING_FALLBACK_WARNING = "usingFallbackWarning";
|
|
4
|
-
|
|
4
|
+
const USING_DEFAULT_WARNING = "usingDefaultWarning";
|
|
5
5
|
export const PARSE_ERROR = "parseError";
|
|
6
6
|
export const UNSUPPORTED_ERROR = "unsupportedError";
|
|
7
7
|
export const PATTERN_SYNTAX_ERROR = "patternSyntaxError";
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
// player's input and frame events and playerglobal's dispatchEvent all
|
|
5
5
|
// go through it.
|
|
6
6
|
import { avm2 } from "../../runtime/index.js";
|
|
7
|
-
|
|
7
|
+
const CAPTURING_PHASE = 1;
|
|
8
8
|
export const AT_TARGET = 2;
|
|
9
|
-
|
|
9
|
+
const BUBBLING_PHASE = 3;
|
|
10
10
|
/** The fields of `s`'s events, found once playerglobal is loaded. */
|
|
11
11
|
export function eventFields(s) {
|
|
12
12
|
if (s.eventFields) {
|
|
@@ -45,7 +45,7 @@ export class Lifecycle {
|
|
|
45
45
|
* order, as Flash dispatches them.
|
|
46
46
|
*/
|
|
47
47
|
added(display) {
|
|
48
|
-
this.
|
|
48
|
+
this.dropOrphan(display.serial);
|
|
49
49
|
this.dispatch(display.object, "added", true);
|
|
50
50
|
if (this.onStage(display)) {
|
|
51
51
|
this.eachObject(display, (o) => this.dispatch(o, "addedToStage", false));
|
|
@@ -136,6 +136,7 @@ export class Lifecycle {
|
|
|
136
136
|
orphan(display, keep = true) {
|
|
137
137
|
if (display.object && !this.orphans.has(display.serial)) {
|
|
138
138
|
this.orphans.set(display.serial, { ref: display.ref, keep, since: this.s.frames });
|
|
139
|
+
this.sortedOrphans = null;
|
|
139
140
|
scriptWork.changes++;
|
|
140
141
|
}
|
|
141
142
|
}
|
|
@@ -152,24 +153,42 @@ export class Lifecycle {
|
|
|
152
153
|
display.fresh = true;
|
|
153
154
|
}
|
|
154
155
|
}
|
|
155
|
-
/**
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
156
|
+
/**
|
|
157
|
+
* The orphans, newest first, as Flash runs their frames: kept sorted
|
|
158
|
+
* until one comes or goes, as the player walks them twice a frame.
|
|
159
|
+
*/
|
|
160
|
+
sortedOrphans = null;
|
|
161
|
+
dropOrphan(serial) {
|
|
162
|
+
if (this.orphans.delete(serial)) {
|
|
163
|
+
this.sortedOrphans = null;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/** Each orphan still there, newest first, to `f`, which must leave the orphans as they are. */
|
|
167
|
+
eachOrphanRoot(f) {
|
|
168
|
+
let sorted = this.sortedOrphans;
|
|
169
|
+
if (!sorted) {
|
|
170
|
+
sorted = [];
|
|
171
|
+
for (const [serial, orphan] of this.orphans) {
|
|
172
|
+
sorted.push({ serial, ref: orphan.ref });
|
|
173
|
+
}
|
|
174
|
+
sorted.sort((a, b) => b.serial - a.serial);
|
|
175
|
+
this.sortedOrphans = sorted;
|
|
176
|
+
}
|
|
177
|
+
for (let i = 0; i < sorted.length; i++) {
|
|
178
|
+
const display = sorted[i].ref.deref();
|
|
160
179
|
if (!display) {
|
|
161
|
-
this.
|
|
180
|
+
this.dropOrphan(sorted[i].serial);
|
|
162
181
|
continue;
|
|
163
182
|
}
|
|
164
|
-
|
|
183
|
+
f(display);
|
|
165
184
|
}
|
|
166
|
-
return roots.sort((a, b) => b.serial - a.serial);
|
|
167
185
|
}
|
|
168
186
|
/** Whether `display` or anything under it listens for a frame's broadcast events. */
|
|
169
187
|
hearsFrames(display) {
|
|
170
188
|
if (display.object) {
|
|
171
|
-
|
|
172
|
-
|
|
189
|
+
const sets = this.s.broadcastSets;
|
|
190
|
+
for (let i = 0; i < sets.length; i++) {
|
|
191
|
+
if (sets[i].has(display.object)) {
|
|
173
192
|
return true;
|
|
174
193
|
}
|
|
175
194
|
}
|
|
@@ -187,7 +206,7 @@ export class Lifecycle {
|
|
|
187
206
|
* does: timelines stopped, frame broadcasts no longer heard, no orphan.
|
|
188
207
|
*/
|
|
189
208
|
stopAll(display) {
|
|
190
|
-
this.
|
|
209
|
+
this.dropOrphan(display.serial);
|
|
191
210
|
stopTimelineSoundsUnder(this.s, display);
|
|
192
211
|
const stop = (o) => {
|
|
193
212
|
if (o instanceof MovieClip) {
|
|
@@ -230,24 +249,25 @@ export class Lifecycle {
|
|
|
230
249
|
// What the timeline took off this frame has had its frame; it stops here. So
|
|
231
250
|
// does one that has played ORPHAN_FRAMES off the list, but for one that
|
|
232
251
|
// listens for a frame's events, which hold it in Flash too.
|
|
233
|
-
for
|
|
252
|
+
// forEach, as for-of makes an entry for each of what may be thousands, every frame.
|
|
253
|
+
this.orphans.forEach((orphan, serial) => {
|
|
234
254
|
if (!orphan.keep) {
|
|
235
|
-
this.
|
|
236
|
-
|
|
255
|
+
this.dropOrphan(serial);
|
|
256
|
+
return;
|
|
237
257
|
}
|
|
238
258
|
if (this.s.frames - orphan.since < ORPHAN_FRAMES) {
|
|
239
|
-
|
|
259
|
+
return;
|
|
240
260
|
}
|
|
241
261
|
const display = orphan.ref.deref();
|
|
242
262
|
if (display && this.hearsFrames(display)) {
|
|
243
263
|
orphan.since = this.s.frames;
|
|
244
|
-
|
|
264
|
+
return;
|
|
245
265
|
}
|
|
246
|
-
this.
|
|
266
|
+
this.dropOrphan(serial);
|
|
247
267
|
if (display) {
|
|
248
268
|
stopTimelineSoundsUnder(this.s, display);
|
|
249
269
|
}
|
|
250
|
-
}
|
|
270
|
+
});
|
|
251
271
|
// What scripts made this frame and left off the display list plays on as an orphan.
|
|
252
272
|
const made = this.madeThisFrame.splice(0);
|
|
253
273
|
if (made.length > 0) {
|
|
@@ -269,36 +269,30 @@ export class Symbols {
|
|
|
269
269
|
}
|
|
270
270
|
return display;
|
|
271
271
|
}
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
return new VideoObject();
|
|
297
|
-
}
|
|
298
|
-
if (t.name === "flash.text::TextField") {
|
|
299
|
-
const text = new TextObject(null);
|
|
300
|
-
text.fonts = (this.s.code.codeLibrary() ?? library).fonts;
|
|
301
|
-
return text;
|
|
272
|
+
switch (t.name) {
|
|
273
|
+
case "flash.display::SimpleButton":
|
|
274
|
+
return new ButtonObject();
|
|
275
|
+
case "flash.display::MovieClip":
|
|
276
|
+
return new MovieClip(EMPTY_TIMELINE, library);
|
|
277
|
+
case "flash.display::Shape":
|
|
278
|
+
return new ShapeObject(null);
|
|
279
|
+
// Only a timeline makes a MorphShape or a StaticText.
|
|
280
|
+
case "flash.display::MorphShape":
|
|
281
|
+
throw this.s.rt.error("ArgumentError", 2012, "MorphShape$");
|
|
282
|
+
case "flash.text::StaticText":
|
|
283
|
+
throw this.s.rt.error("ArgumentError", 2012, "StaticText$");
|
|
284
|
+
// Only a load of an AVM1 SWF makes one (requestLoad).
|
|
285
|
+
case "flash.display::AVM1Movie":
|
|
286
|
+
throw this.s.rt.error("ArgumentError", 2012, "AVM1Movie$");
|
|
287
|
+
case "flash.display::Bitmap":
|
|
288
|
+
return new BitmapObject(null);
|
|
289
|
+
case "flash.media::Video":
|
|
290
|
+
return new VideoObject();
|
|
291
|
+
case "flash.text::TextField": {
|
|
292
|
+
const text = new TextObject(null);
|
|
293
|
+
text.fonts = (this.s.code.codeLibrary() ?? library).fonts;
|
|
294
|
+
return text;
|
|
295
|
+
}
|
|
302
296
|
}
|
|
303
297
|
}
|
|
304
298
|
return new Container();
|
|
@@ -203,13 +203,13 @@ export class Scripting {
|
|
|
203
203
|
inFrameScript = null;
|
|
204
204
|
/** The display objects listening for each frame event, in the order they first listened; a broadcast reaches these. */
|
|
205
205
|
broadcasts = new Map();
|
|
206
|
+
/** The same sets, for a walk by index that makes no iterator; the map never lets one go. */
|
|
207
|
+
broadcastSets = [];
|
|
206
208
|
/** The dispatchers listening for ACTIVATE or DEACTIVATE, held weakly. */
|
|
207
209
|
activation = new Map();
|
|
208
210
|
/** What flash.display.Stage reports and sets; the player copies the frame rate back each frame. */
|
|
209
211
|
stageWidth = 0;
|
|
210
212
|
stageHeight = 0;
|
|
211
|
-
/** Live Stage layout is part of the opt-in Context3D installation. */
|
|
212
|
-
liveStageLayout = false;
|
|
213
213
|
stageScaleMode = "showAll";
|
|
214
214
|
stageAlign = "";
|
|
215
215
|
/** A script's setting takes precedence over the embedding's defaults. */
|
|
@@ -581,14 +581,12 @@ export class Scripting {
|
|
|
581
581
|
if (!targets) {
|
|
582
582
|
targets = new Set();
|
|
583
583
|
this.broadcasts.set(type, targets);
|
|
584
|
+
this.broadcastSets.push(targets);
|
|
584
585
|
}
|
|
585
586
|
return targets;
|
|
586
587
|
}
|
|
587
588
|
/** Embedding defaults apply until ActionScript sets the corresponding property. */
|
|
588
589
|
setStageDefaults(scaleMode, align) {
|
|
589
|
-
if (!this.liveStageLayout) {
|
|
590
|
-
return;
|
|
591
|
-
}
|
|
592
590
|
if (!this.stageScaleModeSet) {
|
|
593
591
|
this.stageScaleMode = scaleMode;
|
|
594
592
|
}
|
|
@@ -598,7 +596,7 @@ export class Scripting {
|
|
|
598
596
|
}
|
|
599
597
|
/** The host's visible size in noScale, the authored size in other modes. */
|
|
600
598
|
resizeStage(width, height) {
|
|
601
|
-
if (
|
|
599
|
+
if (width === this.stageWidth && height === this.stageHeight) {
|
|
602
600
|
return;
|
|
603
601
|
}
|
|
604
602
|
this.stageWidth = width;
|
|
@@ -797,9 +795,7 @@ export class Scripting {
|
|
|
797
795
|
}
|
|
798
796
|
}
|
|
799
797
|
};
|
|
800
|
-
|
|
801
|
-
visit(orphan);
|
|
802
|
-
}
|
|
798
|
+
this.lifecycle.eachOrphanRoot(visit);
|
|
803
799
|
visit(root);
|
|
804
800
|
for (const display of this.lifecycle.fresh) {
|
|
805
801
|
visit(display);
|
|
@@ -16,7 +16,7 @@ export class Halt extends Error {
|
|
|
16
16
|
* own check (adl; Ruffle's continue_if_base_clip_exists). One instance,
|
|
17
17
|
* thrown as a signal and never shown.
|
|
18
18
|
*/
|
|
19
|
-
|
|
19
|
+
class BaseRemoved extends Error {
|
|
20
20
|
name = "Avm1BaseRemoved";
|
|
21
21
|
}
|
|
22
22
|
export const BASE_REMOVED = new BaseRemoved("the clip whose code runs was removed");
|
|
@@ -43,14 +43,13 @@ export function numberToString(n) {
|
|
|
43
43
|
if (Number.isNaN(n)) {
|
|
44
44
|
return "NaN";
|
|
45
45
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
return "0";
|
|
46
|
+
switch (n) {
|
|
47
|
+
case Number.POSITIVE_INFINITY:
|
|
48
|
+
return "Infinity";
|
|
49
|
+
case Number.NEGATIVE_INFINITY:
|
|
50
|
+
return "-Infinity";
|
|
51
|
+
case 0:
|
|
52
|
+
return "0";
|
|
54
53
|
}
|
|
55
54
|
if (n >= -2147483648 && n <= 2147483647 && Number.isInteger(n)) {
|
|
56
55
|
return String(n);
|
|
@@ -13,8 +13,9 @@
|
|
|
13
13
|
// the Mozilla Public License, v. 2.0: http://mozilla.org/MPL/2.0/.
|
|
14
14
|
import { FloatValue } from "./float.js";
|
|
15
15
|
import { NS_PackageInternal, NS_Public, namespace, publicQname, qname } from "./names.js";
|
|
16
|
-
import { bytesOf
|
|
16
|
+
import { bytesOf } from "./natives/bytearray.js";
|
|
17
17
|
import { xmlToXMLString } from "./natives/xml/strings.js";
|
|
18
|
+
import { fromUtf8, utf8 } from "./utf8.js";
|
|
18
19
|
const kUndefined = 0;
|
|
19
20
|
const kNull = 1;
|
|
20
21
|
const kFalse = 2;
|
|
@@ -7,9 +7,6 @@ import { NO_CACHE } from "./property-cache.js";
|
|
|
7
7
|
/** Namespace kinds, numbered as the compiler's NS_* constants. */
|
|
8
8
|
export const NS_Public = 0;
|
|
9
9
|
export const NS_PackageInternal = 1;
|
|
10
|
-
export const NS_Protected = 2;
|
|
11
|
-
export const NS_Explicit = 3;
|
|
12
|
-
export const NS_StaticProtected = 4;
|
|
13
10
|
export const NS_Private = 5;
|
|
14
11
|
export class Namespace {
|
|
15
12
|
kind;
|
|
@@ -77,7 +74,6 @@ export const CONSTANT_Multiname = 0x09;
|
|
|
77
74
|
export const CONSTANT_MultinameA = 0x0e;
|
|
78
75
|
export const CONSTANT_MultinameL = 0x1b;
|
|
79
76
|
export const CONSTANT_MultinameLA = 0x1c;
|
|
80
|
-
export const CONSTANT_TypeName = 0x1d;
|
|
81
77
|
/**
|
|
82
78
|
* A name as a property lookup uses it: its namespaces, each with the API
|
|
83
79
|
* version it sees bindings at, and its local name, null for any name.
|
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
// DataInput/DataOutput implement them. The buffer keeps avmplus' capacity:
|
|
3
3
|
// it grows as avmplus' Grower grows it, zeroing what a reallocation adds,
|
|
4
4
|
// so bytes a shorter length left behind come back when the length grows
|
|
5
|
-
// within the capacity, as they do in avmplus. UTF-8 is avmplus' own
|
|
6
|
-
//
|
|
5
|
+
// within the capacity, as they do in avmplus. UTF-8 is avmplus' own
|
|
6
|
+
// (utf8.ts).
|
|
7
7
|
//
|
|
8
|
-
// Translated from avmplus' core/ByteArrayGlue.cpp
|
|
9
|
-
//
|
|
10
|
-
//
|
|
8
|
+
// Translated from avmplus' core/ByteArrayGlue.cpp and core/DataIO.cpp,
|
|
9
|
+
// this file is subject to the Mozilla Public License, v. 2.0:
|
|
10
|
+
// http://mozilla.org/MPL/2.0/.
|
|
11
11
|
import { CompressedDataError, CompressedDataTooLargeError, deflateCompress, LZMA_HEADER, lzmaByteArrayCompress, lzmaByteArrayUncompress, zlibCompress, zlibUncompress, } from "../../../format/index.js";
|
|
12
|
+
import { fromCodes, fromUtf8, utf8 } from "../utf8.js";
|
|
12
13
|
import { registerNativeClass } from "./define.js";
|
|
13
14
|
const kGrowthIncr = 4096;
|
|
14
15
|
const kHugeGrowthThreshold = 24 * 1024 * 1024;
|
|
@@ -527,167 +528,6 @@ export function sharedByteArray(rt, memory) {
|
|
|
527
528
|
export function knownSharedByteArray(rt, id) {
|
|
528
529
|
return sharedObjectsOf(rt).get(id)?.deref();
|
|
529
530
|
}
|
|
530
|
-
/** The host's UTF-8 encoder, which writes a lone surrogate as U+FFFD, as utf8() does. */
|
|
531
|
-
const encoder = new TextEncoder();
|
|
532
|
-
/**
|
|
533
|
-
* Below this length, a string encodes faster here than through
|
|
534
|
-
* TextEncoder, whose call costs more than the loop saves (about 90
|
|
535
|
-
* characters in V8).
|
|
536
|
-
*/
|
|
537
|
-
const ENCODER_LENGTH = 96;
|
|
538
|
-
/**
|
|
539
|
-
* As UnicodeUtils::Utf16ToUtf8: a surrogate pair as four bytes, a lone
|
|
540
|
-
* surrogate as U+FFFD. avmshell's writeUTFBytes loses characters around a
|
|
541
|
-
* lone one instead; this keeps them, and the UTF-8 valid.
|
|
542
|
-
*/
|
|
543
|
-
export function utf8(s) {
|
|
544
|
-
if (s.length >= ENCODER_LENGTH) {
|
|
545
|
-
return encoder.encode(s);
|
|
546
|
-
}
|
|
547
|
-
// ASCII, byte for byte.
|
|
548
|
-
let ascii = true;
|
|
549
|
-
for (let i = 0; i < s.length && ascii; i++) {
|
|
550
|
-
ascii = s.charCodeAt(i) < 0x80;
|
|
551
|
-
}
|
|
552
|
-
if (ascii) {
|
|
553
|
-
const out = new Uint8Array(s.length);
|
|
554
|
-
for (let i = 0; i < s.length; i++) {
|
|
555
|
-
out[i] = s.charCodeAt(i);
|
|
556
|
-
}
|
|
557
|
-
return out;
|
|
558
|
-
}
|
|
559
|
-
const out = new Uint8Array(s.length * 3);
|
|
560
|
-
let n = 0;
|
|
561
|
-
for (let i = 0; i < s.length; i++) {
|
|
562
|
-
let ch = s.charCodeAt(i);
|
|
563
|
-
if (ch < 0x80) {
|
|
564
|
-
out[n++] = ch;
|
|
565
|
-
continue;
|
|
566
|
-
}
|
|
567
|
-
if (ch < 0x800) {
|
|
568
|
-
out[n++] = 0xc0 | ((ch >> 6) & 0x1f);
|
|
569
|
-
out[n++] = 0x80 | (ch & 0x3f);
|
|
570
|
-
continue;
|
|
571
|
-
}
|
|
572
|
-
if (ch >= 0xd800 && ch <= 0xdbff) {
|
|
573
|
-
const ch2 = i + 1 < s.length ? s.charCodeAt(i + 1) : 0;
|
|
574
|
-
if (ch2 >= 0xdc00 && ch2 <= 0xdfff) {
|
|
575
|
-
i++;
|
|
576
|
-
const ucs4 = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000;
|
|
577
|
-
out[n++] = 0xf0 | ((ucs4 >> 18) & 0x07);
|
|
578
|
-
out[n++] = 0x80 | ((ucs4 >> 12) & 0x3f);
|
|
579
|
-
out[n++] = 0x80 | ((ucs4 >> 6) & 0x3f);
|
|
580
|
-
out[n++] = 0x80 | (ucs4 & 0x3f);
|
|
581
|
-
continue;
|
|
582
|
-
}
|
|
583
|
-
ch = 0xfffd;
|
|
584
|
-
}
|
|
585
|
-
else if (ch >= 0xdc00 && ch <= 0xdfff) {
|
|
586
|
-
ch = 0xfffd;
|
|
587
|
-
}
|
|
588
|
-
out[n++] = 0xe0 | ((ch >> 12) & 0x0f);
|
|
589
|
-
out[n++] = 0x80 | ((ch >> 6) & 0x3f);
|
|
590
|
-
out[n++] = 0x80 | (ch & 0x3f);
|
|
591
|
-
}
|
|
592
|
-
return out.subarray(0, n);
|
|
593
|
-
}
|
|
594
|
-
/**
|
|
595
|
-
* As UnicodeUtils::Utf8ToUtf16, not strict: a byte that does not start a
|
|
596
|
-
* valid sequence is the character of its value, and a four-byte sequence
|
|
597
|
-
* may start with 0xF8 to 0xFF, as Flash Player 9 and 10 read them.
|
|
598
|
-
*/
|
|
599
|
-
/** The length from which fromUtf8 first looks for ASCII. */
|
|
600
|
-
const ASCII_LENGTH = 16;
|
|
601
|
-
export function fromUtf8(bytes) {
|
|
602
|
-
const n = bytes.length;
|
|
603
|
-
// ASCII, as most text is: its bytes are its characters. Below
|
|
604
|
-
// ASCII_LENGTH bytes, a character at a time, until one is not.
|
|
605
|
-
if (n < ASCII_LENGTH) {
|
|
606
|
-
let s = "";
|
|
607
|
-
let k = 0;
|
|
608
|
-
for (; k < n && bytes[k] < 0x80; k++) {
|
|
609
|
-
s += String.fromCharCode(bytes[k]);
|
|
610
|
-
}
|
|
611
|
-
if (k === n) {
|
|
612
|
-
return s;
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
else {
|
|
616
|
-
let ascii = 0;
|
|
617
|
-
while (ascii < n && bytes[ascii] < 0x80) {
|
|
618
|
-
ascii++;
|
|
619
|
-
}
|
|
620
|
-
if (ascii === n) {
|
|
621
|
-
let s = "";
|
|
622
|
-
for (let k = 0; k < n; k += 8192) {
|
|
623
|
-
s += String.fromCharCode.apply(null, bytes.subarray(k, k + 8192));
|
|
624
|
-
}
|
|
625
|
-
return s;
|
|
626
|
-
}
|
|
627
|
-
}
|
|
628
|
-
const out = [];
|
|
629
|
-
let i = 0;
|
|
630
|
-
while (i < n) {
|
|
631
|
-
const c = bytes[i];
|
|
632
|
-
const left = n - i;
|
|
633
|
-
switch (c >> 4) {
|
|
634
|
-
case 12:
|
|
635
|
-
case 13: {
|
|
636
|
-
if (left >= 2 && (bytes[i + 1] & 0xc0) === 0x80) {
|
|
637
|
-
const ch = ((c << 6) & 0x7c0) | (bytes[i + 1] & 0x3f);
|
|
638
|
-
if (ch >= 0x80) {
|
|
639
|
-
out.push(ch);
|
|
640
|
-
i += 2;
|
|
641
|
-
continue;
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
break;
|
|
645
|
-
}
|
|
646
|
-
case 14: {
|
|
647
|
-
if (left >= 3 && (bytes[i + 1] & 0xc0) === 0x80 && (bytes[i + 2] & 0xc0) === 0x80) {
|
|
648
|
-
const ch = ((c << 12) & 0xf000) | ((bytes[i + 1] << 6) & 0xfc0) | (bytes[i + 2] & 0x3f);
|
|
649
|
-
if (ch >= 0x800) {
|
|
650
|
-
out.push(ch);
|
|
651
|
-
i += 3;
|
|
652
|
-
continue;
|
|
653
|
-
}
|
|
654
|
-
}
|
|
655
|
-
break;
|
|
656
|
-
}
|
|
657
|
-
case 15: {
|
|
658
|
-
if (left >= 4 &&
|
|
659
|
-
(bytes[i + 1] & 0xc0) === 0x80 &&
|
|
660
|
-
(bytes[i + 2] & 0xc0) === 0x80 &&
|
|
661
|
-
(bytes[i + 3] & 0xc0) === 0x80) {
|
|
662
|
-
const ch = ((c << 18) & 0x1c0000) |
|
|
663
|
-
((bytes[i + 1] << 12) & 0x3f000) |
|
|
664
|
-
((bytes[i + 2] << 6) & 0xfc0) |
|
|
665
|
-
(bytes[i + 3] & 0x3f);
|
|
666
|
-
if (ch >= 0x10000) {
|
|
667
|
-
out.push((((ch - 0x10000) >> 10) & 0x3ff) + 0xd800, ((ch - 0x10000) & 0x3ff) + 0xdc00);
|
|
668
|
-
i += 4;
|
|
669
|
-
continue;
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
break;
|
|
673
|
-
}
|
|
674
|
-
default:
|
|
675
|
-
break;
|
|
676
|
-
}
|
|
677
|
-
// Not a sequence: the byte itself.
|
|
678
|
-
out.push(c);
|
|
679
|
-
i++;
|
|
680
|
-
}
|
|
681
|
-
return fromCodes(out);
|
|
682
|
-
}
|
|
683
|
-
/** A string of UTF-16 code units, in chunks, as String.fromCharCode takes only so many arguments. */
|
|
684
|
-
function fromCodes(units) {
|
|
685
|
-
let s = "";
|
|
686
|
-
for (let k = 0; k < units.length; k += 8192) {
|
|
687
|
-
s += String.fromCharCode(...units.slice(k, k + 8192));
|
|
688
|
-
}
|
|
689
|
-
return s;
|
|
690
|
-
}
|
|
691
531
|
/** The bytes up to the first NUL, as avmplus reads a C string. */
|
|
692
532
|
function toNul(bytes) {
|
|
693
533
|
const nul = bytes.indexOf(0);
|
|
@@ -170,25 +170,25 @@ function variableLookbehind(source) {
|
|
|
170
170
|
/** The length of the item at i, which it steps past. */
|
|
171
171
|
const item = () => {
|
|
172
172
|
const c = source[i++];
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
173
|
+
switch (c) {
|
|
174
|
+
case "(":
|
|
175
|
+
return group();
|
|
176
|
+
case "^":
|
|
177
|
+
case "$":
|
|
178
|
+
return 0;
|
|
179
|
+
case "[":
|
|
180
|
+
if (source[i] === "^") {
|
|
181
|
+
i++;
|
|
182
|
+
}
|
|
183
|
+
// A ] first is a literal.
|
|
184
|
+
if (source[i] === "]") {
|
|
185
|
+
i++;
|
|
186
|
+
}
|
|
187
|
+
while (i < source.length && source[i] !== "]") {
|
|
188
|
+
i += source[i] === "\\" ? 2 : 1;
|
|
189
|
+
}
|
|
185
190
|
i++;
|
|
186
|
-
|
|
187
|
-
while (i < source.length && source[i] !== "]") {
|
|
188
|
-
i += source[i] === "\\" ? 2 : 1;
|
|
189
|
-
}
|
|
190
|
-
i++;
|
|
191
|
-
return 1;
|
|
191
|
+
return 1;
|
|
192
192
|
}
|
|
193
193
|
if (c !== "\\") {
|
|
194
194
|
// A character beyond the BMP is one in PCRE's UTF-8 too.
|
|
@@ -265,57 +265,61 @@ function nestedTooDeep(source) {
|
|
|
265
265
|
for (let i = 0; i < source.length; i++) {
|
|
266
266
|
const c = source[i];
|
|
267
267
|
let item = 2;
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
268
|
+
switch (c) {
|
|
269
|
+
case "(": {
|
|
270
|
+
const capture = source[i + 1] !== "?" || source.startsWith("(?P<", i);
|
|
271
|
+
outer.push(held);
|
|
272
|
+
held += previous + (capture ? 5 : 3);
|
|
273
|
+
previous = 0;
|
|
274
|
+
if (held > WORKSPACE) {
|
|
275
|
+
return true;
|
|
276
|
+
}
|
|
277
|
+
// Past the group's kind: ?: ?= ?! ?<= ?<! ?P<name> or flags.
|
|
278
|
+
if (source[i + 1] === "?") {
|
|
279
|
+
const end = source.slice(i + 2).search(/[:=!>)]/);
|
|
280
|
+
i = end < 0 ? source.length : i + 2 + end;
|
|
281
|
+
}
|
|
282
|
+
continue;
|
|
280
283
|
}
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
previous = 0;
|
|
291
|
-
continue;
|
|
292
|
-
}
|
|
293
|
-
if (c === "\\") {
|
|
294
|
-
i++;
|
|
295
|
-
}
|
|
296
|
-
else if (c === "[") {
|
|
297
|
-
// A class is its opcode and a 32-byte bitmap.
|
|
298
|
-
item = 33;
|
|
299
|
-
i++;
|
|
300
|
-
if (source[i] === "^") {
|
|
284
|
+
case ")":
|
|
285
|
+
held = outer.pop() ?? held;
|
|
286
|
+
// The group is the next one's previous item, but what it holds is gone.
|
|
287
|
+
previous = 0;
|
|
288
|
+
continue;
|
|
289
|
+
case "|":
|
|
290
|
+
previous = 0;
|
|
291
|
+
continue;
|
|
292
|
+
case "\\":
|
|
301
293
|
i++;
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
294
|
+
break;
|
|
295
|
+
case "[":
|
|
296
|
+
// A class is its opcode and a 32-byte bitmap.
|
|
297
|
+
item = 33;
|
|
305
298
|
i++;
|
|
306
|
-
|
|
307
|
-
while (i < source.length && source[i] !== "]") {
|
|
308
|
-
if (source[i] === "\\") {
|
|
299
|
+
if (source[i] === "^") {
|
|
309
300
|
i++;
|
|
310
301
|
}
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
302
|
+
// A ] first is a literal.
|
|
303
|
+
if (source[i] === "]") {
|
|
304
|
+
i++;
|
|
305
|
+
}
|
|
306
|
+
while (i < source.length && source[i] !== "]") {
|
|
307
|
+
if (source[i] === "\\") {
|
|
308
|
+
i++;
|
|
309
|
+
}
|
|
310
|
+
i++;
|
|
311
|
+
}
|
|
312
|
+
break;
|
|
313
|
+
case ".":
|
|
314
|
+
case "^":
|
|
315
|
+
case "$":
|
|
316
|
+
item = 1;
|
|
317
|
+
break;
|
|
318
|
+
case "*":
|
|
319
|
+
case "+":
|
|
320
|
+
case "?":
|
|
321
|
+
case "{":
|
|
322
|
+
continue;
|
|
319
323
|
}
|
|
320
324
|
previous = item;
|
|
321
325
|
if (held + previous > WORKSPACE) {
|