pyflashkit 1.0.0__py3-none-any.whl
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.
- flashkit/__init__.py +54 -0
- flashkit/abc/__init__.py +79 -0
- flashkit/abc/builder.py +847 -0
- flashkit/abc/constants.py +198 -0
- flashkit/abc/disasm.py +364 -0
- flashkit/abc/parser.py +434 -0
- flashkit/abc/types.py +275 -0
- flashkit/abc/writer.py +230 -0
- flashkit/analysis/__init__.py +28 -0
- flashkit/analysis/call_graph.py +317 -0
- flashkit/analysis/inheritance.py +267 -0
- flashkit/analysis/references.py +371 -0
- flashkit/analysis/strings.py +299 -0
- flashkit/cli/__init__.py +75 -0
- flashkit/cli/_util.py +52 -0
- flashkit/cli/build.py +36 -0
- flashkit/cli/callees.py +30 -0
- flashkit/cli/callers.py +30 -0
- flashkit/cli/class_cmd.py +83 -0
- flashkit/cli/classes.py +71 -0
- flashkit/cli/disasm.py +77 -0
- flashkit/cli/extract.py +36 -0
- flashkit/cli/info.py +41 -0
- flashkit/cli/packages.py +30 -0
- flashkit/cli/refs.py +31 -0
- flashkit/cli/strings.py +58 -0
- flashkit/cli/tags.py +32 -0
- flashkit/cli/tree.py +52 -0
- flashkit/errors.py +33 -0
- flashkit/info/__init__.py +31 -0
- flashkit/info/class_info.py +176 -0
- flashkit/info/member_info.py +275 -0
- flashkit/info/package_info.py +60 -0
- flashkit/search/__init__.py +16 -0
- flashkit/search/search.py +456 -0
- flashkit/swf/__init__.py +66 -0
- flashkit/swf/builder.py +283 -0
- flashkit/swf/parser.py +164 -0
- flashkit/swf/tags.py +120 -0
- flashkit/workspace/__init__.py +20 -0
- flashkit/workspace/resource.py +189 -0
- flashkit/workspace/workspace.py +232 -0
- pyflashkit-1.0.0.dist-info/METADATA +281 -0
- pyflashkit-1.0.0.dist-info/RECORD +48 -0
- pyflashkit-1.0.0.dist-info/WHEEL +5 -0
- pyflashkit-1.0.0.dist-info/entry_points.txt +2 -0
- pyflashkit-1.0.0.dist-info/licenses/LICENSE +21 -0
- pyflashkit-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Unified search engine for workspace content.
|
|
3
|
+
|
|
4
|
+
Provides a high-level query API that combines all analysis indexes
|
|
5
|
+
(inheritance, call graph, references, strings) into a single interface.
|
|
6
|
+
|
|
7
|
+
Usage::
|
|
8
|
+
|
|
9
|
+
from flashkit.workspace import Workspace
|
|
10
|
+
from flashkit.search import SearchEngine
|
|
11
|
+
|
|
12
|
+
ws = Workspace()
|
|
13
|
+
ws.load_swf("application.swf")
|
|
14
|
+
engine = SearchEngine(ws)
|
|
15
|
+
|
|
16
|
+
# Find classes extending a base
|
|
17
|
+
subclasses = engine.find_subclasses("BaseSprite")
|
|
18
|
+
|
|
19
|
+
# Find who instantiates a class
|
|
20
|
+
creators = engine.find_instantiators("Point")
|
|
21
|
+
|
|
22
|
+
# Find classes using a specific string
|
|
23
|
+
matches = engine.find_by_string("config.xml")
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
from __future__ import annotations
|
|
27
|
+
|
|
28
|
+
from dataclasses import dataclass, field
|
|
29
|
+
|
|
30
|
+
from ..info.class_info import ClassInfo
|
|
31
|
+
from ..analysis.inheritance import InheritanceGraph
|
|
32
|
+
from ..analysis.call_graph import CallGraph, CallEdge
|
|
33
|
+
from ..analysis.references import ReferenceIndex, Reference
|
|
34
|
+
from ..analysis.strings import StringIndex, StringUsage
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@dataclass
|
|
38
|
+
class ClassResult:
|
|
39
|
+
"""A class search result with context about why it matched.
|
|
40
|
+
|
|
41
|
+
Attributes:
|
|
42
|
+
class_info: The matched ClassInfo.
|
|
43
|
+
match_reason: Why this class matched (e.g. ``"extends BaseSprite"``).
|
|
44
|
+
"""
|
|
45
|
+
class_info: ClassInfo
|
|
46
|
+
match_reason: str = ""
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
def name(self) -> str:
|
|
50
|
+
return self.class_info.qualified_name
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@dataclass
|
|
54
|
+
class MemberResult:
|
|
55
|
+
"""A member (field or method) search result.
|
|
56
|
+
|
|
57
|
+
Attributes:
|
|
58
|
+
class_name: Owning class qualified name.
|
|
59
|
+
member_name: Field or method name.
|
|
60
|
+
member_type: ``"field"`` or ``"method"``.
|
|
61
|
+
match_reason: Why this member matched.
|
|
62
|
+
"""
|
|
63
|
+
class_name: str
|
|
64
|
+
member_name: str
|
|
65
|
+
member_type: str
|
|
66
|
+
match_reason: str = ""
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@dataclass
|
|
70
|
+
class StringResult:
|
|
71
|
+
"""A string search result.
|
|
72
|
+
|
|
73
|
+
Attributes:
|
|
74
|
+
string: The matched string value.
|
|
75
|
+
usages: Where this string is used.
|
|
76
|
+
"""
|
|
77
|
+
string: str
|
|
78
|
+
usages: list[StringUsage] = field(default_factory=list)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class SearchEngine:
|
|
82
|
+
"""Unified query interface over all analysis indexes.
|
|
83
|
+
|
|
84
|
+
Lazily builds analysis indexes on first use.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
workspace: A Workspace instance with loaded content.
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
def __init__(self, workspace: object) -> None:
|
|
91
|
+
from ..workspace.workspace import Workspace
|
|
92
|
+
self._ws: Workspace = workspace # type: ignore[assignment]
|
|
93
|
+
self._inheritance: InheritanceGraph | None = None
|
|
94
|
+
self._call_graph: CallGraph | None = None
|
|
95
|
+
self._references: ReferenceIndex | None = None
|
|
96
|
+
self._strings: StringIndex | None = None
|
|
97
|
+
|
|
98
|
+
@property
|
|
99
|
+
def inheritance(self) -> InheritanceGraph:
|
|
100
|
+
"""Lazily built inheritance graph."""
|
|
101
|
+
if self._inheritance is None:
|
|
102
|
+
self._inheritance = InheritanceGraph.from_classes(self._ws.classes)
|
|
103
|
+
return self._inheritance
|
|
104
|
+
|
|
105
|
+
@property
|
|
106
|
+
def call_graph(self) -> CallGraph:
|
|
107
|
+
"""Lazily built call graph."""
|
|
108
|
+
if self._call_graph is None:
|
|
109
|
+
self._call_graph = CallGraph.from_workspace(self._ws)
|
|
110
|
+
return self._call_graph
|
|
111
|
+
|
|
112
|
+
@property
|
|
113
|
+
def references(self) -> ReferenceIndex:
|
|
114
|
+
"""Lazily built reference index."""
|
|
115
|
+
if self._references is None:
|
|
116
|
+
self._references = ReferenceIndex.from_workspace(self._ws)
|
|
117
|
+
return self._references
|
|
118
|
+
|
|
119
|
+
@property
|
|
120
|
+
def strings(self) -> StringIndex:
|
|
121
|
+
"""Lazily built string index."""
|
|
122
|
+
if self._strings is None:
|
|
123
|
+
self._strings = StringIndex.from_workspace(self._ws)
|
|
124
|
+
return self._strings
|
|
125
|
+
|
|
126
|
+
# ── Class queries ──────────────────────────────────────────────────────
|
|
127
|
+
|
|
128
|
+
def find_classes(
|
|
129
|
+
self,
|
|
130
|
+
*,
|
|
131
|
+
name: str | None = None,
|
|
132
|
+
extends: str | None = None,
|
|
133
|
+
implements: str | None = None,
|
|
134
|
+
package: str | None = None,
|
|
135
|
+
is_interface: bool | None = None,
|
|
136
|
+
) -> list[ClassResult]:
|
|
137
|
+
"""Find classes matching criteria (delegates to Workspace.find_classes).
|
|
138
|
+
|
|
139
|
+
All criteria are AND-combined.
|
|
140
|
+
|
|
141
|
+
Args:
|
|
142
|
+
name: Substring match on class name.
|
|
143
|
+
extends: Exact match on superclass name.
|
|
144
|
+
implements: Exact match on one of the interface names.
|
|
145
|
+
package: Exact match on package name.
|
|
146
|
+
is_interface: Filter by interface flag.
|
|
147
|
+
|
|
148
|
+
Returns:
|
|
149
|
+
List of ClassResult objects.
|
|
150
|
+
"""
|
|
151
|
+
matches = self._ws.find_classes(
|
|
152
|
+
name=name, extends=extends, implements=implements,
|
|
153
|
+
package=package, is_interface=is_interface,
|
|
154
|
+
)
|
|
155
|
+
reasons: list[str] = []
|
|
156
|
+
if name:
|
|
157
|
+
reasons.append(f"name contains '{name}'")
|
|
158
|
+
if extends:
|
|
159
|
+
reasons.append(f"extends {extends}")
|
|
160
|
+
if implements:
|
|
161
|
+
reasons.append(f"implements {implements}")
|
|
162
|
+
if package:
|
|
163
|
+
reasons.append(f"in package {package}")
|
|
164
|
+
if is_interface is not None:
|
|
165
|
+
reasons.append("is interface" if is_interface else "is class")
|
|
166
|
+
reason = ", ".join(reasons)
|
|
167
|
+
return [ClassResult(class_info=c, match_reason=reason) for c in matches]
|
|
168
|
+
|
|
169
|
+
def find_subclasses(self, class_name: str,
|
|
170
|
+
transitive: bool = False) -> list[ClassResult]:
|
|
171
|
+
"""Find direct or transitive subclasses.
|
|
172
|
+
|
|
173
|
+
Args:
|
|
174
|
+
class_name: The parent class name.
|
|
175
|
+
transitive: If True, include all descendants.
|
|
176
|
+
|
|
177
|
+
Returns:
|
|
178
|
+
List of ClassResult objects.
|
|
179
|
+
"""
|
|
180
|
+
if transitive:
|
|
181
|
+
names = self.inheritance.get_all_children(class_name)
|
|
182
|
+
else:
|
|
183
|
+
names = self.inheritance.get_children(class_name)
|
|
184
|
+
|
|
185
|
+
results: list[ClassResult] = []
|
|
186
|
+
for n in names:
|
|
187
|
+
ci = self._ws.get_class(n)
|
|
188
|
+
if ci:
|
|
189
|
+
results.append(ClassResult(
|
|
190
|
+
class_info=ci,
|
|
191
|
+
match_reason=f"{'transitively ' if transitive else ''}extends {class_name}",
|
|
192
|
+
))
|
|
193
|
+
return results
|
|
194
|
+
|
|
195
|
+
def find_implementors(self, interface_name: str) -> list[ClassResult]:
|
|
196
|
+
"""Find classes implementing an interface.
|
|
197
|
+
|
|
198
|
+
Args:
|
|
199
|
+
interface_name: The interface name.
|
|
200
|
+
|
|
201
|
+
Returns:
|
|
202
|
+
List of ClassResult objects.
|
|
203
|
+
"""
|
|
204
|
+
names = self.inheritance.get_implementors(interface_name)
|
|
205
|
+
results: list[ClassResult] = []
|
|
206
|
+
for n in names:
|
|
207
|
+
ci = self._ws.get_class(n)
|
|
208
|
+
if ci:
|
|
209
|
+
results.append(ClassResult(
|
|
210
|
+
class_info=ci,
|
|
211
|
+
match_reason=f"implements {interface_name}",
|
|
212
|
+
))
|
|
213
|
+
return results
|
|
214
|
+
|
|
215
|
+
# ── Member queries ─────────────────────────────────────────────────────
|
|
216
|
+
|
|
217
|
+
def find_fields(
|
|
218
|
+
self,
|
|
219
|
+
*,
|
|
220
|
+
name: str | None = None,
|
|
221
|
+
type_name: str | None = None,
|
|
222
|
+
is_static: bool | None = None,
|
|
223
|
+
) -> list[MemberResult]:
|
|
224
|
+
"""Find fields across all classes.
|
|
225
|
+
|
|
226
|
+
Args:
|
|
227
|
+
name: Substring match on field name.
|
|
228
|
+
type_name: Exact match on field type.
|
|
229
|
+
is_static: Filter by static flag.
|
|
230
|
+
|
|
231
|
+
Returns:
|
|
232
|
+
List of MemberResult objects.
|
|
233
|
+
"""
|
|
234
|
+
results: list[MemberResult] = []
|
|
235
|
+
for ci in self._ws.classes:
|
|
236
|
+
for f in ci.all_fields:
|
|
237
|
+
if name is not None and name not in f.name:
|
|
238
|
+
continue
|
|
239
|
+
if type_name is not None and f.type_name != type_name:
|
|
240
|
+
continue
|
|
241
|
+
if is_static is not None and f.is_static != is_static:
|
|
242
|
+
continue
|
|
243
|
+
reason_parts = []
|
|
244
|
+
if name:
|
|
245
|
+
reason_parts.append(f"name contains '{name}'")
|
|
246
|
+
if type_name:
|
|
247
|
+
reason_parts.append(f"type={type_name}")
|
|
248
|
+
results.append(MemberResult(
|
|
249
|
+
class_name=ci.qualified_name,
|
|
250
|
+
member_name=f.name,
|
|
251
|
+
member_type="field",
|
|
252
|
+
match_reason=", ".join(reason_parts),
|
|
253
|
+
))
|
|
254
|
+
return results
|
|
255
|
+
|
|
256
|
+
def find_methods(
|
|
257
|
+
self,
|
|
258
|
+
*,
|
|
259
|
+
name: str | None = None,
|
|
260
|
+
return_type: str | None = None,
|
|
261
|
+
param_type: str | None = None,
|
|
262
|
+
is_static: bool | None = None,
|
|
263
|
+
) -> list[MemberResult]:
|
|
264
|
+
"""Find methods across all classes.
|
|
265
|
+
|
|
266
|
+
Args:
|
|
267
|
+
name: Substring match on method name.
|
|
268
|
+
return_type: Exact match on return type.
|
|
269
|
+
param_type: Exact match on any parameter type.
|
|
270
|
+
is_static: Filter by static flag.
|
|
271
|
+
|
|
272
|
+
Returns:
|
|
273
|
+
List of MemberResult objects.
|
|
274
|
+
"""
|
|
275
|
+
results: list[MemberResult] = []
|
|
276
|
+
for ci in self._ws.classes:
|
|
277
|
+
for m in ci.all_methods:
|
|
278
|
+
if name is not None and name not in m.name:
|
|
279
|
+
continue
|
|
280
|
+
if return_type is not None and m.return_type != return_type:
|
|
281
|
+
continue
|
|
282
|
+
if param_type is not None and param_type not in m.param_types:
|
|
283
|
+
continue
|
|
284
|
+
if is_static is not None and m.is_static != is_static:
|
|
285
|
+
continue
|
|
286
|
+
reason_parts = []
|
|
287
|
+
if name:
|
|
288
|
+
reason_parts.append(f"name contains '{name}'")
|
|
289
|
+
if return_type:
|
|
290
|
+
reason_parts.append(f"returns {return_type}")
|
|
291
|
+
if param_type:
|
|
292
|
+
reason_parts.append(f"takes {param_type}")
|
|
293
|
+
results.append(MemberResult(
|
|
294
|
+
class_name=ci.qualified_name,
|
|
295
|
+
member_name=m.name,
|
|
296
|
+
member_type="method",
|
|
297
|
+
match_reason=", ".join(reason_parts),
|
|
298
|
+
))
|
|
299
|
+
return results
|
|
300
|
+
|
|
301
|
+
# ── Reference queries ──────────────────────────────────────────────────
|
|
302
|
+
|
|
303
|
+
def find_instantiators(self, class_name: str) -> list[Reference]:
|
|
304
|
+
"""Find all places that construct instances of a class.
|
|
305
|
+
|
|
306
|
+
Args:
|
|
307
|
+
class_name: The class being instantiated.
|
|
308
|
+
|
|
309
|
+
Returns:
|
|
310
|
+
List of Reference objects with ref_kind="instantiation".
|
|
311
|
+
"""
|
|
312
|
+
return self.references.instantiators(class_name)
|
|
313
|
+
|
|
314
|
+
def find_type_users(self, type_name: str) -> list[Reference]:
|
|
315
|
+
"""Find all places that reference a type (fields, params, returns).
|
|
316
|
+
|
|
317
|
+
Args:
|
|
318
|
+
type_name: The type name.
|
|
319
|
+
|
|
320
|
+
Returns:
|
|
321
|
+
Combined list of field_type, param_type, and return_type references.
|
|
322
|
+
"""
|
|
323
|
+
result = self.references.field_type_users(type_name)
|
|
324
|
+
result += self.references.method_param_users(type_name)
|
|
325
|
+
result += self.references.method_return_users(type_name)
|
|
326
|
+
return result
|
|
327
|
+
|
|
328
|
+
def find_callers(self, method_name: str) -> list[CallEdge]:
|
|
329
|
+
"""Find all callers of a method.
|
|
330
|
+
|
|
331
|
+
Args:
|
|
332
|
+
method_name: The method name.
|
|
333
|
+
|
|
334
|
+
Returns:
|
|
335
|
+
List of CallEdge objects.
|
|
336
|
+
"""
|
|
337
|
+
return self.call_graph.get_callers(method_name)
|
|
338
|
+
|
|
339
|
+
def find_callees(self, caller: str) -> list[CallEdge]:
|
|
340
|
+
"""Find all methods/properties called by a method.
|
|
341
|
+
|
|
342
|
+
Args:
|
|
343
|
+
caller: The caller method name (``"Class.method"``).
|
|
344
|
+
|
|
345
|
+
Returns:
|
|
346
|
+
List of CallEdge objects.
|
|
347
|
+
"""
|
|
348
|
+
return self.call_graph.get_callees(caller)
|
|
349
|
+
|
|
350
|
+
# ── String queries ─────────────────────────────────────────────────────
|
|
351
|
+
|
|
352
|
+
def find_by_string(self, pattern: str,
|
|
353
|
+
regex: bool = False) -> list[StringResult]:
|
|
354
|
+
"""Find string constants matching a pattern.
|
|
355
|
+
|
|
356
|
+
Args:
|
|
357
|
+
pattern: Substring or regex pattern.
|
|
358
|
+
regex: If True, treat as regex.
|
|
359
|
+
|
|
360
|
+
Returns:
|
|
361
|
+
List of StringResult objects with usage locations.
|
|
362
|
+
"""
|
|
363
|
+
matching = self.strings.search(pattern, regex=regex)
|
|
364
|
+
results: list[StringResult] = []
|
|
365
|
+
for s in matching:
|
|
366
|
+
results.append(StringResult(
|
|
367
|
+
string=s,
|
|
368
|
+
usages=self.strings.by_string.get(s, []),
|
|
369
|
+
))
|
|
370
|
+
return results
|
|
371
|
+
|
|
372
|
+
def find_classes_by_string(self, string: str) -> list[ClassResult]:
|
|
373
|
+
"""Find classes that reference a specific string constant.
|
|
374
|
+
|
|
375
|
+
Args:
|
|
376
|
+
string: The exact string value.
|
|
377
|
+
|
|
378
|
+
Returns:
|
|
379
|
+
List of ClassResult objects.
|
|
380
|
+
"""
|
|
381
|
+
class_names = self.strings.classes_using_string(string)
|
|
382
|
+
results: list[ClassResult] = []
|
|
383
|
+
for n in class_names:
|
|
384
|
+
ci = self._ws.get_class(n)
|
|
385
|
+
if ci:
|
|
386
|
+
results.append(ClassResult(
|
|
387
|
+
class_info=ci,
|
|
388
|
+
match_reason=f"uses string '{string[:50]}'",
|
|
389
|
+
))
|
|
390
|
+
return results
|
|
391
|
+
|
|
392
|
+
# ── Structural pattern queries ─────────────────────────────────────────
|
|
393
|
+
|
|
394
|
+
def find_classes_with_field_type(self, type_name: str) -> list[ClassResult]:
|
|
395
|
+
"""Find classes that have a field of the given type.
|
|
396
|
+
|
|
397
|
+
Args:
|
|
398
|
+
type_name: The field type name.
|
|
399
|
+
|
|
400
|
+
Returns:
|
|
401
|
+
List of ClassResult objects.
|
|
402
|
+
"""
|
|
403
|
+
seen: set[str] = set()
|
|
404
|
+
results: list[ClassResult] = []
|
|
405
|
+
for ci in self._ws.classes:
|
|
406
|
+
for f in ci.all_fields:
|
|
407
|
+
if f.type_name == type_name and ci.qualified_name not in seen:
|
|
408
|
+
seen.add(ci.qualified_name)
|
|
409
|
+
results.append(ClassResult(
|
|
410
|
+
class_info=ci,
|
|
411
|
+
match_reason=f"has field of type {type_name}",
|
|
412
|
+
))
|
|
413
|
+
return results
|
|
414
|
+
|
|
415
|
+
def find_classes_with_method_returning(
|
|
416
|
+
self, return_type: str,
|
|
417
|
+
) -> list[ClassResult]:
|
|
418
|
+
"""Find classes that have a method returning the given type.
|
|
419
|
+
|
|
420
|
+
Args:
|
|
421
|
+
return_type: The return type name.
|
|
422
|
+
|
|
423
|
+
Returns:
|
|
424
|
+
List of ClassResult objects.
|
|
425
|
+
"""
|
|
426
|
+
seen: set[str] = set()
|
|
427
|
+
results: list[ClassResult] = []
|
|
428
|
+
for ci in self._ws.classes:
|
|
429
|
+
for m in ci.all_methods:
|
|
430
|
+
if m.return_type == return_type and ci.qualified_name not in seen:
|
|
431
|
+
seen.add(ci.qualified_name)
|
|
432
|
+
results.append(ClassResult(
|
|
433
|
+
class_info=ci,
|
|
434
|
+
match_reason=f"has method returning {return_type}",
|
|
435
|
+
))
|
|
436
|
+
return results
|
|
437
|
+
|
|
438
|
+
# ── Summary ────────────────────────────────────────────────────────────
|
|
439
|
+
|
|
440
|
+
def summary(self) -> str:
|
|
441
|
+
"""Return a summary of the search engine's indexed data."""
|
|
442
|
+
lines = [f"SearchEngine over {self._ws.class_count} classes"]
|
|
443
|
+
if self._inheritance:
|
|
444
|
+
lines.append(
|
|
445
|
+
f" Inheritance: {len(self._inheritance.classes)} nodes")
|
|
446
|
+
if self._call_graph:
|
|
447
|
+
lines.append(
|
|
448
|
+
f" Call graph: {self._call_graph.edge_count} edges")
|
|
449
|
+
if self._references:
|
|
450
|
+
lines.append(
|
|
451
|
+
f" References: {self._references.total_refs} refs")
|
|
452
|
+
if self._strings:
|
|
453
|
+
lines.append(
|
|
454
|
+
f" Strings: {self._strings.unique_string_count} unique, "
|
|
455
|
+
f"{self._strings.total_usages} usages")
|
|
456
|
+
return "\n".join(lines)
|
flashkit/swf/__init__.py
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""
|
|
2
|
+
SWF container format handling.
|
|
3
|
+
|
|
4
|
+
This package handles the SWF (Small Web Format) container — the file
|
|
5
|
+
format used by Adobe Flash Player. A SWF file is a sequence of typed
|
|
6
|
+
tags containing graphics, sounds, scripts (ABC bytecode), and metadata.
|
|
7
|
+
|
|
8
|
+
Quick start::
|
|
9
|
+
|
|
10
|
+
from flashkit.swf import parse_swf, rebuild_swf, TAG_DO_ABC2
|
|
11
|
+
|
|
12
|
+
header, tags, version, length = parse_swf(swf_bytes)
|
|
13
|
+
output = rebuild_swf(header, tags, compress=True)
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from .tags import (
|
|
17
|
+
SWFTag,
|
|
18
|
+
TAG_NAMES,
|
|
19
|
+
TAG_END,
|
|
20
|
+
TAG_SHOW_FRAME,
|
|
21
|
+
TAG_SET_BACKGROUND_COLOR,
|
|
22
|
+
TAG_SCRIPT_LIMITS,
|
|
23
|
+
TAG_FILE_ATTRIBUTES,
|
|
24
|
+
TAG_DO_ABC,
|
|
25
|
+
TAG_SYMBOL_CLASS,
|
|
26
|
+
TAG_DEFINE_BINARY_DATA,
|
|
27
|
+
TAG_DO_ABC2,
|
|
28
|
+
TAG_DEFINE_SCENE_AND_FRAME_LABEL,
|
|
29
|
+
TAG_DEBUG_ID,
|
|
30
|
+
)
|
|
31
|
+
from .parser import parse_swf, print_tags
|
|
32
|
+
from .builder import (
|
|
33
|
+
build_tag_bytes,
|
|
34
|
+
rebuild_swf,
|
|
35
|
+
make_doabc2_tag,
|
|
36
|
+
make_symbol_class_tag,
|
|
37
|
+
make_end_tag,
|
|
38
|
+
SwfBuilder,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
__all__ = [
|
|
42
|
+
# Tags
|
|
43
|
+
"SWFTag",
|
|
44
|
+
"TAG_NAMES",
|
|
45
|
+
"TAG_END",
|
|
46
|
+
"TAG_SHOW_FRAME",
|
|
47
|
+
"TAG_SET_BACKGROUND_COLOR",
|
|
48
|
+
"TAG_SCRIPT_LIMITS",
|
|
49
|
+
"TAG_FILE_ATTRIBUTES",
|
|
50
|
+
"TAG_DO_ABC",
|
|
51
|
+
"TAG_SYMBOL_CLASS",
|
|
52
|
+
"TAG_DEFINE_BINARY_DATA",
|
|
53
|
+
"TAG_DO_ABC2",
|
|
54
|
+
"TAG_DEFINE_SCENE_AND_FRAME_LABEL",
|
|
55
|
+
"TAG_DEBUG_ID",
|
|
56
|
+
# Parser
|
|
57
|
+
"parse_swf",
|
|
58
|
+
"print_tags",
|
|
59
|
+
# Builder
|
|
60
|
+
"build_tag_bytes",
|
|
61
|
+
"rebuild_swf",
|
|
62
|
+
"make_doabc2_tag",
|
|
63
|
+
"make_symbol_class_tag",
|
|
64
|
+
"make_end_tag",
|
|
65
|
+
"SwfBuilder",
|
|
66
|
+
]
|