More type changes for correctness in order to compile with mypyc in the future.
This commit is contained in:
parent
0a1cfb6f07
commit
7809ff360f
@ -132,5 +132,8 @@ def affine_composite(
|
||||
if errors != 0:
|
||||
raise Exception("Error raised in C++!")
|
||||
|
||||
# We blitted in-place, return that.
|
||||
return Image.frombytes('RGBA', (imgwidth, imgheight), imgbytes)
|
||||
# We blitted in-place, return that. There seems to be a reference bug in Cython
|
||||
# when called from compiled mypyc code, so if we don't assign to a local variable
|
||||
# first this function appears to return None.
|
||||
img = Image.frombytes('RGBA', (imgwidth, imgheight), imgbytes)
|
||||
return img
|
||||
|
@ -309,8 +309,8 @@ class TXP2File(TrackedCoverage, VerboseOutput):
|
||||
if name_crc != TXP2File.crc32(name.encode('ascii')):
|
||||
raise Exception(f"Name CRC failed for {name}")
|
||||
|
||||
for i, name in enumerate(names):
|
||||
if name is None:
|
||||
for i, n in enumerate(names):
|
||||
if n is None:
|
||||
raise Exception(f"Didn't get mapping for entry {i + 1}")
|
||||
|
||||
for i, o in enumerate(ordering):
|
||||
@ -318,8 +318,8 @@ class TXP2File(TrackedCoverage, VerboseOutput):
|
||||
raise Exception(f"Didn't get ordering for entry {i + 1}")
|
||||
|
||||
return PMAN(
|
||||
entries=names,
|
||||
ordering=ordering,
|
||||
entries=[n for n in names if n is not None],
|
||||
ordering=[o for o in ordering if o is not None],
|
||||
flags1=flags1,
|
||||
flags2=flags2,
|
||||
flags3=flags3,
|
||||
@ -388,6 +388,7 @@ class TXP2File(TrackedCoverage, VerboseOutput):
|
||||
name = descramble_text(bytedata, self.text_obfuscated)
|
||||
|
||||
if name_offset != 0 and texture_offset != 0:
|
||||
lz_data: Optional[bytes] = None
|
||||
if self.legacy_lz:
|
||||
raise Exception("We don't support legacy lz mode!")
|
||||
elif self.modern_lz:
|
||||
@ -423,7 +424,6 @@ class TXP2File(TrackedCoverage, VerboseOutput):
|
||||
self.vprint(f" {name}, length: {texture_length}, offset: {hex(texture_offset)}, deflated_size: {deflated_size}, inflated_size: {inflated_size}")
|
||||
|
||||
# Just grab the raw data.
|
||||
lz_data = None
|
||||
raw_data = self.data[(texture_offset + 8):(texture_offset + 8 + deflated_size)]
|
||||
self.add_coverage(texture_offset, deflated_size + 8)
|
||||
|
||||
@ -1440,6 +1440,8 @@ class TXP2File(TrackedCoverage, VerboseOutput):
|
||||
bitchunks[16] = struct.pack(f"{self.endian}I", offset)
|
||||
|
||||
# Now, encode the font information.
|
||||
if self.fontdata is None:
|
||||
raise Exception("Container has fontdata, but fontdata is None!")
|
||||
fontbytes = self.benc.encode(self.fontdata)
|
||||
body += struct.pack(
|
||||
f"{self.endian}III",
|
||||
|
@ -683,6 +683,8 @@ class ByteCodeDecompiler(VerboseOutput):
|
||||
if not chunk.next_chunks:
|
||||
num_end_chunks += 1
|
||||
if not chunk.previous_chunks:
|
||||
if bytecode.start_offset is None:
|
||||
raise Exception("Logic error, expected a start offset for bytecode chunk, we shouldn't be decompiling empty bytecode!")
|
||||
if chunk.id != offset_to_id[bytecode.start_offset]:
|
||||
raise Exception(f"Start of graph found at ID {chunk.id} but expected to be {offset_to_id[bytecode.start_offset]}!")
|
||||
num_start_chunks += 1
|
||||
@ -871,7 +873,7 @@ class ByteCodeDecompiler(VerboseOutput):
|
||||
|
||||
chunk.actions[-1] = IntermediateIf(
|
||||
cast(IfAction, last_action),
|
||||
[true_action],
|
||||
[true_action] if true_action else [],
|
||||
[false_action] if false_action else [],
|
||||
)
|
||||
|
||||
@ -1120,7 +1122,7 @@ class ByteCodeDecompiler(VerboseOutput):
|
||||
if true_action or false_action:
|
||||
chunk.actions[-1] = IntermediateIf(
|
||||
cast(IfAction, last_action),
|
||||
[true_action],
|
||||
[true_action] if true_action else [],
|
||||
[false_action] if false_action else [],
|
||||
)
|
||||
|
||||
@ -1540,40 +1542,40 @@ class ByteCodeDecompiler(VerboseOutput):
|
||||
# into the spot where they were called since we know that they aren't used.
|
||||
|
||||
def make_if_expr(action: IfAction) -> IfExpr:
|
||||
if action.comparison in [IfAction.IS_UNDEFINED, IfAction.IS_NOT_UNDEFINED]:
|
||||
if action.comparison in [IfAction.COMP_IS_UNDEFINED, IfAction.COMP_IS_NOT_UNDEFINED]:
|
||||
conditional = stack.pop()
|
||||
return IsUndefinedIf(conditional, negate=(action.comparison != IfAction.IS_UNDEFINED))
|
||||
elif action.comparison in [IfAction.IS_TRUE, IfAction.IS_FALSE]:
|
||||
return IsUndefinedIf(conditional, negate=(action.comparison != IfAction.COMP_IS_UNDEFINED))
|
||||
elif action.comparison in [IfAction.COMP_IS_TRUE, IfAction.COMP_IS_FALSE]:
|
||||
conditional = stack.pop()
|
||||
return IsBooleanIf(conditional, negate=(action.comparison != IfAction.IS_TRUE))
|
||||
return IsBooleanIf(conditional, negate=(action.comparison != IfAction.COMP_IS_TRUE))
|
||||
elif action.comparison in [
|
||||
IfAction.EQUALS,
|
||||
IfAction.NOT_EQUALS,
|
||||
IfAction.STRICT_EQUALS,
|
||||
IfAction.STRICT_NOT_EQUALS,
|
||||
IfAction.LT,
|
||||
IfAction.GT,
|
||||
IfAction.LT_EQUALS,
|
||||
IfAction.GT_EQUALS
|
||||
IfAction.COMP_EQUALS,
|
||||
IfAction.COMP_NOT_EQUALS,
|
||||
IfAction.COMP_STRICT_EQUALS,
|
||||
IfAction.COMP_STRICT_NOT_EQUALS,
|
||||
IfAction.COMP_LT,
|
||||
IfAction.COMP_GT,
|
||||
IfAction.COMP_LT_EQUALS,
|
||||
IfAction.COMP_GT_EQUALS
|
||||
]:
|
||||
conditional2 = stack.pop()
|
||||
conditional1 = stack.pop()
|
||||
comp = {
|
||||
IfAction.EQUALS: TwoParameterIf.EQUALS,
|
||||
IfAction.NOT_EQUALS: TwoParameterIf.NOT_EQUALS,
|
||||
IfAction.STRICT_EQUALS: TwoParameterIf.STRICT_EQUALS,
|
||||
IfAction.STRICT_NOT_EQUALS: TwoParameterIf.STRICT_NOT_EQUALS,
|
||||
IfAction.LT: TwoParameterIf.LT,
|
||||
IfAction.GT: TwoParameterIf.GT,
|
||||
IfAction.LT_EQUALS: TwoParameterIf.LT_EQUALS,
|
||||
IfAction.GT_EQUALS: TwoParameterIf.GT_EQUALS,
|
||||
IfAction.COMP_EQUALS: TwoParameterIf.EQUALS,
|
||||
IfAction.COMP_NOT_EQUALS: TwoParameterIf.NOT_EQUALS,
|
||||
IfAction.COMP_STRICT_EQUALS: TwoParameterIf.STRICT_EQUALS,
|
||||
IfAction.COMP_STRICT_NOT_EQUALS: TwoParameterIf.STRICT_NOT_EQUALS,
|
||||
IfAction.COMP_LT: TwoParameterIf.LT,
|
||||
IfAction.COMP_GT: TwoParameterIf.GT,
|
||||
IfAction.COMP_LT_EQUALS: TwoParameterIf.LT_EQUALS,
|
||||
IfAction.COMP_GT_EQUALS: TwoParameterIf.GT_EQUALS,
|
||||
}[action.comparison]
|
||||
|
||||
return TwoParameterIf(conditional1, comp, conditional2)
|
||||
elif action.comparison in [IfAction.BITAND, IfAction.NOT_BITAND]:
|
||||
elif action.comparison in [IfAction.COMP_BITAND, IfAction.COMP_NOT_BITAND]:
|
||||
conditional2 = stack.pop()
|
||||
conditional1 = stack.pop()
|
||||
comp = TwoParameterIf.NOT_EQUALS if action.comparison == IfAction.BITAND else TwoParameterIf.EQUALS
|
||||
comp = TwoParameterIf.NOT_EQUALS if action.comparison == IfAction.COMP_BITAND else TwoParameterIf.EQUALS
|
||||
|
||||
return TwoParameterIf(
|
||||
ArithmeticExpression(conditional1, "&", conditional2),
|
||||
@ -2385,10 +2387,7 @@ class ByteCodeDecompiler(VerboseOutput):
|
||||
if len(chunk.next_chunks) > 1:
|
||||
# We've checked so this should be impossible.
|
||||
raise Exception("Logic error!")
|
||||
if chunk.next_chunks:
|
||||
next_chunk_id = chunk.next_chunks[0]
|
||||
else:
|
||||
next_chunk_id = next_id
|
||||
next_chunk_id = chunk.next_chunks[0] if chunk.next_chunks else next_id
|
||||
|
||||
if isinstance(chunk, Loop):
|
||||
# Evaluate the loop. No need to update per-chunk stacks here since we will do it in a child eval.
|
||||
@ -2470,6 +2469,8 @@ class ByteCodeDecompiler(VerboseOutput):
|
||||
offset_map,
|
||||
)
|
||||
else:
|
||||
if next_chunk_id is None:
|
||||
raise Exception("Logic error, cannot reconcile stacks when next chunk is the end!")
|
||||
reconcile_stacks(chunk.id, next_chunk_id, stack_leftovers)
|
||||
|
||||
false_statements: List[Statement] = []
|
||||
@ -2494,6 +2495,8 @@ class ByteCodeDecompiler(VerboseOutput):
|
||||
offset_map,
|
||||
)
|
||||
else:
|
||||
if next_chunk_id is None:
|
||||
raise Exception("Logic error, cannot reconcile stacks when next chunk is the end!")
|
||||
reconcile_stacks(chunk.id, next_chunk_id, stack_leftovers)
|
||||
|
||||
# Convert this IfExpr to a full-blown IfStatement.
|
||||
@ -2507,7 +2510,7 @@ class ByteCodeDecompiler(VerboseOutput):
|
||||
chunk = if_body_chunk
|
||||
else:
|
||||
# We must propagate the stack to the next entry. If it already exists we must merge it.
|
||||
new_next_ids: Set[int] = {next_chunk_id}
|
||||
new_next_ids: Set[int] = {next_chunk_id} if next_chunk_id else set()
|
||||
if new_statements:
|
||||
last_new_statement = new_statements[-1]
|
||||
if isinstance(last_new_statement, GotoStatement):
|
||||
@ -2755,7 +2758,7 @@ class ByteCodeDecompiler(VerboseOutput):
|
||||
|
||||
updated: bool = False
|
||||
|
||||
def remove_returns(statement: Statement) -> Statement:
|
||||
def remove_returns(statement: Statement) -> Optional[Statement]:
|
||||
nonlocal updated
|
||||
|
||||
for removable in returns:
|
||||
@ -2877,7 +2880,7 @@ class ByteCodeDecompiler(VerboseOutput):
|
||||
|
||||
updated: bool = False
|
||||
|
||||
def remove_continues(statement: Statement) -> Statement:
|
||||
def remove_continues(statement: Statement) -> Optional[Statement]:
|
||||
nonlocal updated
|
||||
|
||||
for removable in continues:
|
||||
@ -2895,14 +2898,17 @@ class ByteCodeDecompiler(VerboseOutput):
|
||||
if expression.op in {"+", "-", "*", "/"}:
|
||||
# It is, let's see if one of the two sides contains the
|
||||
# variable we care about.
|
||||
left = None
|
||||
try:
|
||||
left = object_ref(expression.left, "")
|
||||
except Exception:
|
||||
left = None
|
||||
pass
|
||||
|
||||
right = None
|
||||
try:
|
||||
right = object_ref(expression.right, "")
|
||||
except Exception:
|
||||
right = None
|
||||
pass
|
||||
|
||||
return left == variable or right == variable
|
||||
return False
|
||||
@ -2943,35 +2949,39 @@ class ByteCodeDecompiler(VerboseOutput):
|
||||
# This is possibly a candidate, check the condition's variable usage.
|
||||
if isinstance(possible_if.cond, IsUndefinedIf):
|
||||
if required_variable is not None:
|
||||
if_variable = None
|
||||
try:
|
||||
if_variable = object_ref(possible_if.cond.conditional, "")
|
||||
except Exception:
|
||||
if_variable = None
|
||||
pass
|
||||
if required_variable != if_variable:
|
||||
return None
|
||||
return None, []
|
||||
return possible_if.cond, possible_if.false_statements
|
||||
elif isinstance(possible_if.cond, IsBooleanIf):
|
||||
if required_variable is not None:
|
||||
if_variable = None
|
||||
try:
|
||||
if_variable = object_ref(possible_if.cond.conditional, "")
|
||||
except Exception:
|
||||
if_variable = None
|
||||
pass
|
||||
if required_variable != if_variable:
|
||||
return None
|
||||
return None, []
|
||||
return possible_if.cond, possible_if.false_statements
|
||||
elif isinstance(possible_if.cond, TwoParameterIf):
|
||||
if required_variable is not None:
|
||||
if_variable1 = None
|
||||
try:
|
||||
if_variable1 = object_ref(possible_if.cond.conditional1, "")
|
||||
except Exception:
|
||||
if_variable1 = None
|
||||
pass
|
||||
if if_variable1 == required_variable:
|
||||
return possible_if.cond, possible_if.false_statements
|
||||
|
||||
if_variable2 = None
|
||||
try:
|
||||
if_variable2 = object_ref(possible_if.cond.conditional2, "")
|
||||
except Exception:
|
||||
if_variable2 = None
|
||||
pass
|
||||
if if_variable2 == required_variable:
|
||||
return possible_if.cond.swap(), possible_if.false_statements
|
||||
return possible_if.cond, possible_if.false_statements
|
||||
@ -3230,6 +3240,8 @@ class ByteCodeDecompiler(VerboseOutput):
|
||||
# First, we need to construct a control flow graph.
|
||||
self.vprint("Generating control flow graph...")
|
||||
chunks, offset_map = self.__graph_control_flow(self.bytecode)
|
||||
if self.bytecode.start_offset is None:
|
||||
raise Exception("Logic error, we should not be decompiling empty bytecode!")
|
||||
start_id = offset_map[self.bytecode.start_offset]
|
||||
|
||||
# Now, compute dominators so we can locate back-refs.
|
||||
|
@ -1006,16 +1006,13 @@ class AFPRenderer(VerboseOutput):
|
||||
|
||||
# Render individual shapes if this is a sprite.
|
||||
if isinstance(renderable, PlacedClip):
|
||||
new_only_depths: Optional[List[int]] = None
|
||||
if only_depths is not None:
|
||||
if renderable.depth not in only_depths:
|
||||
if renderable.depth != -1:
|
||||
# Not on the correct depth plane.
|
||||
return img
|
||||
new_only_depths = only_depths
|
||||
else:
|
||||
new_only_depths = None
|
||||
else:
|
||||
new_only_depths = None
|
||||
|
||||
# This is a sprite placement reference. Make sure that we render lower depths
|
||||
# first, but preserved placed order as well.
|
||||
@ -1062,6 +1059,8 @@ class AFPRenderer(VerboseOutput):
|
||||
# of a rectangle, but let's assume that doesn't happen for now.
|
||||
if len(shape.vertex_points) != 4:
|
||||
print("WARNING: Unsupported non-rectangle shape!")
|
||||
if params.blend is None:
|
||||
raise Exception("Logic error, rectangle without a blend color!")
|
||||
|
||||
x_points = set(p.x for p in shape.vertex_points)
|
||||
y_points = set(p.y for p in shape.vertex_points)
|
||||
@ -1407,10 +1406,9 @@ class AFPRenderer(VerboseOutput):
|
||||
actual_add_color = Color(0.0, 0.0, 0.0, 0.0)
|
||||
actual_blend = 0
|
||||
|
||||
max_frame: Optional[int] = None
|
||||
if only_frames:
|
||||
max_frame = max(only_frames)
|
||||
else:
|
||||
max_frame = None
|
||||
|
||||
# Now play the frames of the root clip.
|
||||
try:
|
||||
|
@ -101,6 +101,8 @@ class Tag:
|
||||
|
||||
|
||||
class AP2ShapeTag(Tag):
|
||||
id: int
|
||||
|
||||
def __init__(self, id: int, reference: str) -> None:
|
||||
super().__init__(id)
|
||||
|
||||
@ -115,6 +117,8 @@ class AP2ShapeTag(Tag):
|
||||
|
||||
|
||||
class AP2ImageTag(Tag):
|
||||
id: int
|
||||
|
||||
def __init__(self, id: int, reference: str) -> None:
|
||||
super().__init__(id)
|
||||
|
||||
@ -129,6 +133,8 @@ class AP2ImageTag(Tag):
|
||||
|
||||
|
||||
class AP2DefineFontTag(Tag):
|
||||
id: int
|
||||
|
||||
def __init__(self, id: int, fontname: str, xml_prefix: str, heights: List[int], text_indexes: List[int]) -> None:
|
||||
super().__init__(id)
|
||||
|
||||
@ -196,6 +202,8 @@ class AP2TextLine:
|
||||
|
||||
|
||||
class AP2DefineMorphShapeTag(Tag):
|
||||
id: int
|
||||
|
||||
def __init__(self, id: int) -> None:
|
||||
# TODO: I need to figure out what morph shapes actually DO, and take the
|
||||
# values that I parsed out store them here...
|
||||
@ -208,6 +216,8 @@ class AP2DefineMorphShapeTag(Tag):
|
||||
|
||||
|
||||
class AP2DefineButtonTag(Tag):
|
||||
id: int
|
||||
|
||||
def __init__(self, id: int) -> None:
|
||||
# TODO: I need to figure out what buttons actually DO, and take the
|
||||
# values that I parsed out store them here...
|
||||
@ -232,6 +242,8 @@ class AP2PlaceCameraTag(Tag):
|
||||
|
||||
|
||||
class AP2DefineTextTag(Tag):
|
||||
id: int
|
||||
|
||||
def __init__(self, id: int, lines: List[AP2TextLine]) -> None:
|
||||
super().__init__(id)
|
||||
|
||||
@ -356,6 +368,8 @@ class AP2RemoveObjectTag(Tag):
|
||||
|
||||
|
||||
class AP2DefineSpriteTag(Tag):
|
||||
id: int
|
||||
|
||||
def __init__(self, id: int, tags: List[Tag], frames: List[Frame], labels: Dict[str, int]) -> None:
|
||||
super().__init__(id)
|
||||
|
||||
@ -379,6 +393,8 @@ class AP2DefineSpriteTag(Tag):
|
||||
|
||||
|
||||
class AP2DefineEditTextTag(Tag):
|
||||
id: int
|
||||
|
||||
def __init__(self, id: int, font_tag_id: int, font_height: int, rect: Rectangle, color: Color, default_text: Optional[str] = None) -> None:
|
||||
super().__init__(id)
|
||||
|
||||
@ -892,7 +908,7 @@ class SWF(TrackedCoverage, VerboseOutput):
|
||||
offset_ptr += 3
|
||||
|
||||
self.vprint(f"{prefix} {lineno}: Offset If True: {jump_if_true_offset}")
|
||||
actions.append(IfAction(lineno, IfAction.IS_TRUE, jump_if_true_offset))
|
||||
actions.append(IfAction(lineno, IfAction.COMP_IS_TRUE, jump_if_true_offset))
|
||||
elif opcode == AP2Action.IF2:
|
||||
if2_type, jump_if_true_offset = struct.unpack(">Bh", datachunk[(offset_ptr + 1):(offset_ptr + 4)])
|
||||
jump_if_true_offset += (lineno + 4)
|
||||
@ -2327,13 +2343,13 @@ class SWF(TrackedCoverage, VerboseOutput):
|
||||
tag_id, frame, action_bytecode_offset, action_bytecode_length = struct.unpack("<HHII", data[item_offset:(item_offset + 12)])
|
||||
self.add_coverage(item_offset, 12)
|
||||
|
||||
bytecode: Optional[ByteCode] = None
|
||||
if action_bytecode_length != 0:
|
||||
self.vprint(f" Tag ID: {tag_id}, Frame: {frame}, ByteCode Offset: {hex(action_bytecode_offset + imported_tag_initializers_offset)}")
|
||||
bytecode_data = data[(action_bytecode_offset + imported_tag_initializers_offset):(action_bytecode_offset + imported_tag_initializers_offset + action_bytecode_length)]
|
||||
bytecode = self.__parse_bytecode(f"on_import_tag_{tag_id}", bytecode_data)
|
||||
else:
|
||||
self.vprint(f" Tag ID: {tag_id}, Frame: {frame}, No ByteCode Present")
|
||||
bytecode = None
|
||||
|
||||
# Add it to the frame's instructions
|
||||
if frame >= len(self.frames):
|
||||
|
@ -1,5 +1,5 @@
|
||||
import os
|
||||
from typing import TYPE_CHECKING, Any, Dict, List, Set, Optional
|
||||
from typing import TYPE_CHECKING, Any, Dict, Final, List, Set, Optional
|
||||
|
||||
from .expression import Register
|
||||
|
||||
@ -11,200 +11,200 @@ if TYPE_CHECKING:
|
||||
class AP2Object:
|
||||
# These are internal object types, useful to have them for understanding
|
||||
# what the original games are doing with data types.
|
||||
UNDEFINED = 0x0
|
||||
NAN = 0x1
|
||||
BOOLEAN = 0x2
|
||||
INTEGER = 0x3
|
||||
S64 = 0x4
|
||||
FLOAT = 0x5
|
||||
DOUBLE = 0x6
|
||||
STRING = 0x7
|
||||
POINTER = 0x8
|
||||
OBJECT = 0x9
|
||||
INFINITY = 0xa
|
||||
CONST_STRING = 0xb
|
||||
BUILT_IN_FUNCTION = 0xc
|
||||
UNDEFINED: Final[int] = 0x0
|
||||
NAN: Final[int] = 0x1
|
||||
BOOLEAN: Final[int] = 0x2
|
||||
INTEGER: Final[int] = 0x3
|
||||
S64: Final[int] = 0x4
|
||||
FLOAT: Final[int] = 0x5
|
||||
DOUBLE: Final[int] = 0x6
|
||||
STRING: Final[int] = 0x7
|
||||
POINTER: Final[int] = 0x8
|
||||
OBJECT: Final[int] = 0x9
|
||||
INFINITY: Final[int] = 0xa
|
||||
CONST_STRING: Final[int] = 0xb
|
||||
BUILT_IN_FUNCTION: Final[int] = 0xc
|
||||
|
||||
|
||||
class AP2Pointer:
|
||||
# The type of the object if it is an AP2Object.POINTER or AP2Object.OBJECT.
|
||||
# These are internal object types as well, and are only useful to have these
|
||||
# around for understanding what games are doing with data types.
|
||||
UNDEFINED = 0x0
|
||||
AFP_TEXT = 0x1
|
||||
AFP_RECT = 0x2
|
||||
AFP_SHAPE = 0x3
|
||||
DRAG = 0x4
|
||||
MATRIX = 0x5
|
||||
POINT = 0x6
|
||||
GETTER_SETTER_PROPERTY = 0x7
|
||||
FUNCTION_WITH_PROTOTYPE = 0x8
|
||||
ROW_DATA = 0x20
|
||||
UNDEFINED: Final[int] = 0x0
|
||||
AFP_TEXT: Final[int] = 0x1
|
||||
AFP_RECT: Final[int] = 0x2
|
||||
AFP_SHAPE: Final[int] = 0x3
|
||||
DRAG: Final[int] = 0x4
|
||||
MATRIX: Final[int] = 0x5
|
||||
POINT: Final[int] = 0x6
|
||||
GETTER_SETTER_PROPERTY: Final[int] = 0x7
|
||||
FUNCTION_WITH_PROTOTYPE: Final[int] = 0x8
|
||||
ROW_DATA: Final[int] = 0x20
|
||||
|
||||
object_W = 0x50
|
||||
movieClip_W = 0x51
|
||||
sound_W = 0x52
|
||||
color_W = 0x53
|
||||
date_W = 0x54
|
||||
array_W = 0x55
|
||||
xml_W = 0x56
|
||||
xmlNode_W = 0x57
|
||||
textFormat_W = 0x58
|
||||
sharedObject_W = 0x59
|
||||
sharedObjectData_W = 0x5a
|
||||
textField_W = 0x5b
|
||||
xmlAttrib_W = 0x5c
|
||||
bitmapdata_W = 0x5d
|
||||
matrix_W = 0x5e
|
||||
point_W = 0x5f
|
||||
ColorMatrixFilter_W = 0x60
|
||||
String_W = 0x61
|
||||
Boolean_W = 0x62
|
||||
Number_W = 0x63
|
||||
function_W = 0x64
|
||||
prototype_W = 0x65
|
||||
super_W = 0x66
|
||||
transform_W = 0x68
|
||||
colorTransform_W = 0x69
|
||||
rectangle_W = 0x6a
|
||||
object_W: Final[int] = 0x50
|
||||
movieClip_W: Final[int] = 0x51
|
||||
sound_W: Final[int] = 0x52
|
||||
color_W: Final[int] = 0x53
|
||||
date_W: Final[int] = 0x54
|
||||
array_W: Final[int] = 0x55
|
||||
xml_W: Final[int] = 0x56
|
||||
xmlNode_W: Final[int] = 0x57
|
||||
textFormat_W: Final[int] = 0x58
|
||||
sharedObject_W: Final[int] = 0x59
|
||||
sharedObjectData_W: Final[int] = 0x5a
|
||||
textField_W: Final[int] = 0x5b
|
||||
xmlAttrib_W: Final[int] = 0x5c
|
||||
bitmapdata_W: Final[int] = 0x5d
|
||||
matrix_W: Final[int] = 0x5e
|
||||
point_W: Final[int] = 0x5f
|
||||
ColorMatrixFilter_W: Final[int] = 0x60
|
||||
String_W: Final[int] = 0x61
|
||||
Boolean_W: Final[int] = 0x62
|
||||
Number_W: Final[int] = 0x63
|
||||
function_W: Final[int] = 0x64
|
||||
prototype_W: Final[int] = 0x65
|
||||
super_W: Final[int] = 0x66
|
||||
transform_W: Final[int] = 0x68
|
||||
colorTransform_W: Final[int] = 0x69
|
||||
rectangle_W: Final[int] = 0x6a
|
||||
|
||||
# All of these can have prototypes, not sure what the "C" stands for.
|
||||
Object_C = 0x78
|
||||
MovieClip_C = 0x79
|
||||
Sound_C = 0x7a
|
||||
Color_C = 0x7b
|
||||
Date_C = 0x7c
|
||||
Array_C = 0x7d
|
||||
XML_C = 0x7e
|
||||
XMLNode_C = 0x7f
|
||||
TextFormat_C = 0x80
|
||||
TextField_C = 0x83
|
||||
BitmapData_C = 0x85
|
||||
matrix_C = 0x86
|
||||
point_C = 0x87
|
||||
String_C = 0x89
|
||||
Boolean_C = 0x8a
|
||||
Number_C = 0x8b
|
||||
Function_C = 0x8c
|
||||
aplib_C = 0x8f
|
||||
transform_C = 0x90
|
||||
colorTransform_C = 0x91
|
||||
rectangle_C = 0x92
|
||||
asdlib_C = 0x93
|
||||
XMLController_C = 0x94
|
||||
eManager_C = 0x95
|
||||
Object_C: Final[int] = 0x78
|
||||
MovieClip_C: Final[int] = 0x79
|
||||
Sound_C: Final[int] = 0x7a
|
||||
Color_C: Final[int] = 0x7b
|
||||
Date_C: Final[int] = 0x7c
|
||||
Array_C: Final[int] = 0x7d
|
||||
XML_C: Final[int] = 0x7e
|
||||
XMLNode_C: Final[int] = 0x7f
|
||||
TextFormat_C: Final[int] = 0x80
|
||||
TextField_C: Final[int] = 0x83
|
||||
BitmapData_C: Final[int] = 0x85
|
||||
matrix_C: Final[int] = 0x86
|
||||
point_C: Final[int] = 0x87
|
||||
String_C: Final[int] = 0x89
|
||||
Boolean_C: Final[int] = 0x8a
|
||||
Number_C: Final[int] = 0x8b
|
||||
Function_C: Final[int] = 0x8c
|
||||
aplib_C: Final[int] = 0x8f
|
||||
transform_C: Final[int] = 0x90
|
||||
colorTransform_C: Final[int] = 0x91
|
||||
rectangle_C: Final[int] = 0x92
|
||||
asdlib_C: Final[int] = 0x93
|
||||
XMLController_C: Final[int] = 0x94
|
||||
eManager_C: Final[int] = 0x95
|
||||
|
||||
stage_O = 0xa0
|
||||
math_O = 0xa1
|
||||
key_O = 0xa2
|
||||
mouse_O = 0xa3
|
||||
system_O = 0xa4
|
||||
sharedObject_O = 0xa5
|
||||
flash_O = 0xa6
|
||||
global_O = 0xa7
|
||||
stage_O: Final[int] = 0xa0
|
||||
math_O: Final[int] = 0xa1
|
||||
key_O: Final[int] = 0xa2
|
||||
mouse_O: Final[int] = 0xa3
|
||||
system_O: Final[int] = 0xa4
|
||||
sharedObject_O: Final[int] = 0xa5
|
||||
flash_O: Final[int] = 0xa6
|
||||
global_O: Final[int] = 0xa7
|
||||
|
||||
display_P = 0xb4
|
||||
geom_P = 0xb5
|
||||
filtesr_P = 0xb6
|
||||
display_P: Final[int] = 0xb4
|
||||
geom_P: Final[int] = 0xb5
|
||||
filtesr_P: Final[int] = 0xb6
|
||||
|
||||
|
||||
class AP2Trigger:
|
||||
# Possible triggers for ByteCode to be attached to on object place tags.
|
||||
ON_LOAD = 0x1
|
||||
ON_ENTER_FRAME = 0x2
|
||||
ON_UNLOAD = 0x4
|
||||
ON_MOUSE_MOVE = 0x8
|
||||
ON_MOUSE_DOWN = 0x10
|
||||
ON_MOUSE_UP = 0x20
|
||||
ON_KEY_DOWN = 0x40
|
||||
ON_KEY_UP = 0x80
|
||||
ON_DATA = 0x100
|
||||
ON_PRESS = 0x400
|
||||
ON_RELEASE = 0x800
|
||||
ON_RELEASE_OUTSIDE = 0x1000
|
||||
ON_ROLL_OVER = 0x2000
|
||||
ON_ROLL_OUT = 0x4000
|
||||
ON_LOAD: Final[int] = 0x1
|
||||
ON_ENTER_FRAME: Final[int] = 0x2
|
||||
ON_UNLOAD: Final[int] = 0x4
|
||||
ON_MOUSE_MOVE: Final[int] = 0x8
|
||||
ON_MOUSE_DOWN: Final[int] = 0x10
|
||||
ON_MOUSE_UP: Final[int] = 0x20
|
||||
ON_KEY_DOWN: Final[int] = 0x40
|
||||
ON_KEY_UP: Final[int] = 0x80
|
||||
ON_DATA: Final[int] = 0x100
|
||||
ON_PRESS: Final[int] = 0x400
|
||||
ON_RELEASE: Final[int] = 0x800
|
||||
ON_RELEASE_OUTSIDE: Final[int] = 0x1000
|
||||
ON_ROLL_OVER: Final[int] = 0x2000
|
||||
ON_ROLL_OUT: Final[int] = 0x4000
|
||||
|
||||
|
||||
class AP2Tag:
|
||||
# Every tag found in an AFP file. The majority of these are identical to tags
|
||||
# in the SWF file specification but are not seen in practice.
|
||||
END = 0x0
|
||||
SHOW_FRAME = 0x1
|
||||
DEFINE_SHAPE = 0x2
|
||||
PLACE_OBJECT = 0x4
|
||||
REMOVE_OBJECT = 0x5
|
||||
DEFINE_BITS = 0x6
|
||||
DEFINE_BUTTON = 0x7
|
||||
JPEG_TABLES = 0x8
|
||||
BACKGROUND_COLOR = 0x9
|
||||
DEFINE_FONT = 0xa
|
||||
DEFINE_TEXT = 0xb
|
||||
DO_ACTION = 0xc
|
||||
DEFINE_FONT_INFO = 0xd
|
||||
DEFINE_SOUND = 0xe
|
||||
START_SOUND = 0xf
|
||||
DEFINE_BUTTON_SOUND = 0x11
|
||||
SOUND_STREAM_HEAD = 0x12
|
||||
SOUND_STREAM_BLOCK = 0x13
|
||||
DEFINE_BITS_LOSSLESS = 0x14
|
||||
DEFINE_BITS_JPEG2 = 0x15
|
||||
DEFINE_SHAPE2 = 0x16
|
||||
DEFINE_BUTTON_CXFORM = 0x17
|
||||
PROTECT = 0x18
|
||||
PLACE_OBJECT2 = 0x1a
|
||||
REMOVE_OBJECT2 = 0x1c
|
||||
DEFINE_SHAPE3 = 0x20
|
||||
DEFINE_TEXT2 = 0x21
|
||||
DEFINE_BUTTON2 = 0x22
|
||||
DEFINE_BITS_JPEG3 = 0x23
|
||||
DEFINE_BITS_LOSSLESS2 = 0x24
|
||||
DEFINE_EDIT_TEXT = 0x25
|
||||
DEFINE_SPRITE = 0x27
|
||||
FRAME_LABEL = 0x2b
|
||||
SOUND_STREAM_HEAD2 = 0x2d
|
||||
DEFINE_MORPH_SHAPE = 0x2e
|
||||
DEFINE_FONT2 = 0x30
|
||||
EXPORT_ASSETS = 0x38
|
||||
IMPORT_ASSETS = 0x39
|
||||
DO_INIT_ACTION = 0x3b
|
||||
DEFINE_VIDEO_STREAM = 0x3c
|
||||
VIDEO_FRAME = 0x3d
|
||||
DEFINE_FONT_INFO2 = 0x3e
|
||||
ENABLE_DEBUGGER2 = 0x40
|
||||
SCRIPT_LIMITS = 0x41
|
||||
SET_TAB_INDEX = 0x42
|
||||
PLACE_OBJECT3 = 0x46
|
||||
IMPORT_ASSETS2 = 0x47
|
||||
DEFINE_FONT3 = 0x4b
|
||||
METADATA = 0x4d
|
||||
DEFINE_SCALING_GRID = 0x4e
|
||||
DEFINE_SHAPE4 = 0x53
|
||||
DEFINE_MORPH_SHAPE2 = 0x54
|
||||
SCENE_LABEL = 0x56
|
||||
AFP_IMAGE = 0x64
|
||||
AFP_DEFINE_SOUND = 0x65
|
||||
AFP_SOUND_STREAM_BLOCK = 0x66
|
||||
AFP_DEFINE_FONT = 0x67
|
||||
AFP_DEFINE_SHAPE = 0x68
|
||||
AEP_PLACE_OBJECT = 0x6e
|
||||
AP2_DEFINE_FONT = 0x78
|
||||
AP2_DEFINE_SPRITE = 0x79
|
||||
AP2_DO_ACTION = 0x7a
|
||||
AP2_DEFINE_BUTTON = 0x7b
|
||||
AP2_DEFINE_BUTTON_SOUND = 0x7c
|
||||
AP2_DEFINE_TEXT = 0x7d
|
||||
AP2_DEFINE_EDIT_TEXT = 0x7e
|
||||
AP2_PLACE_OBJECT = 0x7f
|
||||
AP2_REMOVE_OBJECT = 0x80
|
||||
AP2_START_SOUND = 0x81
|
||||
AP2_DEFINE_MORPH_SHAPE = 0x82
|
||||
AP2_IMAGE = 0x83
|
||||
AP2_SHAPE = 0x84
|
||||
AP2_SOUND = 0x85
|
||||
AP2_VIDEO = 0x86
|
||||
AP2_PLACE_CAMERA = 0x88
|
||||
AP2_SCALING_GRID = 0x89
|
||||
END: Final[int] = 0x0
|
||||
SHOW_FRAME: Final[int] = 0x1
|
||||
DEFINE_SHAPE: Final[int] = 0x2
|
||||
PLACE_OBJECT: Final[int] = 0x4
|
||||
REMOVE_OBJECT: Final[int] = 0x5
|
||||
DEFINE_BITS: Final[int] = 0x6
|
||||
DEFINE_BUTTON: Final[int] = 0x7
|
||||
JPEG_TABLES: Final[int] = 0x8
|
||||
BACKGROUND_COLOR: Final[int] = 0x9
|
||||
DEFINE_FONT: Final[int] = 0xa
|
||||
DEFINE_TEXT: Final[int] = 0xb
|
||||
DO_ACTION: Final[int] = 0xc
|
||||
DEFINE_FONT_INFO: Final[int] = 0xd
|
||||
DEFINE_SOUND: Final[int] = 0xe
|
||||
START_SOUND: Final[int] = 0xf
|
||||
DEFINE_BUTTON_SOUND: Final[int] = 0x11
|
||||
SOUND_STREAM_HEAD: Final[int] = 0x12
|
||||
SOUND_STREAM_BLOCK: Final[int] = 0x13
|
||||
DEFINE_BITS_LOSSLESS: Final[int] = 0x14
|
||||
DEFINE_BITS_JPEG2: Final[int] = 0x15
|
||||
DEFINE_SHAPE2: Final[int] = 0x16
|
||||
DEFINE_BUTTON_CXFORM: Final[int] = 0x17
|
||||
PROTECT: Final[int] = 0x18
|
||||
PLACE_OBJECT2: Final[int] = 0x1a
|
||||
REMOVE_OBJECT2: Final[int] = 0x1c
|
||||
DEFINE_SHAPE3: Final[int] = 0x20
|
||||
DEFINE_TEXT2: Final[int] = 0x21
|
||||
DEFINE_BUTTON2: Final[int] = 0x22
|
||||
DEFINE_BITS_JPEG3: Final[int] = 0x23
|
||||
DEFINE_BITS_LOSSLESS2: Final[int] = 0x24
|
||||
DEFINE_EDIT_TEXT: Final[int] = 0x25
|
||||
DEFINE_SPRITE: Final[int] = 0x27
|
||||
FRAME_LABEL: Final[int] = 0x2b
|
||||
SOUND_STREAM_HEAD2: Final[int] = 0x2d
|
||||
DEFINE_MORPH_SHAPE: Final[int] = 0x2e
|
||||
DEFINE_FONT2: Final[int] = 0x30
|
||||
EXPORT_ASSETS: Final[int] = 0x38
|
||||
IMPORT_ASSETS: Final[int] = 0x39
|
||||
DO_INIT_ACTION: Final[int] = 0x3b
|
||||
DEFINE_VIDEO_STREAM: Final[int] = 0x3c
|
||||
VIDEO_FRAME: Final[int] = 0x3d
|
||||
DEFINE_FONT_INFO2: Final[int] = 0x3e
|
||||
ENABLE_DEBUGGER2: Final[int] = 0x40
|
||||
SCRIPT_LIMITS: Final[int] = 0x41
|
||||
SET_TAB_INDEX: Final[int] = 0x42
|
||||
PLACE_OBJECT3: Final[int] = 0x46
|
||||
IMPORT_ASSETS2: Final[int] = 0x47
|
||||
DEFINE_FONT3: Final[int] = 0x4b
|
||||
METADATA: Final[int] = 0x4d
|
||||
DEFINE_SCALING_GRID: Final[int] = 0x4e
|
||||
DEFINE_SHAPE4: Final[int] = 0x53
|
||||
DEFINE_MORPH_SHAPE2: Final[int] = 0x54
|
||||
SCENE_LABEL: Final[int] = 0x56
|
||||
AFP_IMAGE: Final[int] = 0x64
|
||||
AFP_DEFINE_SOUND: Final[int] = 0x65
|
||||
AFP_SOUND_STREAM_BLOCK: Final[int] = 0x66
|
||||
AFP_DEFINE_FONT: Final[int] = 0x67
|
||||
AFP_DEFINE_SHAPE: Final[int] = 0x68
|
||||
AEP_PLACE_OBJECT: Final[int] = 0x6e
|
||||
AP2_DEFINE_FONT: Final[int] = 0x78
|
||||
AP2_DEFINE_SPRITE: Final[int] = 0x79
|
||||
AP2_DO_ACTION: Final[int] = 0x7a
|
||||
AP2_DEFINE_BUTTON: Final[int] = 0x7b
|
||||
AP2_DEFINE_BUTTON_SOUND: Final[int] = 0x7c
|
||||
AP2_DEFINE_TEXT: Final[int] = 0x7d
|
||||
AP2_DEFINE_EDIT_TEXT: Final[int] = 0x7e
|
||||
AP2_PLACE_OBJECT: Final[int] = 0x7f
|
||||
AP2_REMOVE_OBJECT: Final[int] = 0x80
|
||||
AP2_START_SOUND: Final[int] = 0x81
|
||||
AP2_DEFINE_MORPH_SHAPE: Final[int] = 0x82
|
||||
AP2_IMAGE: Final[int] = 0x83
|
||||
AP2_SHAPE: Final[int] = 0x84
|
||||
AP2_SOUND: Final[int] = 0x85
|
||||
AP2_VIDEO: Final[int] = 0x86
|
||||
AP2_PLACE_CAMERA: Final[int] = 0x88
|
||||
AP2_SCALING_GRID: Final[int] = 0x89
|
||||
|
||||
@classmethod
|
||||
def tag_to_name(cls, tagid: int) -> str:
|
||||
@ -292,61 +292,61 @@ class AP2Tag:
|
||||
|
||||
class AP2Action:
|
||||
# End bytecode processing
|
||||
END = 0
|
||||
END: Final[int] = 0
|
||||
|
||||
# Advance movieclip to next frame.
|
||||
NEXT_FRAME = 1
|
||||
NEXT_FRAME: Final[int] = 1
|
||||
|
||||
# Rewind movieclip to previous frame.
|
||||
PREVIOUS_FRAME = 2
|
||||
PREVIOUS_FRAME: Final[int] = 2
|
||||
|
||||
# Play the movieclip.
|
||||
PLAY = 3
|
||||
PLAY: Final[int] = 3
|
||||
|
||||
# Stop the movieclip.
|
||||
STOP = 4
|
||||
STOP: Final[int] = 4
|
||||
|
||||
# Stop all sound from the movie clip.
|
||||
STOP_SOUND = 5
|
||||
STOP_SOUND: Final[int] = 5
|
||||
|
||||
# Pop two objects from the stack, subtract them, push the result to the stack.
|
||||
SUBTRACT = 7
|
||||
SUBTRACT: Final[int] = 7
|
||||
|
||||
# Pop two objects from the stack, multiply them, push the result to the stack.
|
||||
MULTIPLY = 8
|
||||
MULTIPLY: Final[int] = 8
|
||||
|
||||
# Pop two objects from the stack, divide them, push the result to the stack.
|
||||
DIVIDE = 9
|
||||
DIVIDE: Final[int] = 9
|
||||
|
||||
# Pop an object from the stack, boolean negate it, push the result to the stack.
|
||||
NOT = 12
|
||||
NOT: Final[int] = 12
|
||||
|
||||
# Pop an object from the stack, discard it.
|
||||
POP = 13
|
||||
POP: Final[int] = 13
|
||||
|
||||
# Pop an object off the stack, use that as a string to look up a variable, push
|
||||
# that variable's value onto the stack.
|
||||
GET_VARIABLE = 14
|
||||
GET_VARIABLE: Final[int] = 14
|
||||
|
||||
# Pop two objects from the stack, if the second object is a string or const, define a
|
||||
# variable with that name equal to the first object.
|
||||
SET_VARIABLE = 15
|
||||
SET_VARIABLE: Final[int] = 15
|
||||
|
||||
# Similar to GET_MEMBER, but the member value is an integer in the range 0x0-0x15 which
|
||||
# gets added to 0x100 and looked up in StringConstants.
|
||||
GET_PROPERTY = 16
|
||||
GET_PROPERTY: Final[int] = 16
|
||||
|
||||
# Similar to SET_MEMBER in exactly the same way GET_PROPERTY is similar to GET_MEMBER.
|
||||
SET_PROPERTY = 17
|
||||
SET_PROPERTY: Final[int] = 17
|
||||
|
||||
# Clone a sprite that's specified on the stack.
|
||||
CLONE_SPRITE = 18
|
||||
CLONE_SPRITE: Final[int] = 18
|
||||
|
||||
# Remove a sprite as specified on the stack.
|
||||
REMOVE_SPRITE = 19
|
||||
REMOVE_SPRITE: Final[int] = 19
|
||||
|
||||
# Print a trace of the current object on the stack, and pop it.
|
||||
TRACE = 20
|
||||
TRACE: Final[int] = 20
|
||||
|
||||
# Start dragging an object. It pops a value from the stack to set as the drag target.
|
||||
# It pops a second boolean value from the stack to specify if the drag target should be
|
||||
@ -354,151 +354,151 @@ class AP2Action:
|
||||
# as a rectangle to constrain the mouse if the opcode is > 0, that we don't constrain
|
||||
# at all if the opcode is 0, or that we pop another boolean from the stack and constrain
|
||||
# if that value is true.
|
||||
START_DRAG = 21
|
||||
START_DRAG: Final[int] = 21
|
||||
|
||||
# End dragging the current drag target that was started with START_DRAG.
|
||||
END_DRAG = 22
|
||||
END_DRAG: Final[int] = 22
|
||||
|
||||
# Pop an object from the stack and throw it as an exception.
|
||||
THROW = 23
|
||||
THROW: Final[int] = 23
|
||||
|
||||
# Pop an object from the stack, and an object representing a class. If the first
|
||||
# object is an instance of the class, push it back. Otherwise, push back a null.
|
||||
CAST_OP = 24
|
||||
CAST_OP: Final[int] = 24
|
||||
|
||||
# Unclear exactly what this does on the stack, the implementation seems wrong.
|
||||
IMPLEMENTS_OP = 25
|
||||
IMPLEMENTS_OP: Final[int] = 25
|
||||
|
||||
# Get the current playback position as an integer number of milliseconds, pushed to the stack.
|
||||
GET_TIME = 26
|
||||
GET_TIME: Final[int] = 26
|
||||
|
||||
# Pops two values from the stack to look up what to delete.
|
||||
DELETE = 27
|
||||
DELETE: Final[int] = 27
|
||||
|
||||
# Delete a variable as defined on the stack. Pops that variable name.
|
||||
DELETE2 = 28
|
||||
DELETE2: Final[int] = 28
|
||||
|
||||
# Pop two objects from the stack, and then define a local variable just like "SET_VARIABLE"
|
||||
# but in the scope of the current movieclip or function.
|
||||
DEFINE_LOCAL = 29
|
||||
DEFINE_LOCAL: Final[int] = 29
|
||||
|
||||
# Call a function. Similar to CALL_METHOD but with only one pop for the function name.
|
||||
CALL_FUNCTION = 30
|
||||
CALL_FUNCTION: Final[int] = 30
|
||||
|
||||
# Return the top of the stack as the return value of the function.
|
||||
RETURN = 31
|
||||
RETURN: Final[int] = 31
|
||||
|
||||
# Pop two numbers, modulo them, push them back to the stack.
|
||||
MODULO = 32
|
||||
MODULO: Final[int] = 32
|
||||
|
||||
# Create a new object, I haven't figured out what it pushes and pops from the stack yet.
|
||||
NEW_OBJECT = 33
|
||||
NEW_OBJECT: Final[int] = 33
|
||||
|
||||
# Define a variable in the local movieclip or function, without a value.
|
||||
DEFINE_LOCAL2 = 34
|
||||
DEFINE_LOCAL2: Final[int] = 34
|
||||
|
||||
# Init an array from the stack. Pops the array's number of items, and then an item each
|
||||
# to add to the array. Then it adds the array to the stack.
|
||||
INIT_ARRAY = 35
|
||||
INIT_ARRAY: Final[int] = 35
|
||||
|
||||
# Init an object from the stack.
|
||||
INIT_OBJECT = 36
|
||||
INIT_OBJECT: Final[int] = 36
|
||||
|
||||
# Pop an object off the stack, push the type of the object as a string.
|
||||
TYPEOF = 37
|
||||
TYPEOF: Final[int] = 37
|
||||
|
||||
# Pop an item off the stack, and if it is a movieclip, push the string path. If it isn't
|
||||
# a movieclip, push an undefined object onto the stack.
|
||||
TARGET_PATH = 38
|
||||
TARGET_PATH: Final[int] = 38
|
||||
|
||||
# Add two values on the stack, popping them and pushing the result.
|
||||
ADD2 = 39
|
||||
ADD2: Final[int] = 39
|
||||
|
||||
# Pops two values from the stack, and pushes a boolean representing whether one is less than
|
||||
# the other. If they cannot be compared, pushes an "Undefined" object onto the stack instead.
|
||||
LESS2 = 40
|
||||
LESS2: Final[int] = 40
|
||||
|
||||
# Pop two objects from the stack, get their string equivalent, and push a boolean onto the
|
||||
# stack if those strings match.
|
||||
EQUALS2 = 41
|
||||
EQUALS2: Final[int] = 41
|
||||
|
||||
# Pops the top of the stack, converts it to an integer object, and pushes it. If it can't
|
||||
# convert, instead pushes a "NaN" object.
|
||||
TO_NUMBER = 42
|
||||
TO_NUMBER: Final[int] = 42
|
||||
|
||||
# Pops the top of the stack, converts the object to its string equivalent, and pushes it.
|
||||
TO_STRING = 43
|
||||
TO_STRING: Final[int] = 43
|
||||
|
||||
# Takes the top of the stack and duplicates the object before pushing that object to the stack.
|
||||
PUSH_DUPLICATE = 44
|
||||
PUSH_DUPLICATE: Final[int] = 44
|
||||
|
||||
# Swaps the position of the two two objects on the stack. If there isn't enough to swap, does
|
||||
# nothing.
|
||||
STACK_SWAP = 45
|
||||
STACK_SWAP: Final[int] = 45
|
||||
|
||||
# Get a member value and place it on the stack.
|
||||
GET_MEMBER = 46
|
||||
GET_MEMBER: Final[int] = 46
|
||||
|
||||
# Set member, popping three values from the stack.
|
||||
SET_MEMBER = 47
|
||||
SET_MEMBER: Final[int] = 47
|
||||
|
||||
# Increment value on stack.
|
||||
INCREMENT = 48
|
||||
INCREMENT: Final[int] = 48
|
||||
|
||||
# Decrement value on stack.
|
||||
DECREMENT = 49
|
||||
DECREMENT: Final[int] = 49
|
||||
|
||||
# Call method. Pops two values from the stack to lookup an object method, another value from the
|
||||
# stack for the number of params, and then that many values from the stack as function parameters.
|
||||
CALL_METHOD = 50
|
||||
CALL_METHOD: Final[int] = 50
|
||||
|
||||
# Takes at least 3 objects on the stack, the third being the number of parameters, the second being
|
||||
# the object to add a method to and the first being the member name.
|
||||
NEW_METHOD = 51
|
||||
NEW_METHOD: Final[int] = 51
|
||||
|
||||
# Takes two objects, pops them off the stack and adds a boolean object to the stack set to true
|
||||
# if one is an instance of the other or false otherwise.
|
||||
INSTANCEOF = 52
|
||||
INSTANCEOF: Final[int] = 52
|
||||
|
||||
# Enumerates some sort of object into a variable on the top of the stack.
|
||||
ENUMERATE2 = 53
|
||||
ENUMERATE2: Final[int] = 53
|
||||
|
||||
# Pop two values from the stack, bitwise and them, push the result.
|
||||
BIT_AND = 54
|
||||
BIT_AND: Final[int] = 54
|
||||
|
||||
# Pop two values from the stack, bitwise or them, push the result.
|
||||
BIT_OR = 55
|
||||
BIT_OR: Final[int] = 55
|
||||
|
||||
# Pop two values from the stack, bitwise xor them, push the result.
|
||||
BIT_XOR = 56
|
||||
BIT_XOR: Final[int] = 56
|
||||
|
||||
# Pop the amount to left shift, and an integer from the stack, push the result.
|
||||
BIT_L_SHIFT = 57
|
||||
BIT_L_SHIFT: Final[int] = 57
|
||||
|
||||
# Pop the amount to right shift, and an integer from the stack, push the result.
|
||||
BIT_R_SHIFT = 58
|
||||
BIT_R_SHIFT: Final[int] = 58
|
||||
|
||||
# Same as above but unsigned. It appears that games implement this identically to BIT_U_R_SHIFT.
|
||||
BIT_U_R_SHIFT = 59
|
||||
BIT_U_R_SHIFT: Final[int] = 59
|
||||
|
||||
# Pop two values from the stack, push a boolean set to true if the values are strictly equal.
|
||||
STRICT_EQUALS = 60
|
||||
STRICT_EQUALS: Final[int] = 60
|
||||
|
||||
# Pop two objects off the stack, push a boolean object for whether the first object is greater tha
|
||||
# the second or not.
|
||||
GREATER = 61
|
||||
GREATER: Final[int] = 61
|
||||
|
||||
# Pops two objects off the stack and does some sort of OOP with them, the first being the superclass
|
||||
# and the second being the subclass.
|
||||
EXTENDS = 62
|
||||
EXTENDS: Final[int] = 62
|
||||
|
||||
# Pop a value from the stack and store it in a register specified by the opcode param. Also push
|
||||
# it back onto the stack.
|
||||
STORE_REGISTER = 63
|
||||
STORE_REGISTER: Final[int] = 63
|
||||
|
||||
# Define a function based on parameters on the stack. This reads the next 9 bytes of the bytecode
|
||||
# as parameters, and uses that to read the next N bytes of bytecode as the function definition.
|
||||
DEFINE_FUNCTION2 = 64
|
||||
DEFINE_FUNCTION2: Final[int] = 64
|
||||
|
||||
# Grabs a 16 bit offset pointer as the opcode param, then skips bytecode processing forward
|
||||
# that many bytes, passing the skipped bytes as pointer data to a function that adds it to the
|
||||
@ -506,52 +506,52 @@ class AP2Action:
|
||||
# second new stack entry. Strangely enough, if the object on the top of the stack doesn't meet
|
||||
# some criteria, the skipped bytes are processed as bytecode. I am not sure what the hell is going
|
||||
# on here.
|
||||
WITH = 66
|
||||
WITH: Final[int] = 66
|
||||
|
||||
# Push an object onto the stack. Creates objects based on the bytecode parameters and pushes
|
||||
# them onto the stack.
|
||||
PUSH = 67
|
||||
PUSH: Final[int] = 67
|
||||
|
||||
# Unconditional jump based on bytecode value.
|
||||
JUMP = 68
|
||||
JUMP: Final[int] = 68
|
||||
|
||||
# Gets a single 8-bit integer as an opcode param, take the top two bits of that param as the
|
||||
# action to take. Looks like it is similar to SWF GET_URL2 action. Supported actions are 0,
|
||||
# 1 and 3. It pops two objects from the stack to perform against.
|
||||
GET_URL2 = 69
|
||||
GET_URL2: Final[int] = 69
|
||||
|
||||
# Pops a value from the stack, jumps to offset from opcode params if value is truthy.
|
||||
IF = 70
|
||||
IF: Final[int] = 70
|
||||
|
||||
# Go to frame specified by top of stack, popping that value from the stack. Also specifies
|
||||
# flags for whether to play or stop when going to that frame, and additional frames to advance
|
||||
# in opcode params.
|
||||
GOTO_FRAME2 = 71
|
||||
GOTO_FRAME2: Final[int] = 71
|
||||
|
||||
# Pops the top of the stack, uses that to get a target, pushes a pointer to that target on
|
||||
# the stack.
|
||||
GET_TARGET = 72
|
||||
GET_TARGET: Final[int] = 72
|
||||
|
||||
# Given a subtype of check and a positive offset to jump to on true, perform a conditional check.
|
||||
# Pops two values from the stack for all equality checks except for undefined checks, which pop
|
||||
# one value.
|
||||
IF2 = 73
|
||||
IF2: Final[int] = 73
|
||||
|
||||
# Similar to STORE_REGISTER but does not preserve the value on the stack afterwards.
|
||||
STORE_REGISTER2 = 74
|
||||
STORE_REGISTER2: Final[int] = 74
|
||||
|
||||
# Take one opcode parameter for the number of registers to init, and then one opcode parameter
|
||||
# per the number of registers param as the register number to init, initializing that register
|
||||
# as an "Undefined" object.
|
||||
INIT_REGISTER = 75
|
||||
INIT_REGISTER: Final[int] = 75
|
||||
|
||||
# Similar to ADD_NUM_VARIABLE, but operating on a register number instead of the stack. Takes
|
||||
# two params from opcodes, one for the register number and one for the addition value.
|
||||
ADD_NUM_REGISTER = 76
|
||||
ADD_NUM_REGISTER: Final[int] = 76
|
||||
|
||||
# Add a number dictated by an opcode param to the variable on the stack, popping the variable
|
||||
# name.
|
||||
ADD_NUM_VARIABLE = 77
|
||||
ADD_NUM_VARIABLE: Final[int] = 77
|
||||
|
||||
@classmethod
|
||||
def action_to_name(cls, actionid: int) -> str:
|
||||
@ -805,20 +805,20 @@ class StoreRegisterAction(AP2Action):
|
||||
|
||||
|
||||
class IfAction(AP2Action):
|
||||
EQUALS = 0
|
||||
NOT_EQUALS = 1
|
||||
LT = 2
|
||||
GT = 3
|
||||
LT_EQUALS = 4
|
||||
GT_EQUALS = 5
|
||||
IS_FALSE = 6
|
||||
BITAND = 7
|
||||
NOT_BITAND = 8
|
||||
STRICT_EQUALS = 9
|
||||
STRICT_NOT_EQUALS = 10
|
||||
IS_UNDEFINED = 11
|
||||
IS_NOT_UNDEFINED = 12
|
||||
IS_TRUE = 1000
|
||||
COMP_EQUALS: Final[int] = 0
|
||||
COMP_NOT_EQUALS: Final[int] = 1
|
||||
COMP_LT: Final[int] = 2
|
||||
COMP_GT: Final[int] = 3
|
||||
COMP_LT_EQUALS: Final[int] = 4
|
||||
COMP_GT_EQUALS: Final[int] = 5
|
||||
COMP_IS_FALSE: Final[int] = 6
|
||||
COMP_BITAND: Final[int] = 7
|
||||
COMP_NOT_BITAND: Final[int] = 8
|
||||
COMP_STRICT_EQUALS: Final[int] = 9
|
||||
COMP_STRICT_NOT_EQUALS: Final[int] = 10
|
||||
COMP_IS_UNDEFINED: Final[int] = 11
|
||||
COMP_IS_NOT_UNDEFINED: Final[int] = 12
|
||||
COMP_IS_TRUE: Final[int] = 1000
|
||||
|
||||
def __init__(self, offset: int, comparison: int, jump_if_true_offset: int) -> None:
|
||||
super().__init__(offset, AP2Action.IF)
|
||||
@ -828,20 +828,20 @@ class IfAction(AP2Action):
|
||||
@classmethod
|
||||
def comparison_to_str(cls, comparison: int) -> str:
|
||||
return {
|
||||
cls.EQUALS: "==",
|
||||
cls.NOT_EQUALS: "!=",
|
||||
cls.LT: "<",
|
||||
cls.GT: ">",
|
||||
cls.LT_EQUALS: "<=",
|
||||
cls.GT_EQUALS: ">=",
|
||||
cls.IS_FALSE: "IS FALSE",
|
||||
cls.BITAND: "BITAND",
|
||||
cls.NOT_BITAND: "BITNOTAND",
|
||||
cls.STRICT_EQUALS: "STRICT ==",
|
||||
cls.STRICT_NOT_EQUALS: "STRICT !=",
|
||||
cls.IS_UNDEFINED: "IS UNDEFINED",
|
||||
cls.IS_NOT_UNDEFINED: "IS NOT UNDEFINED",
|
||||
cls.IS_TRUE: "IS TRUE",
|
||||
cls.COMP_EQUALS: "==",
|
||||
cls.COMP_NOT_EQUALS: "!=",
|
||||
cls.COMP_LT: "<",
|
||||
cls.COMP_GT: ">",
|
||||
cls.COMP_LT_EQUALS: "<=",
|
||||
cls.COMP_GT_EQUALS: ">=",
|
||||
cls.COMP_IS_FALSE: "IS FALSE",
|
||||
cls.COMP_BITAND: "BITAND",
|
||||
cls.COMP_NOT_BITAND: "BITNOTAND",
|
||||
cls.COMP_STRICT_EQUALS: "STRICT ==",
|
||||
cls.COMP_STRICT_NOT_EQUALS: "STRICT !=",
|
||||
cls.COMP_IS_UNDEFINED: "IS UNDEFINED",
|
||||
cls.COMP_IS_NOT_UNDEFINED: "IS NOT UNDEFINED",
|
||||
cls.COMP_IS_TRUE: "IS TRUE",
|
||||
}[comparison]
|
||||
|
||||
def as_dict(self, *args: Any, **kwargs: Any) -> Dict[str, Any]:
|
||||
|
@ -1,5 +1,5 @@
|
||||
import os
|
||||
from typing import TYPE_CHECKING, Any, Dict, List, Tuple, Optional, Union
|
||||
from typing import TYPE_CHECKING, Any, Dict, Final, List, Tuple, Optional, Union
|
||||
|
||||
if TYPE_CHECKING:
|
||||
# Circular import otherwise
|
||||
@ -48,7 +48,7 @@ class Register(Expression):
|
||||
|
||||
|
||||
class StringConstant(Expression):
|
||||
__PROPERTIES: List[Tuple[int, str]] = [
|
||||
__PROPERTIES: Final[List[Tuple[int, str]]] = [
|
||||
# Seems to be properties on every object. These also match the original
|
||||
# SWF properties up to 0x115. GET_PROPERTY and SET_PROPERTY use these
|
||||
# values to determine what to look up on an object.
|
||||
|
@ -1,5 +1,5 @@
|
||||
import os
|
||||
from typing import Any, List, Sequence, Union
|
||||
from typing import Any, Final, List, Sequence, Union
|
||||
|
||||
from .expression import (
|
||||
Expression,
|
||||
@ -450,14 +450,14 @@ class IsBooleanIf(IfExpr):
|
||||
|
||||
|
||||
class TwoParameterIf(IfExpr):
|
||||
EQUALS = "=="
|
||||
NOT_EQUALS = "!="
|
||||
LT = "<"
|
||||
GT = ">"
|
||||
LT_EQUALS = "<="
|
||||
GT_EQUALS = ">="
|
||||
STRICT_EQUALS = "==="
|
||||
STRICT_NOT_EQUALS = "!=="
|
||||
EQUALS: Final[str] = "=="
|
||||
NOT_EQUALS: Final[str] = "!="
|
||||
LT: Final[str] = "<"
|
||||
GT: Final[str] = ">"
|
||||
LT_EQUALS: Final[str] = "<="
|
||||
GT_EQUALS: Final[str] = ">="
|
||||
STRICT_EQUALS: Final[str] = "==="
|
||||
STRICT_NOT_EQUALS: Final[str] = "!=="
|
||||
|
||||
def __init__(self, conditional1: Any, comp: str, conditional2: Any) -> None:
|
||||
if comp not in {
|
||||
|
@ -95,6 +95,8 @@ class IFS:
|
||||
elif child.name == "_super_":
|
||||
super_name = child.value
|
||||
super_md5 = child.child_value('md5')
|
||||
if not isinstance(super_name, str) or not isinstance(super_md5, bytes):
|
||||
raise Exception(f'Super definition {child} has invalid data!')
|
||||
supers.append((super_name, super_md5))
|
||||
|
||||
def get_children(parent: str, node: Node) -> None:
|
||||
@ -159,6 +161,7 @@ class IFS:
|
||||
if texdata is None:
|
||||
# Now, try as XML
|
||||
xenc = XmlEncoding()
|
||||
encoding = "ascii"
|
||||
texdata = xenc.decode(
|
||||
b'<?xml encoding="ascii"?>' +
|
||||
self.__files[filename]
|
||||
@ -166,6 +169,10 @@ class IFS:
|
||||
|
||||
if texdata is None:
|
||||
continue
|
||||
else:
|
||||
if benc.encoding is None:
|
||||
raise Exception("Logic error, expected an encoding from binary decoder!")
|
||||
encoding = benc.encoding
|
||||
|
||||
if texdata.name != 'texturelist':
|
||||
raise Exception(f"Unexpected name {texdata.name} in texture list!")
|
||||
@ -180,13 +187,18 @@ class IFS:
|
||||
continue
|
||||
|
||||
textfmt = child.attribute('format')
|
||||
if textfmt is None:
|
||||
raise Exception(f"Texture {child} has no texture format!")
|
||||
|
||||
for subchild in child.children:
|
||||
if subchild.name != 'image':
|
||||
continue
|
||||
md5sum = hashlib.md5(subchild.attribute('name').encode(benc.encoding)).hexdigest()
|
||||
name = subchild.attribute('name')
|
||||
if name is None:
|
||||
raise Exception(f"Texture entry {subchild} has no name!")
|
||||
md5sum = hashlib.md5(name.encode(encoding)).hexdigest()
|
||||
oldname = os.path.join(texdir, md5sum)
|
||||
newname = os.path.join(texdir, subchild.attribute('name'))
|
||||
newname = os.path.join(texdir, name)
|
||||
|
||||
if oldname in self.__files:
|
||||
supported = False
|
||||
@ -236,6 +248,7 @@ class IFS:
|
||||
if afpdata is None:
|
||||
# Now, try as XML
|
||||
xenc = XmlEncoding()
|
||||
encoding = 'ascii'
|
||||
afpdata = xenc.decode(
|
||||
b'<?xml encoding="ascii"?>' +
|
||||
self.__files[filename]
|
||||
@ -243,6 +256,10 @@ class IFS:
|
||||
|
||||
if afpdata is None:
|
||||
continue
|
||||
else:
|
||||
if benc.encoding is None:
|
||||
raise Exception("Logic error, expected an encoding from binary decoder!")
|
||||
encoding = benc.encoding
|
||||
|
||||
if afpdata.name != 'afplist':
|
||||
raise Exception(f"Unexpected name {afpdata.name} in afp list!")
|
||||
@ -253,7 +270,9 @@ class IFS:
|
||||
|
||||
# First, fix up the afp files themselves.
|
||||
name = child.attribute('name')
|
||||
md5sum = hashlib.md5(name.encode(benc.encoding)).hexdigest()
|
||||
if name is None:
|
||||
raise Exception("AFP entry {child} has no name!")
|
||||
md5sum = hashlib.md5(name.encode(encoding)).hexdigest()
|
||||
|
||||
for fixdir in [afpdir, bsidir]:
|
||||
oldname = os.path.join(fixdir, md5sum)
|
||||
@ -270,7 +289,7 @@ class IFS:
|
||||
if geodata is not None:
|
||||
for geoid in geodata:
|
||||
geoname = f"{name}_shape{geoid}"
|
||||
md5sum = hashlib.md5(geoname.encode(benc.encoding)).hexdigest()
|
||||
md5sum = hashlib.md5(geoname.encode(encoding)).hexdigest()
|
||||
|
||||
oldname = os.path.join(geodir, md5sum)
|
||||
newname = os.path.join(geodir, geoname)
|
||||
|
@ -68,6 +68,8 @@ class IIDXChart:
|
||||
|
||||
@property
|
||||
def bpm(self) -> Tuple[int, int]:
|
||||
if self.__bpm_min is None or self.__bpm_max is None:
|
||||
raise Exception("BPM change was not found in the chart!")
|
||||
return (self.__bpm_min, self.__bpm_max)
|
||||
|
||||
@property
|
||||
|
@ -43,6 +43,8 @@ class TwoDX:
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
if self.__name is None:
|
||||
raise Exception("Logic error, tried to get name of 2dx file before setting it or parsing file!")
|
||||
return self.__name
|
||||
|
||||
def set_name(self, name: str) -> None:
|
||||
|
@ -284,7 +284,7 @@ class TestAFPControlGraph(ExtendedTestCase):
|
||||
bytecode = self.__make_bytecode([
|
||||
# Beginning of the if statement.
|
||||
PushAction(100, [True]),
|
||||
IfAction(101, IfAction.IS_FALSE, 103),
|
||||
IfAction(101, IfAction.COMP_IS_FALSE, 103),
|
||||
# False case (fall through from if).
|
||||
AP2Action(102, AP2Action.PLAY),
|
||||
# Line after the if statement.
|
||||
@ -313,7 +313,7 @@ class TestAFPControlGraph(ExtendedTestCase):
|
||||
bytecode = self.__make_bytecode([
|
||||
# Beginning of the if statement.
|
||||
PushAction(100, [True]),
|
||||
IfAction(101, IfAction.IS_FALSE, 103),
|
||||
IfAction(101, IfAction.COMP_IS_FALSE, 103),
|
||||
# False case (fall through from if).
|
||||
AP2Action(102, AP2Action.PLAY),
|
||||
# Some code will jump to the end offset as a way of
|
||||
@ -339,7 +339,7 @@ class TestAFPControlGraph(ExtendedTestCase):
|
||||
bytecode = self.__make_bytecode([
|
||||
# Beginning of the if statement.
|
||||
PushAction(100, [True]),
|
||||
IfAction(101, IfAction.IS_TRUE, 104),
|
||||
IfAction(101, IfAction.COMP_IS_TRUE, 104),
|
||||
# False case (fall through from if).
|
||||
AP2Action(102, AP2Action.STOP),
|
||||
JumpAction(103, 105),
|
||||
@ -374,7 +374,7 @@ class TestAFPControlGraph(ExtendedTestCase):
|
||||
bytecode = self.__make_bytecode([
|
||||
# Beginning of the if statement.
|
||||
PushAction(100, [True]),
|
||||
IfAction(101, IfAction.IS_TRUE, 104),
|
||||
IfAction(101, IfAction.COMP_IS_TRUE, 104),
|
||||
# False case (fall through from if).
|
||||
AP2Action(102, AP2Action.STOP),
|
||||
JumpAction(103, 105),
|
||||
@ -404,7 +404,7 @@ class TestAFPControlGraph(ExtendedTestCase):
|
||||
bytecode = self.__make_bytecode([
|
||||
# Beginning of the if statement.
|
||||
PushAction(100, [True]),
|
||||
IfAction(101, IfAction.IS_TRUE, 104),
|
||||
IfAction(101, IfAction.COMP_IS_TRUE, 104),
|
||||
# False case (fall through from if).
|
||||
PushAction(102, ['b']),
|
||||
AP2Action(103, AP2Action.RETURN),
|
||||
@ -435,21 +435,21 @@ class TestAFPControlGraph(ExtendedTestCase):
|
||||
bytecode = self.__make_bytecode([
|
||||
# Beginning of the first if statement.
|
||||
PushAction(100, [Register(0), 1]),
|
||||
IfAction(101, IfAction.NOT_EQUALS, 104),
|
||||
IfAction(101, IfAction.COMP_NOT_EQUALS, 104),
|
||||
# False case (fall through from if).
|
||||
PushAction(102, ['a']),
|
||||
JumpAction(103, 113),
|
||||
|
||||
# Beginning of the second if statement.
|
||||
PushAction(104, [Register(0), 2]),
|
||||
IfAction(105, IfAction.NOT_EQUALS, 108),
|
||||
IfAction(105, IfAction.COMP_NOT_EQUALS, 108),
|
||||
# False case (fall through from if).
|
||||
PushAction(106, ['b']),
|
||||
JumpAction(107, 113),
|
||||
|
||||
# Beginning of the third if statement.
|
||||
PushAction(108, [Register(0), 3]),
|
||||
IfAction(109, IfAction.NOT_EQUALS, 112),
|
||||
IfAction(109, IfAction.COMP_NOT_EQUALS, 112),
|
||||
# False case (fall through from if).
|
||||
PushAction(110, ['c']),
|
||||
JumpAction(111, 113),
|
||||
@ -498,7 +498,7 @@ class TestAFPControlGraph(ExtendedTestCase):
|
||||
bytecode = self.__make_bytecode([
|
||||
# Beginning of the if statement.
|
||||
PushAction(100, [True]),
|
||||
IfAction(101, IfAction.IS_TRUE, 104),
|
||||
IfAction(101, IfAction.COMP_IS_TRUE, 104),
|
||||
# False case (fall through from if).
|
||||
PushAction(102, ['b']),
|
||||
AP2Action(103, AP2Action.END),
|
||||
@ -614,7 +614,7 @@ class TestAFPDecompile(ExtendedTestCase):
|
||||
bytecode = self.__make_bytecode([
|
||||
# Beginning of the if statement.
|
||||
PushAction(100, [True]),
|
||||
IfAction(101, IfAction.IS_FALSE, 103),
|
||||
IfAction(101, IfAction.COMP_IS_FALSE, 103),
|
||||
# False case (fall through from if).
|
||||
AP2Action(102, AP2Action.PLAY),
|
||||
# Line after the if statement.
|
||||
@ -628,7 +628,7 @@ class TestAFPDecompile(ExtendedTestCase):
|
||||
bytecode = self.__make_bytecode([
|
||||
# Beginning of the if statement.
|
||||
PushAction(100, [True]),
|
||||
IfAction(101, IfAction.IS_FALSE, 103),
|
||||
IfAction(101, IfAction.COMP_IS_FALSE, 103),
|
||||
# False case (fall through from if).
|
||||
AP2Action(102, AP2Action.PLAY),
|
||||
# Some code will jump to the end offset as a way of
|
||||
@ -642,7 +642,7 @@ class TestAFPDecompile(ExtendedTestCase):
|
||||
bytecode = self.__make_bytecode([
|
||||
# Beginning of the if statement.
|
||||
PushAction(100, [True]),
|
||||
IfAction(101, IfAction.IS_TRUE, 104),
|
||||
IfAction(101, IfAction.COMP_IS_TRUE, 104),
|
||||
# False case (fall through from if).
|
||||
AP2Action(102, AP2Action.STOP),
|
||||
JumpAction(103, 105),
|
||||
@ -661,7 +661,7 @@ class TestAFPDecompile(ExtendedTestCase):
|
||||
bytecode = self.__make_bytecode([
|
||||
# Beginning of the if statement.
|
||||
PushAction(100, [True]),
|
||||
IfAction(101, IfAction.IS_TRUE, 104),
|
||||
IfAction(101, IfAction.COMP_IS_TRUE, 104),
|
||||
# False case (fall through from if).
|
||||
AP2Action(102, AP2Action.STOP),
|
||||
JumpAction(103, 105),
|
||||
@ -678,7 +678,7 @@ class TestAFPDecompile(ExtendedTestCase):
|
||||
bytecode = self.__make_bytecode([
|
||||
# Beginning of the if statement.
|
||||
PushAction(100, [True]),
|
||||
IfAction(101, IfAction.IS_TRUE, 104),
|
||||
IfAction(101, IfAction.COMP_IS_TRUE, 104),
|
||||
# False case (fall through from if).
|
||||
PushAction(102, ['b']),
|
||||
AP2Action(103, AP2Action.RETURN),
|
||||
@ -696,21 +696,21 @@ class TestAFPDecompile(ExtendedTestCase):
|
||||
bytecode = self.__make_bytecode([
|
||||
# Beginning of the first if statement.
|
||||
PushAction(100, [Register(0), 1]),
|
||||
IfAction(101, IfAction.NOT_EQUALS, 104),
|
||||
IfAction(101, IfAction.COMP_NOT_EQUALS, 104),
|
||||
# False case (fall through from if).
|
||||
PushAction(102, ['a']),
|
||||
JumpAction(103, 113),
|
||||
|
||||
# Beginning of the second if statement.
|
||||
PushAction(104, [Register(0), 2]),
|
||||
IfAction(105, IfAction.NOT_EQUALS, 108),
|
||||
IfAction(105, IfAction.COMP_NOT_EQUALS, 108),
|
||||
# False case (fall through from if).
|
||||
PushAction(106, ['b']),
|
||||
JumpAction(107, 113),
|
||||
|
||||
# Beginning of the third if statement.
|
||||
PushAction(108, [Register(0), 3]),
|
||||
IfAction(109, IfAction.NOT_EQUALS, 112),
|
||||
IfAction(109, IfAction.COMP_NOT_EQUALS, 112),
|
||||
# False case (fall through from if).
|
||||
PushAction(110, ['c']),
|
||||
JumpAction(111, 113),
|
||||
@ -746,7 +746,7 @@ class TestAFPDecompile(ExtendedTestCase):
|
||||
bytecode = self.__make_bytecode([
|
||||
# Beginning of the if statement.
|
||||
PushAction(100, [True]),
|
||||
IfAction(101, IfAction.IS_TRUE, 104),
|
||||
IfAction(101, IfAction.COMP_IS_TRUE, 104),
|
||||
# False case (fall through from if).
|
||||
AP2Action(102, AP2Action.STOP),
|
||||
AP2Action(103, AP2Action.END),
|
||||
@ -764,10 +764,10 @@ class TestAFPDecompile(ExtendedTestCase):
|
||||
bytecode = self.__make_bytecode([
|
||||
# Beginning of the first if statement.
|
||||
PushAction(100, [Register(0), 1]),
|
||||
IfAction(101, IfAction.EQUALS, 104),
|
||||
IfAction(101, IfAction.COMP_EQUALS, 104),
|
||||
# False case (circuit not broken, register is not equal to 1)
|
||||
PushAction(102, [Register(0), 2]),
|
||||
IfAction(103, IfAction.NOT_EQUALS, 106),
|
||||
IfAction(103, IfAction.COMP_NOT_EQUALS, 106),
|
||||
# This is the true case
|
||||
AP2Action(104, AP2Action.PLAY),
|
||||
JumpAction(105, 107),
|
||||
@ -801,7 +801,7 @@ class TestAFPDecompile(ExtendedTestCase):
|
||||
# Check exit condition.
|
||||
PushAction(102, ["finished"]),
|
||||
AP2Action(103, AP2Action.GET_VARIABLE),
|
||||
IfAction(104, IfAction.IS_TRUE, 107),
|
||||
IfAction(104, IfAction.COMP_IS_TRUE, 107),
|
||||
# Loop code.
|
||||
AP2Action(105, AP2Action.NEXT_FRAME),
|
||||
# Loop finished jump back to beginning.
|
||||
@ -826,11 +826,11 @@ class TestAFPDecompile(ExtendedTestCase):
|
||||
# Check exit condition.
|
||||
PushAction(102, ["finished"]),
|
||||
AP2Action(103, AP2Action.GET_VARIABLE),
|
||||
IfAction(104, IfAction.IS_TRUE, 112),
|
||||
IfAction(104, IfAction.COMP_IS_TRUE, 112),
|
||||
# Loop code with a continue statement.
|
||||
PushAction(105, ["some_condition"]),
|
||||
AP2Action(106, AP2Action.GET_VARIABLE),
|
||||
IfAction(107, IfAction.IS_FALSE, 110),
|
||||
IfAction(107, IfAction.COMP_IS_FALSE, 110),
|
||||
AP2Action(108, AP2Action.NEXT_FRAME),
|
||||
# Continue statement.
|
||||
JumpAction(109, 102),
|
||||
@ -862,7 +862,7 @@ class TestAFPDecompile(ExtendedTestCase):
|
||||
# Check exit condition.
|
||||
PushAction(102, [10, "i"]),
|
||||
AP2Action(103, AP2Action.GET_VARIABLE),
|
||||
IfAction(104, IfAction.LT_EQUALS, 109),
|
||||
IfAction(104, IfAction.COMP_LT_EQUALS, 109),
|
||||
# Loop code.
|
||||
AP2Action(105, AP2Action.NEXT_FRAME),
|
||||
# Increment, also the continue point.
|
||||
@ -889,11 +889,11 @@ class TestAFPDecompile(ExtendedTestCase):
|
||||
# Check exit condition.
|
||||
PushAction(102, [10, "i"]),
|
||||
AP2Action(103, AP2Action.GET_VARIABLE),
|
||||
IfAction(104, IfAction.LT_EQUALS, 115),
|
||||
IfAction(104, IfAction.COMP_LT_EQUALS, 115),
|
||||
# Loop code with a continue statement.
|
||||
PushAction(105, ["some_condition"]),
|
||||
AP2Action(106, AP2Action.GET_VARIABLE),
|
||||
IfAction(107, IfAction.IS_FALSE, 110),
|
||||
IfAction(107, IfAction.COMP_IS_FALSE, 110),
|
||||
AP2Action(108, AP2Action.NEXT_FRAME),
|
||||
# Continue statement.
|
||||
JumpAction(109, 112),
|
||||
|
Loading…
x
Reference in New Issue
Block a user