@swf2es/player-hosts 0.1.4 → 0.1.5
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/displayobject.js +1 -1
- package/dist/thread/player/display/instantiate.js +28 -29
- 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/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/symbols.js +24 -30
- package/dist/thread/player/scripting.js +1 -6
- 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
|
@@ -767,7 +767,10 @@ export class PixelBender {
|
|
|
767
767
|
}
|
|
768
768
|
}
|
|
769
769
|
}
|
|
770
|
-
/**
|
|
770
|
+
/**
|
|
771
|
+
* A float as a bitmap's byte: clamped, NaN as 0, then rounded to the nearest, a half to the even.
|
|
772
|
+
* @public tests/player/pixel-bender.ts imports it into Chrome by name.
|
|
773
|
+
*/
|
|
771
774
|
export function outputByte(v) {
|
|
772
775
|
const c = v > 0 ? (v < 1 ? v : 1) : 0;
|
|
773
776
|
return nearest(Math.fround(c * 255));
|
|
@@ -12,7 +12,7 @@ export const TRANSFORM = 1;
|
|
|
12
12
|
export const CHILDREN = 2;
|
|
13
13
|
export const CONTENT = 4;
|
|
14
14
|
/** A Bitmap's pixels changed in place: the texture uploads again, nothing is rebuilt. */
|
|
15
|
-
|
|
15
|
+
const PIXELS = 8;
|
|
16
16
|
/**
|
|
17
17
|
* A count that moves whenever something changes that a round of frame
|
|
18
18
|
* scripts (Scripting.runFrameScripts) reads to find a script to run: a
|
|
@@ -10,35 +10,34 @@ import { INVALID_PIXELS } from "./timeline.js";
|
|
|
10
10
|
/** A display object for a character, before its first frame: a shape, or a clip. */
|
|
11
11
|
/** `hasImage` is PlaceObject3's flag where a timeline places it, which a bitmap's construction reads. */
|
|
12
12
|
export function displayFor(character, library, hasImage = false) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
return button;
|
|
13
|
+
switch (character.type) {
|
|
14
|
+
case "shape":
|
|
15
|
+
return new ShapeObject(character);
|
|
16
|
+
case "morph":
|
|
17
|
+
return ShapeObject.ofMorph(character);
|
|
18
|
+
case "bitmap": {
|
|
19
|
+
// With scripts, its Bitmap's constructor gives it its data; without, a copy of the pixels.
|
|
20
|
+
const bitmap = new BitmapObject(library.construct ? null : BitmapStore.of(character.pixels ?? INVALID_PIXELS));
|
|
21
|
+
bitmap.character = character;
|
|
22
|
+
bitmap.hasImage = hasImage;
|
|
23
|
+
return bitmap;
|
|
24
|
+
}
|
|
25
|
+
case "static":
|
|
26
|
+
return new StaticTextObject(character, library.characters);
|
|
27
|
+
case "text": {
|
|
28
|
+
const text = new TextObject(character);
|
|
29
|
+
text.fonts = library.fonts;
|
|
30
|
+
return text;
|
|
31
|
+
}
|
|
32
|
+
// Its states are made where it is constructed (Scripting.construct).
|
|
33
|
+
case "button": {
|
|
34
|
+
const button = new ButtonObject();
|
|
35
|
+
button.character = character;
|
|
36
|
+
button.library = library;
|
|
37
|
+
button.trackAsMenu = character.trackAsMenu;
|
|
38
|
+
button.scale9Grid = character.grid;
|
|
39
|
+
return button;
|
|
40
|
+
}
|
|
42
41
|
}
|
|
43
42
|
const clip = new MovieClip(character.timeline, library);
|
|
44
43
|
clip.character = character;
|
|
@@ -13,7 +13,7 @@ import { nativeWindowOf } from "../display/NativeWindow.js";
|
|
|
13
13
|
import { addListener, removeListener } from "../events/EventDispatcher.js";
|
|
14
14
|
import { fileAt } from "../filesystem/File.js";
|
|
15
15
|
/** NativeApplication.runtimeVersion, and its patch level: the AIR these natives follow. */
|
|
16
|
-
|
|
16
|
+
const AIR_RUNTIME_VERSION = "51.3.1.2";
|
|
17
17
|
const AIR_PATCH_LEVEL = 2;
|
|
18
18
|
const INVOKE = "invoke";
|
|
19
19
|
export function nativeApplicationNatives(s) {
|
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
// ArgumentError 2015 for a size it refuses and for a store disposed.
|
|
4
4
|
import { avm2 } from "../../../../runtime/index.js";
|
|
5
5
|
import { BitmapStore, pixelRect, spanRect } from "../../../bitmap/bitmap.js";
|
|
6
|
+
import { drawBitmap } from "../../../bitmap/composite.js";
|
|
6
7
|
import { drawDisplayObject } from "../../../bitmap/draw.js";
|
|
7
8
|
import { applyFilter, filterRefusal, filtersDrawn, GLOWS, generatedRect, } from "../../../bitmap/filters.js";
|
|
8
|
-
import { alphaAt, colorBounds, colorTransform, comparePixels, copyChannel,
|
|
9
|
+
import { alphaAt, colorBounds, colorTransform, comparePixels, copyChannel, floodFill, histogram, isThresholdOperation, merge, noise, paletteMap, perlinNoise, pixelDissolve, scroll, threshold, } from "../../../bitmap/ops.js";
|
|
9
10
|
import { shaderFilter } from "../../../bitmap/pixel-bender.js";
|
|
10
11
|
import { encodePng } from "../../../bitmap/png.js";
|
|
11
12
|
import { INVALID_PIXELS } from "../../../display/timeline.js";
|
|
@@ -74,7 +75,7 @@ function sourceOf(s, v) {
|
|
|
74
75
|
}
|
|
75
76
|
/**
|
|
76
77
|
* draw: a BitmapData, or a Bitmap as its data, its own transform ignored,
|
|
77
|
-
* composited on the CPU (bitmap/
|
|
78
|
+
* composited on the CPU (bitmap/composite.ts); any other display
|
|
78
79
|
* object rendered by the Scripting's drawer at `samples` a side, over its
|
|
79
80
|
* own bounds alone, then composited the same way. A null source is
|
|
80
81
|
* ArgumentError 2005, as Flash words it.
|
|
@@ -24,17 +24,18 @@ export function simpleButtonNatives(s) {
|
|
|
24
24
|
if (d?.parent && d.parent !== b && !d.encloses(b)) {
|
|
25
25
|
d.parent.removeChild(d);
|
|
26
26
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
27
|
+
switch (state) {
|
|
28
|
+
case "up":
|
|
29
|
+
b.upState = d;
|
|
30
|
+
break;
|
|
31
|
+
case "over":
|
|
32
|
+
b.overState = d;
|
|
33
|
+
break;
|
|
34
|
+
case "down":
|
|
35
|
+
b.downState = d;
|
|
36
|
+
break;
|
|
37
|
+
default:
|
|
38
|
+
b.hitTestState = d;
|
|
38
39
|
}
|
|
39
40
|
b.show();
|
|
40
41
|
// adl reports #2150 as an error nothing caught, from the setter of the state the button
|
|
@@ -41,12 +41,9 @@ export function stageNatives(s) {
|
|
|
41
41
|
s.invalidated = true;
|
|
42
42
|
}
|
|
43
43
|
get scaleMode() {
|
|
44
|
-
return s.
|
|
44
|
+
return s.stageScaleMode;
|
|
45
45
|
}
|
|
46
46
|
set scaleMode(v) {
|
|
47
|
-
if (!s.liveStageLayout) {
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
47
|
if (v == null) {
|
|
51
48
|
throw s.rt.error("TypeError", 2007, "scaleMode");
|
|
52
49
|
}
|
|
@@ -67,12 +64,9 @@ export function stageNatives(s) {
|
|
|
67
64
|
}
|
|
68
65
|
}
|
|
69
66
|
get align() {
|
|
70
|
-
return s.
|
|
67
|
+
return s.stageAlign;
|
|
71
68
|
}
|
|
72
69
|
set align(v) {
|
|
73
|
-
if (!s.liveStageLayout) {
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
70
|
if (v == null) {
|
|
77
71
|
throw s.rt.error("TypeError", 2007, "align");
|
|
78
72
|
}
|
|
@@ -29,7 +29,7 @@ export function kernelOfShader(shader) {
|
|
|
29
29
|
* number, or ArgumentError 2004, as many as its type holds, 0 past the
|
|
30
30
|
* Array's end.
|
|
31
31
|
*/
|
|
32
|
-
|
|
32
|
+
function parameterValues(s, data, p) {
|
|
33
33
|
const classes = shaderClasses(s);
|
|
34
34
|
const size = PBJ_TYPE_SIZES[p.type] ?? 0;
|
|
35
35
|
const float = pbjFloatType(p.type);
|
|
@@ -151,6 +151,6 @@ export class NativePaths {
|
|
|
151
151
|
}
|
|
152
152
|
}
|
|
153
153
|
/** A path segment in a URL: UTF-8, percent-encoded as adl writes them ("#?%" and spaces among them). */
|
|
154
|
-
|
|
154
|
+
function encodeSegment(segment) {
|
|
155
155
|
return encodeURIComponent(segment);
|
|
156
156
|
}
|
|
@@ -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) {
|
|
@@ -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();
|
|
@@ -208,8 +208,6 @@ export class Scripting {
|
|
|
208
208
|
/** What flash.display.Stage reports and sets; the player copies the frame rate back each frame. */
|
|
209
209
|
stageWidth = 0;
|
|
210
210
|
stageHeight = 0;
|
|
211
|
-
/** Live Stage layout is part of the opt-in Context3D installation. */
|
|
212
|
-
liveStageLayout = false;
|
|
213
211
|
stageScaleMode = "showAll";
|
|
214
212
|
stageAlign = "";
|
|
215
213
|
/** A script's setting takes precedence over the embedding's defaults. */
|
|
@@ -586,9 +584,6 @@ export class Scripting {
|
|
|
586
584
|
}
|
|
587
585
|
/** Embedding defaults apply until ActionScript sets the corresponding property. */
|
|
588
586
|
setStageDefaults(scaleMode, align) {
|
|
589
|
-
if (!this.liveStageLayout) {
|
|
590
|
-
return;
|
|
591
|
-
}
|
|
592
587
|
if (!this.stageScaleModeSet) {
|
|
593
588
|
this.stageScaleMode = scaleMode;
|
|
594
589
|
}
|
|
@@ -598,7 +593,7 @@ export class Scripting {
|
|
|
598
593
|
}
|
|
599
594
|
/** The host's visible size in noScale, the authored size in other modes. */
|
|
600
595
|
resizeStage(width, height) {
|
|
601
|
-
if (
|
|
596
|
+
if (width === this.stageWidth && height === this.stageHeight) {
|
|
602
597
|
return;
|
|
603
598
|
}
|
|
604
599
|
this.stageWidth = width;
|
|
@@ -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);
|