swf-toolkit 0.0.0-stage → 0.1.0
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 +21 -0
- package/README.md +125 -2
- package/README.tr.md +126 -0
- package/dist/abc/abc-file.d.ts +168 -0
- package/dist/abc/abc-file.js +656 -0
- package/dist/abc/analysis.d.ts +36 -0
- package/dist/abc/analysis.js +213 -0
- package/dist/abc/code.d.ts +59 -0
- package/dist/abc/code.js +379 -0
- package/dist/abc/constants.d.ts +80 -0
- package/dist/abc/constants.js +93 -0
- package/dist/abc/interner.d.ts +46 -0
- package/dist/abc/interner.js +168 -0
- package/dist/abc/model.d.ts +40 -0
- package/dist/abc/model.js +146 -0
- package/dist/abc/opcodes.d.ts +39 -0
- package/dist/abc/opcodes.js +196 -0
- package/dist/abc/pcode/assembler.d.ts +42 -0
- package/dist/abc/pcode/assembler.js +635 -0
- package/dist/abc/pcode/disassembler.d.ts +17 -0
- package/dist/abc/pcode/disassembler.js +147 -0
- package/dist/abc/pcode/format.d.ts +23 -0
- package/dist/abc/pcode/format.js +131 -0
- package/dist/abc/pcode/lexer.d.ts +34 -0
- package/dist/abc/pcode/lexer.js +183 -0
- package/dist/assets/assets.d.ts +26 -0
- package/dist/assets/assets.js +151 -0
- package/dist/assets/images.d.ts +31 -0
- package/dist/assets/images.js +238 -0
- package/dist/assets/png.d.ts +12 -0
- package/dist/assets/png.js +196 -0
- package/dist/assets/sounds.d.ts +37 -0
- package/dist/assets/sounds.js +236 -0
- package/dist/avm1/avm1.d.ts +55 -0
- package/dist/avm1/avm1.js +642 -0
- package/dist/avm1/project.d.ts +16 -0
- package/dist/avm1/project.js +81 -0
- package/dist/cjs/abc/abc-file.d.ts +168 -0
- package/dist/cjs/abc/abc-file.js +663 -0
- package/dist/cjs/abc/analysis.d.ts +36 -0
- package/dist/cjs/abc/analysis.js +221 -0
- package/dist/cjs/abc/code.d.ts +59 -0
- package/dist/cjs/abc/code.js +387 -0
- package/dist/cjs/abc/constants.d.ts +80 -0
- package/dist/cjs/abc/constants.js +97 -0
- package/dist/cjs/abc/interner.d.ts +46 -0
- package/dist/cjs/abc/interner.js +172 -0
- package/dist/cjs/abc/model.d.ts +40 -0
- package/dist/cjs/abc/model.js +155 -0
- package/dist/cjs/abc/opcodes.d.ts +39 -0
- package/dist/cjs/abc/opcodes.js +201 -0
- package/dist/cjs/abc/pcode/assembler.d.ts +42 -0
- package/dist/cjs/abc/pcode/assembler.js +640 -0
- package/dist/cjs/abc/pcode/disassembler.d.ts +17 -0
- package/dist/cjs/abc/pcode/disassembler.js +152 -0
- package/dist/cjs/abc/pcode/format.d.ts +23 -0
- package/dist/cjs/abc/pcode/format.js +141 -0
- package/dist/cjs/abc/pcode/lexer.d.ts +34 -0
- package/dist/cjs/abc/pcode/lexer.js +188 -0
- package/dist/cjs/assets/assets.d.ts +26 -0
- package/dist/cjs/assets/assets.js +159 -0
- package/dist/cjs/assets/images.d.ts +31 -0
- package/dist/cjs/assets/images.js +246 -0
- package/dist/cjs/assets/png.d.ts +12 -0
- package/dist/cjs/assets/png.js +202 -0
- package/dist/cjs/assets/sounds.d.ts +37 -0
- package/dist/cjs/assets/sounds.js +246 -0
- package/dist/cjs/avm1/avm1.d.ts +55 -0
- package/dist/cjs/avm1/avm1.js +649 -0
- package/dist/cjs/avm1/project.d.ts +16 -0
- package/dist/cjs/avm1/project.js +88 -0
- package/dist/cjs/compiler/ast.d.ts +285 -0
- package/dist/cjs/compiler/ast.js +3 -0
- package/dist/cjs/compiler/class-compiler.d.ts +34 -0
- package/dist/cjs/compiler/class-compiler.js +440 -0
- package/dist/cjs/compiler/codegen.d.ts +144 -0
- package/dist/cjs/compiler/codegen.js +1589 -0
- package/dist/cjs/compiler/lexer.d.ts +27 -0
- package/dist/cjs/compiler/lexer.js +254 -0
- package/dist/cjs/compiler/parser.d.ts +58 -0
- package/dist/cjs/compiler/parser.js +989 -0
- package/dist/cjs/compiler/program.d.ts +29 -0
- package/dist/cjs/compiler/program.js +36 -0
- package/dist/cjs/compiler/scope.d.ts +22 -0
- package/dist/cjs/compiler/scope.js +242 -0
- package/dist/cjs/compression/lzma.d.ts +37 -0
- package/dist/cjs/compression/lzma.js +575 -0
- package/dist/cjs/compression/swf-container.d.ts +19 -0
- package/dist/cjs/compression/swf-container.js +92 -0
- package/dist/cjs/decompiler/ast.d.ts +228 -0
- package/dist/cjs/decompiler/ast.js +455 -0
- package/dist/cjs/decompiler/cfg.d.ts +40 -0
- package/dist/cjs/decompiler/cfg.js +236 -0
- package/dist/cjs/decompiler/class-printer.d.ts +9 -0
- package/dist/cjs/decompiler/class-printer.js +173 -0
- package/dist/cjs/decompiler/method.d.ts +41 -0
- package/dist/cjs/decompiler/method.js +436 -0
- package/dist/cjs/decompiler/simulate.d.ts +55 -0
- package/dist/cjs/decompiler/simulate.js +591 -0
- package/dist/cjs/decompiler/structure.d.ts +48 -0
- package/dist/cjs/decompiler/structure.js +764 -0
- package/dist/cjs/errors.d.ts +11 -0
- package/dist/cjs/errors.js +25 -0
- package/dist/cjs/index.d.ts +41 -0
- package/dist/cjs/index.js +82 -0
- package/dist/cjs/io/reader.d.ts +48 -0
- package/dist/cjs/io/reader.js +180 -0
- package/dist/cjs/io/writer.d.ts +37 -0
- package/dist/cjs/io/writer.js +175 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/project/pcode-project.d.ts +32 -0
- package/dist/cjs/project/pcode-project.js +210 -0
- package/dist/cjs/project/source-export.d.ts +12 -0
- package/dist/cjs/project/source-export.js +51 -0
- package/dist/cjs/project/source-import.d.ts +13 -0
- package/dist/cjs/project/source-import.js +73 -0
- package/dist/cjs/swf/swf.d.ts +63 -0
- package/dist/cjs/swf/swf.js +147 -0
- package/dist/cjs/swf/tag-codes.d.ts +77 -0
- package/dist/cjs/swf/tag-codes.js +109 -0
- package/dist/cjs/swf/tags.d.ts +118 -0
- package/dist/cjs/swf/tags.js +330 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +296 -0
- package/dist/compiler/ast.d.ts +285 -0
- package/dist/compiler/ast.js +2 -0
- package/dist/compiler/class-compiler.d.ts +34 -0
- package/dist/compiler/class-compiler.js +437 -0
- package/dist/compiler/codegen.d.ts +144 -0
- package/dist/compiler/codegen.js +1585 -0
- package/dist/compiler/lexer.d.ts +27 -0
- package/dist/compiler/lexer.js +249 -0
- package/dist/compiler/parser.d.ts +58 -0
- package/dist/compiler/parser.js +984 -0
- package/dist/compiler/program.d.ts +29 -0
- package/dist/compiler/program.js +32 -0
- package/dist/compiler/scope.d.ts +22 -0
- package/dist/compiler/scope.js +238 -0
- package/dist/compression/lzma.d.ts +37 -0
- package/dist/compression/lzma.js +569 -0
- package/dist/compression/swf-container.d.ts +19 -0
- package/dist/compression/swf-container.js +87 -0
- package/dist/decompiler/ast.d.ts +228 -0
- package/dist/decompiler/ast.js +441 -0
- package/dist/decompiler/cfg.d.ts +40 -0
- package/dist/decompiler/cfg.js +231 -0
- package/dist/decompiler/class-printer.d.ts +9 -0
- package/dist/decompiler/class-printer.js +170 -0
- package/dist/decompiler/method.d.ts +41 -0
- package/dist/decompiler/method.js +427 -0
- package/dist/decompiler/simulate.d.ts +55 -0
- package/dist/decompiler/simulate.js +586 -0
- package/dist/decompiler/structure.d.ts +48 -0
- package/dist/decompiler/structure.js +760 -0
- package/dist/errors.d.ts +11 -0
- package/dist/errors.js +20 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.js +49 -0
- package/dist/io/reader.d.ts +48 -0
- package/dist/io/reader.js +176 -0
- package/dist/io/writer.d.ts +37 -0
- package/dist/io/writer.js +169 -0
- package/dist/project/pcode-project.d.ts +32 -0
- package/dist/project/pcode-project.js +203 -0
- package/dist/project/source-export.d.ts +12 -0
- package/dist/project/source-export.js +47 -0
- package/dist/project/source-import.d.ts +13 -0
- package/dist/project/source-import.js +70 -0
- package/dist/swf/swf.d.ts +63 -0
- package/dist/swf/swf.js +143 -0
- package/dist/swf/tag-codes.d.ts +77 -0
- package/dist/swf/tag-codes.js +105 -0
- package/dist/swf/tags.d.ts +118 -0
- package/dist/swf/tags.js +316 -0
- package/package.json +71 -4
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/** Namespace kinds (AVM2 overview §4.4.1). */
|
|
2
|
+
export declare const NamespaceKind: {
|
|
3
|
+
readonly Namespace: 8;
|
|
4
|
+
readonly PackageNamespace: 22;
|
|
5
|
+
readonly PackageInternalNs: 23;
|
|
6
|
+
readonly ProtectedNamespace: 24;
|
|
7
|
+
readonly ExplicitNamespace: 25;
|
|
8
|
+
readonly StaticProtectedNs: 26;
|
|
9
|
+
readonly PrivateNs: 5;
|
|
10
|
+
};
|
|
11
|
+
/** Multiname kinds (AVM2 overview §4.4.3). */
|
|
12
|
+
export declare const MultinameKind: {
|
|
13
|
+
readonly QName: 7;
|
|
14
|
+
readonly QNameA: 13;
|
|
15
|
+
readonly RTQName: 15;
|
|
16
|
+
readonly RTQNameA: 16;
|
|
17
|
+
readonly RTQNameL: 17;
|
|
18
|
+
readonly RTQNameLA: 18;
|
|
19
|
+
readonly Multiname: 9;
|
|
20
|
+
readonly MultinameA: 14;
|
|
21
|
+
readonly MultinameL: 27;
|
|
22
|
+
readonly MultinameLA: 28;
|
|
23
|
+
/** Parameterised type, e.g. Vector.<int>. */
|
|
24
|
+
readonly TypeName: 29;
|
|
25
|
+
};
|
|
26
|
+
/** Constant value kinds used for optional parameters and slot defaults. */
|
|
27
|
+
export declare const ConstantKind: {
|
|
28
|
+
readonly Undefined: 0;
|
|
29
|
+
readonly Utf8: 1;
|
|
30
|
+
readonly Decimal: 2;
|
|
31
|
+
readonly Int: 3;
|
|
32
|
+
readonly UInt: 4;
|
|
33
|
+
readonly PrivateNs: 5;
|
|
34
|
+
readonly Double: 6;
|
|
35
|
+
readonly Namespace: 8;
|
|
36
|
+
readonly False: 10;
|
|
37
|
+
readonly True: 11;
|
|
38
|
+
readonly Null: 12;
|
|
39
|
+
readonly PackageNamespace: 22;
|
|
40
|
+
readonly PackageInternalNs: 23;
|
|
41
|
+
readonly ProtectedNamespace: 24;
|
|
42
|
+
readonly ExplicitNamespace: 25;
|
|
43
|
+
readonly StaticProtectedNs: 26;
|
|
44
|
+
};
|
|
45
|
+
export declare const MethodFlags: {
|
|
46
|
+
readonly NEED_ARGUMENTS: 1;
|
|
47
|
+
readonly NEED_ACTIVATION: 2;
|
|
48
|
+
readonly NEED_REST: 4;
|
|
49
|
+
readonly HAS_OPTIONAL: 8;
|
|
50
|
+
readonly IGNORE_REST: 16;
|
|
51
|
+
readonly EXPLICIT: 32;
|
|
52
|
+
readonly SET_DXNS: 64;
|
|
53
|
+
readonly HAS_PARAM_NAMES: 128;
|
|
54
|
+
};
|
|
55
|
+
export declare const InstanceFlags: {
|
|
56
|
+
readonly Sealed: 1;
|
|
57
|
+
readonly Final: 2;
|
|
58
|
+
readonly Interface: 4;
|
|
59
|
+
readonly ProtectedNs: 8;
|
|
60
|
+
};
|
|
61
|
+
export declare const TraitKind: {
|
|
62
|
+
readonly Slot: 0;
|
|
63
|
+
readonly Method: 1;
|
|
64
|
+
readonly Getter: 2;
|
|
65
|
+
readonly Setter: 3;
|
|
66
|
+
readonly Class: 4;
|
|
67
|
+
readonly Function: 5;
|
|
68
|
+
readonly Const: 6;
|
|
69
|
+
};
|
|
70
|
+
export declare const TraitAttr: {
|
|
71
|
+
readonly Final: 1;
|
|
72
|
+
readonly Override: 2;
|
|
73
|
+
readonly Metadata: 4;
|
|
74
|
+
};
|
|
75
|
+
export declare const NAMESPACE_KIND_NAMES: Map<number, string>;
|
|
76
|
+
export declare const NAMESPACE_KIND_BY_NAME: Map<string, number>;
|
|
77
|
+
export declare const MULTINAME_KIND_NAMES: Map<number, "QName" | "QNameA" | "RTQName" | "RTQNameA" | "RTQNameL" | "RTQNameLA" | "Multiname" | "MultinameA" | "MultinameL" | "MultinameLA" | "TypeName">;
|
|
78
|
+
export declare const TRAIT_KIND_NAMES: Map<number, "Slot" | "Method" | "Getter" | "Setter" | "Class" | "Function" | "Const">;
|
|
79
|
+
export declare const METHOD_FLAG_NAMES: Map<number, "NEED_ARGUMENTS" | "NEED_ACTIVATION" | "NEED_REST" | "HAS_OPTIONAL" | "IGNORE_REST" | "EXPLICIT" | "SET_DXNS" | "HAS_PARAM_NAMES">;
|
|
80
|
+
export declare function isNamespaceKind(kind: number): boolean;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.METHOD_FLAG_NAMES = exports.TRAIT_KIND_NAMES = exports.MULTINAME_KIND_NAMES = exports.NAMESPACE_KIND_BY_NAME = exports.NAMESPACE_KIND_NAMES = exports.TraitAttr = exports.TraitKind = exports.InstanceFlags = exports.MethodFlags = exports.ConstantKind = exports.MultinameKind = exports.NamespaceKind = void 0;
|
|
4
|
+
exports.isNamespaceKind = isNamespaceKind;
|
|
5
|
+
/** Namespace kinds (AVM2 overview §4.4.1). */
|
|
6
|
+
exports.NamespaceKind = {
|
|
7
|
+
Namespace: 0x08,
|
|
8
|
+
PackageNamespace: 0x16,
|
|
9
|
+
PackageInternalNs: 0x17,
|
|
10
|
+
ProtectedNamespace: 0x18,
|
|
11
|
+
ExplicitNamespace: 0x19,
|
|
12
|
+
StaticProtectedNs: 0x1a,
|
|
13
|
+
PrivateNs: 0x05,
|
|
14
|
+
};
|
|
15
|
+
/** Multiname kinds (AVM2 overview §4.4.3). */
|
|
16
|
+
exports.MultinameKind = {
|
|
17
|
+
QName: 0x07,
|
|
18
|
+
QNameA: 0x0d,
|
|
19
|
+
RTQName: 0x0f,
|
|
20
|
+
RTQNameA: 0x10,
|
|
21
|
+
RTQNameL: 0x11,
|
|
22
|
+
RTQNameLA: 0x12,
|
|
23
|
+
Multiname: 0x09,
|
|
24
|
+
MultinameA: 0x0e,
|
|
25
|
+
MultinameL: 0x1b,
|
|
26
|
+
MultinameLA: 0x1c,
|
|
27
|
+
/** Parameterised type, e.g. Vector.<int>. */
|
|
28
|
+
TypeName: 0x1d,
|
|
29
|
+
};
|
|
30
|
+
/** Constant value kinds used for optional parameters and slot defaults. */
|
|
31
|
+
exports.ConstantKind = {
|
|
32
|
+
Undefined: 0x00,
|
|
33
|
+
Utf8: 0x01,
|
|
34
|
+
Decimal: 0x02,
|
|
35
|
+
Int: 0x03,
|
|
36
|
+
UInt: 0x04,
|
|
37
|
+
PrivateNs: 0x05,
|
|
38
|
+
Double: 0x06,
|
|
39
|
+
Namespace: 0x08,
|
|
40
|
+
False: 0x0a,
|
|
41
|
+
True: 0x0b,
|
|
42
|
+
Null: 0x0c,
|
|
43
|
+
PackageNamespace: 0x16,
|
|
44
|
+
PackageInternalNs: 0x17,
|
|
45
|
+
ProtectedNamespace: 0x18,
|
|
46
|
+
ExplicitNamespace: 0x19,
|
|
47
|
+
StaticProtectedNs: 0x1a,
|
|
48
|
+
};
|
|
49
|
+
exports.MethodFlags = {
|
|
50
|
+
NEED_ARGUMENTS: 0x01,
|
|
51
|
+
NEED_ACTIVATION: 0x02,
|
|
52
|
+
NEED_REST: 0x04,
|
|
53
|
+
HAS_OPTIONAL: 0x08,
|
|
54
|
+
IGNORE_REST: 0x10,
|
|
55
|
+
EXPLICIT: 0x20,
|
|
56
|
+
SET_DXNS: 0x40,
|
|
57
|
+
HAS_PARAM_NAMES: 0x80,
|
|
58
|
+
};
|
|
59
|
+
exports.InstanceFlags = {
|
|
60
|
+
Sealed: 0x01,
|
|
61
|
+
Final: 0x02,
|
|
62
|
+
Interface: 0x04,
|
|
63
|
+
ProtectedNs: 0x08,
|
|
64
|
+
};
|
|
65
|
+
exports.TraitKind = {
|
|
66
|
+
Slot: 0,
|
|
67
|
+
Method: 1,
|
|
68
|
+
Getter: 2,
|
|
69
|
+
Setter: 3,
|
|
70
|
+
Class: 4,
|
|
71
|
+
Function: 5,
|
|
72
|
+
Const: 6,
|
|
73
|
+
};
|
|
74
|
+
exports.TraitAttr = {
|
|
75
|
+
Final: 0x1,
|
|
76
|
+
Override: 0x2,
|
|
77
|
+
Metadata: 0x4,
|
|
78
|
+
};
|
|
79
|
+
function invert(o) {
|
|
80
|
+
return new Map(Object.entries(o).map(([k, v]) => [v, k]));
|
|
81
|
+
}
|
|
82
|
+
exports.NAMESPACE_KIND_NAMES = new Map([
|
|
83
|
+
[exports.NamespaceKind.Namespace, 'Namespace'],
|
|
84
|
+
[exports.NamespaceKind.PackageNamespace, 'PackageNamespace'],
|
|
85
|
+
[exports.NamespaceKind.PackageInternalNs, 'PackageInternalNs'],
|
|
86
|
+
[exports.NamespaceKind.ProtectedNamespace, 'ProtectedNamespace'],
|
|
87
|
+
[exports.NamespaceKind.ExplicitNamespace, 'ExplicitNamespace'],
|
|
88
|
+
[exports.NamespaceKind.StaticProtectedNs, 'StaticProtectedNs'],
|
|
89
|
+
[exports.NamespaceKind.PrivateNs, 'PrivateNamespace'],
|
|
90
|
+
]);
|
|
91
|
+
exports.NAMESPACE_KIND_BY_NAME = new Map([...exports.NAMESPACE_KIND_NAMES].map(([k, v]) => [v, k]));
|
|
92
|
+
exports.MULTINAME_KIND_NAMES = invert(exports.MultinameKind);
|
|
93
|
+
exports.TRAIT_KIND_NAMES = invert(exports.TraitKind);
|
|
94
|
+
exports.METHOD_FLAG_NAMES = invert(exports.MethodFlags);
|
|
95
|
+
function isNamespaceKind(kind) {
|
|
96
|
+
return exports.NAMESPACE_KIND_NAMES.has(kind);
|
|
97
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { AbcFile, MultinameInfo } from './abc-file.js';
|
|
2
|
+
/**
|
|
3
|
+
* Content-based constant pool interning.
|
|
4
|
+
*
|
|
5
|
+
* Unlike the index-based helpers on {@link AbcFile}, two pool entries are
|
|
6
|
+
* considered equal when they *mean* the same thing (e.g. a QName whose
|
|
7
|
+
* namespace refers to a duplicate-but-equal string), so assembling code
|
|
8
|
+
* reuses existing entries instead of growing the pools. Private namespaces
|
|
9
|
+
* are identity-based and never merged.
|
|
10
|
+
*/
|
|
11
|
+
export declare class Interner {
|
|
12
|
+
readonly abc: AbcFile;
|
|
13
|
+
private strMap;
|
|
14
|
+
private nsMap;
|
|
15
|
+
private nsSetMap;
|
|
16
|
+
private mnMap;
|
|
17
|
+
private nsKeys;
|
|
18
|
+
private nsSetKeys;
|
|
19
|
+
private mnKeys;
|
|
20
|
+
constructor(abc: AbcFile);
|
|
21
|
+
private strKey;
|
|
22
|
+
private registerNs;
|
|
23
|
+
private registerNsSet;
|
|
24
|
+
private mnKeyOf;
|
|
25
|
+
/** Key of an existing multiname; computed on demand because TypeNames may reference later entries. */
|
|
26
|
+
private mnKeyAt;
|
|
27
|
+
private registerMn;
|
|
28
|
+
/** String index; `null` → 0 (no string). */
|
|
29
|
+
string(s: string | null): number;
|
|
30
|
+
/**
|
|
31
|
+
* Namespace index. For private namespaces, `hint` selects an existing
|
|
32
|
+
* entry; without a hint the only private namespace with that name is used,
|
|
33
|
+
* or a new one is created if none exists.
|
|
34
|
+
*/
|
|
35
|
+
namespace(kind: number, name: string | null, hint?: number): number;
|
|
36
|
+
/** Always creates a new namespace entry (e.g. a fresh private namespace). */
|
|
37
|
+
addNs(kind: number, nameIndex: number): number;
|
|
38
|
+
nsSet(namespaces: number[]): number;
|
|
39
|
+
multiname(partial: Partial<MultinameInfo> & {
|
|
40
|
+
kind: number;
|
|
41
|
+
}): number;
|
|
42
|
+
qname(ns: number, name: string | null): number;
|
|
43
|
+
int(v: number): number;
|
|
44
|
+
uint(v: number): number;
|
|
45
|
+
double(v: number): number;
|
|
46
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Interner = void 0;
|
|
4
|
+
const abc_file_js_1 = require("./abc-file.js");
|
|
5
|
+
const constants_js_1 = require("./constants.js");
|
|
6
|
+
/**
|
|
7
|
+
* Content-based constant pool interning.
|
|
8
|
+
*
|
|
9
|
+
* Unlike the index-based helpers on {@link AbcFile}, two pool entries are
|
|
10
|
+
* considered equal when they *mean* the same thing (e.g. a QName whose
|
|
11
|
+
* namespace refers to a duplicate-but-equal string), so assembling code
|
|
12
|
+
* reuses existing entries instead of growing the pools. Private namespaces
|
|
13
|
+
* are identity-based and never merged.
|
|
14
|
+
*/
|
|
15
|
+
class Interner {
|
|
16
|
+
abc;
|
|
17
|
+
strMap = new Map();
|
|
18
|
+
nsMap = new Map();
|
|
19
|
+
nsSetMap = new Map();
|
|
20
|
+
mnMap = new Map();
|
|
21
|
+
nsKeys = [];
|
|
22
|
+
nsSetKeys = [];
|
|
23
|
+
mnKeys = [];
|
|
24
|
+
constructor(abc) {
|
|
25
|
+
this.abc = abc;
|
|
26
|
+
abc.strings.forEach((s, i) => {
|
|
27
|
+
if (i > 0 && !this.strMap.has(s))
|
|
28
|
+
this.strMap.set(s, i);
|
|
29
|
+
});
|
|
30
|
+
abc.namespaces.forEach((_, i) => this.registerNs(i));
|
|
31
|
+
abc.nsSets.forEach((_, i) => this.registerNsSet(i));
|
|
32
|
+
abc.multinames.forEach((_, i) => this.registerMn(i));
|
|
33
|
+
}
|
|
34
|
+
strKey(i) {
|
|
35
|
+
return i === 0 ? '∅' : JSON.stringify(this.abc.strings[i] ?? '');
|
|
36
|
+
}
|
|
37
|
+
registerNs(i) {
|
|
38
|
+
const ns = this.abc.namespaces[i];
|
|
39
|
+
const key = i === 0 ? '*' : ns.kind === constants_js_1.NamespaceKind.PrivateNs ? `${ns.kind}:${this.strKey(ns.name)}#${i}` : `${ns.kind}:${this.strKey(ns.name)}`;
|
|
40
|
+
this.nsKeys[i] = key;
|
|
41
|
+
if (!this.nsMap.has(key))
|
|
42
|
+
this.nsMap.set(key, i);
|
|
43
|
+
}
|
|
44
|
+
registerNsSet(i) {
|
|
45
|
+
const key = (this.abc.nsSets[i] ?? []).map((n) => this.nsKeys[n] ?? `?${n}`).join(',');
|
|
46
|
+
this.nsSetKeys[i] = key;
|
|
47
|
+
if (i > 0 && !this.nsSetMap.has(key))
|
|
48
|
+
this.nsSetMap.set(key, i);
|
|
49
|
+
}
|
|
50
|
+
mnKeyOf(m) {
|
|
51
|
+
switch (m.kind) {
|
|
52
|
+
case constants_js_1.MultinameKind.QName:
|
|
53
|
+
case constants_js_1.MultinameKind.QNameA:
|
|
54
|
+
return `${m.kind}(${this.nsKeys[m.ns]},${this.strKey(m.name)})`;
|
|
55
|
+
case constants_js_1.MultinameKind.RTQName:
|
|
56
|
+
case constants_js_1.MultinameKind.RTQNameA:
|
|
57
|
+
return `${m.kind}(${this.strKey(m.name)})`;
|
|
58
|
+
case constants_js_1.MultinameKind.RTQNameL:
|
|
59
|
+
case constants_js_1.MultinameKind.RTQNameLA:
|
|
60
|
+
return `${m.kind}()`;
|
|
61
|
+
case constants_js_1.MultinameKind.Multiname:
|
|
62
|
+
case constants_js_1.MultinameKind.MultinameA:
|
|
63
|
+
return `${m.kind}(${this.strKey(m.name)},[${this.nsSetKeys[m.nsSet]}])`;
|
|
64
|
+
case constants_js_1.MultinameKind.MultinameL:
|
|
65
|
+
case constants_js_1.MultinameKind.MultinameLA:
|
|
66
|
+
return `${m.kind}([${this.nsSetKeys[m.nsSet]}])`;
|
|
67
|
+
case constants_js_1.MultinameKind.TypeName:
|
|
68
|
+
return `${m.kind}(${this.mnKeyAt(m.base)},${m.params.map((p) => this.mnKeyAt(p)).join(',')})`;
|
|
69
|
+
default:
|
|
70
|
+
return `?${m.kind}`;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/** Key of an existing multiname; computed on demand because TypeNames may reference later entries. */
|
|
74
|
+
mnKeyAt(i, depth = 0) {
|
|
75
|
+
const cached = this.mnKeys[i];
|
|
76
|
+
if (cached !== undefined)
|
|
77
|
+
return cached;
|
|
78
|
+
const m = this.abc.multinames[i];
|
|
79
|
+
if (!m || depth > 32)
|
|
80
|
+
return `?${i}`;
|
|
81
|
+
if (i === 0)
|
|
82
|
+
return '*';
|
|
83
|
+
return this.mnKeyOf(m);
|
|
84
|
+
}
|
|
85
|
+
registerMn(i) {
|
|
86
|
+
const key = i === 0 ? '*' : this.mnKeyOf(this.abc.multinames[i]);
|
|
87
|
+
this.mnKeys[i] = key;
|
|
88
|
+
if (!this.mnMap.has(key))
|
|
89
|
+
this.mnMap.set(key, i);
|
|
90
|
+
}
|
|
91
|
+
/** String index; `null` → 0 (no string). */
|
|
92
|
+
string(s) {
|
|
93
|
+
if (s === null)
|
|
94
|
+
return 0;
|
|
95
|
+
let i = this.strMap.get(s);
|
|
96
|
+
if (i === undefined) {
|
|
97
|
+
i = this.abc.strings.length;
|
|
98
|
+
this.abc.strings.push(s);
|
|
99
|
+
this.strMap.set(s, i);
|
|
100
|
+
}
|
|
101
|
+
return i;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Namespace index. For private namespaces, `hint` selects an existing
|
|
105
|
+
* entry; without a hint the only private namespace with that name is used,
|
|
106
|
+
* or a new one is created if none exists.
|
|
107
|
+
*/
|
|
108
|
+
namespace(kind, name, hint) {
|
|
109
|
+
const nameIndex = this.string(name);
|
|
110
|
+
if (kind === constants_js_1.NamespaceKind.PrivateNs) {
|
|
111
|
+
if (hint !== undefined) {
|
|
112
|
+
const ns = this.abc.namespaces[hint];
|
|
113
|
+
if (ns && ns.kind === kind && this.strKey(ns.name) === this.strKey(nameIndex))
|
|
114
|
+
return hint;
|
|
115
|
+
}
|
|
116
|
+
const matches = [];
|
|
117
|
+
this.abc.namespaces.forEach((ns, i) => {
|
|
118
|
+
if (i > 0 && ns.kind === kind && this.strKey(ns.name) === this.strKey(nameIndex))
|
|
119
|
+
matches.push(i);
|
|
120
|
+
});
|
|
121
|
+
if (matches.length === 1)
|
|
122
|
+
return matches[0];
|
|
123
|
+
if (matches.length > 1) {
|
|
124
|
+
throw new Error(`Ambiguous PrivateNamespace(${name === null ? 'null' : JSON.stringify(name)}): candidates ${matches.join(', ')}; add the index, e.g. PrivateNamespace(${JSON.stringify(name)}, ${matches[0]})`);
|
|
125
|
+
}
|
|
126
|
+
return this.addNs(kind, nameIndex);
|
|
127
|
+
}
|
|
128
|
+
const key = `${kind}:${this.strKey(nameIndex)}`;
|
|
129
|
+
return this.nsMap.get(key) ?? this.addNs(kind, nameIndex);
|
|
130
|
+
}
|
|
131
|
+
/** Always creates a new namespace entry (e.g. a fresh private namespace). */
|
|
132
|
+
addNs(kind, nameIndex) {
|
|
133
|
+
const i = this.abc.namespaces.length;
|
|
134
|
+
this.abc.namespaces.push({ kind, name: nameIndex });
|
|
135
|
+
this.registerNs(i);
|
|
136
|
+
return i;
|
|
137
|
+
}
|
|
138
|
+
nsSet(namespaces) {
|
|
139
|
+
const key = namespaces.map((n) => this.nsKeys[n] ?? `?${n}`).join(',');
|
|
140
|
+
let i = this.nsSetMap.get(key);
|
|
141
|
+
if (i === undefined) {
|
|
142
|
+
i = this.abc.nsSets.length;
|
|
143
|
+
this.abc.nsSets.push([...namespaces]);
|
|
144
|
+
this.registerNsSet(i);
|
|
145
|
+
}
|
|
146
|
+
return i;
|
|
147
|
+
}
|
|
148
|
+
multiname(partial) {
|
|
149
|
+
const m = { ...(0, abc_file_js_1.emptyMultiname)(partial.kind), ...partial, params: [...(partial.params ?? [])] };
|
|
150
|
+
const key = this.mnKeyOf(m);
|
|
151
|
+
let i = this.mnMap.get(key);
|
|
152
|
+
if (i === undefined) {
|
|
153
|
+
i = this.abc.multinames.length;
|
|
154
|
+
this.abc.multinames.push(m);
|
|
155
|
+
this.registerMn(i);
|
|
156
|
+
}
|
|
157
|
+
return i;
|
|
158
|
+
}
|
|
159
|
+
qname(ns, name) {
|
|
160
|
+
return this.multiname({ kind: constants_js_1.MultinameKind.QName, ns, name: this.string(name) });
|
|
161
|
+
}
|
|
162
|
+
int(v) {
|
|
163
|
+
return this.abc.int(v);
|
|
164
|
+
}
|
|
165
|
+
uint(v) {
|
|
166
|
+
return this.abc.uint(v);
|
|
167
|
+
}
|
|
168
|
+
double(v) {
|
|
169
|
+
return this.abc.double(v);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
exports.Interner = Interner;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Higher-level navigation over an ABC file: classes, their methods, and
|
|
3
|
+
* human-readable method descriptions.
|
|
4
|
+
*/
|
|
5
|
+
import type { AbcFile, Trait } from './abc-file.js';
|
|
6
|
+
export type MethodRole = 'script-init' | 'class-init' | 'constructor' | 'method' | 'getter' | 'setter' | 'function' | 'closure';
|
|
7
|
+
export interface MethodRef {
|
|
8
|
+
methodIndex: number;
|
|
9
|
+
role: MethodRole;
|
|
10
|
+
/** Trait / method name ("" for initialisers and anonymous closures). */
|
|
11
|
+
name: string;
|
|
12
|
+
isStatic: boolean;
|
|
13
|
+
trait?: Trait;
|
|
14
|
+
}
|
|
15
|
+
/** Methods created with `newfunction` inside the given methods (recursively). */
|
|
16
|
+
export declare function closuresOf(abc: AbcFile, methodIndices: Iterable<number>): number[];
|
|
17
|
+
/** Script index whose traits define class `classIndex` (-1 if none). */
|
|
18
|
+
export declare function scriptOfClass(abc: AbcFile, classIndex: number): number;
|
|
19
|
+
/**
|
|
20
|
+
* All methods belonging to a class: static initialiser, constructor, static
|
|
21
|
+
* and instance methods/accessors and the closures they create.
|
|
22
|
+
*/
|
|
23
|
+
export declare function classMethods(abc: AbcFile, classIndex: number, includeClosures?: boolean): MethodRef[];
|
|
24
|
+
/** Methods of a script: its initialiser plus package-level functions. */
|
|
25
|
+
export declare function scriptMethods(abc: AbcFile, scriptIndex: number, includeClosures?: boolean): MethodRef[];
|
|
26
|
+
export interface FindMethodOptions {
|
|
27
|
+
/** Restrict to static (true) or instance (false) members. */
|
|
28
|
+
isStatic?: boolean;
|
|
29
|
+
role?: MethodRole;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Finds a method of a class by name. Use the class's own name (or
|
|
33
|
+
* "constructor") for the constructor and "cinit" for the static initialiser.
|
|
34
|
+
* Returns the method index or -1.
|
|
35
|
+
*/
|
|
36
|
+
export declare function findMethod(abc: AbcFile, className: string, methodName: string, options?: FindMethodOptions): number;
|
|
37
|
+
/** "com.foo.Bar/doThing", "com.foo.Bar/static get value", "com.foo.Bar/<cinit>", ... */
|
|
38
|
+
export declare function describeMethodRef(abc: AbcFile, owner: string, r: MethodRef): string;
|
|
39
|
+
/** Finds the owner of every method (class or script) and describes it. */
|
|
40
|
+
export declare function methodOwners(abc: AbcFile): Map<number, string>;
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.closuresOf = closuresOf;
|
|
4
|
+
exports.scriptOfClass = scriptOfClass;
|
|
5
|
+
exports.classMethods = classMethods;
|
|
6
|
+
exports.scriptMethods = scriptMethods;
|
|
7
|
+
exports.findMethod = findMethod;
|
|
8
|
+
exports.describeMethodRef = describeMethodRef;
|
|
9
|
+
exports.methodOwners = methodOwners;
|
|
10
|
+
const code_js_1 = require("./code.js");
|
|
11
|
+
const constants_js_1 = require("./constants.js");
|
|
12
|
+
const opcodes_js_1 = require("./opcodes.js");
|
|
13
|
+
const ROLE_BY_TRAIT = {
|
|
14
|
+
[constants_js_1.TraitKind.Method]: 'method',
|
|
15
|
+
[constants_js_1.TraitKind.Getter]: 'getter',
|
|
16
|
+
[constants_js_1.TraitKind.Setter]: 'setter',
|
|
17
|
+
[constants_js_1.TraitKind.Function]: 'function',
|
|
18
|
+
};
|
|
19
|
+
function traitMethods(abc, traits, isStatic) {
|
|
20
|
+
const out = [];
|
|
21
|
+
for (const t of traits) {
|
|
22
|
+
const role = ROLE_BY_TRAIT[t.kind];
|
|
23
|
+
if (role)
|
|
24
|
+
out.push({ methodIndex: t.method, role, name: abc.multinameName(t.name), isStatic, trait: t });
|
|
25
|
+
}
|
|
26
|
+
return out;
|
|
27
|
+
}
|
|
28
|
+
/** Methods created with `newfunction` inside the given methods (recursively). */
|
|
29
|
+
function closuresOf(abc, methodIndices) {
|
|
30
|
+
const seen = new Set(methodIndices);
|
|
31
|
+
const queue = [...seen];
|
|
32
|
+
const found = [];
|
|
33
|
+
while (queue.length) {
|
|
34
|
+
const m = queue.pop();
|
|
35
|
+
const body = abc.methodBody(m);
|
|
36
|
+
if (!body)
|
|
37
|
+
continue;
|
|
38
|
+
let items;
|
|
39
|
+
try {
|
|
40
|
+
items = (0, code_js_1.decodeCode)(body.code, body.exceptions).items;
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
for (const it of items) {
|
|
46
|
+
if (it.type === 'op' && it.op === opcodes_js_1.Op.newfunction) {
|
|
47
|
+
const f = it.args[0];
|
|
48
|
+
if (!seen.has(f)) {
|
|
49
|
+
seen.add(f);
|
|
50
|
+
found.push(f);
|
|
51
|
+
queue.push(f);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return found;
|
|
57
|
+
}
|
|
58
|
+
/** Script index whose traits define class `classIndex` (-1 if none). */
|
|
59
|
+
function scriptOfClass(abc, classIndex) {
|
|
60
|
+
for (let s = 0; s < abc.scripts.length; s++) {
|
|
61
|
+
if (abc.scripts[s].traits.some((t) => t.kind === constants_js_1.TraitKind.Class && t.classIndex === classIndex))
|
|
62
|
+
return s;
|
|
63
|
+
}
|
|
64
|
+
return -1;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* All methods belonging to a class: static initialiser, constructor, static
|
|
68
|
+
* and instance methods/accessors and the closures they create.
|
|
69
|
+
*/
|
|
70
|
+
function classMethods(abc, classIndex, includeClosures = true) {
|
|
71
|
+
const inst = abc.instances[classIndex];
|
|
72
|
+
const cls = abc.classes[classIndex];
|
|
73
|
+
if (!inst || !cls)
|
|
74
|
+
throw new Error(`Class index ${classIndex} out of range`);
|
|
75
|
+
const refs = [
|
|
76
|
+
{ methodIndex: cls.cinit, role: 'class-init', name: '', isStatic: true },
|
|
77
|
+
{ methodIndex: inst.iinit, role: 'constructor', name: abc.multinameName(inst.name), isStatic: false },
|
|
78
|
+
...traitMethods(abc, cls.traits, true),
|
|
79
|
+
...traitMethods(abc, inst.traits, false),
|
|
80
|
+
];
|
|
81
|
+
if (includeClosures) {
|
|
82
|
+
for (const m of closuresOf(abc, refs.map((r) => r.methodIndex)))
|
|
83
|
+
refs.push({ methodIndex: m, role: 'closure', name: abc.strings[abc.methods[m]?.name ?? 0] ?? '', isStatic: false });
|
|
84
|
+
}
|
|
85
|
+
return refs;
|
|
86
|
+
}
|
|
87
|
+
/** Methods of a script: its initialiser plus package-level functions. */
|
|
88
|
+
function scriptMethods(abc, scriptIndex, includeClosures = true) {
|
|
89
|
+
const s = abc.scripts[scriptIndex];
|
|
90
|
+
if (!s)
|
|
91
|
+
throw new Error(`Script index ${scriptIndex} out of range`);
|
|
92
|
+
const refs = [{ methodIndex: s.init, role: 'script-init', name: '', isStatic: true }, ...traitMethods(abc, s.traits, true)];
|
|
93
|
+
if (includeClosures) {
|
|
94
|
+
for (const m of closuresOf(abc, refs.map((r) => r.methodIndex)))
|
|
95
|
+
refs.push({ methodIndex: m, role: 'closure', name: abc.strings[abc.methods[m]?.name ?? 0] ?? '', isStatic: true });
|
|
96
|
+
}
|
|
97
|
+
return refs;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Finds a method of a class by name. Use the class's own name (or
|
|
101
|
+
* "constructor") for the constructor and "cinit" for the static initialiser.
|
|
102
|
+
* Returns the method index or -1.
|
|
103
|
+
*/
|
|
104
|
+
function findMethod(abc, className, methodName, options = {}) {
|
|
105
|
+
const ci = abc.findClass(className);
|
|
106
|
+
if (ci < 0)
|
|
107
|
+
return -1;
|
|
108
|
+
const refs = classMethods(abc, ci, false);
|
|
109
|
+
for (const r of refs) {
|
|
110
|
+
if (options.isStatic !== undefined && r.isStatic !== options.isStatic)
|
|
111
|
+
continue;
|
|
112
|
+
if (options.role !== undefined && r.role !== options.role)
|
|
113
|
+
continue;
|
|
114
|
+
if (methodName === 'constructor' && r.role === 'constructor')
|
|
115
|
+
return r.methodIndex;
|
|
116
|
+
if (methodName === 'cinit' && r.role === 'class-init')
|
|
117
|
+
return r.methodIndex;
|
|
118
|
+
if (r.role !== 'class-init' && r.name === methodName)
|
|
119
|
+
return r.methodIndex;
|
|
120
|
+
}
|
|
121
|
+
return -1;
|
|
122
|
+
}
|
|
123
|
+
/** "com.foo.Bar/doThing", "com.foo.Bar/static get value", "com.foo.Bar/<cinit>", ... */
|
|
124
|
+
function describeMethodRef(abc, owner, r) {
|
|
125
|
+
switch (r.role) {
|
|
126
|
+
case 'script-init':
|
|
127
|
+
return `${owner}/<script init>`;
|
|
128
|
+
case 'class-init':
|
|
129
|
+
return `${owner}/<cinit>`;
|
|
130
|
+
case 'constructor':
|
|
131
|
+
return `${owner}/<constructor>`;
|
|
132
|
+
case 'closure':
|
|
133
|
+
return `${owner}/<closure${r.name ? ' ' + r.name : ''}> (method ${r.methodIndex})`;
|
|
134
|
+
default: {
|
|
135
|
+
const prefix = (r.isStatic ? 'static ' : '') + (r.role === 'getter' ? 'get ' : r.role === 'setter' ? 'set ' : r.role === 'function' ? 'function ' : '');
|
|
136
|
+
return `${owner}/${prefix}${r.name}`;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/** Finds the owner of every method (class or script) and describes it. */
|
|
141
|
+
function methodOwners(abc) {
|
|
142
|
+
const map = new Map();
|
|
143
|
+
for (let c = 0; c < abc.instances.length; c++) {
|
|
144
|
+
const owner = abc.className(c);
|
|
145
|
+
for (const r of classMethods(abc, c))
|
|
146
|
+
if (!map.has(r.methodIndex))
|
|
147
|
+
map.set(r.methodIndex, describeMethodRef(abc, owner, r));
|
|
148
|
+
}
|
|
149
|
+
for (let s = 0; s < abc.scripts.length; s++) {
|
|
150
|
+
for (const r of scriptMethods(abc, s))
|
|
151
|
+
if (!map.has(r.methodIndex))
|
|
152
|
+
map.set(r.methodIndex, describeMethodRef(abc, `script${s}`, r));
|
|
153
|
+
}
|
|
154
|
+
return map;
|
|
155
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AVM2 instruction set table (AVM2 overview, chapter 5).
|
|
3
|
+
*/
|
|
4
|
+
export type OperandType =
|
|
5
|
+
/** Unsigned byte. */
|
|
6
|
+
'u8'
|
|
7
|
+
/** Signed byte (pushbyte). */
|
|
8
|
+
| 's8'
|
|
9
|
+
/** Generic u30 immediate (slot index, disp id, line number, ...). */
|
|
10
|
+
| 'u30'
|
|
11
|
+
/** Signed 32-bit immediate stored as u30 (pushshort). */
|
|
12
|
+
| 'short'
|
|
13
|
+
/** Argument count (affects stack effect). */
|
|
14
|
+
| 'argc'
|
|
15
|
+
/** Local register index. */
|
|
16
|
+
| 'reg' | 'int' | 'uint' | 'double' | 'string' | 'namespace' | 'multiname' | 'method' | 'class' | 'exception'
|
|
17
|
+
/** s24 branch offset, resolved to a label. */
|
|
18
|
+
| 'branch'
|
|
19
|
+
/** lookupswitch: default + case_count + cases. */
|
|
20
|
+
| 'switch';
|
|
21
|
+
export type FlowKind = 'jump' | 'cond' | 'switch' | 'return' | 'throw';
|
|
22
|
+
export interface OpInfo {
|
|
23
|
+
code: number;
|
|
24
|
+
name: string;
|
|
25
|
+
operands: OperandType[];
|
|
26
|
+
/** Fixed number of values popped. */
|
|
27
|
+
pop: number;
|
|
28
|
+
/** Extra values popped per argc (0, 1 or 2). */
|
|
29
|
+
popArgc: number;
|
|
30
|
+
/** Pops runtime multiname parts (namespace/name) of the multiname operand. */
|
|
31
|
+
popMn: boolean;
|
|
32
|
+
push: number;
|
|
33
|
+
/** Scope stack delta. */
|
|
34
|
+
scope: number;
|
|
35
|
+
flow?: FlowKind;
|
|
36
|
+
}
|
|
37
|
+
export declare function opInfo(code: number): OpInfo | undefined;
|
|
38
|
+
export declare function opByName(name: string): OpInfo | undefined;
|
|
39
|
+
export declare const Op: Record<string, number>;
|