swfparser.py 63 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733
  1. # Copyright 2013-2014 Facundo Batista
  2. #
  3. # This program is free software: you can redistribute it and/or modify it
  4. # under the terms of the GNU General Public License version 3, as published
  5. # by the Free Software Foundation.
  6. #
  7. # This program is distributed in the hope that it will be useful, but
  8. # WITHOUT ANY WARRANTY; without even the implied warranties of
  9. # MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
  10. # PURPOSE. See the GNU General Public License for more details.
  11. #
  12. # You should have received a copy of the GNU General Public License along
  13. # with this program. If not, see <http://www.gnu.org/licenses/>.
  14. #
  15. # For further info, check http://github.com/facundobatista/yaswfp
  16. """Parse a SWF file and expose all its internals.
  17. This follows the SWF FILE FORMAT SPECIFICATION VERSION 19 which is not
  18. included in this project for your easier finding because Adobe forbids
  19. the spec distribution.
  20. The attributes names are CamelCase to match as close as possible the
  21. spec.
  22. Note: not all the spec is covered (work in progress!), there's a flag
  23. in the SWFParser to change the behaviour when an still-not-done object
  24. is found.
  25. """
  26. import collections
  27. import io
  28. import os
  29. import sys
  30. import warnings
  31. import zlib
  32. sys.path.append(os.path.dirname(__file__))
  33. sys.path.append(os.path.dirname(__file__) + '/../../')
  34. from helpers import (
  35. BitConsumer,
  36. ReadQuantityController,
  37. unpack_si16,
  38. unpack_ui16,
  39. unpack_ui32,
  40. unpack_ui8,
  41. unpack_fixed8,
  42. unpack_fixed16,
  43. unpack_float16,
  44. unpack_float,
  45. unpack_double,
  46. )
  47. VERSION = "0.9.3"
  48. # name of each tag (as a dict, not a list, for easier human consumption)
  49. TAG_NAMES = {
  50. 0: "End",
  51. 1: "ShowFrame",
  52. 2: "DefineShape",
  53. 4: "PlaceObject",
  54. 5: "RemoveObject",
  55. 6: "DefineBits",
  56. 7: "DefineButton",
  57. 8: "JPEGTables",
  58. 9: "SetBackgroundColor",
  59. 10: "DefineFont",
  60. 11: "DefineText",
  61. 12: "DoAction",
  62. 13: "DefineFontInfo",
  63. 14: "DefineSound",
  64. 15: "StartSound",
  65. 17: "DefineButtonSound",
  66. 18: "SoundStreamHead",
  67. 19: "SoundStreamBlock",
  68. 20: "DefineBitsLossless",
  69. 21: "DefineBitsJPEG2",
  70. 22: "DefineShape2",
  71. 23: "DefineButtonCxform",
  72. 24: "Protect",
  73. 26: "PlaceObject2",
  74. 28: "RemoveObject2",
  75. 32: "DefineShape3",
  76. 33: "DefineText2",
  77. 34: "DefineButton2",
  78. 35: "DefineBitsJPEG3",
  79. 36: "DefineBitsLossless2",
  80. 37: "DefineEditText",
  81. 39: "DefineSprite",
  82. 43: "FrameLabel",
  83. 45: "SoundStreamHead2",
  84. 46: "DefineMorphShape",
  85. 48: "DefineFont2",
  86. 56: "ExportAssets",
  87. 57: "ImportAssets",
  88. 58: "EnableDebugger",
  89. 59: "DoInitAction",
  90. 60: "DefineVideoStream",
  91. 61: "VideoFrame",
  92. 62: "DefineFontInfo2",
  93. 64: "EnableDebugger2",
  94. 65: "ScriptLimits",
  95. 66: "SetTabIndex",
  96. 69: "FileAttributes",
  97. 70: "PlaceObject3",
  98. 71: "ImportAssets2",
  99. 73: "DefineFontAlignZones",
  100. 74: "CSMTextSettings",
  101. 75: "DefineFont3",
  102. 76: "SymbolClass",
  103. 77: "Metadata",
  104. 78: "DefineScalingGrid",
  105. 82: "DoABC",
  106. 83: "DefineShape4",
  107. 84: "DefineMorphShape2",
  108. 86: "DefineSceneAndFrameLabelData",
  109. 87: "DefineBinaryData",
  110. 88: "DefineFontName",
  111. 89: "StartSound2",
  112. 90: "DefineBitsJPEG4",
  113. 91: "DefineFont4",
  114. }
  115. LANGCODES = {
  116. 0: "Sys",
  117. 1: "Latin",
  118. 2: "Japanese",
  119. 3: "Korean",
  120. 4: "Simplified Chinese",
  121. 5: "Traditional Chinese",
  122. }
  123. ACTION_NAMES = {
  124. 0x04: 'ActionNextFrame',
  125. 0x05: 'ActionPrevFrame',
  126. 0x06: 'ActionPlay',
  127. 0x07: 'ActionStop',
  128. 0x08: 'ActionToggleQualty',
  129. 0x09: 'ActionStopSounds',
  130. 0x0A: 'ActionAdd',
  131. 0x0B: 'ActionSubtract',
  132. 0x0C: 'ActionMultiply',
  133. 0x0D: 'ActionDivide',
  134. 0x0E: 'ActionEquals',
  135. 0x0F: 'ActionLess',
  136. 0x10: 'ActionAnd',
  137. 0x11: 'ActionOr',
  138. 0x12: 'ActionNot',
  139. 0x13: 'ActionStringEquals',
  140. 0x14: 'ActionStringLength',
  141. 0x15: 'ActionStringExtract',
  142. 0x17: 'ActionPop',
  143. 0x18: 'ActionToInteger',
  144. 0x1C: 'ActionGetVariable',
  145. 0x1D: 'ActionSetVariable',
  146. 0x20: 'ActionSetTarget2',
  147. 0x21: 'ActionStringAdd',
  148. 0x22: 'ActionGetProperty',
  149. 0x23: 'ActionSetProperty',
  150. 0x24: 'ActionCloneSprite',
  151. 0x25: 'ActionRemoveSprite',
  152. 0x26: 'ActionTrace',
  153. 0x27: 'ActionStartDrag',
  154. 0x28: 'ActionEndDrag',
  155. 0x29: 'ActionStringLess',
  156. 0x2A: 'ActionThrow',
  157. 0x2B: 'ActionCastOp',
  158. 0x2C: 'ActionImplementsOp',
  159. 0x30: 'ActionRandomNumber',
  160. 0x31: 'ActionMBStringLength',
  161. 0x32: 'ActionCharToAscii',
  162. 0x33: 'ActionAsciiToChar',
  163. 0x34: 'ActionGetTime',
  164. 0x35: 'ActionMBStringExtract',
  165. 0x36: 'ActionMBCharToAscii',
  166. 0x37: 'ActionMBAsciiToChar',
  167. 0x3A: 'ActionDelete',
  168. 0x3B: 'ActionDelete2',
  169. 0x3C: 'ActionDefineLocal',
  170. 0x3D: 'ActionCallFunction',
  171. 0x3E: 'ActionReturn',
  172. 0x3F: 'ActionModulo',
  173. 0x40: 'ActionNewObject',
  174. 0x41: 'ActionDefineLocal2',
  175. 0x42: 'ActionInitArray',
  176. 0x43: 'ActionInitObject',
  177. 0x44: 'ActionTypeOf',
  178. 0x45: 'ActionTargetPath',
  179. 0x46: 'ActionEnumerate',
  180. 0x47: 'ActionAdd2',
  181. 0x48: 'ActionLess2',
  182. 0x49: 'ActionEquals2',
  183. 0x4A: 'ActionToNumber',
  184. 0x4B: 'ActionToString',
  185. 0x4C: 'ActionPushDuplicate',
  186. 0x4D: 'ActionStackSwap',
  187. 0x4E: 'ActionGetMember',
  188. 0x4F: 'ActionSetMember',
  189. 0x50: 'ActionIncrement',
  190. 0x51: 'ActionDecrement',
  191. 0x52: 'ActionCallMethod',
  192. 0x53: 'ActionNewMethod',
  193. 0x54: 'ActionInstanceOf',
  194. 0x55: 'ActionEnumerate2',
  195. 0x60: 'ActionBitAnd',
  196. 0x61: 'ActionBitOr',
  197. 0x62: 'ActionBitXor',
  198. 0x63: 'ActionBitLShift',
  199. 0x64: 'ActionBitRShift',
  200. 0x65: 'ActionBitURShift',
  201. 0x66: 'ActionStrictEquals',
  202. 0x67: 'ActionGreater',
  203. 0x68: 'ActionStringGreater',
  204. 0x69: 'ActionExtends',
  205. 0x81: 'ActionGotoFrame',
  206. 0x83: 'ActionGetURL',
  207. 0x87: 'ActionStoreRegister',
  208. 0x88: 'ActionConstantPool',
  209. 0x8A: 'ActionWaitForFrame',
  210. 0x8B: 'ActionSetTarget',
  211. 0x8C: 'ActionGoToLabel',
  212. 0x8D: 'ActionWaitForFrame2',
  213. 0x8E: 'ActionDefineFunction2',
  214. 0x8F: 'ActionTry',
  215. 0x94: 'ActionWith',
  216. 0x96: 'ActionPush',
  217. 0x99: 'ActionJump',
  218. 0x9A: 'ActionGetURL2',
  219. 0x9B: 'ActionDefineFunction',
  220. 0x9D: 'ActionIf',
  221. 0x9E: 'ActionCall',
  222. 0x9F: 'ActionGotoFrame2',
  223. }
  224. def _str(obj):
  225. """Show nicely the generic object received."""
  226. values = []
  227. for name in obj._attribs:
  228. val = getattr(obj, name)
  229. if isinstance(val, str):
  230. val = repr(val)
  231. val = str(val) if len(str(val)) < 10 else "(...)"
  232. values.append((name, val))
  233. values = ", ".join("{}={}".format(k, v) for k, v in values)
  234. return "{}({})".format(obj.__class__.__name__, values)
  235. def _repr(obj):
  236. """Show the received object as precise as possible."""
  237. vals = ", ".join("{}={!r}".format(
  238. name, getattr(obj, name)) for name in obj._attribs)
  239. if vals:
  240. t = "{}(name={}, {})".format(obj.__class__.__name__, obj.name, vals)
  241. else:
  242. t = "{}(name={})".format(obj.__class__.__name__, obj.name)
  243. return t
  244. class SWFObject:
  245. """A super class for all the objects created here."""
  246. def __init__(self):
  247. self._attribs = []
  248. def __setattr__(self, name, value):
  249. if name != "_attribs":
  250. if name not in self._attribs:
  251. self._attribs.append(name)
  252. super(SWFObject, self).__setattr__(name, value)
  253. def _make_object(name):
  254. """Create a generic object for the tags."""
  255. klass = type(name, (SWFObject,),
  256. {'__str__': _str, '__repr__': _repr, 'name': name})
  257. return klass()
  258. class SWFParser:
  259. """Read (at a byte or bit level) the SWF structure from a fileobject.
  260. When the parser finds a structure that still can't process (because more
  261. programming is needed), will just return an UnknownObject object with
  262. the unparsed bytes, or will raise an exception if you set
  263. the unknown_alert flag::
  264. SWFParser.unknown_alert = True
  265. """
  266. unknown_alert = False
  267. def __init__(self, src, read_twips=True):
  268. self._src = src
  269. self._read_twips = read_twips
  270. self._version = None
  271. self._last_defined_glyphs_quantity = None
  272. self.header = self._get_header()
  273. self.tags = self._process_tags()
  274. def _get_header(self):
  275. """Parse the SWF header."""
  276. fh = self._src
  277. obj = _make_object("Header")
  278. # first part of the header
  279. obj.Signature = sign = "".join(chr(unpack_ui8(fh)) for _ in range(3))
  280. obj.Version = self._version = unpack_ui8(fh)
  281. obj.FileLength = file_length = unpack_ui32(fh)
  282. # deal with compressed content
  283. if sign[0] == 'C':
  284. uncompressed = zlib.decompress(fh.read())
  285. if len(uncompressed) + 8 != file_length:
  286. raise ValueError("Problems dealing with compressed content")
  287. fh = self._src = io.BytesIO(uncompressed)
  288. # second part of the header
  289. obj.FrameSize = self._get_struct_rect()
  290. obj.FrameRate = unpack_ui16(fh)
  291. obj.FrameCount = unpack_ui16(fh)
  292. return obj
  293. def _process_tags(self):
  294. """Get a sequence of tags."""
  295. tags = []
  296. while True:
  297. tag_bf = unpack_ui16(self._src)
  298. tag_type = tag_bf >> 6 # upper 10 bits
  299. if tag_type == 0:
  300. # the end
  301. break
  302. tag_len = tag_bf & 0x3f # last 6 bits
  303. if tag_len == 0x3f:
  304. # the length is the next four bytes!
  305. tag_len = unpack_ui32(self._src)
  306. try:
  307. tag_name = TAG_NAMES[tag_type]
  308. except KeyError:
  309. warnings.warn('unkonwn tag type: {}'.format(tag_type))
  310. # malformed SWF, create and unknown object with malformed tag
  311. tag_payload = self._src.read(tag_len)
  312. _dict = {
  313. '__str__': _repr,
  314. '__repr__': _repr,
  315. 'name': 'UnspecifiedObject(tag={!r})'.format(tag_type),
  316. }
  317. tag = type("UnknownObject", (SWFObject,), _dict)()
  318. tag.raw_payload = tag_payload
  319. tags.append(tag)
  320. continue
  321. try:
  322. tag_meth = getattr(self, "_handle_tag_" + tag_name.lower())
  323. except AttributeError:
  324. if self.unknown_alert:
  325. raise ValueError("Unknown tag: " + repr(tag_name))
  326. warnings.warn('tag not supported: {}'.format(tag_name))
  327. tag_payload = self._src.read(tag_len)
  328. _dict = {'__str__': _repr, '__repr__': _repr, 'name': tag_name}
  329. tag = type("UnknownObject", (SWFObject,), _dict)()
  330. tag.raw_payload = tag_payload
  331. tags.append(tag)
  332. continue
  333. # we know the tag type, and have the handler, let's process it
  334. prev_pos = self._src.tell()
  335. self._src.guard = tag_len
  336. try:
  337. with ReadQuantityController(self._src, tag_len):
  338. tag = tag_meth()
  339. assert tag is not None, tag_name
  340. except ValueError as e:
  341. warnings.warn('processing {} tag: {}'.format(tag_name, e))
  342. # an attempt to read too much happened; create a failing
  343. # object with the raw payload
  344. self._src.guard = None
  345. self._src.seek(prev_pos)
  346. tag_payload = self._src.read(tag_len)
  347. _dict = {'__str__': _repr, '__repr__': _repr, 'name': tag_name}
  348. tag = type("FailingObject", (SWFObject,), _dict)()
  349. tag.raw_payload = tag_payload
  350. tags.append(tag)
  351. return tags
  352. def _handle_tag_definebits(self):
  353. """Handle the DefineBits tag."""
  354. tag_end = self._src.tell() + self._src.guard
  355. obj = _make_object("DefineBits")
  356. obj.CharacterID = unpack_ui16(self._src)
  357. obj.JPEGData = self._get_raw_bytes(-tag_end)
  358. return obj
  359. def _handle_tag_definebitsjpeg2(self):
  360. """Handle the DefineBitsJPEG2 tag."""
  361. tag_end = self._src.tell() + self._src.guard
  362. obj = _make_object("DefineBitsJPEG2")
  363. obj.CharacterID = unpack_ui16(self._src)
  364. obj.ImageData = self._get_raw_bytes(-tag_end)
  365. return obj
  366. def _generic_definebitsjpeg_parser(self, obj, version):
  367. """Handle the DefineBitsJPEGN tag."""
  368. tag_end = self._src.tell() + self._src.guard
  369. obj.CharacterID = unpack_ui16(self._src)
  370. obj.AlphaDataOffset = unpack_ui32(self._src)
  371. if 4 == version:
  372. # FIXME: 8.8 fixed point format in Comment
  373. obj.DeblockParam = unpack_ui16(self._src)
  374. obj.ImageData = self._get_raw_bytes(obj.AlphaDataOffset)
  375. obj.BitmapAlphaData = self._get_raw_bytes(-tag_end, unzip=True)
  376. def _handle_tag_definebitsjpeg3(self):
  377. """Handle the DefineBitsJPEG3 tag."""
  378. obj = _make_object("DefineBitsJPEG3")
  379. self._generic_definebitsjpeg_parser(obj, 3)
  380. return obj
  381. def _handle_tag_definebitsjpeg4(self):
  382. """Handle the DefineBitsJPEG4 tag."""
  383. obj = _make_object("DefineBitsJPEG4")
  384. self._generic_definebitsjpeg_parser(obj, 4)
  385. return obj
  386. def _generic_definebitslossless_parser(self, obj, version):
  387. """Generic parser for the DefineBitsLosslessN tags."""
  388. tag_end = self._src.tell() + self._src.guard
  389. obj.CharacterID = unpack_ui16(self._src)
  390. obj.BitmapFormat = unpack_ui8(self._src)
  391. obj.BitmapWidth = unpack_ui16(self._src)
  392. obj.BitmapHeight = unpack_ui16(self._src)
  393. if 3 == obj.BitmapFormat:
  394. obj.BitmapColorTableSize = unpack_ui8(self._src)
  395. BitmapData = self._get_raw_bytes(-tag_end, unzip=True)
  396. _src = self._src
  397. try:
  398. self._src = io.BytesIO(BitmapData)
  399. if 3 == obj.BitmapFormat:
  400. if 1 == version:
  401. color = self._get_struct_rgb
  402. elif 2 == version:
  403. color = self._get_struct_rgba
  404. else:
  405. raise ValueError("unknown version: {}".format(version))
  406. obj.ColorTableRGB = [
  407. color() for _ in range(obj.BitmapColorTableSize + 1)]
  408. obj.ColormapPixelData = self._get_raw_bytes(-len(BitmapData))
  409. elif obj.BitmapFormat in (4, 5):
  410. obj.BitmapPixelData = BitmapData
  411. else:
  412. raise ValueError("BitmapFormat: {}".format(obj.BitmapFormat))
  413. finally:
  414. self._src = _src
  415. def _handle_tag_definebitslossless(self):
  416. """Handle the DefineBitsLossless tag."""
  417. obj = _make_object("DefineBitsLossless")
  418. self._generic_definebitslossless_parser(obj, 1)
  419. return obj
  420. def _handle_tag_definebitslossless2(self):
  421. """Handle the DefineBitsLossless2 tag."""
  422. obj = _make_object("DefineBitsLossless2")
  423. self._generic_definebitslossless_parser(obj, 2)
  424. return obj
  425. def _generic_definetext_parser(self, obj, rgb_struct):
  426. """Generic parser for the DefineTextN tags."""
  427. obj.CharacterID = unpack_ui16(self._src)
  428. obj.TextBounds = self._get_struct_rect()
  429. obj.TextMatrix = self._get_struct_matrix()
  430. obj.GlyphBits = glyph_bits = unpack_ui8(self._src)
  431. obj.AdvanceBits = advance_bits = unpack_ui8(self._src)
  432. # textrecords
  433. obj.TextRecords = records = []
  434. while True:
  435. endofrecords_flag = unpack_ui8(self._src)
  436. if endofrecords_flag == 0:
  437. # all done
  438. obj.EndOfRecordsFlag = 0
  439. break
  440. # we have a TEXTRECORD, let's go back the 8 bits and set the obj
  441. self._src.seek(-1, io.SEEK_CUR)
  442. record = _make_object("TextRecord")
  443. records.append(record)
  444. bc = BitConsumer(self._src)
  445. record.TextRecordType = bc.u_get(1)
  446. record.StyleFlagsReserved = bc.u_get(3)
  447. record.StyleFlagsHasFont = bc.u_get(1)
  448. record.StyleFlagsHasColor = bc.u_get(1)
  449. record.StyleFlagsHasYOffset = bc.u_get(1)
  450. record.StyleFlagsHasXOffset = bc.u_get(1)
  451. if record.StyleFlagsHasFont:
  452. record.FontID = unpack_ui16(self._src)
  453. if record.StyleFlagsHasColor:
  454. record.TextColor = rgb_struct()
  455. if record.StyleFlagsHasXOffset:
  456. record.XOffset = unpack_si16(self._src)
  457. if record.StyleFlagsHasYOffset:
  458. record.YOffset = unpack_si16(self._src)
  459. if record.StyleFlagsHasFont:
  460. record.TextHeight = unpack_ui16(self._src)
  461. record.GlyphCount = unpack_ui8(self._src)
  462. bc = BitConsumer(self._src)
  463. record.GlyphEntries = glyphs = []
  464. for _ in range(record.GlyphCount):
  465. glyph = _make_object("GlyphEntry")
  466. glyphs.append(glyph)
  467. glyph.GlyphIndex = bc.u_get(glyph_bits)
  468. glyph.GlyphAdvance = bc.u_get(advance_bits)
  469. def _handle_tag_definetext(self):
  470. """Handle the DefineText tag."""
  471. obj = _make_object("DefineText")
  472. self._generic_definetext_parser(obj, self._get_struct_rgb)
  473. return obj
  474. def _handle_tag_definetext2(self):
  475. """Handle the DefineText2 tag."""
  476. obj = _make_object("DefineText2")
  477. self._generic_definetext_parser(obj, self._get_struct_rgba)
  478. return obj
  479. def _handle_tag_defineedittext(self):
  480. """Handle the DefineEditText tag."""
  481. obj = _make_object("DefineEditText")
  482. obj.CharacterID = unpack_ui16(self._src)
  483. obj.Bounds = self._get_struct_rect()
  484. bc = BitConsumer(self._src)
  485. obj.HasText = bc.u_get(1)
  486. obj.WordWrap = bc.u_get(1)
  487. obj.Multiline = bc.u_get(1)
  488. obj.Password = bc.u_get(1)
  489. obj.ReadOnly = bc.u_get(1)
  490. obj.HasTextColor = bc.u_get(1)
  491. obj.HasMaxLength = bc.u_get(1)
  492. obj.HasFont = bc.u_get(1)
  493. obj.HasFontClass = bc.u_get(1)
  494. obj.AutoSize = bc.u_get(1)
  495. obj.HasLayout = bc.u_get(1)
  496. obj.NoSelect = bc.u_get(1)
  497. obj.Border = bc.u_get(1)
  498. obj.WasStatic = bc.u_get(1)
  499. obj.HTML = bc.u_get(1)
  500. obj.UseOutlines = bc.u_get(1)
  501. if obj.HasFont:
  502. obj.FontID = unpack_ui16(self._src)
  503. if obj.HasFontClass:
  504. obj.FontClass = self._get_struct_string()
  505. if obj.HasFont:
  506. obj.FontHeight = unpack_ui16(self._src)
  507. if obj.HasTextColor:
  508. obj.TextColor = self._get_struct_rgba()
  509. if obj.HasMaxLength:
  510. obj.MaxLength = unpack_ui16(self._src)
  511. if obj.HasLayout:
  512. obj.Align = unpack_ui8(self._src)
  513. obj.LeftMargin = unpack_ui16(self._src)
  514. obj.RightMargin = unpack_ui16(self._src)
  515. obj.Indent = unpack_ui16(self._src)
  516. obj.Leading = unpack_ui16(self._src)
  517. obj.VariableName = self._get_struct_string()
  518. if obj.HasText:
  519. obj.InitialText = self._get_struct_string()
  520. return obj
  521. def _generic_placeobject_parser(self, obj, version):
  522. """A generic parser for several PlaceObjectX."""
  523. bc = BitConsumer(self._src)
  524. obj.PlaceFlagHasClipActions = bc.u_get(1)
  525. obj.PlaceFlagHasClipDepth = bc.u_get(1)
  526. obj.PlaceFlagHasName = bc.u_get(1)
  527. obj.PlaceFlagHasRatio = bc.u_get(1)
  528. obj.PlaceFlagHasColorTransform = bc.u_get(1)
  529. obj.PlaceFlagHasMatrix = bc.u_get(1)
  530. obj.PlaceFlagHasCharacter = bc.u_get(1)
  531. obj.PlaceFlagMove = bc.u_get(1)
  532. if version == 3:
  533. obj.Reserved = bc.u_get(1)
  534. obj.PlaceFlagOpaqueBackground = bc.u_get(1)
  535. obj.PlaceFlagHasVisible = bc.u_get(1)
  536. obj.PlaceFlagHasImage = bc.u_get(1)
  537. obj.PlaceFlagHasClassName = bc.u_get(1)
  538. obj.PlaceFlagHasCacheAsBitmap = bc.u_get(1)
  539. obj.PlaceFlagHasBlendMode = bc.u_get(1)
  540. obj.PlaceFlagHasFilterList = bc.u_get(1)
  541. obj.Depth = unpack_ui16(self._src)
  542. if version == 3:
  543. if obj.PlaceFlagHasClassName or (
  544. obj.PlaceFlagHasImage and obj.PlaceFlagHasCharacter):
  545. obj.ClassName = self._get_struct_string()
  546. if obj.PlaceFlagHasCharacter:
  547. obj.CharacterId = unpack_ui16(self._src)
  548. if obj.PlaceFlagHasMatrix:
  549. obj.Matrix = self._get_struct_matrix()
  550. if obj.PlaceFlagHasColorTransform:
  551. obj.ColorTransform = self._get_struct_cxformwithalpha()
  552. if obj.PlaceFlagHasRatio:
  553. obj.Ratio = unpack_ui16(self._src)
  554. if obj.PlaceFlagHasName:
  555. obj.Name = self._get_struct_string()
  556. if obj.PlaceFlagHasClipDepth:
  557. obj.ClipDepth = unpack_ui16(self._src)
  558. if version == 3:
  559. if obj.PlaceFlagHasFilterList:
  560. obj.SurfaceFilterList = self._get_struct_filterlist()
  561. if obj.PlaceFlagHasBlendMode:
  562. obj.BlendMode = unpack_ui8(self._src)
  563. if obj.PlaceFlagHasCacheAsBitmap:
  564. obj.BitmapCache = unpack_ui8(self._src)
  565. if obj.PlaceFlagHasVisible:
  566. obj.Visible = unpack_ui8(self._src)
  567. obj.BackgroundColor = self._get_struct_rgba()
  568. if obj.PlaceFlagHasClipActions:
  569. obj.ClipActions = self._get_struct_clipactions()
  570. def _handle_tag_placeobject2(self):
  571. """Handle the PlaceObject2 tag."""
  572. obj = _make_object("PlaceObject2")
  573. self._generic_placeobject_parser(obj, 2)
  574. return obj
  575. def _handle_tag_placeobject3(self):
  576. """Handle the PlaceObject3 tag."""
  577. obj = _make_object("PlaceObject3")
  578. self._generic_placeobject_parser(obj, 3)
  579. return obj
  580. def _handle_tag_definesprite(self):
  581. """Handle the DefineSprite tag."""
  582. obj = _make_object("DefineSprite")
  583. obj.CharacterID = unpack_ui16(self._src)
  584. obj.FrameCount = unpack_ui16(self._src)
  585. tags = self._process_tags()
  586. obj.ControlTags = tags
  587. return obj
  588. def _generic_action_parser(self):
  589. """Generic parser for Actions."""
  590. actions = []
  591. while True:
  592. action_code = unpack_ui8(self._src)
  593. if action_code == 0:
  594. break
  595. action_name = ACTION_NAMES[action_code]
  596. if action_code > 128:
  597. # have a payload!
  598. action_len = unpack_ui16(self._src)
  599. try:
  600. action_meth = getattr(
  601. self, "_handle_" + action_name.lower())
  602. except AttributeError:
  603. if self.unknown_alert:
  604. raise ValueError(
  605. "Unknown action: " + repr(action_name))
  606. action_payload = self._src.read(action_len)
  607. _dict = {'__str__': _repr, '__repr__': _repr,
  608. 'name': action_name}
  609. action = type("UnknownAction", (SWFObject,), _dict)()
  610. action.raw_payload = action_payload
  611. actions.append(action)
  612. else:
  613. prev_pos = self._src.tell()
  614. for action in action_meth(action_len):
  615. assert action is not None, action_name
  616. actions.append(action)
  617. quant_read = self._src.tell() - prev_pos
  618. if quant_read != action_len:
  619. raise RuntimeError(
  620. "Bad bytes consumption by action {!r} handler "
  621. "(did {}, should {})".format(
  622. action_name, quant_read, action_len))
  623. else:
  624. action = _make_object(action_name)
  625. actions.append(action)
  626. return actions
  627. def _handle_tag_doaction(self):
  628. """Handle the DoAction tag."""
  629. obj = _make_object("DoAction")
  630. obj.Actions = self._generic_action_parser()
  631. return obj
  632. def _handle_tag_fileattributes(self):
  633. """Handle the FileAttributes tag."""
  634. obj = _make_object("FileAttributes")
  635. bc = BitConsumer(self._src)
  636. bc.u_get(1) # reserved
  637. obj.UseDirectBlit = bc.u_get(1)
  638. obj.UseGPU = bc.u_get(1)
  639. obj.HasMetadata = bc.u_get(1)
  640. obj.ActionScript3 = bc.u_get(1)
  641. bc.u_get(2) # reserved
  642. obj.UseNetwork = bc.u_get(1)
  643. bc.u_get(24) # reserved
  644. return obj
  645. def _handle_tag_metadata(self):
  646. """Handle the Metadata tag."""
  647. obj = _make_object("Metadata")
  648. obj.Metadata = self._get_struct_string()
  649. return obj
  650. def _handle_tag_setbackgroundcolor(self):
  651. """Handle the SetBackgroundColor tag."""
  652. obj = _make_object("SetBackgroundColor")
  653. obj.BackgroundColor = self._get_struct_rgb()
  654. return obj
  655. def _handle_tag_definesceneandframelabeldata(self):
  656. """Handle the DefineSceneAndFrameLabelData tag."""
  657. obj = _make_object("DefineSceneAndFrameLabelData")
  658. obj.SceneCount = self._get_struct_encodedu32()
  659. for i in range(1, obj.SceneCount + 1):
  660. setattr(obj, 'Offset{}'.format(i), self._get_struct_encodedu32())
  661. setattr(obj, 'Name{}'.format(i), self._get_struct_string())
  662. obj.FrameLabelCount = self._get_struct_encodedu32()
  663. for i in range(1, obj.FrameLabelCount + 1):
  664. setattr(obj, 'FrameNum{}'.format(i), self._get_struct_encodedu32())
  665. setattr(obj, 'FrameLabel{}'.format(i), self._get_struct_string())
  666. return obj
  667. def _handle_tag_defineshape4(self):
  668. """Handle the DefineShape4 tag."""
  669. obj = _make_object("DefineShape4")
  670. obj.ShapeId = unpack_ui16(self._src)
  671. obj.ShapeBounds = self._get_struct_rect()
  672. obj.EdgeBounds = self._get_struct_rect()
  673. bc = BitConsumer(self._src)
  674. bc.u_get(5) # reserved
  675. obj.UsesFillWindingRule = bc.u_get(1)
  676. obj.UsesNonScalingStrokes = bc.u_get(1)
  677. obj.UsesScalingStrokes = bc.u_get(1)
  678. obj.Shapes = self._get_struct_shapewithstyle(4)
  679. return obj
  680. def _handle_tag_definemorphshape2(self):
  681. """Handle the DefineMorphShape2 tag."""
  682. obj = _make_object("DefineMorphShape2")
  683. obj.CharacterId = unpack_ui16(self._src)
  684. obj.StartBounds = self._get_struct_rect()
  685. obj.EndBounds = self._get_struct_rect()
  686. obj.StartEdgeBounds = self._get_struct_rect()
  687. obj.EndEdgeBounds = self._get_struct_rect()
  688. bc = BitConsumer(self._src)
  689. bc.u_get(6) # reserved
  690. obj.UsesNonScalingStrokes = bc.u_get(1)
  691. obj.UsesScalingStrokes = bc.u_get(1)
  692. obj.Offset = unpack_ui32(self._src)
  693. # FIXME: this tag needs more work; I'm skipping some attributes here
  694. self._src.read(obj.Offset)
  695. obj.EndEdges = self._get_struct_shape()
  696. return obj
  697. def _handle_tag_showframe(self):
  698. """Handle the ShowFrame tag."""
  699. return _make_object("ShowFrame")
  700. def _handle_tag_removeobject(self):
  701. """Handle the RemoveObject tag."""
  702. obj = _make_object("RemoveObject")
  703. obj.CharacterId = unpack_ui16(self._src)
  704. obj.Depth = unpack_ui16(self._src)
  705. return obj
  706. def _handle_tag_removeobject2(self):
  707. """Handle the RemoveObject2 tag."""
  708. obj = _make_object("RemoveObject2")
  709. obj.Depth = unpack_ui16(self._src)
  710. return obj
  711. def _handle_tag_defineshape(self):
  712. """Handle the DefineShape tag."""
  713. obj = _make_object("DefineShape")
  714. obj.ShapeId = unpack_ui16(self._src)
  715. obj.ShapeBounds = self._get_struct_rect()
  716. obj.Shapes = self._get_struct_shapewithstyle(1)
  717. return obj
  718. def _handle_tag_defineshape2(self):
  719. """Handle the DefineShape2 tag."""
  720. obj = _make_object("DefineShape2")
  721. obj.ShapeId = unpack_ui16(self._src)
  722. obj.ShapeBounds = self._get_struct_rect()
  723. obj.Shapes = self._get_struct_shapewithstyle(2)
  724. return obj
  725. def _handle_tag_defineshape3(self):
  726. """Handle the DefineShape3 tag."""
  727. obj = _make_object("DefineShape3")
  728. obj.ShapeId = unpack_ui16(self._src)
  729. obj.ShapeBounds = self._get_struct_rect()
  730. obj.Shapes = self._get_struct_shapewithstyle(3)
  731. return obj
  732. def _generic_definefont_parser(self, obj):
  733. """A generic parser for several DefineFontX."""
  734. obj.FontID = unpack_ui16(self._src)
  735. bc = BitConsumer(self._src)
  736. obj.FontFlagsHasLayout = bc.u_get(1)
  737. obj.FontFlagsShiftJIS = bc.u_get(1)
  738. obj.FontFlagsSmallText = bc.u_get(1)
  739. obj.FontFlagsANSI = bc.u_get(1)
  740. obj.FontFlagsWideOffsets = bc.u_get(1)
  741. obj.FontFlagsWideCodes = bc.u_get(1)
  742. obj.FontFlagsItalic = bc.u_get(1)
  743. obj.FontFlagsBold = bc.u_get(1)
  744. obj.LanguageCode = self._get_struct_langcode()
  745. obj.FontNameLen = unpack_ui8(self._src)
  746. obj.FontName = "".join(chr(unpack_ui8(self._src))
  747. for i in range(obj.FontNameLen))
  748. if obj.FontName[-1] == '\x00': # most probably ends in null, clean it
  749. obj.FontName = obj.FontName[:-1]
  750. obj.NumGlyphs = num_glyphs = unpack_ui16(self._src)
  751. self._last_defined_glyphs_quantity = num_glyphs
  752. getter_wide = unpack_ui32 if obj.FontFlagsWideOffsets else unpack_ui16
  753. obj.OffsetTable = [getter_wide(self._src) for _ in range(num_glyphs)]
  754. obj.CodeTableOffset = getter_wide(self._src)
  755. obj.GlyphShapeTable = [self._get_struct_shape()
  756. for _ in range(num_glyphs)]
  757. obj.CodeTable = [unpack_ui16(self._src) for _ in range(num_glyphs)]
  758. if obj.FontFlagsHasLayout:
  759. obj.FontAscent = unpack_ui16(self._src)
  760. obj.FontDecent = unpack_ui16(self._src)
  761. obj.FontLeading = unpack_ui16(self._src)
  762. obj.FontAdvanceTable = [unpack_si16(self._src)
  763. for _ in range(num_glyphs)]
  764. obj.FontBoundsTable = [self._get_struct_rect()
  765. for _ in range(num_glyphs)]
  766. obj.KerningCount = unpack_ui16(self._src)
  767. obj.FontKerningTable = [
  768. self._get_struct_kerningrecord(obj.FontFlagsWideCodes)
  769. for _ in range(obj.KerningCount)]
  770. def _handle_tag_definefont2(self):
  771. """Handle the DefineFont2 tag."""
  772. obj = _make_object("DefineFont2")
  773. self._generic_definefont_parser(obj)
  774. return obj
  775. def _handle_tag_definefont3(self):
  776. """Handle the DefineFont3 tag."""
  777. obj = _make_object("DefineFont3")
  778. self._generic_definefont_parser(obj)
  779. return obj
  780. def _handle_tag_definebutton2(self):
  781. """Handle the DefineButton2 tag."""
  782. obj = _make_object("DefineButton2")
  783. obj.ButtonId = unpack_ui16(self._src)
  784. bc = BitConsumer(self._src)
  785. bc.ReservedFlags = bc.u_get(7)
  786. bc.TrackAsMenu = bc.u_get(1)
  787. obj.ActionOffset = unpack_ui16(self._src)
  788. # characters
  789. obj.Characters = characters = []
  790. while True:
  791. end_flag = unpack_ui8(self._src)
  792. if end_flag == 0:
  793. # all done
  794. obj.CharacterEndFlag = 0
  795. break
  796. # we have a BUTTONRECORD, let's go back the 8 bits and set the obj
  797. self._src.seek(-1, io.SEEK_CUR)
  798. character = _make_object("ButtonRecord")
  799. characters.append(character)
  800. bc = BitConsumer(self._src)
  801. character.ButtonReserved = bc.u_get(2)
  802. character.ButtonHasBlendMode = bc.u_get(1)
  803. character.ButtonHasFilterList = bc.u_get(1)
  804. character.ButtonStateHitTest = bc.u_get(1)
  805. character.ButtonStateDown = bc.u_get(1)
  806. character.ButtonStateOver = bc.u_get(1)
  807. character.ButtonStateUp = bc.u_get(1)
  808. character.CharacterId = unpack_ui16(self._src)
  809. character.PlaceDepth = unpack_ui16(self._src)
  810. character.PlaceMatrix = self._get_struct_matrix()
  811. character.ColorTransform = self._get_struct_cxformwithalpha()
  812. if character.ButtonHasFilterList:
  813. character.FilterList = self._get_struct_filterlist()
  814. if character.ButtonHasBlendMode:
  815. character.BlendMode = unpack_ui8(self._src)
  816. obj.Actions = actions = []
  817. still_have_actions = True
  818. while still_have_actions:
  819. end_flag = unpack_ui16(self._src)
  820. if end_flag == 0:
  821. # this is the last action, parse it and then exit
  822. still_have_actions = False
  823. bca = _make_object("ButtonCondAction")
  824. actions.append(bca)
  825. bca.CondActionSize = end_flag
  826. bc = BitConsumer(self._src)
  827. bca.CondIdleToOverDown = bc.u_get(1)
  828. bca.CondOutDownToIdle = bc.u_get(1)
  829. bca.CondOutDownToOverDown = bc.u_get(1)
  830. bca.CondOverDownToOutDown = bc.u_get(1)
  831. bca.CondOverDownToOverUp = bc.u_get(1)
  832. bca.CondOverUpToOverDown = bc.u_get(1)
  833. bca.CondOverUpToIdle = bc.u_get(1)
  834. bca.CondIdleToOverUp = bc.u_get(1)
  835. bca.CondKeyPress = bc.u_get(7)
  836. bca.CondOverDownToIdle = bc.u_get(1)
  837. bca.Actions = self._generic_action_parser()
  838. return obj
  839. def _handle_tag_enabledebugger2(self):
  840. """Handle the EnableDebugger2 tag."""
  841. obj = _make_object("EnableDebugger2")
  842. obj.Reserved = unpack_ui16(self._src)
  843. obj.Password = self._get_struct_string()
  844. return obj
  845. def _handle_tag_scriptlimits(self):
  846. """Handle the ScriptLimits tag."""
  847. obj = _make_object("ScriptLimits")
  848. obj.MaxRecursionDepth = unpack_ui16(self._src)
  849. obj.ScriptTimeoutSeconds = unpack_ui16(self._src)
  850. return obj
  851. def _handle_tag_framelabel(self):
  852. """Handle the FrameLabel tag."""
  853. obj = _make_object("FrameLabel")
  854. obj.Name = self._get_struct_string()
  855. return obj
  856. def _handle_tag_jpegtables(self):
  857. """Handle the JPEGTables tag."""
  858. obj = _make_object("JPEGTables")
  859. assert self._src.read(2) == b'\xFF\xD8' # SOI marker
  860. eoimark1 = eoimark2 = None
  861. allbytes = [b'\xFF\xD8']
  862. while not (eoimark1 == b'\xFF' and eoimark2 == b'\xD9'):
  863. newbyte = self._src.read(1)
  864. allbytes.append(newbyte)
  865. eoimark1 = eoimark2
  866. eoimark2 = newbyte
  867. # concatenate everything, removing the end mark
  868. obj.JPEGData = b"".join(allbytes[:-2])
  869. return obj
  870. def _handle_tag_definefontalignzones(self):
  871. """Handle the DefineFontAlignZones tag."""
  872. obj = _make_object("DefineFontAlignZones")
  873. obj.FontId = unpack_ui16(self._src)
  874. bc = BitConsumer(self._src)
  875. obj.CSMTableHint = bc.u_get(2)
  876. obj.Reserved = bc.u_get(6)
  877. obj.ZoneTable = zone_records = []
  878. glyph_count = self._last_defined_glyphs_quantity
  879. self._last_defined_glyphs_quantity = None
  880. for _ in range(glyph_count):
  881. zone_record = _make_object("ZoneRecord")
  882. zone_records.append(zone_record)
  883. zone_record.NumZoneData = unpack_ui8(self._src)
  884. zone_record.ZoneData = zone_data = []
  885. for _ in range(zone_record.NumZoneData):
  886. zone_datum = _make_object("ZoneData")
  887. zone_data.append(zone_datum)
  888. zone_datum.AlignmentCoordinate = unpack_float16(self._src)
  889. zone_datum.Range = unpack_float16(self._src)
  890. bc = BitConsumer(self._src)
  891. zone_record.Reserved = bc.u_get(6)
  892. zone_record.ZoneMaskY = bc.u_get(1)
  893. zone_record.ZoneMaskX = bc.u_get(1)
  894. return obj
  895. def _handle_tag_definefontname(self):
  896. """Handle the DefineFontName tag."""
  897. obj = _make_object("DefineFontName")
  898. obj.FontId = unpack_ui16(self._src)
  899. obj.FontName = self._get_struct_string()
  900. obj.FontCopyright = self._get_struct_string()
  901. return obj
  902. def _handle_tag_csmtextsettings(self):
  903. """Handle the CSMTextSettings tag."""
  904. obj = _make_object("CSMTextSettings")
  905. obj.TextId = unpack_ui16(self._src)
  906. bc = BitConsumer(self._src)
  907. obj.UseFlashType = bc.u_get(2)
  908. obj.GridFit = bc.u_get(3)
  909. obj.Reserved1 = bc.u_get(3)
  910. obj.Thickness = unpack_float(self._src)
  911. obj.Sharpness = unpack_float(self._src)
  912. obj.Reserved2 = unpack_ui8(self._src)
  913. return obj
  914. def _get_raw_bytes(self, size, unzip=False):
  915. '''Get raw bytes data, optional uncompress with ZLIB'''
  916. pos = self._src.tell()
  917. try:
  918. # < 0: read until this pos
  919. if size < 0:
  920. assert abs(size) > pos
  921. size = abs(size) - pos
  922. data = self._src.read(size)
  923. if unzip:
  924. return zlib.decompress(data)
  925. else:
  926. return data
  927. except Exception:
  928. self._src.seek(pos, io.SEEK_SET)
  929. raise
  930. def _get_struct_rect(self):
  931. """Get the RECT structure."""
  932. bc = BitConsumer(self._src)
  933. nbits = bc.u_get(5)
  934. if self._read_twips:
  935. return tuple(bc.s_get(nbits) for _ in range(4))
  936. else:
  937. return tuple(bc.s_get(nbits) / 20.0 for _ in range(4))
  938. def _get_struct_rgb(self):
  939. """Get the RGB structure."""
  940. return [unpack_ui8(self._src) for _ in range(3)]
  941. def _get_struct_rgba(self):
  942. """Get the RGBA structure."""
  943. return [unpack_ui8(self._src) for _ in range(4)]
  944. def _get_struct_langcode(self):
  945. """Get the LANGCODE structure."""
  946. code = unpack_ui8(self._src)
  947. return LANGCODES[code]
  948. def _get_struct_kerningrecord(self, font_flags_wide_codes):
  949. """Get the KERNINGRECORD structure."""
  950. getter = unpack_ui16 if font_flags_wide_codes else unpack_ui8
  951. data = {}
  952. data['FontKerningCode1'] = getter(self._src)
  953. data['FontKerningCode2'] = getter(self._src)
  954. data['FontKerningAdjustment'] = unpack_si16(self._src)
  955. return data
  956. def _get_struct_clipactions(self):
  957. """Get the several CLIPACTIONRECORDs."""
  958. obj = _make_object("ClipActions")
  959. # In SWF 5 and earlier, these are 2 bytes wide; in SWF 6
  960. # and later 4 bytes
  961. clipeventflags_size = 2 if self._version <= 5 else 4
  962. clipactionend_size = 2 if self._version <= 5 else 4
  963. all_zero = b"\x00" * clipactionend_size
  964. assert unpack_ui16(self._src) == 0 # reserved
  965. obj.AllEventFlags = self._src.read(clipeventflags_size)
  966. obj.ClipActionRecords = records = []
  967. while True:
  968. next_bytes = self._src.read(clipactionend_size)
  969. if next_bytes == all_zero:
  970. # was the ClipActionEndFlag
  971. return
  972. record = _make_object("ClipActionRecord")
  973. records.append(record)
  974. # as event flags and end flag has same size, we can do this trick
  975. record.EventFlags = next_bytes
  976. record.ActionRecordSize = unpack_ui32(self._src)
  977. record.TheRestTODO = self._src.read(record.ActionRecordSize)
  978. # FIXME: this struct needs more work; the EventFlags should be
  979. # expanded and each ActionRecord(s) should be detailed more
  980. return obj
  981. def _get_struct_string(self):
  982. """Get the STRING structure."""
  983. data = []
  984. while True:
  985. t = self._src.read(1)
  986. if t == b'\x00':
  987. break
  988. data.append(t)
  989. val = b''.join(data)
  990. return val.decode("utf8")
  991. def _get_struct_matrix(self):
  992. """Get the values for the MATRIX record."""
  993. obj = _make_object("Matrix")
  994. bc = BitConsumer(self._src)
  995. # scale
  996. obj.HasScale = bc.u_get(1)
  997. if obj.HasScale:
  998. obj.NScaleBits = n_scale_bits = bc.u_get(5)
  999. obj.ScaleX = bc.fb_get(n_scale_bits)
  1000. obj.ScaleY = bc.fb_get(n_scale_bits)
  1001. # rotate
  1002. obj.HasRotate = bc.u_get(1)
  1003. if obj.HasRotate:
  1004. obj.NRotateBits = n_rotate_bits = bc.u_get(5)
  1005. obj.RotateSkew0 = bc.fb_get(n_rotate_bits)
  1006. obj.RotateSkew1 = bc.fb_get(n_rotate_bits)
  1007. # translate
  1008. obj.NTranslateBits = n_translate_bits = bc.u_get(5)
  1009. obj.TranslateX = bc.s_get(n_translate_bits)
  1010. obj.TranslateY = bc.s_get(n_translate_bits)
  1011. if not self._read_twips:
  1012. obj.TranslateX /= 20.0
  1013. obj.TranslateY /= 20.0
  1014. return obj
  1015. def _get_struct_cxformwithalpha(self):
  1016. """Get the values for the CXFORMWITHALPHA record."""
  1017. obj = _make_object("CXformWithAlpha")
  1018. bc = BitConsumer(self._src)
  1019. obj.HasAddTerms = bc.u_get(1)
  1020. obj.HasMultTerms = bc.u_get(1)
  1021. obj.NBits = nbits = bc.u_get(4)
  1022. if obj.HasMultTerms:
  1023. obj.RedMultTerm = bc.s_get(nbits)
  1024. obj.GreenMultTerm = bc.s_get(nbits)
  1025. obj.BlueMultTerm = bc.s_get(nbits)
  1026. obj.AlphaMultTerm = bc.s_get(nbits)
  1027. if obj.HasAddTerms:
  1028. obj.RedAddTerm = bc.s_get(nbits)
  1029. obj.GreenAddTerm = bc.s_get(nbits)
  1030. obj.BlueAddTerm = bc.s_get(nbits)
  1031. obj.AlphaAddTerm = bc.s_get(nbits)
  1032. return obj
  1033. def _get_shaperecords(self, num_fill_bits,
  1034. num_line_bits, shape_number):
  1035. """Return an array of SHAPERECORDS."""
  1036. shape_records = []
  1037. bc = BitConsumer(self._src)
  1038. while True:
  1039. type_flag = bc.u_get(1)
  1040. if type_flag:
  1041. # edge record
  1042. straight_flag = bc.u_get(1)
  1043. num_bits = bc.u_get(4)
  1044. if straight_flag:
  1045. record = _make_object('StraightEdgeRecord')
  1046. record.TypeFlag = 1
  1047. record.StraightFlag = 1
  1048. record.NumBits = num_bits
  1049. record.GeneralLineFlag = general_line_flag = bc.u_get(1)
  1050. if general_line_flag:
  1051. record.DeltaX = bc.s_get(num_bits + 2)
  1052. record.DeltaY = bc.s_get(num_bits + 2)
  1053. else:
  1054. record.VertLineFlag = vert_line_flag = bc.s_get(1)
  1055. if vert_line_flag:
  1056. record.DeltaY = bc.s_get(num_bits + 2)
  1057. else:
  1058. record.DeltaX = bc.s_get(num_bits + 2)
  1059. else:
  1060. record = _make_object('CurvedEdgeRecord')
  1061. record.TypeFlag = 1
  1062. record.StraightFlag = 0
  1063. record.NumBits = num_bits
  1064. record.ControlDeltaX = bc.s_get(num_bits + 2)
  1065. record.ControlDeltaY = bc.s_get(num_bits + 2)
  1066. record.AnchorDeltaX = bc.s_get(num_bits + 2)
  1067. record.AnchorDeltaY = bc.s_get(num_bits + 2)
  1068. else:
  1069. # non edge record
  1070. record = _make_object('StyleChangeRecord')
  1071. record.TypeFlag = 0
  1072. five_bits = [bc.u_get(1) for _ in range(5)]
  1073. if not any(five_bits):
  1074. # the five bits are zero, this is an EndShapeRecord
  1075. break
  1076. # we're not done, store the proper flags
  1077. (record.StateNewStyles, record.StateLineStyle,
  1078. record.StateFillStyle1, record.StateFillStyle0,
  1079. record.StateMoveTo) = five_bits
  1080. if record.StateMoveTo:
  1081. record.MoveBits = move_bits = bc.u_get(5)
  1082. record.MoveDeltaX = bc.s_get(move_bits)
  1083. record.MoveDeltaY = bc.s_get(move_bits)
  1084. if record.StateFillStyle0:
  1085. record.FillStyle0 = bc.u_get(num_fill_bits)
  1086. if record.StateFillStyle1:
  1087. record.FillStyle1 = bc.u_get(num_fill_bits)
  1088. if record.StateLineStyle:
  1089. record.LineStyle = bc.u_get(num_line_bits)
  1090. if record.StateNewStyles:
  1091. record.FillStyles = self._get_struct_fillstylearray(
  1092. shape_number)
  1093. record.LineStyles = self._get_struct_linestylearray(
  1094. shape_number)
  1095. # these two not only belong to the record, but also
  1096. # modifies the number of bits read in the future
  1097. # if shape number bigs enough (didn't find this in the
  1098. # spec, but works for now, maybe '2' is not the limit...)
  1099. if shape_number > 2:
  1100. record.NumFillBits = num_fill_bits = bc.u_get(4)
  1101. record.NumLineBits = num_line_bits = bc.u_get(4)
  1102. else:
  1103. record.NumFillBits = bc.u_get(4)
  1104. record.NumLineBits = bc.u_get(4)
  1105. # reset the BC here, as the structures just read work at
  1106. # byte level
  1107. bc = BitConsumer(self._src)
  1108. shape_records.append(record)
  1109. return shape_records
  1110. def _get_struct_shape(self):
  1111. """Get the values for the SHAPE record."""
  1112. obj = _make_object("Shape")
  1113. bc = BitConsumer(self._src)
  1114. obj.NumFillBits = n_fill_bits = bc.u_get(4)
  1115. obj.NumLineBits = n_line_bits = bc.u_get(4)
  1116. obj.ShapeRecords = self._get_shaperecords(
  1117. n_fill_bits, n_line_bits, 0)
  1118. return obj
  1119. def _get_struct_fillstyle(self, shape_number):
  1120. """Get the values for the FILLSTYLE record."""
  1121. obj = _make_object("FillStyle")
  1122. obj.FillStyleType = style_type = unpack_ui8(self._src)
  1123. if style_type == 0x00:
  1124. if shape_number <= 2:
  1125. obj.Color = self._get_struct_rgb()
  1126. else:
  1127. obj.Color = self._get_struct_rgba()
  1128. if style_type in (0x10, 0x12, 0x13):
  1129. obj.GradientMatrix = self._get_struct_matrix()
  1130. if style_type in (0x10, 0x12):
  1131. obj.Gradient = self._get_struct_gradient(shape_number)
  1132. if style_type == 0x13:
  1133. obj.Gradient = self._get_struct_focalgradient(shape_number)
  1134. if style_type in (0x40, 0x41, 0x42, 0x43):
  1135. obj.BitmapId = unpack_ui16(self._src)
  1136. obj.BitmapMatrix = self._get_struct_matrix()
  1137. return obj
  1138. def _get_struct_fillstylearray(self, shape_number):
  1139. """Get the values for the FILLSTYLEARRAY record."""
  1140. obj = _make_object("FillStyleArray")
  1141. obj.FillStyleCount = count = unpack_ui8(self._src)
  1142. if count == 0xFF:
  1143. obj.FillStyleCountExtended = count = unpack_ui16(self._src)
  1144. obj.FillStyles = [self._get_struct_fillstyle(shape_number)
  1145. for _ in range(count)]
  1146. return obj
  1147. def _get_struct_linestylearray(self, shape_number):
  1148. """Get the values for the LINESTYLEARRAY record."""
  1149. obj = _make_object("LineStyleArray")
  1150. obj.LineStyleCount = count = unpack_ui8(self._src)
  1151. if count == 0xFF:
  1152. obj.LineStyleCountExtended = count = unpack_ui16(self._src)
  1153. obj.LineStyles = line_styles = []
  1154. for _ in range(count):
  1155. if shape_number <= 3:
  1156. record = _make_object("LineStyle")
  1157. record.Width = unpack_ui16(self._src)
  1158. if shape_number <= 2:
  1159. record.Color = self._get_struct_rgb()
  1160. else:
  1161. record.Color = self._get_struct_rgba()
  1162. else:
  1163. record = _make_object("LineStyle2")
  1164. record.Width = unpack_ui16(self._src)
  1165. bc = BitConsumer(self._src)
  1166. record.StartCapStyle = bc.u_get(2)
  1167. record.JoinStyle = bc.u_get(2)
  1168. record.HasFillFlag = bc.u_get(1)
  1169. record.NoHScaleFlag = bc.u_get(1)
  1170. record.NoVScaleFlag = bc.u_get(1)
  1171. record.PixelHintingFlag = bc.u_get(1)
  1172. bc.u_get(5) # reserved
  1173. record.NoClose = bc.u_get(1)
  1174. record.EndCapStyle = bc.u_get(2)
  1175. if record.JoinStyle == 2:
  1176. record.MiterLimitFactor = unpack_ui16(self._src)
  1177. if record.HasFillFlag == 0:
  1178. record.Color = self._get_struct_rgba()
  1179. else:
  1180. record.Color = self._get_struct_fillstyle(shape_number)
  1181. line_styles.append(record)
  1182. return obj
  1183. def _get_struct_encodedu32(self):
  1184. """Get a EncodedU32 number."""
  1185. useful = []
  1186. while True:
  1187. byte = ord(self._src.read(1))
  1188. useful.append(byte)
  1189. if byte < 127:
  1190. # got all the useful bytes
  1191. break
  1192. # transform into bits reordering the bytes
  1193. useful = ['00000000' + bin(b)[2:] for b in useful[::-1]]
  1194. # get the top 7 (*seven*, as the eight one is the flag) and convert
  1195. return int(''.join([b[-7:] for b in useful]), 2)
  1196. def _get_struct_shapewithstyle(self, shape_number):
  1197. """Get the values for the SHAPEWITHSTYLE record."""
  1198. obj = _make_object("ShapeWithStyle")
  1199. obj.FillStyles = self._get_struct_fillstylearray(shape_number)
  1200. obj.LineStyles = self._get_struct_linestylearray(shape_number)
  1201. bc = BitConsumer(self._src)
  1202. obj.NumFillBits = n_fill_bits = bc.u_get(4)
  1203. obj.NumlineBits = n_line_bits = bc.u_get(4)
  1204. obj.ShapeRecords = self._get_shaperecords(
  1205. n_fill_bits, n_line_bits, shape_number)
  1206. return obj
  1207. def _get_struct_gradient(self, shape_number):
  1208. """Get the values for the GRADIENT record."""
  1209. obj = _make_object("Gradient")
  1210. bc = BitConsumer(self._src)
  1211. obj.SpreadMode = bc.u_get(2)
  1212. obj.InterpolationMode = bc.u_get(2)
  1213. obj.NumGradients = bc.u_get(4)
  1214. obj.GradientRecords = gradient_records = []
  1215. for _ in range(obj.NumGradients):
  1216. record = _make_object("GradRecord")
  1217. gradient_records.append(record)
  1218. record.Ratio = unpack_ui8(self._src)
  1219. if shape_number <= 2:
  1220. record.Color = self._get_struct_rgb()
  1221. else:
  1222. record.Color = self._get_struct_rgba()
  1223. return obj
  1224. def _get_struct_focalgradient(self, shape_number):
  1225. """Get the values for the FOCALGRADIENT record."""
  1226. obj = _make_object("FocalGradient")
  1227. bc = BitConsumer(self._src)
  1228. obj.SpreadMode = bc.u_get(2)
  1229. obj.InterpolationMode = bc.u_get(2)
  1230. obj.NumGradients = bc.u_get(4)
  1231. obj.GradientRecords = gradient_records = []
  1232. for _ in range(obj.NumGradients):
  1233. record = _make_object("GradRecord")
  1234. gradient_records.append(record)
  1235. record.Ratio = unpack_ui8(self._src)
  1236. if shape_number <= 2:
  1237. record.Color = self._get_struct_rgb()
  1238. else:
  1239. record.Color = self._get_struct_rgba()
  1240. obj.FocalPoint = unpack_fixed8(self._src)
  1241. return obj
  1242. def _get_struct_filterlist(self):
  1243. """Get the values for the FILTERLIST record."""
  1244. obj = _make_object("FilterList")
  1245. obj.NumberOfFilters = unpack_ui8(self._src)
  1246. obj.Filter = filters = []
  1247. # how to decode each filter type (and name), according to the filter id
  1248. filter_type = [
  1249. ("DropShadowFilter", self._get_struct_dropshadowfilter), # 0
  1250. ("BlurFilter", self._get_struct_blurfilter), # 1
  1251. ("GlowFilter", self._get_struct_glowfilter), # 2...
  1252. ("BevelFilter", self._get_struct_bevelfilter),
  1253. ("GradientGlowFilter", self._get_struct_gradientglowfilter),
  1254. ("ConvolutionFilter", self._get_struct_convolutionfilter),
  1255. ("ColorMatrixFilter", self._get_struct_colormatrixfilter),
  1256. ("GradientBevelFilter", self._get_struct_gradientbevelfilter), # 7
  1257. ]
  1258. for _ in range(obj.NumberOfFilters):
  1259. _filter = _make_object("Filter")
  1260. filters.append(_filter)
  1261. _filter.FilterId = unpack_ui8(self._src)
  1262. name, func = filter_type[_filter.FilterId]
  1263. setattr(_filter, name, func())
  1264. def _get_struct_dropshadowfilter(self):
  1265. """Get the values for the DROPSHADOWFILTER record."""
  1266. obj = _make_object("DropShadowFilter")
  1267. obj.DropShadowColor = self._get_struct_rgba()
  1268. obj.BlurX = unpack_fixed16(self._src)
  1269. obj.BlurY = unpack_fixed16(self._src)
  1270. obj.Angle = unpack_fixed16(self._src)
  1271. obj.Distance = unpack_fixed16(self._src)
  1272. obj.Strength = unpack_fixed8(self._src)
  1273. bc = BitConsumer(self._src)
  1274. obj.InnerShadow = bc.u_get(1)
  1275. obj.Knockout = bc.u_get(1)
  1276. obj.CompositeSource = bc.u_get(1)
  1277. obj.Passes = bc.u_get(5)
  1278. return obj
  1279. def _get_struct_blurfilter(self):
  1280. """Get the values for the BLURFILTER record."""
  1281. obj = _make_object("BlurFilter")
  1282. obj.BlurX = unpack_fixed16(self._src)
  1283. obj.BlurY = unpack_fixed16(self._src)
  1284. bc = BitConsumer(self._src)
  1285. obj.Passes = bc.u_get(5)
  1286. obj.Reserved = bc.u_get(3)
  1287. return obj
  1288. def _get_struct_glowfilter(self):
  1289. """Get the values for the GLOWFILTER record."""
  1290. obj = _make_object("GlowFilter")
  1291. obj.GlowColor = self._get_struct_rgba()
  1292. obj.BlurX = unpack_fixed16(self._src)
  1293. obj.BlurY = unpack_fixed16(self._src)
  1294. obj.Strength = unpack_fixed8(self._src)
  1295. bc = BitConsumer(self._src)
  1296. obj.InnerGlow = bc.u_get(1)
  1297. obj.Knockout = bc.u_get(1)
  1298. obj.CompositeSource = bc.u_get(1)
  1299. obj.Passes = bc.u_get(5)
  1300. return obj
  1301. def _get_struct_bevelfilter(self):
  1302. """Get the values for the BEVELFILTER record."""
  1303. obj = _make_object("BevelFilter")
  1304. obj.ShadowColor = self._get_struct_rgba()
  1305. obj.HighlightColor = self._get_struct_rgba()
  1306. obj.BlurX = unpack_fixed16(self._src)
  1307. obj.BlurY = unpack_fixed16(self._src)
  1308. obj.Angle = unpack_fixed16(self._src)
  1309. obj.Distance = unpack_fixed16(self._src)
  1310. obj.Strength = unpack_fixed8(self._src)
  1311. bc = BitConsumer(self._src)
  1312. obj.InnerShadow = bc.u_get(1)
  1313. obj.Knockout = bc.u_get(1)
  1314. obj.CompositeSource = bc.u_get(1)
  1315. obj.OnTop = bc.u_get(1)
  1316. obj.Passes = bc.u_get(4)
  1317. return obj
  1318. def _get_struct_gradientglowfilter(self):
  1319. """Get the values for the GRADIENTGLOWFILTER record."""
  1320. obj = _make_object("GradientGlowFilter")
  1321. obj.NumColors = num_colors = unpack_ui8(self._src)
  1322. obj.GradientColors = [self._get_struct_rgba()
  1323. for _ in range(num_colors)]
  1324. obj.GradientRatio = [unpack_ui8(self._src)
  1325. for _ in range(num_colors)]
  1326. obj.BlurX = unpack_fixed16(self._src)
  1327. obj.BlurY = unpack_fixed16(self._src)
  1328. obj.Angle = unpack_fixed16(self._src)
  1329. obj.Distance = unpack_fixed16(self._src)
  1330. obj.Strength = unpack_fixed8(self._src)
  1331. bc = BitConsumer(self._src)
  1332. obj.InnerShadow = bc.u_get(1)
  1333. obj.Knockout = bc.u_get(1)
  1334. obj.CompositeSource = bc.u_get(1)
  1335. obj.OnTop = bc.u_get(1)
  1336. obj.Passes = bc.u_get(4)
  1337. return obj
  1338. def _get_struct_convolutionfilter(self):
  1339. """Get the values for the CONVOLUTIONFILTER record."""
  1340. obj = _make_object("ConvolutionFilter")
  1341. obj.MatrixX = unpack_ui8(self._src)
  1342. obj.MatrixY = unpack_ui8(self._src)
  1343. obj.Divisor = unpack_float(self._src)
  1344. obj.Bias = unpack_float(self._src)
  1345. _quant = obj.MatrixX * obj.MatrixY
  1346. obj.Matrix = [unpack_float(self._src) for _ in range(_quant)]
  1347. obj.DefaultColor = self._get_struct_rgba()
  1348. bc = BitConsumer(self._src)
  1349. obj.Reserved = bc.u_get(6)
  1350. obj.Clamp = bc.u_get(1)
  1351. obj.PreserveAlpha = bc.u_get(1)
  1352. return obj
  1353. def _get_struct_colormatrixfilter(self):
  1354. """Get the values for the COLORMATRIXFILTER record."""
  1355. obj = _make_object("ColorMatrixFilter")
  1356. obj.Matrix = [unpack_float(self._src) for _ in range(20)]
  1357. return obj
  1358. def _get_struct_gradientbevelfilter(self):
  1359. """Get the values for the GRADIENTBEVELFILTER record."""
  1360. obj = _make_object("GradientBevelFilter")
  1361. obj.NumColors = num_colors = unpack_ui8(self._src)
  1362. obj.GradientColors = [self._get_struct_rgba()
  1363. for _ in range(num_colors)]
  1364. obj.GradientRatio = [unpack_ui8(self._src)
  1365. for _ in range(num_colors)]
  1366. obj.BlurX = unpack_fixed16(self._src)
  1367. obj.BlurY = unpack_fixed16(self._src)
  1368. obj.Angle = unpack_fixed16(self._src)
  1369. obj.Distance = unpack_fixed16(self._src)
  1370. obj.Strength = unpack_fixed8(self._src)
  1371. bc = BitConsumer(self._src)
  1372. obj.InnerShadow = bc.u_get(1)
  1373. obj.Knockout = bc.u_get(1)
  1374. obj.CompositeSource = bc.u_get(1)
  1375. obj.OnTop = bc.u_get(1)
  1376. obj.Passes = bc.u_get(4)
  1377. return obj
  1378. def _handle_actionconstantpool(self, _):
  1379. """Handle the ActionConstantPool action."""
  1380. obj = _make_object("ActionConstantPool")
  1381. obj.Count = count = unpack_ui16(self._src)
  1382. obj.ConstantPool = pool = []
  1383. for _ in range(count):
  1384. pool.append(self._get_struct_string())
  1385. yield obj
  1386. def _handle_actiongeturl(self, _):
  1387. """Handle the ActionGetURL action."""
  1388. obj = _make_object("ActionGetURL")
  1389. obj.UrlString = self._get_struct_string()
  1390. obj.TargetString = self._get_struct_string()
  1391. yield obj
  1392. def _handle_actionpush(self, length):
  1393. """Handle the ActionPush action."""
  1394. init_pos = self._src.tell()
  1395. while self._src.tell() < init_pos + length:
  1396. obj = _make_object("ActionPush")
  1397. obj.Type = unpack_ui8(self._src)
  1398. # name and how to read each type
  1399. push_types = {
  1400. 0: ("String", self._get_struct_string),
  1401. 1: ("Float", lambda: unpack_float(self._src)),
  1402. 2: ("Null", lambda: None),
  1403. 4: ("RegisterNumber", lambda: unpack_ui8(self._src)),
  1404. 5: ("Boolean", lambda: unpack_ui8(self._src)),
  1405. 6: ("Double", lambda: unpack_double(self._src)),
  1406. 7: ("Integer", lambda: unpack_ui32(self._src)),
  1407. 8: ("Constant8", lambda: unpack_ui8(self._src)),
  1408. 9: ("Constant16", lambda: unpack_ui16(self._src)),
  1409. }
  1410. name, func = push_types[obj.Type]
  1411. setattr(obj, name, func())
  1412. yield obj
  1413. def _handle_actiondefinefunction(self, _):
  1414. """Handle the ActionDefineFunction action."""
  1415. obj = _make_object("ActionDefineFunction")
  1416. obj.FunctionName = self._get_struct_string()
  1417. obj.NumParams = unpack_ui16(self._src)
  1418. for i in range(1, obj.NumParams + 1):
  1419. setattr(obj, "param" + str(i), self._get_struct_string())
  1420. obj.CodeSize = unpack_ui16(self._src)
  1421. yield obj
  1422. def _handle_actionif(self, _):
  1423. """Handle the ActionIf action."""
  1424. obj = _make_object("ActionIf")
  1425. obj.BranchOffset = unpack_si16(self._src)
  1426. yield obj
  1427. def _handle_actiondefinefunction2(self, _):
  1428. """Handle the ActionDefineFunction2 action."""
  1429. obj = _make_object("ActionDefineFunction2")
  1430. obj.FunctionName = self._get_struct_string()
  1431. obj.NumParams = unpack_ui16(self._src)
  1432. obj.RegisterCount = unpack_ui8(self._src)
  1433. bc = BitConsumer(self._src)
  1434. obj.PreloadParentFlag = bc.u_get(1)
  1435. obj.PreloadRootFlag = bc.u_get(1)
  1436. obj.SupressSuperFlag = bc.u_get(1)
  1437. obj.PreloadSuperFlag = bc.u_get(1)
  1438. obj.SupressArgumentsFlag = bc.u_get(1)
  1439. obj.PreloadArgumentsFlag = bc.u_get(1)
  1440. obj.SupressThisFlag = bc.u_get(1)
  1441. obj.PreloadThisFlag = bc.u_get(1)
  1442. obj.Reserved = bc.u_get(7)
  1443. obj.PreloadGlobalFlag = bc.u_get(1)
  1444. obj.Parameters = parameters = []
  1445. for _ in range(obj.NumParams):
  1446. parameter = _make_object("Parameter")
  1447. parameters.append(parameter)
  1448. parameter.Register = unpack_ui8(self._src)
  1449. parameter.ParamName = self._get_struct_string()
  1450. obj.CodeSize = unpack_ui16(self._src)
  1451. yield obj
  1452. def coverage(self):
  1453. """Calculate the coverage of a file."""
  1454. items_unk = collections.Counter()
  1455. items_ok = collections.Counter()
  1456. def _go_deep(obj):
  1457. """Recursive function to find internal attributes."""
  1458. if type(obj).__name__ in ('UnknownObject', 'UnknownAction'):
  1459. # blatantly unknown
  1460. items_unk[obj.name] += 1
  1461. elif obj.name in ('DefineMorphShape2', 'ClipActions'):
  1462. # these are incomplete, see FIXMEs in the code above
  1463. items_unk[obj.name] += 1
  1464. else:
  1465. # fully parsed
  1466. items_ok[obj.name] += 1
  1467. for name in obj._attribs:
  1468. attr = getattr(obj, name)
  1469. if isinstance(attr, SWFObject):
  1470. _go_deep(attr)
  1471. for tag in self.tags:
  1472. _go_deep(tag)
  1473. full_count = sum(items_ok.values()) + sum(items_unk.values())
  1474. coverage = 100 * sum(items_ok.values()) / full_count
  1475. print("Coverage is {:.1f}% of {} total items".format(coverage,
  1476. full_count))
  1477. print("Most common parsed objects:")
  1478. for k, v in items_ok.most_common(3):
  1479. print("{:5d} {}".format(v, k))
  1480. if items_unk:
  1481. print("Most common Unknown objects")
  1482. for k, v in items_unk.most_common(3):
  1483. print("{:5d} {}".format(v, k))
  1484. def parsefile(filename, read_twips=True):
  1485. """Parse a SWF.
  1486. If you have a file object already, just use SWFParser directly.
  1487. read_twips: True - return values as read from the SWF
  1488. False - return values in pixels (at 100% zoom)
  1489. """
  1490. with open(filename, 'rb') as fh:
  1491. return SWFParser(fh, read_twips)
  1492. if __name__ == "__main__":
  1493. import cv2
  1494. import numpy as np
  1495. import time
  1496. import traceback
  1497. from PIL import Image
  1498. from format_convert.utils import pil2np
  1499. start_time = time.time()
  1500. p = "C:/Users/Administrator/Downloads/13035f4a379c4d24b89835456e047c14.swf"
  1501. # p = "C:/Users/Administrator/Desktop/test_swf/error1.swf"
  1502. swf_parser = parsefile(p)
  1503. index = 0
  1504. for tag in swf_parser.tags:
  1505. try:
  1506. if not hasattr(tag, 'ImageData'):
  1507. continue
  1508. byte_data = tag.ImageData
  1509. with open('images/' + str(index) + '.png', 'wb') as f:
  1510. f.write(byte_data)
  1511. # with open('images/' + str(index) + '.txt', 'w') as f:
  1512. # f.write(str(byte_data))
  1513. image = Image.open('images/' + str(index) + '.png')
  1514. # image_np = pil2np(image)
  1515. print(index, image.size)
  1516. if image.size[0] > 1000 and image.size[1] > 1000:
  1517. image = image.resize((600, 1000), Image.BILINEAR)
  1518. image.save('images/' + str(index) + '.png', quality=10, )
  1519. #
  1520. # with open('images/' + str(index) + '.png', 'rb') as f:
  1521. # byte_data = f.read()
  1522. # with open('images/' + str(index) + '.txt', 'w') as f:
  1523. # f.write(str(byte_data))
  1524. except:
  1525. traceback.print_exc()
  1526. index += 1
  1527. print(time.time()-start_time)