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,93 @@
|
|
|
1
|
+
/** Namespace kinds (AVM2 overview §4.4.1). */
|
|
2
|
+
export const NamespaceKind = {
|
|
3
|
+
Namespace: 0x08,
|
|
4
|
+
PackageNamespace: 0x16,
|
|
5
|
+
PackageInternalNs: 0x17,
|
|
6
|
+
ProtectedNamespace: 0x18,
|
|
7
|
+
ExplicitNamespace: 0x19,
|
|
8
|
+
StaticProtectedNs: 0x1a,
|
|
9
|
+
PrivateNs: 0x05,
|
|
10
|
+
};
|
|
11
|
+
/** Multiname kinds (AVM2 overview §4.4.3). */
|
|
12
|
+
export const MultinameKind = {
|
|
13
|
+
QName: 0x07,
|
|
14
|
+
QNameA: 0x0d,
|
|
15
|
+
RTQName: 0x0f,
|
|
16
|
+
RTQNameA: 0x10,
|
|
17
|
+
RTQNameL: 0x11,
|
|
18
|
+
RTQNameLA: 0x12,
|
|
19
|
+
Multiname: 0x09,
|
|
20
|
+
MultinameA: 0x0e,
|
|
21
|
+
MultinameL: 0x1b,
|
|
22
|
+
MultinameLA: 0x1c,
|
|
23
|
+
/** Parameterised type, e.g. Vector.<int>. */
|
|
24
|
+
TypeName: 0x1d,
|
|
25
|
+
};
|
|
26
|
+
/** Constant value kinds used for optional parameters and slot defaults. */
|
|
27
|
+
export const ConstantKind = {
|
|
28
|
+
Undefined: 0x00,
|
|
29
|
+
Utf8: 0x01,
|
|
30
|
+
Decimal: 0x02,
|
|
31
|
+
Int: 0x03,
|
|
32
|
+
UInt: 0x04,
|
|
33
|
+
PrivateNs: 0x05,
|
|
34
|
+
Double: 0x06,
|
|
35
|
+
Namespace: 0x08,
|
|
36
|
+
False: 0x0a,
|
|
37
|
+
True: 0x0b,
|
|
38
|
+
Null: 0x0c,
|
|
39
|
+
PackageNamespace: 0x16,
|
|
40
|
+
PackageInternalNs: 0x17,
|
|
41
|
+
ProtectedNamespace: 0x18,
|
|
42
|
+
ExplicitNamespace: 0x19,
|
|
43
|
+
StaticProtectedNs: 0x1a,
|
|
44
|
+
};
|
|
45
|
+
export const MethodFlags = {
|
|
46
|
+
NEED_ARGUMENTS: 0x01,
|
|
47
|
+
NEED_ACTIVATION: 0x02,
|
|
48
|
+
NEED_REST: 0x04,
|
|
49
|
+
HAS_OPTIONAL: 0x08,
|
|
50
|
+
IGNORE_REST: 0x10,
|
|
51
|
+
EXPLICIT: 0x20,
|
|
52
|
+
SET_DXNS: 0x40,
|
|
53
|
+
HAS_PARAM_NAMES: 0x80,
|
|
54
|
+
};
|
|
55
|
+
export const InstanceFlags = {
|
|
56
|
+
Sealed: 0x01,
|
|
57
|
+
Final: 0x02,
|
|
58
|
+
Interface: 0x04,
|
|
59
|
+
ProtectedNs: 0x08,
|
|
60
|
+
};
|
|
61
|
+
export const TraitKind = {
|
|
62
|
+
Slot: 0,
|
|
63
|
+
Method: 1,
|
|
64
|
+
Getter: 2,
|
|
65
|
+
Setter: 3,
|
|
66
|
+
Class: 4,
|
|
67
|
+
Function: 5,
|
|
68
|
+
Const: 6,
|
|
69
|
+
};
|
|
70
|
+
export const TraitAttr = {
|
|
71
|
+
Final: 0x1,
|
|
72
|
+
Override: 0x2,
|
|
73
|
+
Metadata: 0x4,
|
|
74
|
+
};
|
|
75
|
+
function invert(o) {
|
|
76
|
+
return new Map(Object.entries(o).map(([k, v]) => [v, k]));
|
|
77
|
+
}
|
|
78
|
+
export const NAMESPACE_KIND_NAMES = new Map([
|
|
79
|
+
[NamespaceKind.Namespace, 'Namespace'],
|
|
80
|
+
[NamespaceKind.PackageNamespace, 'PackageNamespace'],
|
|
81
|
+
[NamespaceKind.PackageInternalNs, 'PackageInternalNs'],
|
|
82
|
+
[NamespaceKind.ProtectedNamespace, 'ProtectedNamespace'],
|
|
83
|
+
[NamespaceKind.ExplicitNamespace, 'ExplicitNamespace'],
|
|
84
|
+
[NamespaceKind.StaticProtectedNs, 'StaticProtectedNs'],
|
|
85
|
+
[NamespaceKind.PrivateNs, 'PrivateNamespace'],
|
|
86
|
+
]);
|
|
87
|
+
export const NAMESPACE_KIND_BY_NAME = new Map([...NAMESPACE_KIND_NAMES].map(([k, v]) => [v, k]));
|
|
88
|
+
export const MULTINAME_KIND_NAMES = invert(MultinameKind);
|
|
89
|
+
export const TRAIT_KIND_NAMES = invert(TraitKind);
|
|
90
|
+
export const METHOD_FLAG_NAMES = invert(MethodFlags);
|
|
91
|
+
export function isNamespaceKind(kind) {
|
|
92
|
+
return NAMESPACE_KIND_NAMES.has(kind);
|
|
93
|
+
}
|
|
@@ -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,168 @@
|
|
|
1
|
+
import { emptyMultiname } from './abc-file.js';
|
|
2
|
+
import { MultinameKind, NamespaceKind } from './constants.js';
|
|
3
|
+
/**
|
|
4
|
+
* Content-based constant pool interning.
|
|
5
|
+
*
|
|
6
|
+
* Unlike the index-based helpers on {@link AbcFile}, two pool entries are
|
|
7
|
+
* considered equal when they *mean* the same thing (e.g. a QName whose
|
|
8
|
+
* namespace refers to a duplicate-but-equal string), so assembling code
|
|
9
|
+
* reuses existing entries instead of growing the pools. Private namespaces
|
|
10
|
+
* are identity-based and never merged.
|
|
11
|
+
*/
|
|
12
|
+
export class Interner {
|
|
13
|
+
abc;
|
|
14
|
+
strMap = new Map();
|
|
15
|
+
nsMap = new Map();
|
|
16
|
+
nsSetMap = new Map();
|
|
17
|
+
mnMap = new Map();
|
|
18
|
+
nsKeys = [];
|
|
19
|
+
nsSetKeys = [];
|
|
20
|
+
mnKeys = [];
|
|
21
|
+
constructor(abc) {
|
|
22
|
+
this.abc = abc;
|
|
23
|
+
abc.strings.forEach((s, i) => {
|
|
24
|
+
if (i > 0 && !this.strMap.has(s))
|
|
25
|
+
this.strMap.set(s, i);
|
|
26
|
+
});
|
|
27
|
+
abc.namespaces.forEach((_, i) => this.registerNs(i));
|
|
28
|
+
abc.nsSets.forEach((_, i) => this.registerNsSet(i));
|
|
29
|
+
abc.multinames.forEach((_, i) => this.registerMn(i));
|
|
30
|
+
}
|
|
31
|
+
strKey(i) {
|
|
32
|
+
return i === 0 ? '∅' : JSON.stringify(this.abc.strings[i] ?? '');
|
|
33
|
+
}
|
|
34
|
+
registerNs(i) {
|
|
35
|
+
const ns = this.abc.namespaces[i];
|
|
36
|
+
const key = i === 0 ? '*' : ns.kind === NamespaceKind.PrivateNs ? `${ns.kind}:${this.strKey(ns.name)}#${i}` : `${ns.kind}:${this.strKey(ns.name)}`;
|
|
37
|
+
this.nsKeys[i] = key;
|
|
38
|
+
if (!this.nsMap.has(key))
|
|
39
|
+
this.nsMap.set(key, i);
|
|
40
|
+
}
|
|
41
|
+
registerNsSet(i) {
|
|
42
|
+
const key = (this.abc.nsSets[i] ?? []).map((n) => this.nsKeys[n] ?? `?${n}`).join(',');
|
|
43
|
+
this.nsSetKeys[i] = key;
|
|
44
|
+
if (i > 0 && !this.nsSetMap.has(key))
|
|
45
|
+
this.nsSetMap.set(key, i);
|
|
46
|
+
}
|
|
47
|
+
mnKeyOf(m) {
|
|
48
|
+
switch (m.kind) {
|
|
49
|
+
case MultinameKind.QName:
|
|
50
|
+
case MultinameKind.QNameA:
|
|
51
|
+
return `${m.kind}(${this.nsKeys[m.ns]},${this.strKey(m.name)})`;
|
|
52
|
+
case MultinameKind.RTQName:
|
|
53
|
+
case MultinameKind.RTQNameA:
|
|
54
|
+
return `${m.kind}(${this.strKey(m.name)})`;
|
|
55
|
+
case MultinameKind.RTQNameL:
|
|
56
|
+
case MultinameKind.RTQNameLA:
|
|
57
|
+
return `${m.kind}()`;
|
|
58
|
+
case MultinameKind.Multiname:
|
|
59
|
+
case MultinameKind.MultinameA:
|
|
60
|
+
return `${m.kind}(${this.strKey(m.name)},[${this.nsSetKeys[m.nsSet]}])`;
|
|
61
|
+
case MultinameKind.MultinameL:
|
|
62
|
+
case MultinameKind.MultinameLA:
|
|
63
|
+
return `${m.kind}([${this.nsSetKeys[m.nsSet]}])`;
|
|
64
|
+
case MultinameKind.TypeName:
|
|
65
|
+
return `${m.kind}(${this.mnKeyAt(m.base)},${m.params.map((p) => this.mnKeyAt(p)).join(',')})`;
|
|
66
|
+
default:
|
|
67
|
+
return `?${m.kind}`;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/** Key of an existing multiname; computed on demand because TypeNames may reference later entries. */
|
|
71
|
+
mnKeyAt(i, depth = 0) {
|
|
72
|
+
const cached = this.mnKeys[i];
|
|
73
|
+
if (cached !== undefined)
|
|
74
|
+
return cached;
|
|
75
|
+
const m = this.abc.multinames[i];
|
|
76
|
+
if (!m || depth > 32)
|
|
77
|
+
return `?${i}`;
|
|
78
|
+
if (i === 0)
|
|
79
|
+
return '*';
|
|
80
|
+
return this.mnKeyOf(m);
|
|
81
|
+
}
|
|
82
|
+
registerMn(i) {
|
|
83
|
+
const key = i === 0 ? '*' : this.mnKeyOf(this.abc.multinames[i]);
|
|
84
|
+
this.mnKeys[i] = key;
|
|
85
|
+
if (!this.mnMap.has(key))
|
|
86
|
+
this.mnMap.set(key, i);
|
|
87
|
+
}
|
|
88
|
+
/** String index; `null` → 0 (no string). */
|
|
89
|
+
string(s) {
|
|
90
|
+
if (s === null)
|
|
91
|
+
return 0;
|
|
92
|
+
let i = this.strMap.get(s);
|
|
93
|
+
if (i === undefined) {
|
|
94
|
+
i = this.abc.strings.length;
|
|
95
|
+
this.abc.strings.push(s);
|
|
96
|
+
this.strMap.set(s, i);
|
|
97
|
+
}
|
|
98
|
+
return i;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Namespace index. For private namespaces, `hint` selects an existing
|
|
102
|
+
* entry; without a hint the only private namespace with that name is used,
|
|
103
|
+
* or a new one is created if none exists.
|
|
104
|
+
*/
|
|
105
|
+
namespace(kind, name, hint) {
|
|
106
|
+
const nameIndex = this.string(name);
|
|
107
|
+
if (kind === NamespaceKind.PrivateNs) {
|
|
108
|
+
if (hint !== undefined) {
|
|
109
|
+
const ns = this.abc.namespaces[hint];
|
|
110
|
+
if (ns && ns.kind === kind && this.strKey(ns.name) === this.strKey(nameIndex))
|
|
111
|
+
return hint;
|
|
112
|
+
}
|
|
113
|
+
const matches = [];
|
|
114
|
+
this.abc.namespaces.forEach((ns, i) => {
|
|
115
|
+
if (i > 0 && ns.kind === kind && this.strKey(ns.name) === this.strKey(nameIndex))
|
|
116
|
+
matches.push(i);
|
|
117
|
+
});
|
|
118
|
+
if (matches.length === 1)
|
|
119
|
+
return matches[0];
|
|
120
|
+
if (matches.length > 1) {
|
|
121
|
+
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]})`);
|
|
122
|
+
}
|
|
123
|
+
return this.addNs(kind, nameIndex);
|
|
124
|
+
}
|
|
125
|
+
const key = `${kind}:${this.strKey(nameIndex)}`;
|
|
126
|
+
return this.nsMap.get(key) ?? this.addNs(kind, nameIndex);
|
|
127
|
+
}
|
|
128
|
+
/** Always creates a new namespace entry (e.g. a fresh private namespace). */
|
|
129
|
+
addNs(kind, nameIndex) {
|
|
130
|
+
const i = this.abc.namespaces.length;
|
|
131
|
+
this.abc.namespaces.push({ kind, name: nameIndex });
|
|
132
|
+
this.registerNs(i);
|
|
133
|
+
return i;
|
|
134
|
+
}
|
|
135
|
+
nsSet(namespaces) {
|
|
136
|
+
const key = namespaces.map((n) => this.nsKeys[n] ?? `?${n}`).join(',');
|
|
137
|
+
let i = this.nsSetMap.get(key);
|
|
138
|
+
if (i === undefined) {
|
|
139
|
+
i = this.abc.nsSets.length;
|
|
140
|
+
this.abc.nsSets.push([...namespaces]);
|
|
141
|
+
this.registerNsSet(i);
|
|
142
|
+
}
|
|
143
|
+
return i;
|
|
144
|
+
}
|
|
145
|
+
multiname(partial) {
|
|
146
|
+
const m = { ...emptyMultiname(partial.kind), ...partial, params: [...(partial.params ?? [])] };
|
|
147
|
+
const key = this.mnKeyOf(m);
|
|
148
|
+
let i = this.mnMap.get(key);
|
|
149
|
+
if (i === undefined) {
|
|
150
|
+
i = this.abc.multinames.length;
|
|
151
|
+
this.abc.multinames.push(m);
|
|
152
|
+
this.registerMn(i);
|
|
153
|
+
}
|
|
154
|
+
return i;
|
|
155
|
+
}
|
|
156
|
+
qname(ns, name) {
|
|
157
|
+
return this.multiname({ kind: MultinameKind.QName, ns, name: this.string(name) });
|
|
158
|
+
}
|
|
159
|
+
int(v) {
|
|
160
|
+
return this.abc.int(v);
|
|
161
|
+
}
|
|
162
|
+
uint(v) {
|
|
163
|
+
return this.abc.uint(v);
|
|
164
|
+
}
|
|
165
|
+
double(v) {
|
|
166
|
+
return this.abc.double(v);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
@@ -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,146 @@
|
|
|
1
|
+
import { decodeCode } from './code.js';
|
|
2
|
+
import { TraitKind } from './constants.js';
|
|
3
|
+
import { Op } from './opcodes.js';
|
|
4
|
+
const ROLE_BY_TRAIT = {
|
|
5
|
+
[TraitKind.Method]: 'method',
|
|
6
|
+
[TraitKind.Getter]: 'getter',
|
|
7
|
+
[TraitKind.Setter]: 'setter',
|
|
8
|
+
[TraitKind.Function]: 'function',
|
|
9
|
+
};
|
|
10
|
+
function traitMethods(abc, traits, isStatic) {
|
|
11
|
+
const out = [];
|
|
12
|
+
for (const t of traits) {
|
|
13
|
+
const role = ROLE_BY_TRAIT[t.kind];
|
|
14
|
+
if (role)
|
|
15
|
+
out.push({ methodIndex: t.method, role, name: abc.multinameName(t.name), isStatic, trait: t });
|
|
16
|
+
}
|
|
17
|
+
return out;
|
|
18
|
+
}
|
|
19
|
+
/** Methods created with `newfunction` inside the given methods (recursively). */
|
|
20
|
+
export function closuresOf(abc, methodIndices) {
|
|
21
|
+
const seen = new Set(methodIndices);
|
|
22
|
+
const queue = [...seen];
|
|
23
|
+
const found = [];
|
|
24
|
+
while (queue.length) {
|
|
25
|
+
const m = queue.pop();
|
|
26
|
+
const body = abc.methodBody(m);
|
|
27
|
+
if (!body)
|
|
28
|
+
continue;
|
|
29
|
+
let items;
|
|
30
|
+
try {
|
|
31
|
+
items = decodeCode(body.code, body.exceptions).items;
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
for (const it of items) {
|
|
37
|
+
if (it.type === 'op' && it.op === Op.newfunction) {
|
|
38
|
+
const f = it.args[0];
|
|
39
|
+
if (!seen.has(f)) {
|
|
40
|
+
seen.add(f);
|
|
41
|
+
found.push(f);
|
|
42
|
+
queue.push(f);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return found;
|
|
48
|
+
}
|
|
49
|
+
/** Script index whose traits define class `classIndex` (-1 if none). */
|
|
50
|
+
export function scriptOfClass(abc, classIndex) {
|
|
51
|
+
for (let s = 0; s < abc.scripts.length; s++) {
|
|
52
|
+
if (abc.scripts[s].traits.some((t) => t.kind === TraitKind.Class && t.classIndex === classIndex))
|
|
53
|
+
return s;
|
|
54
|
+
}
|
|
55
|
+
return -1;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* All methods belonging to a class: static initialiser, constructor, static
|
|
59
|
+
* and instance methods/accessors and the closures they create.
|
|
60
|
+
*/
|
|
61
|
+
export function classMethods(abc, classIndex, includeClosures = true) {
|
|
62
|
+
const inst = abc.instances[classIndex];
|
|
63
|
+
const cls = abc.classes[classIndex];
|
|
64
|
+
if (!inst || !cls)
|
|
65
|
+
throw new Error(`Class index ${classIndex} out of range`);
|
|
66
|
+
const refs = [
|
|
67
|
+
{ methodIndex: cls.cinit, role: 'class-init', name: '', isStatic: true },
|
|
68
|
+
{ methodIndex: inst.iinit, role: 'constructor', name: abc.multinameName(inst.name), isStatic: false },
|
|
69
|
+
...traitMethods(abc, cls.traits, true),
|
|
70
|
+
...traitMethods(abc, inst.traits, false),
|
|
71
|
+
];
|
|
72
|
+
if (includeClosures) {
|
|
73
|
+
for (const m of closuresOf(abc, refs.map((r) => r.methodIndex)))
|
|
74
|
+
refs.push({ methodIndex: m, role: 'closure', name: abc.strings[abc.methods[m]?.name ?? 0] ?? '', isStatic: false });
|
|
75
|
+
}
|
|
76
|
+
return refs;
|
|
77
|
+
}
|
|
78
|
+
/** Methods of a script: its initialiser plus package-level functions. */
|
|
79
|
+
export function scriptMethods(abc, scriptIndex, includeClosures = true) {
|
|
80
|
+
const s = abc.scripts[scriptIndex];
|
|
81
|
+
if (!s)
|
|
82
|
+
throw new Error(`Script index ${scriptIndex} out of range`);
|
|
83
|
+
const refs = [{ methodIndex: s.init, role: 'script-init', name: '', isStatic: true }, ...traitMethods(abc, s.traits, true)];
|
|
84
|
+
if (includeClosures) {
|
|
85
|
+
for (const m of closuresOf(abc, refs.map((r) => r.methodIndex)))
|
|
86
|
+
refs.push({ methodIndex: m, role: 'closure', name: abc.strings[abc.methods[m]?.name ?? 0] ?? '', isStatic: true });
|
|
87
|
+
}
|
|
88
|
+
return refs;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Finds a method of a class by name. Use the class's own name (or
|
|
92
|
+
* "constructor") for the constructor and "cinit" for the static initialiser.
|
|
93
|
+
* Returns the method index or -1.
|
|
94
|
+
*/
|
|
95
|
+
export function findMethod(abc, className, methodName, options = {}) {
|
|
96
|
+
const ci = abc.findClass(className);
|
|
97
|
+
if (ci < 0)
|
|
98
|
+
return -1;
|
|
99
|
+
const refs = classMethods(abc, ci, false);
|
|
100
|
+
for (const r of refs) {
|
|
101
|
+
if (options.isStatic !== undefined && r.isStatic !== options.isStatic)
|
|
102
|
+
continue;
|
|
103
|
+
if (options.role !== undefined && r.role !== options.role)
|
|
104
|
+
continue;
|
|
105
|
+
if (methodName === 'constructor' && r.role === 'constructor')
|
|
106
|
+
return r.methodIndex;
|
|
107
|
+
if (methodName === 'cinit' && r.role === 'class-init')
|
|
108
|
+
return r.methodIndex;
|
|
109
|
+
if (r.role !== 'class-init' && r.name === methodName)
|
|
110
|
+
return r.methodIndex;
|
|
111
|
+
}
|
|
112
|
+
return -1;
|
|
113
|
+
}
|
|
114
|
+
/** "com.foo.Bar/doThing", "com.foo.Bar/static get value", "com.foo.Bar/<cinit>", ... */
|
|
115
|
+
export function describeMethodRef(abc, owner, r) {
|
|
116
|
+
switch (r.role) {
|
|
117
|
+
case 'script-init':
|
|
118
|
+
return `${owner}/<script init>`;
|
|
119
|
+
case 'class-init':
|
|
120
|
+
return `${owner}/<cinit>`;
|
|
121
|
+
case 'constructor':
|
|
122
|
+
return `${owner}/<constructor>`;
|
|
123
|
+
case 'closure':
|
|
124
|
+
return `${owner}/<closure${r.name ? ' ' + r.name : ''}> (method ${r.methodIndex})`;
|
|
125
|
+
default: {
|
|
126
|
+
const prefix = (r.isStatic ? 'static ' : '') + (r.role === 'getter' ? 'get ' : r.role === 'setter' ? 'set ' : r.role === 'function' ? 'function ' : '');
|
|
127
|
+
return `${owner}/${prefix}${r.name}`;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/** Finds the owner of every method (class or script) and describes it. */
|
|
132
|
+
export function methodOwners(abc) {
|
|
133
|
+
const map = new Map();
|
|
134
|
+
for (let c = 0; c < abc.instances.length; c++) {
|
|
135
|
+
const owner = abc.className(c);
|
|
136
|
+
for (const r of classMethods(abc, c))
|
|
137
|
+
if (!map.has(r.methodIndex))
|
|
138
|
+
map.set(r.methodIndex, describeMethodRef(abc, owner, r));
|
|
139
|
+
}
|
|
140
|
+
for (let s = 0; s < abc.scripts.length; s++) {
|
|
141
|
+
for (const r of scriptMethods(abc, s))
|
|
142
|
+
if (!map.has(r.methodIndex))
|
|
143
|
+
map.set(r.methodIndex, describeMethodRef(abc, `script${s}`, r));
|
|
144
|
+
}
|
|
145
|
+
return map;
|
|
146
|
+
}
|
|
@@ -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>;
|