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,105 @@
1
+ /** SWF tag codes (SWF File Format Specification v19). */
2
+ export const TagCode = {
3
+ End: 0,
4
+ ShowFrame: 1,
5
+ DefineShape: 2,
6
+ FreeCharacter: 3,
7
+ PlaceObject: 4,
8
+ RemoveObject: 5,
9
+ DefineBits: 6,
10
+ DefineButton: 7,
11
+ JPEGTables: 8,
12
+ SetBackgroundColor: 9,
13
+ DefineFont: 10,
14
+ DefineText: 11,
15
+ DoAction: 12,
16
+ DefineFontInfo: 13,
17
+ DefineSound: 14,
18
+ StartSound: 15,
19
+ DefineButtonSound: 17,
20
+ SoundStreamHead: 18,
21
+ SoundStreamBlock: 19,
22
+ DefineBitsLossless: 20,
23
+ DefineBitsJPEG2: 21,
24
+ DefineShape2: 22,
25
+ DefineButtonCxform: 23,
26
+ Protect: 24,
27
+ PlaceObject2: 26,
28
+ RemoveObject2: 28,
29
+ DefineShape3: 32,
30
+ DefineText2: 33,
31
+ DefineButton2: 34,
32
+ DefineBitsJPEG3: 35,
33
+ DefineBitsLossless2: 36,
34
+ DefineEditText: 37,
35
+ DefineSprite: 39,
36
+ ProductInfo: 41,
37
+ FrameLabel: 43,
38
+ SoundStreamHead2: 45,
39
+ DefineMorphShape: 46,
40
+ DefineFont2: 48,
41
+ ExportAssets: 56,
42
+ ImportAssets: 57,
43
+ EnableDebugger: 58,
44
+ DoInitAction: 59,
45
+ DefineVideoStream: 60,
46
+ VideoFrame: 61,
47
+ DefineFontInfo2: 62,
48
+ DebugID: 63,
49
+ EnableDebugger2: 64,
50
+ ScriptLimits: 65,
51
+ SetTabIndex: 66,
52
+ FileAttributes: 69,
53
+ PlaceObject3: 70,
54
+ ImportAssets2: 71,
55
+ DoABC: 72,
56
+ DefineFontAlignZones: 73,
57
+ CSMTextSettings: 74,
58
+ DefineFont3: 75,
59
+ SymbolClass: 76,
60
+ Metadata: 77,
61
+ DefineScalingGrid: 78,
62
+ DoABC2: 82,
63
+ DefineShape4: 83,
64
+ DefineMorphShape2: 84,
65
+ DefineSceneAndFrameLabelData: 86,
66
+ DefineBinaryData: 87,
67
+ DefineFontName: 88,
68
+ StartSound2: 89,
69
+ DefineBitsJPEG4: 90,
70
+ DefineFont4: 91,
71
+ EnableTelemetry: 93,
72
+ PlaceObject4: 94,
73
+ };
74
+ const NAMES = new Map(Object.entries(TagCode).map(([k, v]) => [v, k]));
75
+ export function tagName(code) {
76
+ return NAMES.get(code) ?? `Unknown(${code})`;
77
+ }
78
+ /** Tags whose body starts with the u16 id of the character they define. */
79
+ export const CHARACTER_DEFINING_TAGS = new Set([
80
+ TagCode.DefineShape,
81
+ TagCode.DefineBits,
82
+ TagCode.DefineButton,
83
+ TagCode.DefineFont,
84
+ TagCode.DefineText,
85
+ TagCode.DefineSound,
86
+ TagCode.DefineBitsLossless,
87
+ TagCode.DefineBitsJPEG2,
88
+ TagCode.DefineShape2,
89
+ TagCode.DefineShape3,
90
+ TagCode.DefineText2,
91
+ TagCode.DefineButton2,
92
+ TagCode.DefineBitsJPEG3,
93
+ TagCode.DefineBitsLossless2,
94
+ TagCode.DefineEditText,
95
+ TagCode.DefineSprite,
96
+ TagCode.DefineMorphShape,
97
+ TagCode.DefineFont2,
98
+ TagCode.DefineVideoStream,
99
+ TagCode.DefineFont3,
100
+ TagCode.DefineShape4,
101
+ TagCode.DefineMorphShape2,
102
+ TagCode.DefineBinaryData,
103
+ TagCode.DefineBitsJPEG4,
104
+ TagCode.DefineFont4,
105
+ ]);
@@ -0,0 +1,118 @@
1
+ import { ByteWriter } from '../io/writer.js';
2
+ import { AbcFile } from '../abc/abc-file.js';
3
+ /** Base class for all SWF tags. */
4
+ export declare abstract class Tag {
5
+ abstract readonly code: number;
6
+ /**
7
+ * Write this tag with a long (6-byte) record header even if its body is
8
+ * shorter than 63 bytes. Set automatically when parsed from a file that
9
+ * used the long form, so unmodified files round-trip byte-for-byte.
10
+ */
11
+ longHeader: boolean;
12
+ get name(): string;
13
+ /** Serialised tag body (without the record header). */
14
+ abstract encodeBody(): Uint8Array;
15
+ /** Character id for character-defining tags, otherwise `undefined`. */
16
+ get characterId(): number | undefined;
17
+ }
18
+ /** A tag kept as opaque bytes. Every tag type not modelled explicitly is a RawTag. */
19
+ export declare class RawTag extends Tag {
20
+ code: number;
21
+ data: Uint8Array;
22
+ constructor(code: number, data: Uint8Array);
23
+ get characterId(): number | undefined;
24
+ /** Change the character id of a character-defining tag in place. */
25
+ setCharacterId(id: number): void;
26
+ encodeBody(): Uint8Array;
27
+ }
28
+ /**
29
+ * DoABC (72) / DoABC2 (82): an ActionScript 3 bytecode block.
30
+ *
31
+ * The ABC payload is parsed lazily on first access to {@link abc}. As long as
32
+ * it has not been accessed, the original bytes are written back untouched.
33
+ */
34
+ export declare class DoABCTag extends Tag {
35
+ readonly code: number;
36
+ /** DoABC2 flags. 1 = kDoAbcLazyInitializeFlag. */
37
+ flags: number;
38
+ /** DoABC2 name. */
39
+ abcName: string;
40
+ private raw;
41
+ private parsed;
42
+ constructor(code: number, flags: number, abcName: string, abc: Uint8Array | AbcFile);
43
+ static create(abc: AbcFile, name?: string, flags?: number): DoABCTag;
44
+ /** Parsed ABC file. Parsing happens once, on first access. */
45
+ get abc(): AbcFile;
46
+ set abc(value: AbcFile);
47
+ /** True once the ABC has been parsed (and will therefore be re-serialised on save). */
48
+ get isParsed(): boolean;
49
+ /** Raw ABC bytes (serialises the parsed ABC if needed). */
50
+ abcBytes(): Uint8Array;
51
+ encodeBody(): Uint8Array;
52
+ }
53
+ export interface SymbolEntry {
54
+ id: number;
55
+ name: string;
56
+ }
57
+ /** SymbolClass (76) and ExportAssets (56): character id ↔ name mappings. */
58
+ export declare class SymbolTableTag extends Tag {
59
+ readonly code: number;
60
+ symbols: SymbolEntry[];
61
+ constructor(code: number, symbols: SymbolEntry[]);
62
+ encodeBody(): Uint8Array;
63
+ }
64
+ /** DefineSprite (39): a movie clip with its own control-tag timeline. */
65
+ export declare class DefineSpriteTag extends Tag {
66
+ spriteId: number;
67
+ frameCount: number;
68
+ tags: Tag[];
69
+ /** Bytes after the nested End tag (normally empty). */
70
+ trailing: Uint8Array;
71
+ readonly code: 39;
72
+ constructor(spriteId: number, frameCount: number, tags: Tag[],
73
+ /** Bytes after the nested End tag (normally empty). */
74
+ trailing?: Uint8Array);
75
+ get characterId(): number;
76
+ encodeBody(): Uint8Array;
77
+ }
78
+ /** DefineBinaryData (87). */
79
+ export declare class DefineBinaryDataTag extends Tag {
80
+ id: number;
81
+ data: Uint8Array;
82
+ reserved: number;
83
+ readonly code: 87;
84
+ constructor(id: number, data: Uint8Array, reserved?: number);
85
+ get characterId(): number;
86
+ encodeBody(): Uint8Array;
87
+ }
88
+ /** Metadata (77): XMP/RDF XML string. */
89
+ export declare class MetadataTag extends Tag {
90
+ xml: string;
91
+ readonly code: 77;
92
+ constructor(xml: string);
93
+ encodeBody(): Uint8Array;
94
+ }
95
+ /** FileAttributes (69). */
96
+ export declare class FileAttributesTag extends Tag {
97
+ flags: number;
98
+ readonly code: 69;
99
+ constructor(flags: number);
100
+ get useDirectBlit(): boolean;
101
+ get useGPU(): boolean;
102
+ get hasMetadata(): boolean;
103
+ get actionScript3(): boolean;
104
+ set actionScript3(v: boolean);
105
+ get useNetwork(): boolean;
106
+ set useNetwork(v: boolean);
107
+ encodeBody(): Uint8Array;
108
+ }
109
+ /**
110
+ * Reads a tag stream until (and including) the End tag or the end of data.
111
+ * Returns the tags and the offset right after the last consumed byte.
112
+ */
113
+ export declare function readTags(bytes: Uint8Array, start: number, end: number): {
114
+ tags: Tag[];
115
+ end: number;
116
+ };
117
+ export declare function writeTag(w: ByteWriter, tag: Tag): void;
118
+ export declare function writeTags(w: ByteWriter, tags: readonly Tag[]): void;
@@ -0,0 +1,316 @@
1
+ import { ByteReader } from '../io/reader.js';
2
+ import { ByteWriter } from '../io/writer.js';
3
+ import { AbcFile } from '../abc/abc-file.js';
4
+ import { CHARACTER_DEFINING_TAGS, TagCode, tagName } from './tag-codes.js';
5
+ /** Base class for all SWF tags. */
6
+ export class Tag {
7
+ /**
8
+ * Write this tag with a long (6-byte) record header even if its body is
9
+ * shorter than 63 bytes. Set automatically when parsed from a file that
10
+ * used the long form, so unmodified files round-trip byte-for-byte.
11
+ */
12
+ longHeader = false;
13
+ get name() {
14
+ return tagName(this.code);
15
+ }
16
+ /** Character id for character-defining tags, otherwise `undefined`. */
17
+ get characterId() {
18
+ return undefined;
19
+ }
20
+ }
21
+ /** A tag kept as opaque bytes. Every tag type not modelled explicitly is a RawTag. */
22
+ export class RawTag extends Tag {
23
+ code;
24
+ data;
25
+ constructor(code, data) {
26
+ super();
27
+ this.code = code;
28
+ this.data = data;
29
+ }
30
+ get characterId() {
31
+ if (CHARACTER_DEFINING_TAGS.has(this.code) && this.data.length >= 2) {
32
+ return this.data[0] | (this.data[1] << 8);
33
+ }
34
+ return undefined;
35
+ }
36
+ /** Change the character id of a character-defining tag in place. */
37
+ setCharacterId(id) {
38
+ if (!CHARACTER_DEFINING_TAGS.has(this.code))
39
+ throw new Error(`${this.name} does not define a character`);
40
+ this.data = this.data.slice();
41
+ this.data[0] = id & 0xff;
42
+ this.data[1] = (id >> 8) & 0xff;
43
+ }
44
+ encodeBody() {
45
+ return this.data;
46
+ }
47
+ }
48
+ /**
49
+ * DoABC (72) / DoABC2 (82): an ActionScript 3 bytecode block.
50
+ *
51
+ * The ABC payload is parsed lazily on first access to {@link abc}. As long as
52
+ * it has not been accessed, the original bytes are written back untouched.
53
+ */
54
+ export class DoABCTag extends Tag {
55
+ code;
56
+ /** DoABC2 flags. 1 = kDoAbcLazyInitializeFlag. */
57
+ flags;
58
+ /** DoABC2 name. */
59
+ abcName;
60
+ raw;
61
+ parsed;
62
+ constructor(code, flags, abcName, abc) {
63
+ super();
64
+ this.code = code;
65
+ this.flags = flags;
66
+ this.abcName = abcName;
67
+ if (abc instanceof AbcFile)
68
+ this.parsed = abc;
69
+ else
70
+ this.raw = abc;
71
+ }
72
+ static create(abc, name = '', flags = 1) {
73
+ return new DoABCTag(TagCode.DoABC2, flags, name, abc);
74
+ }
75
+ /** Parsed ABC file. Parsing happens once, on first access. */
76
+ get abc() {
77
+ if (!this.parsed) {
78
+ this.parsed = AbcFile.parse(this.raw);
79
+ this.raw = undefined;
80
+ }
81
+ return this.parsed;
82
+ }
83
+ set abc(value) {
84
+ this.parsed = value;
85
+ this.raw = undefined;
86
+ }
87
+ /** True once the ABC has been parsed (and will therefore be re-serialised on save). */
88
+ get isParsed() {
89
+ return this.parsed !== undefined;
90
+ }
91
+ /** Raw ABC bytes (serialises the parsed ABC if needed). */
92
+ abcBytes() {
93
+ return this.parsed ? this.parsed.toBytes() : this.raw;
94
+ }
95
+ encodeBody() {
96
+ const abc = this.abcBytes();
97
+ if (this.code === TagCode.DoABC)
98
+ return abc;
99
+ const w = new ByteWriter(abc.length + this.abcName.length + 8);
100
+ w.u32(this.flags);
101
+ w.cstring(this.abcName);
102
+ w.bytes(abc);
103
+ return w.toBytes();
104
+ }
105
+ }
106
+ /** SymbolClass (76) and ExportAssets (56): character id ↔ name mappings. */
107
+ export class SymbolTableTag extends Tag {
108
+ code;
109
+ symbols;
110
+ constructor(code, symbols) {
111
+ super();
112
+ this.code = code;
113
+ this.symbols = symbols;
114
+ }
115
+ encodeBody() {
116
+ const w = new ByteWriter();
117
+ w.u16(this.symbols.length);
118
+ for (const s of this.symbols) {
119
+ w.u16(s.id);
120
+ w.cstring(s.name);
121
+ }
122
+ return w.toBytes();
123
+ }
124
+ }
125
+ /** DefineSprite (39): a movie clip with its own control-tag timeline. */
126
+ export class DefineSpriteTag extends Tag {
127
+ spriteId;
128
+ frameCount;
129
+ tags;
130
+ trailing;
131
+ code = TagCode.DefineSprite;
132
+ constructor(spriteId, frameCount, tags,
133
+ /** Bytes after the nested End tag (normally empty). */
134
+ trailing = new Uint8Array(0)) {
135
+ super();
136
+ this.spriteId = spriteId;
137
+ this.frameCount = frameCount;
138
+ this.tags = tags;
139
+ this.trailing = trailing;
140
+ }
141
+ get characterId() {
142
+ return this.spriteId;
143
+ }
144
+ encodeBody() {
145
+ const w = new ByteWriter();
146
+ w.u16(this.spriteId);
147
+ w.u16(this.frameCount);
148
+ writeTags(w, this.tags);
149
+ w.bytes(this.trailing);
150
+ return w.toBytes();
151
+ }
152
+ }
153
+ /** DefineBinaryData (87). */
154
+ export class DefineBinaryDataTag extends Tag {
155
+ id;
156
+ data;
157
+ reserved;
158
+ code = TagCode.DefineBinaryData;
159
+ constructor(id, data, reserved = 0) {
160
+ super();
161
+ this.id = id;
162
+ this.data = data;
163
+ this.reserved = reserved;
164
+ }
165
+ get characterId() {
166
+ return this.id;
167
+ }
168
+ encodeBody() {
169
+ const w = new ByteWriter(this.data.length + 6);
170
+ w.u16(this.id);
171
+ w.u32(this.reserved);
172
+ w.bytes(this.data);
173
+ return w.toBytes();
174
+ }
175
+ }
176
+ /** Metadata (77): XMP/RDF XML string. */
177
+ export class MetadataTag extends Tag {
178
+ xml;
179
+ code = TagCode.Metadata;
180
+ constructor(xml) {
181
+ super();
182
+ this.xml = xml;
183
+ }
184
+ encodeBody() {
185
+ return new ByteWriter().cstring(this.xml).toBytes();
186
+ }
187
+ }
188
+ /** FileAttributes (69). */
189
+ export class FileAttributesTag extends Tag {
190
+ flags;
191
+ code = TagCode.FileAttributes;
192
+ constructor(flags) {
193
+ super();
194
+ this.flags = flags;
195
+ }
196
+ get useDirectBlit() {
197
+ return (this.flags & 0x40) !== 0;
198
+ }
199
+ get useGPU() {
200
+ return (this.flags & 0x20) !== 0;
201
+ }
202
+ get hasMetadata() {
203
+ return (this.flags & 0x10) !== 0;
204
+ }
205
+ get actionScript3() {
206
+ return (this.flags & 0x08) !== 0;
207
+ }
208
+ set actionScript3(v) {
209
+ this.flags = v ? this.flags | 0x08 : this.flags & ~0x08;
210
+ }
211
+ get useNetwork() {
212
+ return (this.flags & 0x01) !== 0;
213
+ }
214
+ set useNetwork(v) {
215
+ this.flags = v ? this.flags | 0x01 : this.flags & ~0x01;
216
+ }
217
+ encodeBody() {
218
+ return new ByteWriter(4).u32(this.flags).toBytes();
219
+ }
220
+ }
221
+ // ---------------------------------------------------------------------------
222
+ // Tag stream parsing / writing
223
+ // ---------------------------------------------------------------------------
224
+ function decodeTag(code, body) {
225
+ const r = new ByteReader(body);
226
+ switch (code) {
227
+ case TagCode.DoABC:
228
+ return new DoABCTag(code, 0, '', body);
229
+ case TagCode.DoABC2: {
230
+ const flags = r.u32();
231
+ const name = r.cstring();
232
+ return new DoABCTag(code, flags, name, r.rest());
233
+ }
234
+ case TagCode.SymbolClass:
235
+ case TagCode.ExportAssets: {
236
+ const count = r.u16();
237
+ const symbols = [];
238
+ for (let i = 0; i < count; i++)
239
+ symbols.push({ id: r.u16(), name: r.cstring() });
240
+ if (!r.eof)
241
+ return new RawTag(code, body);
242
+ return new SymbolTableTag(code, symbols);
243
+ }
244
+ case TagCode.DefineSprite: {
245
+ const id = r.u16();
246
+ const frameCount = r.u16();
247
+ const { tags, end } = readTags(body, r.pos, body.length);
248
+ return new DefineSpriteTag(id, frameCount, tags, body.slice(end));
249
+ }
250
+ case TagCode.DefineBinaryData: {
251
+ const id = r.u16();
252
+ const reserved = r.u32();
253
+ return new DefineBinaryDataTag(id, r.rest(), reserved);
254
+ }
255
+ case TagCode.Metadata: {
256
+ const xml = r.cstring();
257
+ if (!r.eof)
258
+ return new RawTag(code, body);
259
+ return new MetadataTag(xml);
260
+ }
261
+ case TagCode.FileAttributes:
262
+ if (body.length !== 4)
263
+ return new RawTag(code, body);
264
+ return new FileAttributesTag(r.u32());
265
+ default:
266
+ return new RawTag(code, body);
267
+ }
268
+ }
269
+ /**
270
+ * Reads a tag stream until (and including) the End tag or the end of data.
271
+ * Returns the tags and the offset right after the last consumed byte.
272
+ */
273
+ export function readTags(bytes, start, end) {
274
+ const r = new ByteReader(bytes, start, end);
275
+ const tags = [];
276
+ while (r.remaining >= 2) {
277
+ const codeAndLength = r.u16();
278
+ const code = codeAndLength >> 6;
279
+ let length = codeAndLength & 0x3f;
280
+ const long = length === 0x3f;
281
+ if (long) {
282
+ if (r.remaining < 4)
283
+ break;
284
+ length = r.u32();
285
+ }
286
+ // Clamp truncated tags instead of failing the whole file.
287
+ const body = r.bytesView(Math.min(length, r.remaining)).slice();
288
+ let tag;
289
+ try {
290
+ tag = decodeTag(code, body);
291
+ }
292
+ catch {
293
+ tag = new RawTag(code, body);
294
+ }
295
+ tag.longHeader = long;
296
+ tags.push(tag);
297
+ if (code === TagCode.End)
298
+ break;
299
+ }
300
+ return { tags, end: r.pos };
301
+ }
302
+ export function writeTag(w, tag) {
303
+ const body = tag.encodeBody();
304
+ if (body.length >= 0x3f || tag.longHeader) {
305
+ w.u16((tag.code << 6) | 0x3f);
306
+ w.u32(body.length);
307
+ }
308
+ else {
309
+ w.u16((tag.code << 6) | body.length);
310
+ }
311
+ w.bytes(body);
312
+ }
313
+ export function writeTags(w, tags) {
314
+ for (const t of tags)
315
+ writeTag(w, t);
316
+ }
package/package.json CHANGED
@@ -1,6 +1,73 @@
1
1
  {
2
2
  "name": "swf-toolkit",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0",
4
+ "description": "Pure TypeScript toolkit for Adobe Flash SWF files: read/write, AS3 decompiler and compiler, AVM2/AVM1 assemblers, asset export/import.",
5
+ "author": "Recep Asan (https://github.com/recepasan)",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/recepasan/swf-toolkit.git"
9
+ },
10
+ "homepage": "https://github.com/recepasan/swf-toolkit#readme",
11
+ "bugs": {
12
+ "url": "https://github.com/recepasan/swf-toolkit/issues"
13
+ },
14
+ "type": "module",
15
+ "main": "./dist/cjs/index.js",
16
+ "module": "./dist/index.js",
17
+ "types": "./dist/index.d.ts",
18
+ "exports": {
19
+ ".": {
20
+ "import": {
21
+ "types": "./dist/index.d.ts",
22
+ "default": "./dist/index.js"
23
+ },
24
+ "require": {
25
+ "types": "./dist/cjs/index.d.ts",
26
+ "default": "./dist/cjs/index.js"
27
+ }
28
+ },
29
+ "./package.json": "./package.json"
30
+ },
31
+ "bin": {
32
+ "swf-toolkit": "./dist/cli.js"
33
+ },
34
+ "files": [
35
+ "dist",
36
+ "README.md",
37
+ "LICENSE"
38
+ ],
39
+ "scripts": {
40
+ "build": "tsc -p tsconfig.json && tsc -p tsconfig.cjs.json && node scripts/finish-build.mjs",
41
+ "clean": "rm -rf dist",
42
+ "typecheck": "tsc -p tsconfig.json --noEmit",
43
+ "prepublishOnly": "npm run clean && npm test",
44
+ "test": "npm run build && node --test test/*.test.mjs"
45
+ },
46
+ "engines": {
47
+ "node": ">=18"
48
+ },
49
+ "keywords": [
50
+ "abc",
51
+ "actionscript",
52
+ "as2",
53
+ "as3",
54
+ "assembler",
55
+ "avm1",
56
+ "avm2",
57
+ "compiler",
58
+ "decompiler",
59
+ "disassembler",
60
+ "flash",
61
+ "pcode",
62
+ "swf"
63
+ ],
64
+ "license": "MIT",
65
+ "sideEffects": false,
66
+ "publishConfig": {
67
+ "access": "public"
68
+ },
69
+ "devDependencies": {
70
+ "@types/node": "22.20.5",
71
+ "typescript": "5.9.3"
72
+ }
73
+ }