1
0
mirror of synced 2024-09-24 03:18:22 +02:00

Update with working RE for all remaining known data pieces including properties and object events.

This commit is contained in:
Jennifer Taylor 2021-04-06 22:24:36 +00:00
parent eda60c065c
commit 32cc4a071c

View File

@ -317,7 +317,7 @@ class AP2Tag:
cls.AP2_VIDEO: 'AP2_VIDEO',
}
return resources.get(tagid, "UNKNOWN")
return resources.get(tagid, f"<UNKNOWN {tagid}>")
class AP2Action:
@ -577,7 +577,7 @@ class AP2Action:
cls.ADD_NUM_VARIABLE: 'ADD_NUM_VARIABLE',
}
return resources.get(actionid, "UNKNOWN")
return resources.get(actionid, f"<UNKNOWN {actionid}>")
@classmethod
def actions_without_params(cls) -> Set[int]:
@ -709,6 +709,524 @@ class AP2PointerType:
filtesr_P = 0xb6
class AP2PropertyType:
# TODO: This is missing some properties for newer games.
__PROPERTIES: List[Tuple[int, str]] = [
# Global properties on every object.
(0x120, 'this'),
(0x121, '_root'),
(0x122, '_parent'),
(0x123, '_global'),
(0x124, 'arguments'),
# Object properties?
(0x140, 'blendMode'),
(0x141, 'enabled'),
(0x142, 'hitArea'),
(0x143, '_lockroot'),
(0x144, '$version'),
# Text input properties.
(0x160, 'textWidth'),
(0x161, 'textHeight'),
(0x162, 'text'),
(0x163, 'autoSize'),
(0x164, 'textColor'),
(0x165, 'selectable'),
# Color properties?
(0x180, 'ra'),
(0x181, 'rb'),
(0x182, 'ga'),
(0x183, 'gb'),
(0x184, 'ba'),
(0x185, 'bb'),
(0x186, 'aa'),
(0x187, 'ab'),
# Text properties?
(0x1a0, 'font'),
(0x1a1, 'size'),
(0x1a2, 'color'),
(0x1a3, 'bold'),
(0x1a4, 'italic'),
(0x1a5, 'underline'),
(0x1a6, 'url'),
(0x1a7, 'target'),
(0x1a8, 'align'),
(0x1a9, 'leftMargin'),
(0x1aa, 'rightMargin'),
(0x1ab, 'indent'),
(0x1ac, 'leading'),
# Who the fuck knows...
(0x1c0, 'a'),
(0x1c1, 'b'),
(0x1c2, 'c'),
(0x1c3, 'd'),
(0x1c4, 'e'),
(0x1c5, 'f'),
(0x1c6, 'g'),
(0x1c7, 'h'),
(0x1c8, 'i'),
(0x1c9, 'j'),
(0x1ca, 'k'),
(0x1cb, 'l'),
(0x1cc, 'm'),
(0x1cd, 'n'),
(0x1ce, 'o'),
(0x1cf, 'p'),
(0x1d0, 'q'),
(0x1d1, 'r'),
(0x1d2, 's'),
(0x1d3, 't'),
(0x1d4, 'u'),
(0x1d5, 'v'),
(0x1d6, 'w'),
(0x1d7, 'x'),
(0x1d8, 'y'),
(0x1d9, 'z'),
(0x1da, 'tx'),
(0x1db, 'ty'),
(0x1dc, 'length'),
(0x1dd, 'ignoreWhite'),
(0x1de, 'loaded'),
(0x1df, 'childNodes'),
(0x1e0, 'firstChild'),
(0x1e1, 'nodeValue'),
(0x1e2, 'nextSibling'),
(0x1e3, 'nodeName'),
(0x1e4, 'nodeType'),
(0x1e5, 'attributes'),
(0x1e6, '__count'),
(0x1e7, '__type'),
(0x1e8, 'width'),
(0x1e9, 'height'),
(0x1ea, 'useCodepage'),
(0x1eb, 'duration'),
(0x1ec, 'position'),
(0x1ed, 'matrixType'),
(0x1ee, 'matrix'),
(0x1ef, 'prototype'),
(0x1f0, '__proto__'),
(0x1f1, 'xMin'),
(0x1f2, 'xMax'),
(0x1f3, 'yMin'),
(0x1f4, 'yMax'),
(0x1f5, 'lastChild'),
(0x1f6, 'parentNode'),
(0x1f7, 'previousSibling'),
(0x1f8, 'callee'),
(0x1f9, 'caller'),
(0x1fa, 'colorTransform'),
(0x1fb, 'concatenatedColorTransform'),
(0x1fc, 'concatenatedMatrix'),
(0x1fd, 'pixelBounds'),
# Commands and object references?
(0x200, 'FSCommand:fullscreen'),
(0x201, 'FSCommand:showmenu'),
(0x202, 'FSCommand:allowscale'),
(0x203, 'FSCommand:quit'),
(0x204, 'NaN'),
(0x205, 'Infinity'),
(0x206, 'number'),
(0x207, 'boolean'),
(0x208, 'string'),
(0x209, 'object'),
(0x20a, 'movieclip'),
(0x20b, 'null'),
(0x20c, 'undefined'),
(0x20d, 'function'),
(0x20e, 'normal'),
(0x20f, 'layer'),
(0x210, 'darken'),
(0x211, 'multiply'),
(0x212, 'lighten'),
(0x213, 'screen'),
(0x214, 'overlay'),
(0x215, 'hardlight'),
(0x216, 'subtract'),
(0x217, 'difference'),
(0x218, 'invert'),
(0x219, 'alpha'),
(0x21a, 'erase'),
(0x21b, '/'),
(0x21c, '..'),
(0x21d, 'linear'),
(0x21e, 'radial'),
(0x21f, 'none'),
(0x220, 'square'),
(0x221, 'miter'),
(0x222, 'bevel'),
(0x223, 'left'),
(0x224, 'right'),
(0x225, 'center'),
(0x226, 'box'),
(0x227, 'reflect'),
(0x228, 'repeat'),
(0x229, 'RGB'),
(0x22a, 'linearRGB'),
(0x22b, 'justify'),
# Layer depths
(0x2e0, '_level0'),
(0x2e1, '_level1'),
(0x2e2, '_level2'),
(0x2e3, '_level3'),
(0x2e4, '_level4'),
(0x2e5, '_level5'),
(0x2e6, '_level6'),
(0x2e7, '_level7'),
(0x2e8, '_level8'),
(0x2e9, '_level9'),
(0x2ea, '_level10'),
(0x2eb, '_level11'),
(0x2ec, '_level12'),
(0x2ed, '_level13'),
(0x2ee, '_level14'),
(0x2ef, '_level15'),
# System objects
(0x300, 'System'),
(0x301, 'Stage'),
(0x302, 'Key'),
(0x303, 'Math'),
(0x304, 'flash'),
(0x305, 'MovieClip'),
(0x306, 'String'),
(0x307, 'TextField'),
(0x308, 'Color'),
(0x309, 'Date'),
(0x30a, 'SharedObject'),
(0x30b, 'Mouse'),
(0x30c, 'Object'),
(0x30d, 'Sound'),
(0x30e, 'Number'),
(0x30f, 'Array'),
(0x310, 'XML'),
(0x311, 'TextFormat'),
(0x312, 'display'),
(0x313, 'geom'),
(0x314, 'Matrix'),
(0x315, 'Point'),
(0x316, 'BitmapData'),
(0x317, 'data'),
(0x318, 'filters'),
(0x319, 'ColorMatrixFilter'),
(0x31a, 'Function'),
(0x31b, 'XMLNode'),
(0x31c, 'aplib'),
(0x31d, 'Transform'),
(0x31e, 'ColorTransform'),
(0x31f, 'Rectangle'),
(0x320, 'asdlib'),
(0x321, 'XMLController'),
(0x322, 'eManager'),
# XML functions
(0x400, 'afp_prop_init'),
(0x401, 'afp_prop'),
(0x402, 'afp_prop_dummy'),
(0x403, 'afp_prop_destroy'),
(0x404, 'afp_sync'),
(0x405, 'afp_node_search'),
(0x406, 'afp_node_value'),
(0x407, 'afp_node_array_value'),
(0x408, 'afp_complete'),
(0x409, 'afp_sound_fade_in'),
(0x40a, 'afp_sound_fade_out'),
(0x40b, 'afp_make_gradient_data'),
(0x40c, 'afp_make_alpha_texture'),
(0x40d, 'afp_node_set_value'),
(0x40e, 'afp_node_date_value'),
(0x40f, 'afp_node_num_value'),
(0x410, 'afp_node_array_num_value'),
# System functions
(0x420, 'updateAfterEvent'),
(0x421, 'parseInt'),
(0x422, 'parseFloat'),
(0x423, 'Boolean'),
(0x424, 'setInterval'),
(0x425, 'clearInterval'),
(0x426, 'escape'),
(0x427, 'ASSetPropFlags'),
(0x428, 'unescape'),
(0x429, 'isNaN'),
(0x42a, 'isFinite'),
# Current movie manipulation functions.
(0x440, 'stop'),
(0x441, 'play'),
(0x442, 'gotoAndPlay'),
(0x443, 'gotoAndStop'),
(0x444, 'prevFrame'),
(0x445, 'nextFrame'),
(0x446, 'createEmptyMovieClip'),
(0x447, 'duplicateMovieClip'),
(0x448, 'attachMovie'),
(0x449, 'attachBitmap'),
(0x44a, 'removeMovieClip'),
(0x44b, 'unloadMovie'),
(0x44c, 'loadMovie'),
(0x44d, 'loadVariables'),
(0x44e, 'startDrag'),
(0x44f, 'stopDrag'),
(0x450, 'setMask'),
(0x451, 'hitTest'),
(0x452, 'lineStyle'),
(0x453, 'lineGradientStyle'),
(0x454, 'beginFill'),
(0x455, 'beginBitmapFill'),
(0x456, 'endFill'),
(0x457, 'moveTo'),
(0x458, 'lineTo'),
(0x459, 'curveTo'),
(0x45a, 'clear'),
(0x45b, 'getBytesLoaded'),
(0x45c, 'getBytesTotal'),
(0x45d, 'getDepth'),
(0x45e, 'getNextHighestDepth'),
(0x45f, 'swapDepths'),
(0x460, 'localToGlobal'),
(0x461, 'beginGradientFill'),
(0x462, 'getSWFVersion'),
(0x463, 'getRect'),
(0x464, 'getBounds'),
(0x465, 'getInstanceAtDepth'),
(0x466, 'getURL'),
# System object manipulation functions.
(0x480, 'toString'),
(0x481, 'distance'),
(0x482, 'translate'),
(0x483, 'rotate'),
(0x484, 'scale'),
(0x485, 'clone'),
(0x486, 'transformPoint'),
(0x487, 'add'),
(0x488, 'cos'),
(0x489, 'sin'),
(0x48a, 'sqrt'),
(0x48b, 'atan2'),
(0x48c, 'log'),
(0x48d, 'abs'),
(0x48e, 'floor'),
(0x48f, 'ceil'),
(0x490, 'round'),
(0x491, 'pow'),
(0x492, 'max'),
(0x493, 'min'),
(0x494, 'random'),
(0x495, 'acos'),
(0x496, 'asin'),
(0x497, 'atan'),
(0x498, 'tan'),
(0x499, 'exp'),
(0x49a, 'getRGB'),
(0x49b, 'setRGB'),
(0x49c, 'getTransform'),
(0x49d, 'setTransform'),
(0x49e, 'fromCharCode'),
(0x49f, 'substr'),
(0x4a0, 'substring'),
(0x4a1, 'toUpperCase'),
(0x4a2, 'toLowerCase'),
(0x4a3, 'indexOf'),
(0x4a4, 'lastIndexOf'),
(0x4a5, 'charAt'),
(0x4a6, 'charCodeAt'),
(0x4a7, 'split'),
(0x4a8, 'concat'),
(0x4a9, 'getFullYear'),
(0x4aa, 'getUTCFullYear'),
(0x4ab, 'getMonth'),
(0x4ac, 'getUTCMonth'),
(0x4ad, 'getDate'),
(0x4ae, 'getUTCDate'),
(0x4af, 'getDay'),
(0x4b0, 'getHours'),
(0x4b1, 'getUTCHours'),
(0x4b2, 'getMinutes'),
(0x4b3, 'getUTCMinutes'),
(0x4b4, 'getSeconds'),
(0x4b5, 'getUTCSeconds'),
(0x4b6, 'getTime'),
(0x4b7, 'getTimezoneOffset'),
(0x4b8, 'UTC'),
(0x4b9, 'createElement'),
(0x4ba, 'appendChild'),
(0x4bb, 'createTextNode'),
(0x4bc, 'parseXML'),
(0x4bd, 'load'),
(0x4be, 'hasChildNodes'),
(0x4bf, 'cloneNode'),
(0x4c0, 'removeNode'),
(0x4c1, 'loadInAdvance'),
(0x4c2, 'createGradientBox'),
(0x4c3, 'loadBitmap'),
(0x4c4, 'hide'),
(0x4c5, 'show'),
(0x4c6, 'addListener'),
(0x4c7, 'removeListener'),
(0x4c8, 'isDown'),
(0x4c9, 'getCode'),
(0x4ca, 'getAscii'),
(0x4cb, 'attachSound'),
(0x4cc, 'start'),
(0x4cd, 'getVolume'),
(0x4ce, 'setVolume'),
(0x4cf, 'setPan'),
(0x4d0, 'loadSound'),
(0x4d1, 'setTextFormat'),
(0x4d2, 'getTextFormat'),
(0x4d3, 'push'),
(0x4d4, 'pop'),
(0x4d5, 'slice'),
(0x4d6, 'splice'),
(0x4d7, 'reverse'),
(0x4d8, 'sort'),
(0x4d9, 'flush'),
(0x4da, 'getLocal'),
(0x4db, 'shift'),
(0x4dc, 'unshift'),
(0x4dd, 'registerClass'),
(0x4de, 'getUTCDay'),
(0x4df, 'getMilliseconds'),
(0x4e0, 'getUTCMilliseconds'),
(0x4e1, 'addProperty'),
(0x4e2, 'hasOwnProperty'),
(0x4e3, 'isPropertyEnumerable'),
(0x4e4, 'isPrototypeOf'),
(0x4e5, 'unwatch'),
(0x4e6, 'valueOf'),
(0x4e7, 'watch'),
(0x4e8, 'apply'),
(0x4e9, 'call'),
(0x4ea, 'contains'),
(0x4eb, 'containsPoint'),
(0x4ec, 'containsRectangle'),
(0x4ed, 'equals'),
(0x4ee, 'inflate'),
(0x4ef, 'inflatePoint'),
(0x4f0, 'intersection'),
(0x4f1, 'intersects'),
(0x4f2, 'isEmpty'),
(0x4f3, 'offset'),
(0x4f4, 'offsetPoint'),
(0x4f5, 'setEmpty'),
(0x4f6, 'union'),
(0x4f7, 'interpolate'),
# Event constants
(0x500, 'onKeyDown'),
(0x501, 'onKeyUp'),
(0x502, 'onMouseDown'),
(0x503, 'onMouseUp'),
(0x504, 'onMouseMove'),
(0x505, 'onLoad'),
(0x506, 'onEnterFrame'),
(0x507, 'onUnload'),
(0x508, 'onRollOver'),
(0x509, 'onRollOut'),
(0x50a, 'onPress'),
(0x50b, 'onRelease'),
(0x50c, 'onReleaseOutside'),
(0x50d, 'onData'),
(0x50e, 'onSoundComplete'),
(0x50f, 'onDragOver'),
(0x510, 'onDragOut'),
# Key constants
(0x600, 'BACKSPACE'),
(0x601, 'CAPSLOCK'),
(0x602, 'CONTROL'),
(0x603, 'DELETEKEY'),
(0x604, 'DOWN'),
(0x605, 'END'),
(0x606, 'ENTER'),
(0x607, 'ESCAPE'),
(0x608, 'HOME'),
(0x609, 'INSERT'),
(0x60a, 'LEFT'),
(0x60b, 'PGDN'),
(0x60c, 'PGUP'),
(0x60d, 'RIGHT'),
(0x60e, 'SHIFT'),
(0x60f, 'SPACE'),
(0x610, 'TAB'),
(0x611, 'UP'),
# Some sort of sorting constants.
(0x620, 'CASEINSENSITIVE'),
(0x621, 'DESCENDING'),
(0x622, 'UNIQUESORT'),
(0x623, 'RETURNINDEXEDARRAY'),
(0x624, 'NUMERIC'),
# Shape constants?
(0x700, 'redMultiplier'),
(0x701, 'greenMultiplier'),
(0x702, 'blueMultiplier'),
(0x703, 'alphaMultiplier'),
(0x704, 'redOffset'),
(0x705, 'greenOffset'),
(0x706, 'blueOffset'),
(0x707, 'alphaOffset'),
(0x708, 'rgb'),
(0x709, 'bottom'),
(0x70a, 'bottomRight'),
(0x70b, 'top'),
(0x70c, 'topLeft'),
(0x70d, 'LOW'),
(0x70e, 'MEDIUM'),
(0x70f, 'HIGH'),
(0x710, 'BEST'),
# Some more system functions?
(0x800, 'sound_play'),
(0x801, 'sound_stop'),
(0x802, 'sound_stop_all'),
(0x803, 'set_top_mc'),
(0x804, 'set_controlled_XML'),
(0x805, 'set_config_XML'),
(0x806, 'set_data_top'),
(0x807, 'attach_event'),
(0x808, 'detach_event'),
(0x809, 'set'),
(0x80a, 'get'),
(0x80b, 'ready'),
(0x80c, 'afp_available'),
# Time functions
(0x900, 'setDate'),
(0x901, 'setUTCDate'),
(0x902, 'setFullYear'),
(0x903, 'setUTCFullYear'),
(0x904, 'setHours'),
(0x905, 'setUTCHours'),
(0x906, 'setMilliseconds'),
(0x907, 'setUTCMilliseconds'),
(0x908, 'setMinutes'),
(0x909, 'setUTCMinutes'),
(0x90a, 'setMonth'),
(0x90b, 'setUTCMonth'),
(0x90c, 'setSeconds'),
(0x90d, 'setUTCSeconds'),
(0x90e, 'setTime'),
(0x90f, 'setYear'),
]
@classmethod
def property_to_name(cls, propid: int) -> str:
for i, p in cls.__PROPERTIES:
if i == propid:
return p
return f"<UNKNOWN {propid}>"
class SWF:
def __init__(
self,
@ -919,30 +1437,22 @@ class SWF:
# Unknown property name.
propertyval = struct.unpack(">B", datachunk[offset_ptr:(offset_ptr + 1)])[0] + 0x100
offset_ptr += 1
# TODO: Resolve these!
vprint(f"{prefix} PROPERTY CONST NAME: {hex(propertyval)}")
vprint(f"{prefix} PROPERTY CONST NAME: {AP2PropertyType.property_to_name(propertyval)}")
elif obj_to_create == 0x13:
# Class property name.
propertyval = struct.unpack(">B", datachunk[offset_ptr:(offset_ptr + 1)])[0] + 0x300
offset_ptr += 1
# TODO: Resolve these!
vprint(f"{prefix} CLASS CONST NAME: {hex(propertyval)}")
vprint(f"{prefix} CLASS CONST NAME: {AP2PropertyType.property_to_name(propertyval)}")
elif obj_to_create == 0x16:
# Func property name.
propertyval = struct.unpack(">B", datachunk[offset_ptr:(offset_ptr + 1)])[0] + 0x400
offset_ptr += 1
# TODO: Resolve these!
vprint(f"{prefix} FUNC CONST NAME: {hex(propertyval)}")
vprint(f"{prefix} FUNC CONST NAME: {AP2PropertyType.property_to_name(propertyval)}")
elif obj_to_create == 0x1c:
# Event property name.
propertyval = struct.unpack(">B", datachunk[offset_ptr:(offset_ptr + 1)])[0] + 0x500
offset_ptr += 1
# TODO: Resolve these!
vprint(f"{prefix} EVENT CONST NAME: {hex(propertyval)}")
vprint(f"{prefix} EVENT CONST NAME: {AP2PropertyType.property_to_name(propertyval)}")
elif obj_to_create == 0x22:
# Pointer to global object.
vprint(f"{prefix} POINTER TO GLOBAL OBJECT")
@ -950,9 +1460,7 @@ class SWF:
# Some other property name.
propertyval = struct.unpack(">B", datachunk[offset_ptr:(offset_ptr + 1)])[0] + 0x800
offset_ptr += 1
# TODO: Resolve these!
vprint(f"{prefix} ORGFUNC2 CONST NAME: {hex(propertyval)}")
vprint(f"{prefix} ORGFUNC2 CONST NAME: {AP2PropertyType.property_to_name(propertyval)}")
else:
raise Exception(f"Unsupported object {hex(obj_to_create)} to push!")
@ -1107,20 +1615,24 @@ class SWF:
vprint(f"{prefix} Flags: {hex(flags)}, Object ID: {object_id}, Depth: {depth}")
running_pointer = 8
unhandled_flags = flags
if flags & 0x2:
unhandled_flags &= ~0x2
src_tag_id = struct.unpack("<H", datachunk[running_pointer:(running_pointer + 2)])[0]
add_coverage(dataoffset + running_pointer, 2)
running_pointer += 2
vprint(f"{prefix} Source Tag ID: {src_tag_id}")
if flags & 0x10:
unhandled_flags &= ~0x10
unk2 = struct.unpack("<H", datachunk[running_pointer:(running_pointer + 2)])[0]
add_coverage(dataoffset + running_pointer, 2)
running_pointer += 2
vprint(f"{prefix} Unk2: {hex(unk2)}")
if flags & 0x20:
unhandled_flags &= ~0x20
nameoffset = struct.unpack("<H", datachunk[running_pointer:(running_pointer + 2)])[0]
add_coverage(dataoffset + running_pointer, 2)
name = self.__get_string(nameoffset)
@ -1128,12 +1640,14 @@ class SWF:
vprint(f"{prefix} Name: {name}")
if flags & 0x40:
unhandled_flags &= ~0x40
unk3 = struct.unpack("<H", datachunk[running_pointer:(running_pointer + 2)])[0]
add_coverage(dataoffset + running_pointer, 2)
running_pointer += 2
vprint(f"{prefix} Unk3: {hex(unk3)}")
if flags & 0x20000:
unhandled_flags &= ~0x20000
blend = struct.unpack("<B", datachunk[running_pointer:(running_pointer + 1)])[0]
add_coverage(dataoffset + running_pointer, 1)
running_pointer += 1
@ -1150,6 +1664,7 @@ class SWF:
transform = Matrix.identity()
if flags & 0x100:
unhandled_flags &= ~0x100
a_int, d_int = struct.unpack("<II", datachunk[running_pointer:(running_pointer + 8)])
add_coverage(dataoffset + running_pointer, 8)
running_pointer += 8
@ -1159,6 +1674,7 @@ class SWF:
vprint(f"{prefix} Transform Matrix A: {transform.a}, D: {transform.d}")
if flags & 0x200:
unhandled_flags &= ~0x200
b_int, c_int = struct.unpack("<II", datachunk[running_pointer:(running_pointer + 8)])
add_coverage(dataoffset + running_pointer, 8)
running_pointer += 8
@ -1168,6 +1684,7 @@ class SWF:
vprint(f"{prefix} Transform Matrix B: {transform.b}, C: {transform.c}")
if flags & 0x400:
unhandled_flags &= ~0x400
tx_int, ty_int = struct.unpack("<II", datachunk[running_pointer:(running_pointer + 8)])
add_coverage(dataoffset + running_pointer, 8)
running_pointer += 8
@ -1181,6 +1698,7 @@ class SWF:
acolor = Color(1.0, 1.0, 1.0, 1.0)
if flags & 0x800:
unhandled_flags &= ~0x800
r, g, b, a = struct.unpack("<HHHH", datachunk[running_pointer:(running_pointer + 8)])
add_coverage(dataoffset + running_pointer, 8)
running_pointer += 8
@ -1192,6 +1710,7 @@ class SWF:
vprint(f"{prefix} Color: {color}")
if flags & 0x1000:
unhandled_flags &= ~0x1000
r, g, b, a = struct.unpack("<HHHH", datachunk[running_pointer:(running_pointer + 8)])
add_coverage(dataoffset + running_pointer, 8)
running_pointer += 8
@ -1203,6 +1722,7 @@ class SWF:
vprint(f"{prefix} AColor: {color}")
if flags & 0x2000:
unhandled_flags &= ~0x2000
rgba = struct.unpack("<I", datachunk[running_pointer:(running_pointer + 4)])[0]
add_coverage(dataoffset + running_pointer, 4)
running_pointer += 4
@ -1214,6 +1734,7 @@ class SWF:
vprint(f"{prefix} Color: {color}")
if flags & 0x4000:
unhandled_flags &= ~0x4000
rgba = struct.unpack("<I", datachunk[running_pointer:(running_pointer + 4)])[0]
add_coverage(dataoffset + running_pointer, 4)
running_pointer += 4
@ -1225,44 +1746,102 @@ class SWF:
vprint(f"{prefix} AColor: {color}")
if flags & 0x80:
# 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)])
# Object event triggers.
unhandled_flags &= ~0x80
event_flags, event_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}")
if event_flags != 0:
_, count = struct.unpack("<HH", datachunk[(running_pointer + 8):(running_pointer + 12)])
add_coverage(dataoffset + running_pointer + 8, 4)
# The game does not seem to care about length here, but we do, so let's calculate
# offsets and use that for lengths.
bytecode_offsets: List[int] = []
for evt in range(count):
evt_offset = running_pointer + 12 + (evt * 8)
bytecode_offset = struct.unpack("<H", datachunk[(evt_offset + 6):(evt_offset + 8)])[0] + evt_offset
bytecode_offsets.append(bytecode_offset)
bytecode_offsets.append(event_size + running_pointer)
beginning_to_end: Dict[int, int] = {}
for i, bytecode_offset in enumerate(bytecode_offsets[:-1]):
beginning_to_end[bytecode_offset] = bytecode_offsets[i + 1]
vprint(f"{prefix} Event Triggers, Count: {count}")
for evt in range(count):
evt_offset = running_pointer + 12 + (evt * 8)
evt_flags, _, keycode, bytecode_offset = struct.unpack("<IBBH", datachunk[evt_offset:(evt_offset + 8)])
add_coverage(dataoffset + evt_offset, 8)
events: List[str] = []
if evt_flags & 0x1:
events.append("ON_LOAD")
if evt_flags & 0x2:
events.append("ON_ENTER_FRAME")
if evt_flags & 0x4:
events.append("ON_UNLOAD")
if evt_flags & 0x8:
events.append("ON_MOUSE_MOVE")
if evt_flags & 0x10:
events.append("ON_MOUSE_DOWN")
if evt_flags & 0x20:
events.append("ON_MOUSE_UP")
if evt_flags & 0x40:
events.append("ON_KEY_DOWN")
if evt_flags & 0x80:
events.append("ON_KEY_UP")
if evt_flags & 0x100:
events.append("ON_DATA")
if evt_flags & 0x400:
events.append("ON_PRESS")
if evt_flags & 0x800:
events.append("ON_RELEASE")
if evt_flags & 0x1000:
events.append("ON_RELEASE_OUTSIDE")
if evt_flags & 0x2000:
events.append("ON_ROLL_OVER")
if evt_flags & 0x4000:
events.append("ON_ROLL_OUT")
bytecode_offset += evt_offset
bytecode_length = beginning_to_end[bytecode_offset] - bytecode_offset
vprint(f"{prefix} Flags: {hex(evt_flags)} ({', '.join(events)}), KeyCode: {hex(keycode)}, Bytecode Offset: {hex(dataoffset + bytecode_offset)}, Length: {bytecode_length}")
self.__parse_bytecode(datachunk[bytecode_offset:(bytecode_offset + bytecode_length)], prefix=prefix + " ", verbose=verbose)
add_coverage(dataoffset + bytecode_offset, bytecode_length)
running_pointer += event_size
if flags & 0x10000:
# 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)])
unhandled_flags &= ~0x10000
count, filter_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 += filter_size
# TODO: This is not understood at all. I need to find data that uses it to continue.
# 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.
vprint(f"{prefix} Unknown Filter data Count: {count}, Size: {filter_size}")
if flags & 0x1000000:
# Some sort of point, perhaps an x, y offset for the object?
unhandled_flags &= ~0x1000000
x, y = struct.unpack("<ff", datachunk[running_pointer:(running_pointer + 8)])
add_coverage(dataoffset + running_pointer, 8)
running_pointer += 8
# TODO: This doesn't seem right when run past Pop'n Music data.
point = Point(x / 20.0, y / 20.0)
vprint(f"{prefix} Point: {point}")
if flags & 0x2000000:
# Same as above, but initializing to 0, 0 instead of from data.
unhandled_flags &= ~0x2000000
point = Point(0.0, 0.0)
vprint(f"{prefix} Point: {point}")
@ -1271,13 +1850,22 @@ class SWF:
# does it slot in for when to decode it?
# This flag states whether we are creating a new object on this depth, or updating one.
unhandled_flags &= ~0x5
if flags & 0x1:
vprint(f"{prefix} Update object request")
else:
vprint(f"{prefix} Create object request")
if flags & 0x4:
vprint(f"{prefix} Use transform matrix")
else:
vprint(f"{prefix} Ignore transform matrix")
if unhandled_flags != 0:
raise Exception(f"Did not handle {hex(unhandled_flags)} flag bits!")
if running_pointer < size:
raise Exception(f"Did not consume {size - running_pointer} bytes ({[hex(x) for x in datachunk[running_pointer:]]}) in object instantiation!")
if running_pointer != size:
raise Exception("Logic error!")
elif tagid == AP2Tag.AP2_REMOVE_OBJECT:
if size != 4:
@ -1622,6 +2210,8 @@ class DrawParams:
flagbits.append("(Instantiable)")
if self.flags & 0x2:
flagbits.append("(Includes Texture)")
if self.flags & 0x4:
flagbits.append("(Includes Texture Color)")
if self.flags & 0x8:
flagbits.append("(Includes Blend Color)")
if self.flags & 0x40:
@ -1656,6 +2246,9 @@ class Shape:
# Texture points, as used alongside vertex chunks when the shape contains a texture.
self.tex_points: List[Point] = []
# Colors for texture points, if they exist in the file.
self.tex_colors: List[Color] = []
# Actual shape drawing parameters.
self.draw_params: List[DrawParams] = []
@ -1664,6 +2257,7 @@ class Shape:
'name': self.name,
'vertex_points': [p.as_dict() for p in self.vertex_points],
'tex_points': [p.as_dict() for p in self.tex_points],
'tex_colors': [c.as_dict() for c in self.tex_colors],
'draw_params': [d.as_dict() for d in self.draw_params],
}
@ -1671,6 +2265,7 @@ class Shape:
return os.linesep.join([
*[f"vertex point: {vertex}" for vertex in self.vertex_points],
*[f"tex point: {tex}" for tex in self.tex_points],
*[f"tex color: {color}" for color in self.tex_colors],
*[f"draw params: {params}" for params in self.draw_params],
])
@ -1703,12 +2298,12 @@ class Shape:
if self.data[16:20] != b"\0\0\0\0":
raise Exception("Unhandled flag data bytes in GE2D structure!")
vertex_count, tex_count, unk1_count, label_count, render_params_count, _ = struct.unpack(
vertex_count, tex_count, color_count, label_count, render_params_count, _ = struct.unpack(
f"{endian}HHHHHH",
self.data[20:32],
)
vertex_offset, tex_offset, unk1_offset, label_offset, render_params_offset = struct.unpack(
vertex_offset, tex_offset, color_offset, label_offset, render_params_offset = struct.unpack(
f"{endian}IIIII",
self.data[32:52],
)
@ -1729,10 +2324,19 @@ class Shape:
tex_points.append(Point(x, y))
self.tex_points = tex_points
if unk1_offset != 0:
# These are supposedly colors, but I've never found a GE2D structure using this
# nor code that cares so I have no way of verifying.
raise Exception("Unknown offset pointer data present!")
colors: List[Color] = []
if color_offset != 0:
for colorno in range(color_count):
colorno_offset = color_offset + (4 * colorno)
rgba = struct.unpack(f"{endian}I", self.data[colorno_offset:colorno_offset + 4])[0]
color = Color(
a=(rgba & 0xFF) / 255.0,
b=((rgba >> 8) & 0xFF) / 255.0,
g=((rgba >> 16) & 0xFF) / 255.0,
r=((rgba >> 24) & 0xFF) / 255.0,
)
colors.append(color)
self.tex_colors = colors
labels: List[str] = []
if label_offset != 0:
@ -1749,19 +2353,19 @@ class Shape:
# are used when drawing shapes, whether to use a blend value or draw a primitive, etc.
for render_paramsno in range(render_params_count):
render_paramsno_offset = render_params_offset + (16 * render_paramsno)
points, flags, tex1, tex2, trianglecount, _, rgba, triangleoffset = struct.unpack(
mode, flags, tex1, tex2, trianglecount, _, rgba, triangleoffset = struct.unpack(
f"{endian}BBBBHHII",
self.data[(render_paramsno_offset):(render_paramsno_offset + 16)]
)
if points != 4:
raise Exception("Unexpected number of points in GE2D structure!")
if mode != 4:
raise Exception("Unexpected mode in GE2D structure!")
if (flags & 0x2) and len(labels) == 0:
raise Exception("GE2D structure has a texture, but no region labels present!")
if (flags & 0x2) and (tex1 == 0xFF):
raise Exception("GE2D structure requests a texture, but no texture pointer present!")
if (flags & 0x4) or (tex2 != 0xFF):
raise Exception("GE2D structure has second texture, but we don't support this!")
if tex2 != 0xFF:
raise Exception("GE2D structure requests a second texture, but we don't support this!")
color = Color(
r=(rgba & 0xFF) / 255.0,
@ -1776,10 +2380,10 @@ class Shape:
tex_offset = struct.unpack(f"{endian}H", self.data[render_paramstriangleno_offset:(render_paramstriangleno_offset + 2)])[0]
verticies.append(tex_offset)
# Seen bits are 0x1, 0x2, 0x8 so far.
# Seen bits are 0x1, 0x2, 0x4, 0x8 so far.
# 0x1 Is a "this shape is instantiable/drawable" bit.
# 0x2 Is the shape having a texture.
# 0x4 Is probably the shape having a second texture, but I don't know of any data using this.
# 0x4 Is the shape having a texture color per texture point.
# 0x8 Is "draw background color/blend" flag.
# 0x40 Is a "normalize texture coordinates" flag. It performs the below algorithm.
@ -1796,7 +2400,7 @@ class Shape:
DrawParams(
flags=flags,
region=labels[tex1] if (flags & 0x2) else None,
vertexes=verticies if (flags & 0x2) else [],
vertexes=verticies if (flags & 0x6) else [],
blend=color if (flags & 0x8) else None,
)
)