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.
Files changed (175) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +125 -2
  3. package/README.tr.md +126 -0
  4. package/dist/abc/abc-file.d.ts +168 -0
  5. package/dist/abc/abc-file.js +656 -0
  6. package/dist/abc/analysis.d.ts +36 -0
  7. package/dist/abc/analysis.js +213 -0
  8. package/dist/abc/code.d.ts +59 -0
  9. package/dist/abc/code.js +379 -0
  10. package/dist/abc/constants.d.ts +80 -0
  11. package/dist/abc/constants.js +93 -0
  12. package/dist/abc/interner.d.ts +46 -0
  13. package/dist/abc/interner.js +168 -0
  14. package/dist/abc/model.d.ts +40 -0
  15. package/dist/abc/model.js +146 -0
  16. package/dist/abc/opcodes.d.ts +39 -0
  17. package/dist/abc/opcodes.js +196 -0
  18. package/dist/abc/pcode/assembler.d.ts +42 -0
  19. package/dist/abc/pcode/assembler.js +635 -0
  20. package/dist/abc/pcode/disassembler.d.ts +17 -0
  21. package/dist/abc/pcode/disassembler.js +147 -0
  22. package/dist/abc/pcode/format.d.ts +23 -0
  23. package/dist/abc/pcode/format.js +131 -0
  24. package/dist/abc/pcode/lexer.d.ts +34 -0
  25. package/dist/abc/pcode/lexer.js +183 -0
  26. package/dist/assets/assets.d.ts +26 -0
  27. package/dist/assets/assets.js +151 -0
  28. package/dist/assets/images.d.ts +31 -0
  29. package/dist/assets/images.js +238 -0
  30. package/dist/assets/png.d.ts +12 -0
  31. package/dist/assets/png.js +196 -0
  32. package/dist/assets/sounds.d.ts +37 -0
  33. package/dist/assets/sounds.js +236 -0
  34. package/dist/avm1/avm1.d.ts +55 -0
  35. package/dist/avm1/avm1.js +642 -0
  36. package/dist/avm1/project.d.ts +16 -0
  37. package/dist/avm1/project.js +81 -0
  38. package/dist/cjs/abc/abc-file.d.ts +168 -0
  39. package/dist/cjs/abc/abc-file.js +663 -0
  40. package/dist/cjs/abc/analysis.d.ts +36 -0
  41. package/dist/cjs/abc/analysis.js +221 -0
  42. package/dist/cjs/abc/code.d.ts +59 -0
  43. package/dist/cjs/abc/code.js +387 -0
  44. package/dist/cjs/abc/constants.d.ts +80 -0
  45. package/dist/cjs/abc/constants.js +97 -0
  46. package/dist/cjs/abc/interner.d.ts +46 -0
  47. package/dist/cjs/abc/interner.js +172 -0
  48. package/dist/cjs/abc/model.d.ts +40 -0
  49. package/dist/cjs/abc/model.js +155 -0
  50. package/dist/cjs/abc/opcodes.d.ts +39 -0
  51. package/dist/cjs/abc/opcodes.js +201 -0
  52. package/dist/cjs/abc/pcode/assembler.d.ts +42 -0
  53. package/dist/cjs/abc/pcode/assembler.js +640 -0
  54. package/dist/cjs/abc/pcode/disassembler.d.ts +17 -0
  55. package/dist/cjs/abc/pcode/disassembler.js +152 -0
  56. package/dist/cjs/abc/pcode/format.d.ts +23 -0
  57. package/dist/cjs/abc/pcode/format.js +141 -0
  58. package/dist/cjs/abc/pcode/lexer.d.ts +34 -0
  59. package/dist/cjs/abc/pcode/lexer.js +188 -0
  60. package/dist/cjs/assets/assets.d.ts +26 -0
  61. package/dist/cjs/assets/assets.js +159 -0
  62. package/dist/cjs/assets/images.d.ts +31 -0
  63. package/dist/cjs/assets/images.js +246 -0
  64. package/dist/cjs/assets/png.d.ts +12 -0
  65. package/dist/cjs/assets/png.js +202 -0
  66. package/dist/cjs/assets/sounds.d.ts +37 -0
  67. package/dist/cjs/assets/sounds.js +246 -0
  68. package/dist/cjs/avm1/avm1.d.ts +55 -0
  69. package/dist/cjs/avm1/avm1.js +649 -0
  70. package/dist/cjs/avm1/project.d.ts +16 -0
  71. package/dist/cjs/avm1/project.js +88 -0
  72. package/dist/cjs/compiler/ast.d.ts +285 -0
  73. package/dist/cjs/compiler/ast.js +3 -0
  74. package/dist/cjs/compiler/class-compiler.d.ts +34 -0
  75. package/dist/cjs/compiler/class-compiler.js +440 -0
  76. package/dist/cjs/compiler/codegen.d.ts +144 -0
  77. package/dist/cjs/compiler/codegen.js +1589 -0
  78. package/dist/cjs/compiler/lexer.d.ts +27 -0
  79. package/dist/cjs/compiler/lexer.js +254 -0
  80. package/dist/cjs/compiler/parser.d.ts +58 -0
  81. package/dist/cjs/compiler/parser.js +989 -0
  82. package/dist/cjs/compiler/program.d.ts +29 -0
  83. package/dist/cjs/compiler/program.js +36 -0
  84. package/dist/cjs/compiler/scope.d.ts +22 -0
  85. package/dist/cjs/compiler/scope.js +242 -0
  86. package/dist/cjs/compression/lzma.d.ts +37 -0
  87. package/dist/cjs/compression/lzma.js +575 -0
  88. package/dist/cjs/compression/swf-container.d.ts +19 -0
  89. package/dist/cjs/compression/swf-container.js +92 -0
  90. package/dist/cjs/decompiler/ast.d.ts +228 -0
  91. package/dist/cjs/decompiler/ast.js +455 -0
  92. package/dist/cjs/decompiler/cfg.d.ts +40 -0
  93. package/dist/cjs/decompiler/cfg.js +236 -0
  94. package/dist/cjs/decompiler/class-printer.d.ts +9 -0
  95. package/dist/cjs/decompiler/class-printer.js +173 -0
  96. package/dist/cjs/decompiler/method.d.ts +41 -0
  97. package/dist/cjs/decompiler/method.js +436 -0
  98. package/dist/cjs/decompiler/simulate.d.ts +55 -0
  99. package/dist/cjs/decompiler/simulate.js +591 -0
  100. package/dist/cjs/decompiler/structure.d.ts +48 -0
  101. package/dist/cjs/decompiler/structure.js +764 -0
  102. package/dist/cjs/errors.d.ts +11 -0
  103. package/dist/cjs/errors.js +25 -0
  104. package/dist/cjs/index.d.ts +41 -0
  105. package/dist/cjs/index.js +82 -0
  106. package/dist/cjs/io/reader.d.ts +48 -0
  107. package/dist/cjs/io/reader.js +180 -0
  108. package/dist/cjs/io/writer.d.ts +37 -0
  109. package/dist/cjs/io/writer.js +175 -0
  110. package/dist/cjs/package.json +1 -0
  111. package/dist/cjs/project/pcode-project.d.ts +32 -0
  112. package/dist/cjs/project/pcode-project.js +210 -0
  113. package/dist/cjs/project/source-export.d.ts +12 -0
  114. package/dist/cjs/project/source-export.js +51 -0
  115. package/dist/cjs/project/source-import.d.ts +13 -0
  116. package/dist/cjs/project/source-import.js +73 -0
  117. package/dist/cjs/swf/swf.d.ts +63 -0
  118. package/dist/cjs/swf/swf.js +147 -0
  119. package/dist/cjs/swf/tag-codes.d.ts +77 -0
  120. package/dist/cjs/swf/tag-codes.js +109 -0
  121. package/dist/cjs/swf/tags.d.ts +118 -0
  122. package/dist/cjs/swf/tags.js +330 -0
  123. package/dist/cli.d.ts +2 -0
  124. package/dist/cli.js +296 -0
  125. package/dist/compiler/ast.d.ts +285 -0
  126. package/dist/compiler/ast.js +2 -0
  127. package/dist/compiler/class-compiler.d.ts +34 -0
  128. package/dist/compiler/class-compiler.js +437 -0
  129. package/dist/compiler/codegen.d.ts +144 -0
  130. package/dist/compiler/codegen.js +1585 -0
  131. package/dist/compiler/lexer.d.ts +27 -0
  132. package/dist/compiler/lexer.js +249 -0
  133. package/dist/compiler/parser.d.ts +58 -0
  134. package/dist/compiler/parser.js +984 -0
  135. package/dist/compiler/program.d.ts +29 -0
  136. package/dist/compiler/program.js +32 -0
  137. package/dist/compiler/scope.d.ts +22 -0
  138. package/dist/compiler/scope.js +238 -0
  139. package/dist/compression/lzma.d.ts +37 -0
  140. package/dist/compression/lzma.js +569 -0
  141. package/dist/compression/swf-container.d.ts +19 -0
  142. package/dist/compression/swf-container.js +87 -0
  143. package/dist/decompiler/ast.d.ts +228 -0
  144. package/dist/decompiler/ast.js +441 -0
  145. package/dist/decompiler/cfg.d.ts +40 -0
  146. package/dist/decompiler/cfg.js +231 -0
  147. package/dist/decompiler/class-printer.d.ts +9 -0
  148. package/dist/decompiler/class-printer.js +170 -0
  149. package/dist/decompiler/method.d.ts +41 -0
  150. package/dist/decompiler/method.js +427 -0
  151. package/dist/decompiler/simulate.d.ts +55 -0
  152. package/dist/decompiler/simulate.js +586 -0
  153. package/dist/decompiler/structure.d.ts +48 -0
  154. package/dist/decompiler/structure.js +760 -0
  155. package/dist/errors.d.ts +11 -0
  156. package/dist/errors.js +20 -0
  157. package/dist/index.d.ts +41 -0
  158. package/dist/index.js +49 -0
  159. package/dist/io/reader.d.ts +48 -0
  160. package/dist/io/reader.js +176 -0
  161. package/dist/io/writer.d.ts +37 -0
  162. package/dist/io/writer.js +169 -0
  163. package/dist/project/pcode-project.d.ts +32 -0
  164. package/dist/project/pcode-project.js +203 -0
  165. package/dist/project/source-export.d.ts +12 -0
  166. package/dist/project/source-export.js +47 -0
  167. package/dist/project/source-import.d.ts +13 -0
  168. package/dist/project/source-import.js +70 -0
  169. package/dist/swf/swf.d.ts +63 -0
  170. package/dist/swf/swf.js +143 -0
  171. package/dist/swf/tag-codes.d.ts +77 -0
  172. package/dist/swf/tag-codes.js +105 -0
  173. package/dist/swf/tags.d.ts +118 -0
  174. package/dist/swf/tags.js +316 -0
  175. package/package.json +71 -4
@@ -0,0 +1,663 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AbcFile = void 0;
4
+ exports.emptyMultiname = emptyMultiname;
5
+ exports.newTrait = newTrait;
6
+ exports.splitQualifiedName = splitQualifiedName;
7
+ const reader_js_1 = require("../io/reader.js");
8
+ const writer_js_1 = require("../io/writer.js");
9
+ const errors_js_1 = require("../errors.js");
10
+ const constants_js_1 = require("./constants.js");
11
+ function emptyMultiname(kind = 0) {
12
+ return { kind, ns: 0, name: 0, nsSet: 0, base: 0, params: [] };
13
+ }
14
+ function newTrait(partial) {
15
+ return {
16
+ attrs: 0,
17
+ id: 0,
18
+ typeName: 0,
19
+ valueIndex: 0,
20
+ valueKind: 0,
21
+ classIndex: 0,
22
+ method: 0,
23
+ metadata: [],
24
+ ...partial,
25
+ };
26
+ }
27
+ const utf8Strict = new TextDecoder('utf-8', { fatal: true });
28
+ const utf8Lossy = new TextDecoder('utf-8');
29
+ const utf8Encoder = new TextEncoder();
30
+ /** Simple pool lookup cache that tolerates direct pushes to the pool array. */
31
+ class PoolCache {
32
+ pool;
33
+ key;
34
+ first;
35
+ map = new Map();
36
+ scanned = 0;
37
+ constructor(pool, key, first = 1) {
38
+ this.pool = pool;
39
+ this.key = key;
40
+ this.first = first;
41
+ }
42
+ find(k) {
43
+ const pool = this.pool();
44
+ if (this.scanned > pool.length) {
45
+ this.map.clear();
46
+ this.scanned = 0;
47
+ }
48
+ for (let i = Math.max(this.scanned, this.first); i < pool.length; i++) {
49
+ const pk = this.key(pool[i]);
50
+ if (!this.map.has(pk))
51
+ this.map.set(pk, i);
52
+ }
53
+ this.scanned = pool.length;
54
+ const hit = this.map.get(k);
55
+ if (hit !== undefined) {
56
+ if (hit < pool.length && this.key(pool[hit]) === k)
57
+ return hit;
58
+ // Entry was modified in place: rebuild.
59
+ this.map.clear();
60
+ this.scanned = 0;
61
+ return this.find(k);
62
+ }
63
+ return -1;
64
+ }
65
+ }
66
+ const nsKey = (n) => `${n.kind}:${n.name}`;
67
+ const nsSetKey = (s) => s.join(',');
68
+ const mnKey = (m) => `${m.kind}:${m.ns}:${m.name}:${m.nsSet}:${m.base}:${m.params.join(',')}`;
69
+ /** A parsed ActionScript Byte Code (ABC) file. */
70
+ class AbcFile {
71
+ minorVersion = 16;
72
+ majorVersion = 46;
73
+ ints = [0];
74
+ uints = [0];
75
+ doubles = [NaN];
76
+ strings = [''];
77
+ namespaces = [{ kind: 0, name: 0 }];
78
+ nsSets = [[]];
79
+ multinames = [emptyMultiname()];
80
+ methods = [];
81
+ metadata = [];
82
+ instances = [];
83
+ classes = [];
84
+ scripts = [];
85
+ bodies = [];
86
+ /** Raw bytes of strings that are not valid UTF-8, keyed by pool index. */
87
+ rawStrings = new Map();
88
+ /** Pools whose count was written as 1 (instead of 0) while empty; preserved for exact round-trips. */
89
+ onePools = new Set();
90
+ intCache = new PoolCache(() => this.ints, (v) => String(v));
91
+ uintCache = new PoolCache(() => this.uints, (v) => String(v));
92
+ doubleCache = new PoolCache(() => this.doubles, (v) => (Object.is(v, -0) ? '-0' : String(v)));
93
+ stringCache = new PoolCache(() => this.strings, (v) => v);
94
+ nsCache = new PoolCache(() => this.namespaces, nsKey);
95
+ nsSetCache = new PoolCache(() => this.nsSets, nsSetKey);
96
+ mnCache = new PoolCache(() => this.multinames, mnKey);
97
+ bodyIndex;
98
+ bodyIndexSize = -1;
99
+ // -------------------------------------------------------------------------
100
+ // Parsing
101
+ // -------------------------------------------------------------------------
102
+ static parse(bytes) {
103
+ const r = new reader_js_1.ByteReader(bytes);
104
+ const abc = new AbcFile();
105
+ const u30 = () => r.encodedU32();
106
+ abc.minorVersion = r.u16();
107
+ abc.majorVersion = r.u16();
108
+ let n = u30();
109
+ if (n === 1)
110
+ abc.onePools.add('ints');
111
+ for (let i = 1; i < n; i++)
112
+ abc.ints.push(u30() | 0);
113
+ n = u30();
114
+ if (n === 1)
115
+ abc.onePools.add('uints');
116
+ for (let i = 1; i < n; i++)
117
+ abc.uints.push(u30() >>> 0);
118
+ n = u30();
119
+ if (n === 1)
120
+ abc.onePools.add('doubles');
121
+ for (let i = 1; i < n; i++)
122
+ abc.doubles.push(r.f64());
123
+ n = u30();
124
+ if (n === 1)
125
+ abc.onePools.add('strings');
126
+ for (let i = 1; i < n; i++) {
127
+ const len = u30();
128
+ const raw = r.bytesView(len);
129
+ let s;
130
+ try {
131
+ s = utf8Strict.decode(raw);
132
+ }
133
+ catch {
134
+ s = utf8Lossy.decode(raw);
135
+ abc.rawStrings.set(i, { decoded: s, bytes: raw.slice() });
136
+ }
137
+ abc.strings.push(s);
138
+ }
139
+ n = u30();
140
+ if (n === 1)
141
+ abc.onePools.add('namespaces');
142
+ for (let i = 1; i < n; i++)
143
+ abc.namespaces.push({ kind: r.u8(), name: u30() });
144
+ n = u30();
145
+ if (n === 1)
146
+ abc.onePools.add('nsSets');
147
+ for (let i = 1; i < n; i++) {
148
+ const c = u30();
149
+ const set = [];
150
+ for (let j = 0; j < c; j++)
151
+ set.push(u30());
152
+ abc.nsSets.push(set);
153
+ }
154
+ n = u30();
155
+ if (n === 1)
156
+ abc.onePools.add('multinames');
157
+ for (let i = 1; i < n; i++) {
158
+ const kind = r.u8();
159
+ const m = emptyMultiname(kind);
160
+ switch (kind) {
161
+ case constants_js_1.MultinameKind.QName:
162
+ case constants_js_1.MultinameKind.QNameA:
163
+ m.ns = u30();
164
+ m.name = u30();
165
+ break;
166
+ case constants_js_1.MultinameKind.RTQName:
167
+ case constants_js_1.MultinameKind.RTQNameA:
168
+ m.name = u30();
169
+ break;
170
+ case constants_js_1.MultinameKind.RTQNameL:
171
+ case constants_js_1.MultinameKind.RTQNameLA:
172
+ break;
173
+ case constants_js_1.MultinameKind.Multiname:
174
+ case constants_js_1.MultinameKind.MultinameA:
175
+ m.name = u30();
176
+ m.nsSet = u30();
177
+ break;
178
+ case constants_js_1.MultinameKind.MultinameL:
179
+ case constants_js_1.MultinameKind.MultinameLA:
180
+ m.nsSet = u30();
181
+ break;
182
+ case constants_js_1.MultinameKind.TypeName: {
183
+ m.base = u30();
184
+ const c = u30();
185
+ for (let j = 0; j < c; j++)
186
+ m.params.push(u30());
187
+ break;
188
+ }
189
+ default:
190
+ throw new errors_js_1.SwfFormatError(`Unknown multiname kind 0x${kind.toString(16)} at pool index ${i}`);
191
+ }
192
+ abc.multinames.push(m);
193
+ }
194
+ n = u30();
195
+ for (let i = 0; i < n; i++) {
196
+ const paramCount = u30();
197
+ const returnType = u30();
198
+ const paramTypes = [];
199
+ for (let j = 0; j < paramCount; j++)
200
+ paramTypes.push(u30());
201
+ const name = u30();
202
+ const flags = r.u8();
203
+ const optional = [];
204
+ if (flags & constants_js_1.MethodFlags.HAS_OPTIONAL) {
205
+ const c = u30();
206
+ for (let j = 0; j < c; j++) {
207
+ const value = u30();
208
+ optional.push({ value, kind: r.u8() });
209
+ }
210
+ }
211
+ const paramNames = [];
212
+ if (flags & constants_js_1.MethodFlags.HAS_PARAM_NAMES)
213
+ for (let j = 0; j < paramCount; j++)
214
+ paramNames.push(u30());
215
+ abc.methods.push({ paramTypes, returnType, name, flags, optional, paramNames });
216
+ }
217
+ n = u30();
218
+ for (let i = 0; i < n; i++) {
219
+ const name = u30();
220
+ const c = u30();
221
+ const keys = [];
222
+ const values = [];
223
+ for (let j = 0; j < c; j++)
224
+ keys.push(u30());
225
+ for (let j = 0; j < c; j++)
226
+ values.push(u30());
227
+ abc.metadata.push({ name, keys, values });
228
+ }
229
+ const readTraits = () => {
230
+ const c = u30();
231
+ const traits = [];
232
+ for (let j = 0; j < c; j++) {
233
+ const name = u30();
234
+ const kindByte = r.u8();
235
+ const t = newTrait({ name, kind: kindByte & 0x0f, attrs: kindByte >> 4 });
236
+ switch (t.kind) {
237
+ case constants_js_1.TraitKind.Slot:
238
+ case constants_js_1.TraitKind.Const:
239
+ t.id = u30();
240
+ t.typeName = u30();
241
+ t.valueIndex = u30();
242
+ if (t.valueIndex !== 0)
243
+ t.valueKind = r.u8();
244
+ break;
245
+ case constants_js_1.TraitKind.Class:
246
+ t.id = u30();
247
+ t.classIndex = u30();
248
+ break;
249
+ case constants_js_1.TraitKind.Function:
250
+ t.id = u30();
251
+ t.method = u30();
252
+ break;
253
+ case constants_js_1.TraitKind.Method:
254
+ case constants_js_1.TraitKind.Getter:
255
+ case constants_js_1.TraitKind.Setter:
256
+ t.id = u30();
257
+ t.method = u30();
258
+ break;
259
+ default:
260
+ throw new errors_js_1.SwfFormatError(`Unknown trait kind ${t.kind}`);
261
+ }
262
+ if (t.attrs & constants_js_1.TraitAttr.Metadata) {
263
+ const mc = u30();
264
+ for (let k = 0; k < mc; k++)
265
+ t.metadata.push(u30());
266
+ }
267
+ traits.push(t);
268
+ }
269
+ return traits;
270
+ };
271
+ const classCount = u30();
272
+ for (let i = 0; i < classCount; i++) {
273
+ const name = u30();
274
+ const superName = u30();
275
+ const flags = r.u8();
276
+ const protectedNs = flags & constants_js_1.InstanceFlags.ProtectedNs ? u30() : 0;
277
+ const ic = u30();
278
+ const interfaces = [];
279
+ for (let j = 0; j < ic; j++)
280
+ interfaces.push(u30());
281
+ const iinit = u30();
282
+ abc.instances.push({ name, superName, flags, protectedNs, interfaces, iinit, traits: readTraits() });
283
+ }
284
+ for (let i = 0; i < classCount; i++) {
285
+ const cinit = u30();
286
+ abc.classes.push({ cinit, traits: readTraits() });
287
+ }
288
+ n = u30();
289
+ for (let i = 0; i < n; i++) {
290
+ const init = u30();
291
+ abc.scripts.push({ init, traits: readTraits() });
292
+ }
293
+ n = u30();
294
+ for (let i = 0; i < n; i++) {
295
+ const method = u30();
296
+ const maxStack = u30();
297
+ const localCount = u30();
298
+ const initScopeDepth = u30();
299
+ const maxScopeDepth = u30();
300
+ const codeLength = u30();
301
+ const code = r.bytesCopy(codeLength);
302
+ const ec = u30();
303
+ const exceptions = [];
304
+ for (let j = 0; j < ec; j++) {
305
+ exceptions.push({ from: u30(), to: u30(), target: u30(), excType: u30(), varName: u30() });
306
+ }
307
+ abc.bodies.push({ method, maxStack, localCount, initScopeDepth, maxScopeDepth, code, exceptions, traits: readTraits() });
308
+ }
309
+ return abc;
310
+ }
311
+ // -------------------------------------------------------------------------
312
+ // Serialisation
313
+ // -------------------------------------------------------------------------
314
+ toBytes() {
315
+ const w = new writer_js_1.ByteWriter(1 << 16);
316
+ const u30 = (v) => {
317
+ w.encodedU32(v);
318
+ };
319
+ const count = (items, name) => items.length > 1 ? items.length : this.onePools.has(name) ? 1 : 0;
320
+ const pool = (items, name, write) => {
321
+ u30(count(items, name));
322
+ for (let i = 1; i < items.length; i++)
323
+ write(items[i]);
324
+ };
325
+ w.u16(this.minorVersion);
326
+ w.u16(this.majorVersion);
327
+ pool(this.ints, 'ints', (v) => u30(v >>> 0));
328
+ pool(this.uints, 'uints', (v) => u30(v >>> 0));
329
+ pool(this.doubles, 'doubles', (v) => w.f64(v));
330
+ u30(count(this.strings, 'strings'));
331
+ for (let i = 1; i < this.strings.length; i++) {
332
+ const s = this.strings[i];
333
+ const raw = this.rawStrings.get(i);
334
+ const bytes = raw && raw.decoded === s ? raw.bytes : utf8Encoder.encode(s);
335
+ u30(bytes.length);
336
+ w.bytes(bytes);
337
+ }
338
+ pool(this.namespaces, 'namespaces', (ns) => {
339
+ w.u8(ns.kind);
340
+ u30(ns.name);
341
+ });
342
+ pool(this.nsSets, 'nsSets', (set) => {
343
+ u30(set.length);
344
+ for (const ns of set)
345
+ u30(ns);
346
+ });
347
+ pool(this.multinames, 'multinames', (m) => {
348
+ w.u8(m.kind);
349
+ switch (m.kind) {
350
+ case constants_js_1.MultinameKind.QName:
351
+ case constants_js_1.MultinameKind.QNameA:
352
+ u30(m.ns);
353
+ u30(m.name);
354
+ break;
355
+ case constants_js_1.MultinameKind.RTQName:
356
+ case constants_js_1.MultinameKind.RTQNameA:
357
+ u30(m.name);
358
+ break;
359
+ case constants_js_1.MultinameKind.RTQNameL:
360
+ case constants_js_1.MultinameKind.RTQNameLA:
361
+ break;
362
+ case constants_js_1.MultinameKind.Multiname:
363
+ case constants_js_1.MultinameKind.MultinameA:
364
+ u30(m.name);
365
+ u30(m.nsSet);
366
+ break;
367
+ case constants_js_1.MultinameKind.MultinameL:
368
+ case constants_js_1.MultinameKind.MultinameLA:
369
+ u30(m.nsSet);
370
+ break;
371
+ case constants_js_1.MultinameKind.TypeName:
372
+ u30(m.base);
373
+ u30(m.params.length);
374
+ for (const p of m.params)
375
+ u30(p);
376
+ break;
377
+ default:
378
+ throw new Error(`Cannot write multiname kind 0x${m.kind.toString(16)}`);
379
+ }
380
+ });
381
+ u30(this.methods.length);
382
+ for (const m of this.methods) {
383
+ u30(m.paramTypes.length);
384
+ u30(m.returnType);
385
+ for (const p of m.paramTypes)
386
+ u30(p);
387
+ u30(m.name);
388
+ let flags = m.flags;
389
+ if (m.optional.length > 0)
390
+ flags |= constants_js_1.MethodFlags.HAS_OPTIONAL;
391
+ if (m.paramNames.length > 0)
392
+ flags |= constants_js_1.MethodFlags.HAS_PARAM_NAMES;
393
+ if (flags & constants_js_1.MethodFlags.HAS_PARAM_NAMES && m.paramNames.length !== m.paramTypes.length) {
394
+ if (m.paramNames.length === 0)
395
+ flags &= ~constants_js_1.MethodFlags.HAS_PARAM_NAMES;
396
+ else
397
+ throw new Error('MethodInfo.paramNames must be empty or have one entry per parameter');
398
+ }
399
+ w.u8(flags);
400
+ if (flags & constants_js_1.MethodFlags.HAS_OPTIONAL) {
401
+ u30(m.optional.length);
402
+ for (const o of m.optional) {
403
+ u30(o.value);
404
+ w.u8(o.kind);
405
+ }
406
+ }
407
+ if (flags & constants_js_1.MethodFlags.HAS_PARAM_NAMES) {
408
+ for (const p of m.paramNames)
409
+ u30(p);
410
+ }
411
+ }
412
+ u30(this.metadata.length);
413
+ for (const md of this.metadata) {
414
+ u30(md.name);
415
+ u30(md.keys.length);
416
+ for (const k of md.keys)
417
+ u30(k);
418
+ for (const v of md.values)
419
+ u30(v);
420
+ }
421
+ const writeTraits = (traits) => {
422
+ u30(traits.length);
423
+ for (const t of traits) {
424
+ u30(t.name);
425
+ let attrs = t.attrs;
426
+ if (t.metadata.length > 0)
427
+ attrs |= constants_js_1.TraitAttr.Metadata;
428
+ w.u8((attrs << 4) | t.kind);
429
+ switch (t.kind) {
430
+ case constants_js_1.TraitKind.Slot:
431
+ case constants_js_1.TraitKind.Const:
432
+ u30(t.id);
433
+ u30(t.typeName);
434
+ u30(t.valueIndex);
435
+ if (t.valueIndex !== 0)
436
+ w.u8(t.valueKind);
437
+ break;
438
+ case constants_js_1.TraitKind.Class:
439
+ u30(t.id);
440
+ u30(t.classIndex);
441
+ break;
442
+ default:
443
+ u30(t.id);
444
+ u30(t.method);
445
+ }
446
+ if (attrs & constants_js_1.TraitAttr.Metadata) {
447
+ u30(t.metadata.length);
448
+ for (const m of t.metadata)
449
+ u30(m);
450
+ }
451
+ }
452
+ };
453
+ if (this.instances.length !== this.classes.length) {
454
+ throw new Error('AbcFile.instances and AbcFile.classes must have the same length');
455
+ }
456
+ u30(this.instances.length);
457
+ for (const inst of this.instances) {
458
+ u30(inst.name);
459
+ u30(inst.superName);
460
+ w.u8(inst.flags);
461
+ if (inst.flags & constants_js_1.InstanceFlags.ProtectedNs)
462
+ u30(inst.protectedNs);
463
+ u30(inst.interfaces.length);
464
+ for (const i of inst.interfaces)
465
+ u30(i);
466
+ u30(inst.iinit);
467
+ writeTraits(inst.traits);
468
+ }
469
+ for (const c of this.classes) {
470
+ u30(c.cinit);
471
+ writeTraits(c.traits);
472
+ }
473
+ u30(this.scripts.length);
474
+ for (const s of this.scripts) {
475
+ u30(s.init);
476
+ writeTraits(s.traits);
477
+ }
478
+ u30(this.bodies.length);
479
+ for (const b of this.bodies) {
480
+ u30(b.method);
481
+ u30(b.maxStack);
482
+ u30(b.localCount);
483
+ u30(b.initScopeDepth);
484
+ u30(b.maxScopeDepth);
485
+ u30(b.code.length);
486
+ w.bytes(b.code);
487
+ u30(b.exceptions.length);
488
+ for (const e of b.exceptions) {
489
+ u30(e.from);
490
+ u30(e.to);
491
+ u30(e.target);
492
+ u30(e.excType);
493
+ u30(e.varName);
494
+ }
495
+ writeTraits(b.traits);
496
+ }
497
+ return w.toBytes();
498
+ }
499
+ // -------------------------------------------------------------------------
500
+ // Constant pool interning (find-or-add)
501
+ // -------------------------------------------------------------------------
502
+ /** String pool index for `s` (adds it if missing). */
503
+ string(s) {
504
+ let i = this.stringCache.find(s);
505
+ if (i < 0) {
506
+ i = this.strings.length;
507
+ this.strings.push(s);
508
+ }
509
+ return i;
510
+ }
511
+ int(v) {
512
+ v |= 0;
513
+ let i = this.intCache.find(String(v));
514
+ if (i < 0) {
515
+ i = this.ints.length;
516
+ this.ints.push(v);
517
+ }
518
+ return i;
519
+ }
520
+ uint(v) {
521
+ v >>>= 0;
522
+ let i = this.uintCache.find(String(v));
523
+ if (i < 0) {
524
+ i = this.uints.length;
525
+ this.uints.push(v);
526
+ }
527
+ return i;
528
+ }
529
+ double(v) {
530
+ let i = this.doubleCache.find(Object.is(v, -0) ? '-0' : String(v));
531
+ if (i < 0) {
532
+ i = this.doubles.length;
533
+ this.doubles.push(v);
534
+ }
535
+ return i;
536
+ }
537
+ /** Namespace pool index. `PrivateNs` entries are always created fresh unless `reuse` is set. */
538
+ namespace(kind, name, reuse = kind !== constants_js_1.NamespaceKind.PrivateNs) {
539
+ const nameIndex = typeof name === 'number' ? name : this.string(name);
540
+ const info = { kind, name: nameIndex };
541
+ if (reuse) {
542
+ const i = this.nsCache.find(nsKey(info));
543
+ if (i >= 0)
544
+ return i;
545
+ }
546
+ this.namespaces.push(info);
547
+ return this.namespaces.length - 1;
548
+ }
549
+ packageNamespace(name) {
550
+ return this.namespace(constants_js_1.NamespaceKind.PackageNamespace, name);
551
+ }
552
+ nsSet(namespaces) {
553
+ let i = this.nsSetCache.find(nsSetKey(namespaces));
554
+ if (i < 0) {
555
+ i = this.nsSets.length;
556
+ this.nsSets.push([...namespaces]);
557
+ }
558
+ return i;
559
+ }
560
+ multiname(info) {
561
+ const m = { ...emptyMultiname(info.kind), ...info, params: [...(info.params ?? [])] };
562
+ let i = this.mnCache.find(mnKey(m));
563
+ if (i < 0) {
564
+ i = this.multinames.length;
565
+ this.multinames.push(m);
566
+ }
567
+ return i;
568
+ }
569
+ /** QName multiname index. `ns` may be a namespace index or a package name. */
570
+ qname(ns, name) {
571
+ const nsIndex = typeof ns === 'number' ? ns : this.packageNamespace(ns);
572
+ return this.multiname({ kind: constants_js_1.MultinameKind.QName, ns: nsIndex, name: this.string(name) });
573
+ }
574
+ /** QName for a fully qualified name like "flash.display.Sprite" (or "flash.display:Sprite"). */
575
+ qnameFor(qualified) {
576
+ const { pkg, name } = splitQualifiedName(qualified);
577
+ return this.qname(pkg, name);
578
+ }
579
+ // -------------------------------------------------------------------------
580
+ // Lookup helpers
581
+ // -------------------------------------------------------------------------
582
+ /** Method body for a method index, if the method has one. */
583
+ methodBody(methodIndex) {
584
+ if (!this.bodyIndex || this.bodyIndexSize !== this.bodies.length) {
585
+ this.bodyIndex = new Map();
586
+ this.bodies.forEach((b, i) => this.bodyIndex.set(b.method, i));
587
+ this.bodyIndexSize = this.bodies.length;
588
+ }
589
+ const i = this.bodyIndex.get(methodIndex);
590
+ const body = i === undefined ? undefined : this.bodies[i];
591
+ if (body && body.method !== methodIndex) {
592
+ this.bodyIndexSize = -1;
593
+ return this.methodBody(methodIndex);
594
+ }
595
+ return body;
596
+ }
597
+ /** Namespace URI string (empty for the public/unnamed namespace). */
598
+ namespaceName(nsIndex) {
599
+ const ns = this.namespaces[nsIndex];
600
+ return ns ? (this.strings[ns.name] ?? '') : '';
601
+ }
602
+ /** Local name of a multiname ("*" if any). */
603
+ multinameName(mnIndex) {
604
+ const m = this.multinames[mnIndex];
605
+ if (!m || mnIndex === 0)
606
+ return '*';
607
+ if (m.kind === constants_js_1.MultinameKind.TypeName) {
608
+ return `${this.multinameName(m.base)}.<${m.params.map((p) => this.qualifiedName(p)).join(',')}>`;
609
+ }
610
+ return m.name === 0 && m.kind !== constants_js_1.MultinameKind.QName && m.kind !== constants_js_1.MultinameKind.QNameA ? '*' : (this.strings[m.name] ?? '');
611
+ }
612
+ /**
613
+ * Fully qualified dotted name of a multiname, e.g. "flash.display.Sprite".
614
+ * For non-QName multinames this is just the local name.
615
+ */
616
+ qualifiedName(mnIndex) {
617
+ const m = this.multinames[mnIndex];
618
+ if (!m || mnIndex === 0)
619
+ return '*';
620
+ if (m.kind === constants_js_1.MultinameKind.QName || m.kind === constants_js_1.MultinameKind.QNameA) {
621
+ const ns = this.namespaces[m.ns];
622
+ const pkg = ns && (ns.kind === constants_js_1.NamespaceKind.PackageNamespace || ns.kind === constants_js_1.NamespaceKind.PackageInternalNs) ? this.namespaceName(m.ns) : '';
623
+ const name = this.strings[m.name] ?? '';
624
+ return pkg ? `${pkg}.${name}` : name;
625
+ }
626
+ if (m.kind === constants_js_1.MultinameKind.TypeName) {
627
+ return `${this.qualifiedName(m.base)}.<${m.params.map((p) => this.qualifiedName(p)).join(',')}>`;
628
+ }
629
+ return this.multinameName(mnIndex);
630
+ }
631
+ /** Fully qualified name of class `classIndex`. */
632
+ className(classIndex) {
633
+ const inst = this.instances[classIndex];
634
+ return inst ? this.qualifiedName(inst.name) : `<class ${classIndex}>`;
635
+ }
636
+ /** Class index by fully qualified name ("com.example.Foo" or "com.example:Foo"); -1 if not found. */
637
+ findClass(qualified) {
638
+ const { pkg, name } = splitQualifiedName(qualified);
639
+ const full = pkg ? `${pkg}.${name}` : name;
640
+ for (let i = 0; i < this.instances.length; i++)
641
+ if (this.qualifiedName(this.instances[i].name) === full)
642
+ return i;
643
+ return -1;
644
+ }
645
+ /** Names of all classes defined in this ABC. */
646
+ classNames() {
647
+ return this.instances.map((_, i) => this.className(i));
648
+ }
649
+ }
650
+ exports.AbcFile = AbcFile;
651
+ /** Split "a.b.C" / "a.b:C" into package and local name. */
652
+ function splitQualifiedName(qualified) {
653
+ const colon = qualified.lastIndexOf(':');
654
+ if (colon >= 0)
655
+ return { pkg: qualified.slice(0, colon), name: qualified.slice(colon + 1) };
656
+ // Do not split generic type names like Vector.<int>.
657
+ const generic = qualified.indexOf('.<');
658
+ const searchEnd = generic >= 0 ? generic : qualified.length;
659
+ const dot = qualified.lastIndexOf('.', searchEnd - 1);
660
+ if (dot < 0)
661
+ return { pkg: '', name: qualified };
662
+ return { pkg: qualified.slice(0, dot), name: qualified.slice(dot + 1) };
663
+ }
@@ -0,0 +1,36 @@
1
+ import type { AbcFile, MethodInfo } from './abc-file.js';
2
+ import type { CodeException, CodeItem, Instruction } from './code.js';
3
+ /** Number of values a multiname pops from the stack at runtime (namespace and/or name). */
4
+ export declare function multinameRuntimeArity(abc: AbcFile, mnIndex: number): number;
5
+ /** Values popped / pushed by an instruction. */
6
+ export declare function stackEffect(abc: AbcFile, i: Instruction): {
7
+ pop: number;
8
+ push: number;
9
+ };
10
+ /** Local registers referenced by an instruction. */
11
+ export declare function registersUsed(i: Instruction): number[];
12
+ export interface CodeLimits {
13
+ maxStack: number;
14
+ /** Maximum scope stack height relative to init_scope_depth. */
15
+ maxScope: number;
16
+ /** Highest register index referenced + 1. */
17
+ registers: number;
18
+ }
19
+ /**
20
+ * Computes stack / scope / register requirements by walking all control-flow
21
+ * paths (including exception handlers).
22
+ */
23
+ export declare function computeLimits(abc: AbcFile, items: readonly CodeItem[], exceptions?: readonly CodeException[]): CodeLimits;
24
+ /** Minimum local_count required by a method signature (this + params + rest/arguments). */
25
+ export declare function minLocalCount(method: MethodInfo): number;
26
+ export interface VerifyIssue {
27
+ /** Index into the code item list. */
28
+ item: number;
29
+ message: string;
30
+ }
31
+ /**
32
+ * Structural verification similar to the AVM2 verifier's first pass:
33
+ * stack underflow, inconsistent stack / scope heights at merge points,
34
+ * falling off the end of the code and scope underflow.
35
+ */
36
+ export declare function verifyCode(abc: AbcFile, items: readonly CodeItem[], exceptions?: readonly CodeException[]): VerifyIssue[];