1
0
mirror of synced 2024-12-01 00:57:18 +01:00

Last few object bits implemented enough to parse Pop'n Music, a few more annotations.

This commit is contained in:
Jennifer Taylor 2021-04-05 00:52:10 +00:00
parent d26f3e0238
commit 0bfec7655c

View File

@ -162,7 +162,7 @@ class Point:
return f"x: {round(self.x, 5)}, y: {round(self.y, 5)}" return f"x: {round(self.x, 5)}, y: {round(self.y, 5)}"
class Tag: class AP2Tag:
END = 0x0 END = 0x0
SHOW_FRAME = 0x1 SHOW_FRAME = 0x1
DEFINE_SHAPE = 0x2 DEFINE_SHAPE = 0x2
@ -486,6 +486,101 @@ class AP2Action:
return resources.get(tagid, "UNKNOWN") return resources.get(tagid, "UNKNOWN")
class AP2ObjectType:
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
class AP2PointerType:
# The type of the object if it is an AP2ObjectType.POINTER or AP2ObjectType.OBJECT
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
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
# 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
stage_O = 0xa0
math_O = 0xa1
key_O = 0xa2
mouse_O = 0xa3
system_O = 0xa4
sharedObject_O = 0xa5
flash_O = 0xa6
global_O = 0xa7
display_P = 0xb4
geom_P = 0xb5
filtesr_P = 0xb6
class SWF: class SWF:
def __init__( def __init__(
self, self,
@ -557,7 +652,7 @@ class SWF:
def add_coverage(*args: Any, **kwargs: Any) -> None: # type: ignore def add_coverage(*args: Any, **kwargs: Any) -> None: # type: ignore
pass pass
if tagid == Tag.AP2_SHAPE: if tagid == AP2Tag.AP2_SHAPE:
if size != 4: if size != 4:
raise Exception(f"Invalid shape size {size}") raise Exception(f"Invalid shape size {size}")
@ -566,7 +661,7 @@ class SWF:
shape_reference = f"{self.exported_name}_shape{shape_id}" shape_reference = f"{self.exported_name}_shape{shape_id}"
vprint(f"{prefix} Tag ID: {shape_id}, AFP Reference: {shape_reference}, IFS GEO Filename: {md5(shape_reference.encode('utf-8')).hexdigest()}") vprint(f"{prefix} Tag ID: {shape_id}, AFP Reference: {shape_reference}, IFS GEO Filename: {md5(shape_reference.encode('utf-8')).hexdigest()}")
elif tagid == Tag.AP2_DEFINE_SPRITE: elif tagid == AP2Tag.AP2_DEFINE_SPRITE:
sprite_flags, sprite_id = struct.unpack("<HH", ap2data[dataoffset:(dataoffset + 4)]) sprite_flags, sprite_id = struct.unpack("<HH", ap2data[dataoffset:(dataoffset + 4)])
add_coverage(dataoffset, 4) add_coverage(dataoffset, 4)
@ -580,14 +675,14 @@ class SWF:
vprint(f"{prefix} Tag ID: {sprite_id}") vprint(f"{prefix} Tag ID: {sprite_id}")
self.__parse_tags(ap2_version, afp_version, ap2data, subtags_offset, prefix=" " + prefix, verbose=verbose) self.__parse_tags(ap2_version, afp_version, ap2data, subtags_offset, prefix=" " + prefix, verbose=verbose)
elif tagid == Tag.AP2_DEFINE_FONT: elif tagid == AP2Tag.AP2_DEFINE_FONT:
wat, font_id = struct.unpack("<HH", ap2data[dataoffset:(dataoffset + 4)]) wat, font_id = struct.unpack("<HH", ap2data[dataoffset:(dataoffset + 4)])
vprint(f"{prefix} Tag ID: {font_id}") vprint(f"{prefix} Tag ID: {font_id}")
elif tagid == Tag.AP2_DO_ACTION: elif tagid == AP2Tag.AP2_DO_ACTION:
# TODO: This is wrong, this is only for defined functions. # TODO: This is wrong, this is only for defined functions.
flags, unk1, nameoffset, unk2, _, unk3 = struct.unpack(">BHHHBH", ap2data[dataoffset:(dataoffset + 10)]) flags, unk1, nameoffset, unk2, _, unk3 = struct.unpack(">BHHHBH", ap2data[dataoffset:(dataoffset + 10)])
vprint(f"{prefix} Flags: {hex(flags)}, Unk1: {hex(unk1)}, Name: {hex(nameoffset)}, Unk2: {hex(unk2)}, Unk3: {hex(unk3)}") vprint(f"{prefix} Flags: {hex(flags)}, Unk1: {hex(unk1)}, Name: {hex(nameoffset)}, Unk2: {hex(unk2)}, Unk3: {hex(unk3)}")
elif tagid == Tag.AP2_PLACE_OBJECT: elif tagid == AP2Tag.AP2_PLACE_OBJECT:
# Allow us to keep track of what we've consumed. # Allow us to keep track of what we've consumed.
datachunk = ap2data[dataoffset:(dataoffset + size)] datachunk = ap2data[dataoffset:(dataoffset + size)]
flags, depth, object_id = struct.unpack("<IHH", datachunk[0:8]) flags, depth, object_id = struct.unpack("<IHH", datachunk[0:8])
@ -713,19 +808,47 @@ class SWF:
acolor.a = float(rgba & 0xFF) * 0.003921569 acolor.a = float(rgba & 0xFF) * 0.003921569
vprint(f"{prefix} AColor: {color}") vprint(f"{prefix} AColor: {color}")
# Completely unsure what this is
if flags & 0x80: if flags & 0x80:
raise Exception("Unhandled flag!") # Some sort of event data? I dunno, but it changes the running pointer for data
# following it. Not sure what the data itself contains. This looks like it contains
# some lengths such as length of bytecode contained, and length of some values
# contained.
flags, size = struct.unpack("<II", datachunk[running_pointer:(running_pointer + 8)])
add_coverage(dataoffset + running_pointer, 8)
running_pointer += size
# TODO: This is basically not understood at all, I can't make heads or tails of
# the code. This definitely contains bytecode in some circumstances, maybe sprite
# init portion of the SWF spec?
vprint(f"{prefix} Unknown Event data Flags: {hex(flags)}, Size: {size}")
# Completely unsure what this is
if flags & 0x10000: if flags & 0x10000:
raise Exception("Unhandled flag!") # Some sort of filter data? Not sure what this is either. Needs more investigation
# if I encounter files with it.
count, size = struct.unpack("<HH", datachunk[running_pointer:(running_pointer + 4)])
add_coverage(dataoffset + running_pointer, 4)
running_pointer += size
vprint(f"{prefix} Unknown Filter data Count: {count}, Size: {size}")
# running_pointer + 4 starts a series of shorts (exactly count of them) which are
# all in the range of 0-7, corresponding to some sort of filter. They get sizes
# looked up and I presume there's data following this corresponding to those sizes.
# I don't know however as I've not encountered data with this bit.
if flags & 0x1000000: if flags & 0x1000000:
raise Exception("Unhandled flag!") # Some sort of point, perhaps an x, y offset for the object?
x, y = struct.unpack("<ff", datachunk[running_pointer:(running_pointer + 8)])
add_coverage(dataoffset + running_pointer, 8)
running_pointer += 8
point = Point(x / 20.0, y / 20.0)
vprint(f"{prefix} Point: {point}")
if flags & 0x2000000: if flags & 0x2000000:
raise Exception("Unhandled flag!") # Same as above, but initializing to 0, 0 instead of from data.
point = Point(0.0, 0.0)
vprint(f"{prefix} Point: {point}")
# This flag states whether we are creating a new object on this depth, or updating one. # This flag states whether we are creating a new object on this depth, or updating one.
if flags & 0x1: if flags & 0x1:
@ -736,7 +859,7 @@ class SWF:
if running_pointer < size: if running_pointer < size:
raise Exception(f"Did not consume {size - running_pointer} bytes in object instantiation!") raise Exception(f"Did not consume {size - running_pointer} bytes in object instantiation!")
elif tagid == Tag.AP2_REMOVE_OBJECT: elif tagid == AP2Tag.AP2_REMOVE_OBJECT:
if size != 4: if size != 4:
raise Exception(f"Invalid shape size {size}") raise Exception(f"Invalid shape size {size}")
@ -781,7 +904,7 @@ class SWF:
if size > 0x200000: if size > 0x200000:
raise Exception(f"Invalid tag size {size}") raise Exception(f"Invalid tag size {size}")
vprint(f"{prefix} Tag: {hex(tagid)} ({Tag.tag_to_name(tagid)}), Size: {hex(size)}, Offset: {hex(tags_offset + 4)}") vprint(f"{prefix} Tag: {hex(tagid)} ({AP2Tag.tag_to_name(tagid)}), Size: {hex(size)}, Offset: {hex(tags_offset + 4)}")
self.__parse_tag(ap2_version, afp_version, ap2data, tagid, size, tags_offset + 4, prefix=prefix, verbose=verbose) self.__parse_tag(ap2_version, afp_version, ap2data, tagid, size, tags_offset + 4, prefix=prefix, verbose=verbose)
tags_offset += size + 4 # Skip past tag header and data. tags_offset += size + 4 # Skip past tag header and data.
@ -906,7 +1029,8 @@ class SWF:
if flags & 0x1: if flags & 0x1:
# I have no idea what this is, but its treated as 4 bytes and something # I have no idea what this is, but its treated as 4 bytes and something
# happens if they aren't all 0xFF. # happens if they aren't all 0xFF. It looks like this is an animation
# background color.
unknown_bytes = struct.unpack("<4B", data[28:32]) unknown_bytes = struct.unpack("<4B", data[28:32])
else: else:
unknown_bytes = None unknown_bytes = None