diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b344137b..32b1f67ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,2287 +1,2287 @@ -# Change Log -All notable changes to this project will be documented in this file. - -## [Unreleased] -### Added -- [#1240] AS search using multiple threads when parallel speedup is enabled -- [#1308] Search by all P-code files in AS3 -- [#1333] Exporting sprites as swf files -- [#1365] Allow to configure all types of configuration settings from command line -- [#1369] Allow zoom in sprite (and button) export - -### Fixed -- [#1327] P-code editing: error message and syntax highlighting fixed when instruction name contains upper cased letter -- [#1343] AS 1/2 direct editation critical bug -- [#1348] Cannot properly export frame with cyrillic symbols to SVG -- [#1354] Various FLA export problem fixes -- [#1367] Raw edit conditional type fix. -- [#1401] SVG export: duplicate pattern IDs fixed -- [#1402] SVG export: certain font characters not exported properly fixed - -## [10.0.0] - 2016-12-24 -### Added -- Iggy Files support - reading and (limited) editation of fonts, texts and AS3 - 64 bit variant only -- optional AS3 direct editation with Flex SDK -- AS3 p-code editing - metadata read/write support -- AS3 p-code editing - end of the block command like in RABCDasm -- AS3 p-code editing - popup docs for more than instructions -- Debugger - New columns for variable details - scope, flags, trait -- Debugger - Add watch feature -- AS3 decompilation - colliding trait/class names handling - show hash suffix with namespace index on such cases -- Deobfuscation Tool - Fix colliding trait/classes via toolbar command -- Auto rename identifiers option now fixes colliding trait/classes aswell -- [#1254] FLA export - detecting scripts on AS3 timeline -- [#907] FFDec Library JAR file has version inside it. -- [#1311], [#1313] actionScript source font size -- Display warning when library version and GUI version mismatch -- Changelog file -- [#1308] Search by all P-code files (AS 1/2 only) - -### Changed -- [#1189] AS3 - sort imports to have same order always -- GUI: AS3 P-code header show actual trait type and method type -- GUI: Script editing buttons now named "Edit ActionScript" and "Edit P-code" -- Set advance values button has confirm dialog with information -- [#1274] Linux package no longer requires Oracle Java only -- Library now packaged inside ZIP file - -### Fixed -- P-code docs formatting fix -- Export dialog - handling sprite and SWF frames correctly -- [#1275] debugger - show local variables fixes -- AS3 p-code editing - popup docs correctly displayed when label on line start -- [#1278] replacing DefineBits error -- [#1281] DefineFont 2/3 getting character advance value when replacing fix -- Set advance values button - Do not set advance if the char cannot be displayed in source font -- AS3 Goto declaration for single character names -- Identifier renaming for top level classes -- AS3 direct editation not correctly saving local register names -- [#1254] FLA export - placing AS3 classes to FLA directory instead of scripts dir -- Mac OS X installer fix (.pkg) -- [#1289] AS1/2 direct editation - variables used in inner functions must not be stored in local registers -- [#1283] AS3 Unbounded Vector - Vector<*> decompilation and direct editation fix -- [#1294] Font editation (DefineFont2/3) - correct switching of wide character codes -- [#1302] Callpropvoid instruction docblock not correct -- [#1309] recent files not getting updates -- [#1312] faster colliding usages finder -- [#1303] garbled text when exporting frame with text -- [#1314] user interface: button order -- Internal viewer shows red image when bitmap fill is not available (see issue [#1320]) -- [#1323] Audio playback fails - -## [9.0.0] - 2016-08-12 -### Added -- Instance metadata (AMF3) editing in PlaceObject4 -- [#1156] Flash Viewer - DefineScalingGrid support (9-slice scaling) -- [#1171] Export stroke scale to FLA -- FLA export - check invalid unicode characters -- [#1170] Extract from memory in commandline -- Reload one vs Reload all buttons -- ABC: Float and Float4 support -- AS3 p-code instruction documentation in GUI -- [#1241] Settings to show original bytes in hex view -- Search in dump view -- Jump to resources view from hex view -- Show warning on 32bit JRE - -### Changed -- [#1162] improved opening loaded SWF files -- Flash Viewer - skip frames when not on time -- [#1199] Automatically import alpha channel to JPEG3/4 from PNG - -### Fixed -- [#1151] Filters on texts fixed -- [#1128] Adding characters to font fixed (FontAlignZones not removed) -- [#1163] Clicking open->file makes program buggy -- Refresh tree after raw edit -- [#1172] Text double escape fix -- [#1174] Change language fix -- some AS2 deobfuscation fixes -- [#1183] Index out of bounds fix -- Implicit coersion on binary/unary opfix -- debugger: corect display variable values through getters -- Multiple XLF export fix -- [#1193] FLA export - text tag advance fix, one layer shape fix -- [#1193] FLA export - smoothed image detection, export raw JPEG data -- [#1193] Export space character to TTF correctly -- [#1200] Previous search text selected when quick find -- Flash viewer: aspect ratio on startup fix -- [#1198] Saving trait slot const value -- Zoom parameter commandline fixed -- [#1205] clipping fixed -- [#1194] Wrong sound effects in FLA -- [#1210] Frame Export fix -- Improved/fixed go to declaration in AS3 -- [#1217] PCode window not in same position as AS -- Hide memor search on non windows platform -- [#1244] Incorrect showing of NOP instructions -- [#1244] Remove unknown actions when deobfuscation is enabled, compole unknown instructions back -- [#1241] File content is different from hex view -- [#1247] Incorrectly handling remainingbytes for DefineCompactedFont -- [#1236] won't open fixed -- [#1251] SWF not same after export XML and import back -- [#1265] Error during export -- [#1268] Font export - Using second glyph when two glyphs for one character found -- [#1268] GFX compacted font - fixed advance values on export - -## [8.0.1] - 2016-02-20 -### Changed -- FFDec debug tab in advanced settings moved to other tabs - -### Fixed -- [#1161] AS1/2 deobfuscation broken -- AS1/2 Simplify expressions fix - -## [8.0.0] - 2016-02-18 -### Added -- Debugger - AS1/2 Show registers -- Debugger - display variables in the tree structure -- Debugger - set value of variable -- Debugger - AS1/2 View constantpool -- Debugger - P-code level debugging for both AS1/2 and AS3 -- Basic SVG import for shapes -- Simplify expression setting -- [#1118] Loading characters through ImportAssets - show as readonly -- [#409], [#1132], [SkinPart] metadata support - decompilation and direct editation in AS3 -- [#1134] compiling §§ instructions back while direct editation (§§goto is still missing) -- [#1121] Ability to save binary data by its name -- [#1052] Add object to existing frame -- Allow adding tag to main timeline -- AS1/2: Ctrl+click to declaration of variables, registers -- Allow trait specification in pcode import -- Icons for tag types in Dump view -- Show error message when a text tag is invalid (glyph index problem) -- AS3 direct editation - store local register names in debug info = allow to rename them - -### Changed -- New application icon and splash screen -- [#1145] AS3 better declaration type detection, better convert_x instruction handling -- Binary export - use .swf extension for swf files -- Better tree labels in generic tag editor (Raw edit) -- [#758] Allow zooming more than preview area in internal viewer - -### Fixed -- [#1096] FLA export - pretty print -- [#1104] AS1/2/3 Script Importat not working -- [#1107] Text Offset Incorrect fixed -- [#1106] New Shapes replace function fix -- [#1113] It takes too long to switch between rendered sprite -- [#1075] Lenght of DefineText in some cases -- [#1127] autoRenameIdentifiers is not supported in CLI mode -- [#1128] Letterspacing bug (after font embed): ignore letterspacing when character changed -- [#1103] Foreach variables fixes -- AS3 Switch fixes -- Default clause position in switch -- [#1133] Incorrect frame order for nested sprite -- [#1135] Handle try "to" in p-code correctly -- Font wideOffsets,wideCodes fixed in DefineFont2/3 -- AS3: super method call -- [#1138] All exported videos are the same file which may be broken -- [#1139],[#930] Windows Installer: Correct ActiveX download link, Download latest java from webpages -- [#1137] running flashplayer(debugger) executable in Linux/MacOs -- [#1144] Command line argument renameInvalidIdentifiers -- [#1145] double not (!!) not removed -- [#1147] Sprite is exported incorrectly -- [#1148] handing end of stream exception in abc reader, loc exception -- [#1152] Font info tag modified tag was not set => saved swf was corrupt -- [#1154] Some 32bit JRE problems - program won't start -- [#1145] Correct precedence handling on binary operators -- [#116] not resolving unusual tags in DefineSprite - -## [7.1.2] - 2015-12-03 -### Fixed -- AS3 debugger start halt fix -- AS1/2 debugger fix on nondebug enabled SWFs -- AS1/2 debugger fix for functions -- Debug menu item enabled fix -- AS3 local reg index fix -- Advanced settings calendar -- AVM2 instructions in hex view -- [#1070] Incorrect switch decompilation -- [#1098] Import XML fix - -## [7.1.1] - 2015-11-23 -### Fixed -- Critical debugger fix - widelines - -## [7.1.0] - 2015-11-23 -### Added -- AS1/2 debugger -- Breakpoint/IP marker on line beginning - -### Changed -- Starting debugger on demand -- Installer message about playerglobal is only warning now - -### Fixed -- [#1033], [#1083] AS3 deobfuscation issues -- [#1091] AS 1/2 direct editation saving - -## [7.0.1] - 2015-11-18 -### Fixed -- Debugger: Adding breakpoint if script initializer not displayed - -## [7.0.0] - 2015-11-18 -### Added -- AS3 Debugger - breakpoints, stepping, show variables -- Faster AS3 direct editation - -### Changed -- Better Configuration of flashplayer paths - -### Removed -- Removed old "debugger" buttons -- Removed search from browsers cache - inactual code - -### Fixed -- Many AS3 direct editation related bugs -- [#1076] export fix - -## [6.1.1] - 2015-10-30 -### Fixed -- Deobfuscate AS3 metadata -- [#1068] MorphShape with focal gradient fix, FLA XML export formatting fix -- [#1063] AS3 direct edit - script initializer fix, generating method names -- XML export/import fixes -- [#1019] Namespace imports fix -- AVM2 code execution fix -- [#1016] AS3 direct editation fixes -- [#1010] AS2 direct editation - internal and override is not a reserved word -- [#1008] pushshort instruction diassembly -- [#1004] this/super can be AS1/2 variable -- [#933] AS3 allow numbers as object literal keys - -## [6.1.0] - 2015-10-26 -### Added -- Open other loaded SWFs during playback (useful for loaders) -- Export uncompressed data from dump tree -- Print performance statistics from commandline -- [#1062] Editing/displaying script initializers -- Enable debugging on SWF file (commandline) - -### Changed -- Faster syntax highlighting -- Better AS1/2 deobfuscator -- [#418] AS3 deobfuscator improved - -### Fixed -- AS call method fix (first parameter is "this") -- [#1047] open all scripts folders -- [#812] decompile fail -- [#1056] deltaY missing when adding a new StraightEdgeRecord -- [#1057] Editing as in editor results in package name moving -- [#991] GUI export -- [#689] Ignore Case not correctly toggled -- [#1060] reversed and/or detection in some cases -- [#1037] isXML call - -## [6.0.2] - 2015-09-12 -### Added -- AS3: Display and direct edit trait Metadata -- Allow to specify tag type on image or shape import -- Convert image tags from commandline -- [#489] Hex decode very large integers -- Add new tags without show empty folders -- Dependent characters in basic tag info -- [#1007] replace bytearray in raw editing -- Italian translation - -### Changed -- AS2 parser - add string to constant pool if there is not enough space -- [#1044] AS2 - order scripts by physical location, name by offset - -### Removed -- Deprecated commandline parameters removed - -### Fixed -- JNA problems on some JDKs -- [#947] Marklevels errors ignored 17a94b7 -- [#953] Mac application permission fix (maybe) -- [#954] IndexOutOfBounds fix -- [#950] AddTrait setting modified fix -- [#945] AS1/2 directeditation fix - member named as global function -- [#957] AS1/2 IndexOutOfBounds fix -- [#956] Invalid jump offsets warning -- [#968] Sprites export with wrong coloring -- [#978] case sensitivity of filenames -- [#955] AS2 decompilation problem -- Image alpha fixes -- [#966] Go to document class -- [#991] scripts exporting -- [#999] save as fla -- [#1000] image export for malformed JPEG3 tags -- [#1017] store alchemy opcodes with wrong order -- [#1030] stack overflow fix - -## [6.0.1] - 2015-07-06 -### Added -- Special §§ instructions marked as red -- [#949] Replace alpha channel from commandline -- AS3 deobfuscation from commandline -- Option to ignore FlashCC/Alchemy packages - -### Changed -- [#944],[#991],[#939],[#942] AS3 deobfuscation improvements - -### Fixed -- AS1/2 deobfuscation fixed -- [#952] Not loading SWF without extension - -## [6.0.0] - 2015-07-04 -### Added -- New AS3 deobfuscation method -- Internal "preprocessor" §§ actions introduced - §§pop,§§push,... -- Allow reload FFDec when no SWF is opened -- [#858] Allow to set compression type in header -- [#905] Show codec details for sound items -- Better alchemy/DomainMemory instruction handling -- Better obfuscated names handling -- [#920] Export instance name to SVG -- [#921] Export html DefineEditText to SVG -- Open multiple files with drag and drop -- Better "multi packs" handling (Alchemy) -- SWF version 29 to flash player 18 mapping -- ImportAssets2 sha1 field -- [#924] Sprites to image from commandline -- AS1/2 direct editation big numbers fix -- Allow to add FILTERs and SHAPERECORDs in generic tag editor -- Enable close all menu when no swf is selected -- Restore modified state even when something goes wrong -- Some old tags added - -### Changed -- AS decompilation highly improved -- Better &&, || handling -- DoABCDefine renamed to DoABC2 -- Separated Sprite export settings - -### Deprecated -- Old AS1/2/3 deobfuscation method marked as deprecated (can be enabled back deep in the configuration) - -### Fixed -- Many decompilation problems - EmptyStack exception, Maximum recursion level reached, etc. -- Few menu issues -- [#895] Correct handling CMYK JPEG -- [#884] AS direct edit assignment -- [#899] Show script after AS3 direct editation -- Some AS1/2 parser problems -- [#903] FLA export - fix for missing fontname, lastframe -- [#855] AS3 direct edit - for..in variable declaration fix -- [#850] Constant initialization for same multinames -- [#832] AS3 direct edit - other ABCs resolving fix -- [#904] Cannot export images -- [#910] Missing instructions -- Opening not existent files on restoring last session -- [#922] Edit text leading -- Put image before shape on shape replace -- [#916] Replacing Shape corrupts SWF -- JRE setup parameters fixed -- [#938] Parallel speedup limit fix - -## [5.3.0] - 2015-05-25 -### Added -- Generic tag editor: improved table editing (import/export assets tags, etc.) - -### Changed -- Classic (nonribbon) UI improved - has same items as Ribbon UI -- Icons improvements -- Disabling menu items when work in progress - -### Fixed -- [#897] Classic UI fix - -## [5.2.0] - 2015-05-22 -### Added -- UI8 editbox for swf version in header panel -- Basic tag information panel - -### Changed -- AS1/2: Shown only the constant pool(s) in pcode editor -- Do not allow to chage tag tree selection, when current tag is under editing -- Faster bitmap export -- Using less memory when playing sounds -- Error message changed when the opened file is not swf - -### Fixed -- [#470] panels size after resizing from/to full screen -- [#877] A small glitch after search in AS -- [#878] small glitch after saving P-code or swf file -- [#470] glitch -- [#845] If frame consist 2 DoAction then it imports only first one -- pdf export (when no frame exists) -- text rendering (alpha channel was ignored), -- bmp export (paddings when width%2==1) -- [#883] -dumpSWF option does not work anymore -- [#882] Canvas export border size -- [#760] Internal viewer line linear gradient fill is not working -- [#887] error on export a special swf's P-CODE -- Extensions of exported images fixed - -## [5.1.0] - 2015-05-04 -### Added -- Allow to copy/move multiple tags, and dependencies -- [#842] For reconstruction if debug line info present -- [#841] Loop control for sound preview -- [#845] Import exported AS1/2 (DefineButton2&DefineSprite) button -- Scrollbar added to fontpanel -- SWF header editor -- Configure what object types to export in exportdialog - -### Changed -- Better gif exporter -- [#772]: closing loading dialog now cancels the loading of the swf -- [#762] export pcode with different extension - -### Fixed -- CRITICAL: Update System Bug causing updates not working -- [#862] AS3 asm: do not read beyond return/throw instructions -- [#865], [#613]: ribbon prefered width fix -- [#868] export path fix, allow to export buttons -- [#865] TagTree font size problem on high resolution screens -- [#713],[#807] Installer for 4.0+ fails to access Adobe Website -- [#728] Large fonts, [#857] add scroll on DefineFont3 - -## [5.0.2] - 2015-04-18 -### Added -- Reopen last session - -### Fixed -- ffdec.sh file line endings fixed - -## [5.0.1] - 2015-04-18 -### Fixed -- [#860]: Opening bundle (zip, swc, any binary file) files fixed - -## [5.0.0] - 2015-04-18 -### Added -- Color skins -- [#824] Mac OS X package -- [#809] Move left,right buttons for DefineTexts using translatex parameter -- [#805] Editor mode for DefineTexts -- [#825] Hotkeys for next/previous DefineText -- Export/Import symbol classes/export asset tags -- Frame export progress -- [#737] Single file script export -- Displaying changed AS3 scripts in GUI as bold -- Additional character info tags placed under character node -- New icons for other tags (metadata,fileattributes,setbackground,place/remove) -- Metadata tag editor - -### Changed -- Default color skin altered -- [#350] Allow only one running instance (Windows only, can be turned off) -- SWFs in zip based bundles (SWC for example) can be modified & saved -- Performace improvements -- More compact SWF-XML format -- Marking changed parentnodes as bold too - -### Fixed -- [#814] Exporting with scale problem -- [#816] P-code not shown after class initializer trait selection -- [#835] Static initializer improvements -- AS3 direct editing - local register decrement fix -- AS3 direct editing - maintain register order/names -- [#836] AS1/2/3 Correct expression precedence handling -- AS3 preincrement -- [#848] Correct toggling text switches -- [#817] AS1/2 for..in variable declaration -- [#849] Attribute member -- [#852] Ignore case for russian characters -- [#837] AS3 try..finally without catch - -## [4.1.1] - 2015-02-21 -### Added -- Export/Import XML added to ribbon menu -- Few GUI enhancements -- Undo tag changes context menu - -### Changed -- Java 8 now required - -### Removed -- Removed support for Java below 8 - -### Fixed -- [#811] export ActionScript - -## [4.1.0] - 2015-02-18 -### Added -- XML export/import -- confirmation dialogs added -- Add support for non-standard ABC-compressed SWF file -- [#745] Copy tag to another SWF -- [#803] Align text in DefineText - -### Changed -- performance improvements -- [#758] Zoom to fit is dynamic - -### Fixed -- [#738] Frame export -- [#742] Can't edit frames -- [#747] Move tag to adds extra frame -- [#749] Internal viewer Sprite fill color -- [#752] Sound is not stopped -- [#753] Reload swf -- [#759] Decompilation § symbol -- [#766] Can't extract all resources -- [#768] Super calls not being correctly recognized -- [#773] Scripts associated with ClipActions are not shown -- [#776] Stop working after setting "number of threads" to 0 -- [#783] No OK box when edited script or text was saved -- [#785] Text search. Remember last choise, Unicode case insensitive search -- [#787] Search in AS bug (when navigating to searched results) -- [#788] Add DefineCompactedFont Tag to gfx file -- [#790] Impossible to change letters under a font -- [#794] Font extraction fails sometimes -- [#798] Close file streams after export, exporting progress -- [#800] Unexpected deleted carrier return in DefineEditText -- Build fix on Linux -- Fis Startup Script for OpenJDK -- Other minor fixes - -## [4.0.5] - 2014-12-01 -### Added -- Escape control characters in strings, identifier names -- [#676] import text error messages / logging enhancement -- [#734] \xAB escapes, \uABCD escapes -- [#687] AS3 - allowing p-code comments on separate line -- [#709] Text Export to Single File with custom filename - -### Fixed -- [#732] Random freezing - JavactiveX library updated. -- [#730] Not working without ActiveX fix on Windows -- [#735] Automatic deobfuscation not correctly switched (required restart) - -## [4.0.4] - 2014-11-23 -### Changed -- better file cache, removing unneccessary temp files - -### Fixed -- obfuscated identifiers - -## [4.0.3] - 2014-11-23 -### Added -- [#722] Go to next/previous frame -- BMP file format export (images,frames,shapes) and import(images) - -### Fixed -- [#725] various AS direct editation bug fixes - namespace compilation, AS 1/2 strict equals, submethod scope, unbounded type -- [#715] namespace resolving fix -- [#635],[#726] placing cursor inside Unicode characters - -## [4.0.2] - 2014-11-22 -### Added -- show frame number during play -- flashplayer - show controls for DefineSprite -- goto frame -- [#716],[#717],[#718] Proxy - save SWF, replace, copy URL, filesizes, table design - -### Changed -- [#720]: edited shape tag is not marked as modified after replacing -- reorganized about dialog - -### Fixed -- [#719] null swf name in Proxy after cancelling rename dialog -- flashplayer - font display -- [#723]: saving swf with invalid referenced characters -- DefineCompactedFont paging -- [#288] Less memory usage during FLA export -- Corrected syntax hilighting for AS3 P-code - -## [4.0.1] - 2014-11-12 -### Fixed -- [#713] Installer can continue when no file can be downloaded -- Fixed shapes -- Checking for updates moved to separate thread - -## [4.0.0] - 2014-11-11 -### Added -- [#677] Zoom level in export settings -- internal viewer: linear/srgb gradients -- zooming buttons for flashplayer/internal viewer -- stroke scaling modes for canvas export -- create snapshot button -- [#389] Selecting font face on import -- [#701] Importing font from TTF file -- Reorganized font panel -- [#707] Debugger for logging messages -- [#302] AS3: Better Ctrl+Click handling with underline, more declaration targets -- [#685] Getting local register names from debug info can be disabled -- Adding new tags -- [#698] Allowing unicode letters in identifiers -- [#710] Information about deobfuscation in error comments -- One EXE for 32/64 bit, uses percentage memory. -- EXE SplashScreen -- New Improved Windows Installer (NSIS) - can install Java and FlashPlayer, download playerglobal.swc -- Config setting to load inner SWFs automatically -- Replace shape with image - -### Changed -- better FlashPlayer integration using JavactiveX library -- Faster building tag tree -- Faster timeline construction -- [#711] Improved folder view - faster and with correct context menu - -### Fixed -- AS2 deobfuscation fixes -- AS2 loops fix -- [#681] Linux script fixes -- AS2 constructor name fix -- [#688] AS3 direct edit fixes -- [#691] AS3 p-code reading/saving fix -- AS3 direct edit -submethod name resolve fix -- frames to html canvas fix -- [#524] Mask layer not applied when nonempty script layer -- [#663] AS3 imports fixes -- Font export of dot character -- Font panel Yes button fixed -- [#702] GFX font reading fix -- Better obfuscated names handling -- [#539] for(each) in declaration fixes - -## [3.0.0] - 2014-09-20 -### Added -- Separated GUI (GPL) and library (now LGPL) -- Editing obfuscated identifiers via new paragraph(§) syntax -- Timeline View with preview and object hilighting -- Show GFX data in dump view -- [#650] New parameter to replace binarydata, images, sounds, scripts from commandline -- Dump view - selecting node -- [#680] Loading subSWFs from binaryTags now optional (button/context menu) to avoid unnecessary memory consumption - -### Removed -- Removed deprecated commandline export formats (see --help) - -### Fixed -- FileAttributes tag reading fix -- [#649] GFX reading fixed -- [#656] Search in memory - 64 bit processes fix -- [#661] scripts not showing -- [#664] expanding fillStyles in raw edit -- [#668] add missing character fix, text tags fix -- [#674] texts hilighting initialization fix -- [#675] AS1/2 and/or operator compilation -- [#632] Locking file after opening (cannot save, etc.) -- [#651] Unnecessary removing expression killed in unreachable part -- [#678] Windows batch file paths fixed -- [#672] Disabling transparency slider on RGB only selection -- [#684] Sound streams inside DefineSprites, soundstream handling - -## [2.1.4] - 2014-08-23 -### Added -- AS1/2: New method for deobfuscation (can be switched off in settings) -- AS1/2: Using eval/set on invalid identifiers, quotes in function names/parameters - -### Fixed -- [#647] Skipping FileAttributesTag with Parallel speedup on -- [#648] Export from embedded SWF - -## [2.1.3] - 2014-08-18 -### Added -- Show "save" and "saveas" in application menu -- Saving data range in dump view -- Show actions, abcdata in dumpview (context menu on the tree node) -- [#612] show color in hex format - -### Changed -- Faster dump info collecting (less memory) -- Allow selecting multiple files in open file dialog - -### Fixed -- [#623] ffdec.sh UNIX file endings, executable -- [#624] search in embedded swf files -- [#632] AS1/2 Unnecessary GetVariable before NewObject -- [#627] filter swf not working -- LZMA saving -- Export pcode&hex from commandline -- [#640] text import fixed, ignore BOM - -## [2.1.2] - 2014-07-20 -### Added -- Dump view -- Context menu: Jump to character, raw edit all tags -- Catalan translation -- SWF header display - -### Fixed -- [#595] AS3 direct edit - Getter/Setter generation - caused FlashPlayer crashes -- [#592] AS3 Multiname resolving in P-code causing different bytecode -- [#585] AS3 moving popped values to output -- [#578] Always on top fixed on search results -- [#501] GotoFrame2 fix -- [#616] Frames to PNG export -- Export context menu -- [#559] Bitmap export opacity -- [#401] Placeobject 3/4 fix -- [#593] Return object newline -- [#594] Setting for curly brace - -## [2.1.1] - 2014-06-05 -### Added -- [#302] Find declaration (Ctrl+click, Ctrl+B), Find usages (Ctrl+U) - Works only for exactly same multinames, not local registers -- AS1/2 direct edit - global functions improvements -- AS1/2 negate operator, unary minus operator -- Opening SWFs in BinaryData tags -- AS1: Old string operators support, and/or, <> operator (editation) -- Statusbar loading animation improved -- [#579] AS3 direct editation - removing old class/methods from ABC -- remove character without the dependencies (remove only the place/remove tags) -- Running on system with no home directory -- [#428] PDF export (as images only) -- Commandline FlashPaper to PDF export -- Select frames / Characters commandline options - -### Changed -- [#337] quickfind visibility improved -- [#584] commandline script export - select whole packages (use .+ at the end of -selectas3class) - -### Fixed -- [#576] AS1/2 direct editation: DefineFunction2 fix -- AS1/2 property fix -- AS1/2 typeof operator fix -- [#250] line spacing fix -- PlaceObject 3-4 className -- [#579] AS3 direct editation bugfixes - property resolving, integer values -- Morphshape canvas export fix -- Canvas export fix - closing path -- [#580] Rename invalid identifiers commandline fix -- [#510] JSyntaxPane find and replace dialog wrap around fix -- No more frame caching during export => memory saving (like [#583]) -- [#586] DropShadow filter fix -- Canvas export colortransform fix - -## [2.1.0 update 2] - 2014-05-08 -### Added -- AS3 decompilation/editation: Vector initializers -- AS3 direct editation: more classes in one file - -### Fixed -- [#574] DefineSprite editing fix -- Various AS3 direct editation fixes - -## [2.1.0 update 1] - 2014-05-05 -### Added -- Portugese-brasilian translation - -### Changed -- HTML Canvas export improvements - -### Fixed -- Various AS3 direct editation bugs, like [#570] - -## [2.1.0] - 2014-05-01 -### Added -- AS3 direct editation (Experimental!) -- Frames SVG Export -- Shape/MorphShape/Frames HTML 5 Canvas Export -- [#559] morphshapes as animated SVG -- [#563] Single file text export/import -- Font WOFF export -- Advanced settings dialog with tabs, config names, descriptions - -### Fixed -- [#561], [#509], [#433]: AS3 EmptyStackException fix - correct hasnext2 arguments -- Internal viewer: Filters fix - -## [2.0.1 update 2] - 2014-04-05 -### Fixed -- [#557] AS3 null namespace fix - p-code not working - -## [2.0.1 update 1] - 2014-04-04 -### Fixed -- [#556] Goto main class on startup fix -- [#557] Nullpointer fix (private namespaces) - -## [2.0.1] - 2014-04-03 -### Added -- Thumbnail view -- Font TTF export -- Exporting frames: PNGs, AVI, GIF (via Internal flash viewer) -- Expand all context menu -- Internal viewer: Button mouse move and click handling -- Playing sounds without flash player -- Internal viewer: Sounds on stage -- All sounds to WAV export -- Internal viewer: Showing texts, dynamic text border/fill -- [#504]: Unicode characters in JSyntaxPane -- Internal viewer: showing object under cursor -- Folder icons -- Sound/Image format on command line. -- Removing placeobject tags -- Removing frames -- AS: "elseif" statements -- Code formatting: space before parenthesis - -### Changed -- Single frames animated. - -### Fixed -- [#529] limit the number of displayed binaryData bytes -- [#538] Interface are sometimes dynamic -- [#537] super is sometime preceded by a dot -- [#540] Saving SWF changes very large static uint values -- [#387] Frames preview bugged -- AS:loop mismatch fix on parallel speedup -- [#552] Some timeout exceptions -- [#494] Fixed nightly builds updates - -## [2.0.0] - 2014-03-02 -### Added -- Generic tag tree editor -- Timeline view (stub only) -- FLA export to CS5, CS5.5, CC format (previously only CS6 was supported) -- [#513]: command line option to extract swf from binary file -- Configurable code formatting (Indentation + brace position) -- [#262] Export FLA: Font character ranges export -- Configurable checking for updates - -### Changed -- Improved Internal Flash viewer - better shapes, morphshapes, DefineEditText tag, clipping, blend modes -- Improved commandline usage -- Automatic deobfuscation default value set to False (See News on webpages) -- Check for updates can be configured to inform about Nightly builds aswell - -### Deprecated -- Some commandline options are now deprecated, see --help - -### Fixed -- [#499] Cannot save via Proxy fixed -- [#504] font name reading fixed -- [#508] Support for OS without GUI -- [#305] Export FLA: empty sound layers -- [#312] Export FLA: Improved Shape/MorphShape fix -- [#503] Export FLA: Smoothing invalid shapes -- [#401] Invalid GFX tags in non GFX files -- [#304],[#306],[#507],[#424],[#425],[#478],[#485],[#517],[#518] Many direct AS1/2 editing issues -- [#361] FFDec icon is not visible on application start -- [#392] Video stream data fix -- [#516] AS3 P-code editor - Null name namespace handling - -## [1.8.1 update 1] - 2014-02-02 -### Fixed -- [#495] font embedding fix -- [#496] date format in new version dialog -- cosmetic changes - -## [1.8.1] - 2014-01-30 -### Added -- [#299] replace DefineBits images -- [#303] open folder with exported FLA -- [#324],[#346] SWC/zip/other binary file support -- [#371] detailed logging -- [#426] command line switch to rename identifiers -- [#457] clear recent opened files list -- [#458] save selected system font for swf fonts -- [#460] text editor: do not scroll to the end automatically -- [#462] font embedding dialog: show more sample characters -- [#463] global search in texts -- [#465] make font properties editable -- [#466] font preview - -### Changed -- [#369] new SVG and preview image rendering -- [#390] refresh font list without reloading the application -- [#453] update texts aftert adding new character to a font tag -- [#459] remember text panel splitter position -- [#461] font panel gui redesigned - -### Fixed -- [#451] dialog windows are not on the center of the screen -- [#454] Text syntax highlighting -- [#455],[#465] classic interface issues -- [#474] changeing language only available one time -- [#477] log window localization -- [#481] SVG export fix -- [#484] Oversized advance value after editing DefineText with DefineFont2 font -- [#493] missing search results - -## [1.8.0 update 1] - 2013-12-27 -### Added -- [#453] refresh (edit+save action) all texts button - -### Fixed -- Flash panel and font panel fixed - -## [1.8.0] - 2013-12-27 -### Added -- [#350] Allow to open multiple SWFs -- [#365] Filter fake SWFs during memory search -- [#366] Allow to sort the result list in memory search window -- [#429] Auto rename invalid identifiers setting -- [#447] Non-ribbon interface - -### Fixed -- [#354] Infinite decompilation fixed -- [#438] Case sensitive Command line arguments fixed -- [#436] Saving actionscript fixed -- [#446] Precedence issue fixed -- [#451] Dialogue window positions on a multi-monitor configuration fixed - -## [1.7.4 update 1] - 2013-12-05 -### Added -- [#426] Command line parameter for renaming invalid identifiers - -### Fixed -- [#427] Exception on linux fixed -- [#405], [#420], [#421] Some decompilation issues fixed -- [#430] Configuration default value problem fixed -- [#397], [#431] Deobfuscation stucked sometimes problem fixed - -## [1.7.4] - 2013-11-10 -### Added -- [#169] hexedit method body bytes -- [#335] last opened files -- [#404] Exporting P-code and Hex + console parameters -- [#407] register name is configurable -- Advanced settings -- Cancellable decompiling, exporting and searching - -### Fixed -- [#399], [#400] performance optimizations - -## [1.7.3 update 2] - 2013-09-29 -### Fixed -- [#398] AS3 p-code values with index 0 (null) - -## [1.7.3 update 1] - 2013-09-28 -### Added -- [#382] AS3: Adding new method - -## [1.7.3] - 2013-09-27 -### Added -- AS3: Multiname and namespace editing. -- [#382],[#396] AS3: Adding new trait (method/slot/const) -- AS3: Highlighting pair parenthesis/bracket -- AS3: Editing various new P-code parameters -- AS3: Highligting of trait names/types/parameters -- AS3: Global rename identifier for traits -- [#357] Playback controls for DefineSound -- [#391] AS3: Native methods mark -- [#395] Support for GFx ScaleForm SWFs (with fonts editing) -- Displaying fonts in internal viewer -- [#334], [#395] New Embed font dialog - selecting character ranges with preview -- Replacing characters in font (Yes/No to all dialog) - -### Changed -- AS3: New p-code syntax inspired by RABCDasm -- AS3: Editing whole trait in one textarea -- AS3: Removed messages about adding new constants -- AS3: Modified colors in editor -- [#301] Clearing error log causes icon to reset - -## [1.7.2 update 2] - 2013-09-13 -### Changed -- Updated translations - -### Fixed -- [#383] Firefox browser cache handling -- [#386] SWF resizing - -## [1.7.2 update 1] - 2013-09-11 -### Changed -- updated translations - -### Fixed -- [#383] Fixed cache loading when Firefox not used - -## [1.7.2] - 2013-09-11 -### Added -- [#357] Sounds Preview (Windows only) -- Movies preview (Windows only) -- Whole SWF display -- Preview controls (Play,Pause,Stop) -- Search SWFs in browsers cache (Firefox, Chrome) -- [#367] Memory search: Save selected files to disk -- Portugese translation - -### Changed -- [#380] Faster displaying DefineBitsLossless(2) images - -### Fixed -- [#292] Background color for Fonts preview fixed -- [#375] Replacing DefineBitsLossless image tag -- [#378] Refreshing language of JSyntaxPane -- MORPHGRADIENT reading fix - -## [1.7.1] - 2013-08-25 -### Added -- Loading SWFs from other processes memory (Windows only, sorry) -- [#325] Spanish translation -- [#210] Ukrainian and Dutch translation -- [#355] Chinese translation -- [#292] Change background color in SWF preview -- [#301] Clear errors log button -- [#313] Command line parameter for ignore all errors -- [#330] Protection agains adding same characters -- [#332] AS1/2 Showing elapsed times during commandline export -- [#344] Reload opened SWF -- Decompilation timeouts - -### Fixed -- [#295] Export FLA: wrong font -- [#297] Too bright titlebar button colors -- [#307] Export FLA: fixed empty textfields -- [#309] Export FLA: static text letter spacing detection -- [#310] Export FLA: Strokes -- [#311] Export FLA: BitmapFill -- [#327] AS1/2 Disassembly error stop application -- [#328] Fixed replacing images in DefineBitsJPEGX -- [#333] AS1/2 action reading -- [#336] Graph window is too small -- [#337] Quick search panel barely visible in same cases -- [#338] Expand/collapse icon in errorlog - -## [1.7.0 update 1] - 2013-08-11 -### Added -- [#315] German translation (partial) - -### Fixed -- [#123] Better context menu integration -- [#243],[#326] Better deobfuscation -- [#287] Typo in parallelSpeedUp parameter -- [#290],[#291] improved select language dialog -- [#294] minor GUI fixes -- [#298] Progressbar positition issues -- [#296] better export directory remembering -- [#314] Better deobfuscating filenames -- [#316] Readonly editor panes accepted Ctrl+Z/Y -- [#318] Export FLA: Shapes export fix -- [#319] AS3: Improved try..catch..finally decompilation -- [#323] AS3: Fixed default switch part - -## [1.7.0] - 2013-08-03 -### Added -- Listing contributors on about page -- [#223] AS2: Detecting uninitialized class fields -- [#250] Export FLA: Detecting static fields margin and spacing -- [#261] Export FLA: AS1/2 Frame scripts on first layer -- [#269] Commandline parameters for switching configuration -- [#274] AS3 Displaying elapsed time during commandline export -- [#275] AS3 Removing returnvoid as last statement - -### Changed -- New GUI based on Substance look and feel -- Menu changed to ribbon panel -- New round icon -- [#258] AS1/2: Improved chained assignments -- [#267] Starting program without choosing a file -- [#286] Saving to temp file first - -### Fixed -- [#123] Improved context menu integration on Windows -- [#233] Globally rename identifier deselects item in the tree -- [#235] Export FLA: Dynamic text fields coordinates -- [#243],[#263],[#264],[#265],[#266],[#281] Improved deobfuscation -- [#251] Export FLA: Fixed filter strength rounding -- [#257] Export FLA: Text field color and size issues -- [#259] Fixed images alpha -- [#260] Export FLA: Labels position -- [#268] AS1/2 Function parameter shown as register instead loc -- [#272] AS3 Class initializer editation fix -- [#276] Fixed anonymous/inline functions handling -- [#220] Improved editing fonts / texts -- [#284],... other small fixes - -## [1.6.7] - 2013-07-20 -### Added -- [#220] Selection of font to import characters from -- [#232] Automatically add .swf extension in saveas dialog -- [#253] Abort/Retry/Ignore dialog on errors with file saving - -### Changed -- Improved translations - -### Fixed -- [#137],[#242], [#243], [#244] AS1/2/3 fixed deobfuscation -- [#203] AS1/2 improved direct editing -- [#220] Adding characters to font fix -- [#225] AS1/2 object literal without name quotes -- [#236] AS1/2 Rename invalid identifiers issues -- [#245] AS3 Double space around "as" keyword -- [#247] AS3 Scrolling to main class at startup -- [#248] Memory issues (slowdown) -- [#254] Expressions as commands -- [#255] Windows 7 loading issues -- [#256] AS3 Object literal in return clause -- SWF text parsing (new lines) -- Labels size by locales - -## [1.6.6 update 2] - 2013-07-16 -### Fixed -- [#241] Program could not be started - -## [1.6.6 update 1] - 2013-07-16 -### Changed -- Better localization support - -### Fixed -- [#238],[#239],[#240] Fixed deobfuscation related problems -- [#237] Parentheses in AS1/2 add,subtract - -## [1.6.6] - 2013-07-16 -### Added -- [#217] Russian translation (focus) -- [#219] Hungarian translation (honfika) -- [#224] Swedish translation (Capasha) -- [#220] Adding characters to Fonts, displaying font info -- [#121] Search progress indication -- Error log - -### Changed -- [#203] Improved direct editing of AS1/2 -- [#207] Update SWF preview after switching external/internal flash player - -### Fixed -- [#151] Memory caching -- [#171] Skipping invalid AS3 code - newobject, newarray -- [#206] AS3 switch problem -- [#208] Renaming anonymous functions -- [#209],[#229] FLA export texts positions -- [#213],[#221] other decompilation issues -- [#225] AS object literal broken with ternar operator -- [#226] onClip indentation in FLA export -- [#227] gotoAndStop wrong frame index -- [#230] FLA export missing strokes -- Shapes viewer - missing strokes - -## [1.6.5 update 1] - 2013-07-09 -### Fixed -- [#151] Fixed caching in memory -- [#172] AS1/2 constant detection fix -- [#174] Renaming SymbolClass fix -- [#175],[#212] Fixed create directory issues on export -- [#185],[#186] on-clip actions indentation -- [#197] AS1/2 Missing storeregister before switch -- [#216] AS2 Fixed field order -- [#213] AS2 Fixed var fields quotes, switch nullpointer - -## [1.6.5] - 2013-07-08 -### Added -- Multilanguage support (currently English and Czech) -- [#151] Option for caching in memory instead of files -- [#168] Export selection in tree context menu -- [#176] option to show main class on startup -- [#177] saving window maximized state -- [#202] Removing tags other than DefineSprite - -### Changed -- [#173],[#190] Better renaming -- [#129], [#153] Better deobfuscation -- [#180] better error handling -- [#185],[#186] better displaying and exporting onclip actions - -### Fixed -- [#123] Better context menu integration -- [#136] FLA export - text sizes -- [#137],[#179] foreach issues (hasNext) -- [#144] Plain text export - empty line fix -- [#144] Not displaying texts -- [#164] DefineMorphShape issues -- [#167] Sprite tag appearing twice in export filename -- [#170] AS3 Try in loop -- [#172] loop detection fix -- [#175] use empty namespace -- [#178] AS subtract with negate -- [#181] AS3 missing quotes in object field -- [#182] missing namespace imports -- [#183] wrong stage size -- [#184] wrong video link -- [#189] Fixed three dots in tree -- [#191] Focalgradient fill fix -- [#195] AS2 issues -- [#196],[#197] switch issues -- [#198] DefineFont2 empty check -- [#200] DefineBitsLossLess fix -- [#201] Nonworking main window in Linux/MacOS (due toAssociation) - -## [1.6.4 update 1] - 2013-06-30 -### Fixed -- [#166] For loops detection -- [#165] AS3:direct lookupswitch support - -## [1.6.4] - 2013-06-30 -### Added -- [#63] Globally rename identifier -- [#67] Deobfuscation - rename identifiers according to type -- [#117] Drag & Drop SWF file to main window opens it -- [#123] Context menu integration on Windows -- [#127] Drag & Drop items from tree outside of application -- [#134] AS3: Find document class -- [#144] New lines in plain text export -- [#155] Remembering window size + splitbar positions between runs - -### Changed -- [#142] Using exportassets tag for tag names -- [#146] Display AS2 classes as tree of packages -- Better loop detection - -### Fixed -- [#129] AS1/2: not refreshing decompiled after rename -- [#130] Renaming SymbolClass identifiers too -- [#132] Renaming identifiers renamed strings -- [#136] Invalid text positions in FLA export -- [#145] Unicode support -- [#147] Escape filenames during obfuscated AS3 export -- [#148] Better package vs classname handling -- [#152] Empty if branches not inverted -- [#156] Better search handling (not freezing) -- [#157] AS3: Try statements in loops -- [#158] Graph repaint problem -- [#159] AS3: Improper rest parameter handling -- [#160] Commandline binaryData export -- [#162] DefineBitsJPEG2 image replacing -- [#163] Closing SWF file after loading -- other minor fixes - -## [1.6.3 update 2] - 2013-06-21 -### Changed -- [#149] Ifs with empty onTrue branches now inverted - -### Fixed -- [#150] Long line restriction removed - -## [1.6.3 update 1] - 2013-06-21 -### Fixed -- Memory limit decreased - FFDec was not working on 32 bit JVM. - -## [1.6.3] - 2013-06-20 -### Changed -- Parallel SpeedUp can be disabled in menu -- Better loop detection - -### Fixed -- [#119] Replacements file not found issue -- [#101] AS1/2 postincrement fix -- [#114],[#116],[#135],[#141] Fixed loop detection -- [#102] Fixed loop highlighting in export -- [#124] Flash player file path detection -- [#128] Improved imports -- [#135] CommentItem fix -- [#129],[#131] Better deobfuscation -- [#104] AS3 inc/dec local deobfuscation fix -- [#113],[#133],[#140] Memory limit increased - -## [1.6.2] - 2013-06-09 -### Added -- New loop detection algorithm - -### Changed -- [#108] - Faster loading and decompiling (Parallelism) -- Improved Internal flash viewer - shapes and morphshapes - -### Fixed -- Ternar operator fix -- [#102] Fixed Shapes to FLA export -- AS1/2 class detection fix -- [#105],[#104],[#101] fixed via new loop detection - -## [1.6.1] - 2013-06-03 -### Added -- Internal Flash Viewer - preview of flash parts (shapes,sprites,frames) without need of Flash Player. (Used on nonWindows platforms by default) -- [#109], [#106], [#107] some code improvements - -### Changed -- Application needs Java 1.7 to run - -### Removed -- Support for Java before 1.7 - -### Fixed -- [#102], [#110] AS3: Class highlight fix -- [#103] AS3:Fixed setslot handling -- [#104] AS3:Inc/Declocal nullpointer fix -- [#104] Multiple conditions in loop fix -- [#111] AS3:Object literal truncates line -- [#105] Better do while..break handling -- loop fixes - -## [1.6.0 update 1] - 2013-05-25 -### Added -- better FLA export - -### Fixed -- Many FLA export related bugs (like [#96]) -- [#98] Empty initializers do not cause empty lines now -- [#99] small logging issues -- [#100] large obfuscated code support - -## [1.6.0] - 2013-05-20 -### Added -- Export to FLA (Experimental BETA!) -- [#85] Search text in all ActionScripts -- SWF 11 support - -### Fixed -- [#79] ActionStartDrag constraint fix -- [#92] Inversed GreaterThan/LessThan -- [#93] AS1/2 fixed switch detection -- [#94] AS1/2 ActionTry - register cast fix -- [#95] Better script end handling - -## [1.5.2] - 2013-05-05 -### Added -- Improved automatic update system (changes log). -- Handling script traits as separate objects. -- [#86] open/save file dialog now accepts absolute paths in quotes - -### Fixed -- [#87] Not displaying image changes in DefineBitsLossLess1 & 2 -- [#88] Fixed graph building -- [#89] AS3: bracket in property name lead to missing dot -- [#82] printgraph issue - -## [1.5.1 update 1] - 2013-05-04 -### Added -- Exporting texts via commandline -- Exporting all via commandline - -### Fixed -- DefineText2 color parameter -- AS3 GetSlot,SetSlot -- [#78],[#81],[#82],[#84] Fixed deobfuscation, exceptions during printgraph,... -- [#83] Fixed images transparency (zlib fix) -- Fixed graphparts with only jump in it (obfuscators) -- MORPHGRADIENT FIX -- Trasparency in DefineBitsJPEG3 and 4 -- Displaying shapes,morphshapes and sprites with bitmaps - -## [1.5.1] - 2013-05-01 -### Added -- Support for larger switches (10+cases) -- Editing text tags -- [#65] Exporting text tags -- Removing sprites -- Replacing images - -### Fixed -- DefineMorphShape2 fix -- [#79] - AS1/2 class detection fix, wrong printgraph fix -- [#78] - script trait slots fix - -## [1.5.0 update 1] - 2013-04-21 -### Fixed -- Automatic deobfuscation config defaulted to Off for AS1/2. - -## [1.5.0] - 2013-04-20 -### Added -- Direct editing of ActionScript 1/2 code (Beta) -- AS1/2: ifFrameLoaded support -- Automatic deobfuscation can be disabled in the menu -- [#48] - Decompile only specified class (commandline option) -- [#53] - AS3: Displaying multiname indices in trait detail, displaying method indices -- [#66] - Decompressing LZMA via commandline -- [#68] - Exporting DefineBinaryData tags, assigning class names to characters (SymbolClass tag) -- [#69] - DoABC vs DoABCDefine tags decompilation -- [#75] - Comma separator in while/do..while conditions, better if..return handling -- AS1/2: parsing NaN,Infinity value (Fix for [#73]) - -### Changed -- New icons (edit/save/cancel and main menu) - -### Fixed -- [#62] - Errors on not defined character tags (import tag) -- [#72] - First ternary operator expression was always true -- Fixed many deobfuscation related bugs - -## [1.4.3 update 2] - 2013-04-10 -### Fixed -- [#64] - AS1/2 Resolving registers in ActionDefineFunction2 (super,this,...and parameters shown as registerxx) -- Try to fix lib/FlashPlayer.exe issue - -## [1.4.3 update 1] - 2013-04-06 -### Fixed -- [#38] - Indentation in const/var initializers, missing semicolon -- [#56] - Test output left in last release -- [#57] - Unknown instructions now do not log an exception (obfuscators do this) -- [#58] - Index out of bounds exception fix on methodinfo indices in imports detection. -- AS3 loops fix -- While true fix - -## [1.4.3] - 2013-04-04 -### Added -- AS1/2 Better deobfuscation - -### Fixed -- [#45] - Unicode characters fix -- [#50] - AS1/2 Function body deobfuscation fix -- [#51] - Displaying java class names instead of expressions -- [#52] - AS1/2 Better constantpool detection (deobfuscation) -- [#38] - AS3 indentation in initialized const/var value for newobject -- Fixed ImportAssets2 tag id - -## [1.4.2 update 1] - 2013-03-25 -### Fixed -- [#47] - wrong AS3 deobfuscation -- AS3 deobfuscation issues -- AS3 switch - -## [1.4.2] - 2013-03-24 -### Added -- [#42] - Displaying code as hex -- AS1/2: Renaming identifiers (deobfuscation) -- AS1/2,AS3: Better deobfuscation -- Storing configuration to user home -- Installer for Windows systems - -### Changed -- Graph button changed to icon. - -### Fixed -- [#39] - AS1/2 NewMethod..Pop fix -- [#40] - No logging + For..in..return decompilation -- [#44] - DefineFont2 fix -- [#36] - Multiname with invalid index -- [#43] - Ternary operator and more -- [#46] - Ifs with empty branches got ignored -- [#3] - Ignoring unknown opcodes -- Logging exceptions during export - -## [1.4.1] - 2013-03-10 -### Added -- Exporting sounds -- Better AS1/2 deobfuscation (disassembly & decompilation) - -### Fixed -- Exporting only first 1000 frames of the movie -- Decompiled code was not refreshed on AS1/2 changes -- Application no longer creates empty directories on export - -## [1.4.0 update 1] - 2013-03-04 -### Fixed -- [#37] - AS3: Reversed loop conditions - -## [1.4.0] - 2013-03-03 -### Added -- AS3: ignoring return void at the end of methods -- New icons - Silk icons -- AS3: Traits list sort button -- Better Graph display -- Frames view -- Exporting of movies (No audio) -- Some AS3 related Tests -- Homepage & Donate link in the menu - -### Changed -- Tree view instead of tabs -- AS1/2 and AS3 now share same decompiling method. - -### Fixed -- [#34] - Reversed loop conditions -- [#35] - Fixed unicode strings (Japanese) - -## [1.3.1] - 2013-02-23 -### Changed -- Flash player no longer uses SWT library - -### Fixed -- [#32] - AS2: Action255 bug -- [#31] - Erorrneous tags are now ignored -- DefineBitsLossLess 1&2 on 8bit colormapped images - -## [1.3.0] - 2013-02-17 -### Added -- Decompilation is more resistant to obfuscation -- Shapes SVG export -- AS2: Decompiling classes & interfaces -- Click&go feature - clicking actionscript source displays appropriate P-code instruction and vice-versa (both AS1/2 and AS3) -- AS3: Deobfuscation menu -- Graph button for displaying code flow Graph - -### Changed -- Complete new decompiling method in both AS1/2 and AS3 -- Application renamed from "JP ActionScript Decompiler" to "JPEXS Free Flash Decompiler". -- To edit source, Edit button must be pressed first (Due to click&go feature) - -### Fixed -- AS3: Method info editor fixed -- Edittext & Button displaying - -## [1.2.0] - 2013-01-19 -### Added -- Displaying various SWF objects (shapes, sprites,...) with flash player library (Windows only, sorry). -- Images display and export -- AS2: Exporting selection -- Progressbar during loading - -### Changed -- One merged window for AS1/2 and 3. -- Updated icons - -### Fixed -- AS3: xml attrib, switch in anonymous function (in AS2 too) - -## [1.1.0] - 2013-01-02 -### Added -- Checking for updates -- AS2: Exporting -- AS3: Decompiling whole scripts instead of just classes -- AS3: Exporting selected scripts -- AS3: Script search bar -- AS3: List of DoABCTags now has default "- all -" item -- AS3: Better imports, use namespaces -- AS3: XML related instructions -- AS3: Anonymous functions with names -- AS3: Better initialization of const values -- Logging exceptions to log.txt file - -### Fixed -- AS3: set_local..get_local, dup, chained assignments, highlighting, callsupervoid, typenames, with statement, loops - -## [1.0.1] - 2012-12-26 -### Added -- AS3: Runtime namespace resolving -- AS3: Arguments variable -- AS3: Better recognizing Pre/Post Increments/Decrements -- AS3: Better declarations - -### Fixed -- AS3: Fixed static variables - -## [1.0.0] - 2012-12-24 -### Added -- Support for LZMA compressed files -- AS3: Detecting local register types for declaration. -- AS3: Displaying inline functions -- AS3: Last save/open dir is remembered -- AS3: Better usage detection for multinames -- AS3: Commandline arguments for exporting -- AS3: Better chained assignments -- AS2: FSCommand2 instruction support -- Proxy: Mimetype application/octet-stream added -- Added executable for Windows users. - -### Changed -- AS3: GUI - Constants tab moved to the top -- AS3: Deobfuscation is now optional, can be accessed via menu - -### Fixed -- AS3: rest parameter, for..in, fail on large classes (due to sub limiter) -- Other minor fixes - -## [beta 1] - 2011-07-30 -### Added -- AS3: Automatic computing method body parameters (EXPERIMENTAL) -- AS3: Editing return type of methods -- AS3: Editing type and default value for variables/constants (Slot/Const traits) -- AS1/2: Few enhancements -- About dialog - -### Changed -- Gui: Updated Icons - -### Fixed -- AS 1/2: Fixed large bug causing Ifs to not decompile properly -- Proxy: Some minor fixes - -## [alpha 10] - 2011-07-13 -### Added -- AS3:Highlighting actual line -- AS3:Completing instruction names via Ctrl+Space -- AS3:Editing method parameters, method body parameters via tab panel -- AS3:ByteCode minor_version 17 supported - decimal datatypes -- AS3:Local variables and method parameters take name from debug information if present -- AS3:Automatic renaming of classes/methods when obfuscated names -- AS3:Better error messages (When cannot decompile obfuscated code) - -### Fixed -- AS3:Fixed Vector datatypes (TypeName multiname, applytype instruction) -- AS3:Hilighting fixes -- AS3:Fixed decrement/increment statements decompilation -- AS3:Decompiler now adds variable declarations on the beginning of decompiled method -- AS3:Try/catch statements fixed when debug information present -- AS3:Fixed for each statements -- AS3:Other minor fixes - -## [alpha 9] - 2011-07-02 -### Added -- AS3: Added disassembling of some new types of instructions -- AS3: Exporting source as PCode - -### Fixed -- AS3: Many other bugfixes... - -## [alpha 8] - 2010-09-19 -### Added -- AS3: Editing exceptions -- AS3: Finding usage of multinames from constant table - -### Changed -- AS1/2: Better GUI -- AS1/2: Better decompiling of Ifs, For..in - -## [alpha 7] - 2010-09-04 -### Added -- Initial public release - -[Unreleased]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version9.0.0...dev -[9.0.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version8.0.1...version9.0.0 -[8.0.1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version8.0.0...version8.0.1 -[8.0.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version7.1.2...version8.0.0 -[7.1.2]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version7.1.1...version7.1.2 -[7.1.1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version7.1.0...version7.1.1 -[7.1.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version7.0.1...version7.1.0 -[7.0.1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version7.0.0...version7.0.1 -[7.0.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version6.1.1...version7.0.0 -[6.1.1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version6.1.0...version6.1.1 -[6.1.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version6.0.2...version6.1.0 -[6.0.2]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version6.0.1...version6.0.2 -[6.0.1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version6.0.0...version6.0.1 -[6.0.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version5.3.0...version6.0.0 -[5.3.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version5.2.0...version5.3.0 -[5.2.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version5.1.0...version5.2.0 -[5.1.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version5.0.2...version5.1.0 -[5.0.2]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version5.0.1...version5.0.2 -[5.0.1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version5.0.0...version5.0.1 -[5.0.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version4.1.1...version5.0.0 -[4.1.1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version4.1.0...version4.1.1 -[4.1.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version4.0.5...version4.1.0 -[4.0.5]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version4.0.4...version4.0.5 -[4.0.4]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version4.0.3...version4.0.4 -[4.0.3]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version4.0.2...version4.0.3 -[4.0.2]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version4.0.1...version4.0.2 -[4.0.1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version4.0.0...version4.0.1 -[4.0.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version3.0.0...version4.0.0 -[3.0.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version2.1.4...version3.0.0 -[2.1.4]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version2.1.3...version2.1.4 -[2.1.3]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version2.1.2...version2.1.3 -[2.1.2]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version2.1.1...version2.1.2 -[2.1.1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version2.1.0u2...version2.1.1 -[2.1.0 update 2]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version2.1.0u1...version2.1.0u2 -[2.1.0 update 1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version2.1.0...version2.1.0u1 -[2.1.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version2.0.1u2...version2.1.0 -[2.0.1 update 2]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version2.0.1u1...version2.0.1u2 -[2.0.1 update 1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version2.0.1...version2.0.1u1 -[2.0.1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version2.0.0...version2.0.1 -[2.0.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.8.1u1...version2.0.0 -[1.8.1 update 1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.8.1...version1.8.1u1 -[1.8.1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.8.0u1...version1.8.1 -[1.8.0 update 1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.8.0...version1.8.0u1 -[1.8.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.7.4u1...version1.8.0 -[1.7.4 update 1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.7.4...version1.7.4u1 -[1.7.4]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.7.3u2...version1.7.4 -[1.7.3 update 2]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.7.3u1...version1.7.3u2 -[1.7.3 update 1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.7.3...version1.7.3u1 -[1.7.3]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.7.2u2...version1.7.3 -[1.7.2 update 2]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.7.2u1...version1.7.2u2 -[1.7.2 update 1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.7.2...version1.7.2u1 -[1.7.2]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.7.1...version1.7.2 -[1.7.1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.7.0u1...version1.7.1 -[1.7.0 update 1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.7.0...version1.7.0u1 -[1.7.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.6.7...version1.7.0 -[1.6.7]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.6.6u2...version1.6.7 -[1.6.6 update 2]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.6.6u1...version1.6.6u2 -[1.6.6 update 1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.6.6...version1.6.6u1 -[1.6.6]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.6.5u1...version1.6.6 -[1.6.5 update 1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.6.5...version1.6.5u1 -[1.6.5]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.6.4u1...version1.6.5 -[1.6.4 update 1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.6.4...version1.6.4u1 -[1.6.4]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.6.3u2...version1.6.4 -[1.6.3 update 2]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.6.3u1...version1.6.3u2 -[1.6.3 update 1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.6.3...version1.6.3u1 -[1.6.3]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.6.2...version1.6.3 -[1.6.2]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.6.1...version1.6.2 -[1.6.1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.6.0u1...version1.6.1 -[1.6.0 update 1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.6.0...version1.6.0u1 -[1.6.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.5.2...version1.6.0 -[1.5.2]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.5.1u1...version1.5.2 -[1.5.1 update 1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.5.1...version1.5.1u1 -[1.5.1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.5.0u1...version1.5.1 -[1.5.0 update 1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.5.0...version1.5.0u1 -[1.5.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.4.3u2...version1.5.0 -[1.4.3 update 2]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.4.3u1...version1.4.3u2 -[1.4.3 update 1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.4.3...version1.4.3u1 -[1.4.3]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.4.2u1...version1.4.3 -[1.4.2 update 1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.4.2...version1.4.2u1 -[1.4.2]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.4.1...version1.4.2 -[1.4.1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.4.0u1...version1.4.1 -[1.4.0 update 1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.4.0...version1.4.0u1 -[1.4.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.3.1...version1.4.0 -[1.3.1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.3.0...version1.3.1 -[1.3.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.2.0...version1.3.0 -[1.2.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.1.0...version1.2.0 -[1.1.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.0.1...version1.1.0 -[1.0.1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.0.0...version1.0.1 -[1.0.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/beta1...version1.0.0 -[beta 1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/alpha10...beta1 -[alpha 10]: https://github.com/jindrapetrik/jpexs-decompiler/compare/alpha9...alpha10 -[alpha 9]: https://github.com/jindrapetrik/jpexs-decompiler/compare/alpha8...alpha9 -[alpha 8]: https://github.com/jindrapetrik/jpexs-decompiler/compare/alpha7...alpha8 -[alpha 7]: https://github.com/jindrapetrik/jpexs-decompiler/releases/tag/alpha7 -[#1156]: https://www.free-decompiler.com/flash/issues/1156 -[#1171]: https://www.free-decompiler.com/flash/issues/1171 -[#1170]: https://www.free-decompiler.com/flash/issues/1170 -[#1241]: https://www.free-decompiler.com/flash/issues/1241 -[#1162]: https://www.free-decompiler.com/flash/issues/1162 -[#1199]: https://www.free-decompiler.com/flash/issues/1199 -[#1151]: https://www.free-decompiler.com/flash/issues/1151 -[#1128]: https://www.free-decompiler.com/flash/issues/1128 -[#1163]: https://www.free-decompiler.com/flash/issues/1163 -[#1172]: https://www.free-decompiler.com/flash/issues/1172 -[#1174]: https://www.free-decompiler.com/flash/issues/1174 -[#1183]: https://www.free-decompiler.com/flash/issues/1183 -[#1193]: https://www.free-decompiler.com/flash/issues/1193 -[#1200]: https://www.free-decompiler.com/flash/issues/1200 -[#1198]: https://www.free-decompiler.com/flash/issues/1198 -[#1205]: https://www.free-decompiler.com/flash/issues/1205 -[#1194]: https://www.free-decompiler.com/flash/issues/1194 -[#1210]: https://www.free-decompiler.com/flash/issues/1210 -[#1217]: https://www.free-decompiler.com/flash/issues/1217 -[#1244]: https://www.free-decompiler.com/flash/issues/1244 -[#1247]: https://www.free-decompiler.com/flash/issues/1247 -[#1236]: https://www.free-decompiler.com/flash/issues/1236 -[#1251]: https://www.free-decompiler.com/flash/issues/1251 -[#1265]: https://www.free-decompiler.com/flash/issues/1265 -[#1268]: https://www.free-decompiler.com/flash/issues/1268 -[#1161]: https://www.free-decompiler.com/flash/issues/1161 -[#1118]: https://www.free-decompiler.com/flash/issues/1118 -[#409]: https://www.free-decompiler.com/flash/issues/409 -[#1132]: https://www.free-decompiler.com/flash/issues/1132 -[#1134]: https://www.free-decompiler.com/flash/issues/1134 -[#1121]: https://www.free-decompiler.com/flash/issues/1121 -[#1052]: https://www.free-decompiler.com/flash/issues/1052 -[#1145]: https://www.free-decompiler.com/flash/issues/1145 -[#758]: https://www.free-decompiler.com/flash/issues/758 -[#1096]: https://www.free-decompiler.com/flash/issues/1096 -[#1104]: https://www.free-decompiler.com/flash/issues/1104 -[#1107]: https://www.free-decompiler.com/flash/issues/1107 -[#1106]: https://www.free-decompiler.com/flash/issues/1106 -[#1113]: https://www.free-decompiler.com/flash/issues/1113 -[#1075]: https://www.free-decompiler.com/flash/issues/1075 -[#1127]: https://www.free-decompiler.com/flash/issues/1127 -[#1103]: https://www.free-decompiler.com/flash/issues/1103 -[#1133]: https://www.free-decompiler.com/flash/issues/1133 -[#1135]: https://www.free-decompiler.com/flash/issues/1135 -[#1138]: https://www.free-decompiler.com/flash/issues/1138 -[#1139]: https://www.free-decompiler.com/flash/issues/1139 -[#930]: https://www.free-decompiler.com/flash/issues/930 -[#1137]: https://www.free-decompiler.com/flash/issues/1137 -[#1144]: https://www.free-decompiler.com/flash/issues/1144 -[#1147]: https://www.free-decompiler.com/flash/issues/1147 -[#1148]: https://www.free-decompiler.com/flash/issues/1148 -[#1152]: https://www.free-decompiler.com/flash/issues/1152 -[#1154]: https://www.free-decompiler.com/flash/issues/1154 -[#116]: https://www.free-decompiler.com/flash/issues/116 -[#1070]: https://www.free-decompiler.com/flash/issues/1070 -[#1098]: https://www.free-decompiler.com/flash/issues/1098 -[#1033]: https://www.free-decompiler.com/flash/issues/1033 -[#1083]: https://www.free-decompiler.com/flash/issues/1083 -[#1091]: https://www.free-decompiler.com/flash/issues/1091 -[#1076]: https://www.free-decompiler.com/flash/issues/1076 -[#1068]: https://www.free-decompiler.com/flash/issues/1068 -[#1063]: https://www.free-decompiler.com/flash/issues/1063 -[#1019]: https://www.free-decompiler.com/flash/issues/1019 -[#1016]: https://www.free-decompiler.com/flash/issues/1016 -[#1010]: https://www.free-decompiler.com/flash/issues/1010 -[#1008]: https://www.free-decompiler.com/flash/issues/1008 -[#1004]: https://www.free-decompiler.com/flash/issues/1004 -[#933]: https://www.free-decompiler.com/flash/issues/933 -[#1062]: https://www.free-decompiler.com/flash/issues/1062 -[#418]: https://www.free-decompiler.com/flash/issues/418 -[#1047]: https://www.free-decompiler.com/flash/issues/1047 -[#812]: https://www.free-decompiler.com/flash/issues/812 -[#1056]: https://www.free-decompiler.com/flash/issues/1056 -[#1057]: https://www.free-decompiler.com/flash/issues/1057 -[#991]: https://www.free-decompiler.com/flash/issues/991 -[#689]: https://www.free-decompiler.com/flash/issues/689 -[#1060]: https://www.free-decompiler.com/flash/issues/1060 -[#1037]: https://www.free-decompiler.com/flash/issues/1037 -[#489]: https://www.free-decompiler.com/flash/issues/489 -[#1007]: https://www.free-decompiler.com/flash/issues/1007 -[#1044]: https://www.free-decompiler.com/flash/issues/1044 -[#947]: https://www.free-decompiler.com/flash/issues/947 -[#953]: https://www.free-decompiler.com/flash/issues/953 -[#954]: https://www.free-decompiler.com/flash/issues/954 -[#950]: https://www.free-decompiler.com/flash/issues/950 -[#945]: https://www.free-decompiler.com/flash/issues/945 -[#957]: https://www.free-decompiler.com/flash/issues/957 -[#956]: https://www.free-decompiler.com/flash/issues/956 -[#968]: https://www.free-decompiler.com/flash/issues/968 -[#978]: https://www.free-decompiler.com/flash/issues/978 -[#955]: https://www.free-decompiler.com/flash/issues/955 -[#966]: https://www.free-decompiler.com/flash/issues/966 -[#999]: https://www.free-decompiler.com/flash/issues/999 -[#1000]: https://www.free-decompiler.com/flash/issues/1000 -[#1017]: https://www.free-decompiler.com/flash/issues/1017 -[#1030]: https://www.free-decompiler.com/flash/issues/1030 -[#949]: https://www.free-decompiler.com/flash/issues/949 -[#944]: https://www.free-decompiler.com/flash/issues/944 -[#939]: https://www.free-decompiler.com/flash/issues/939 -[#942]: https://www.free-decompiler.com/flash/issues/942 -[#952]: https://www.free-decompiler.com/flash/issues/952 -[#858]: https://www.free-decompiler.com/flash/issues/858 -[#905]: https://www.free-decompiler.com/flash/issues/905 -[#920]: https://www.free-decompiler.com/flash/issues/920 -[#921]: https://www.free-decompiler.com/flash/issues/921 -[#924]: https://www.free-decompiler.com/flash/issues/924 -[#895]: https://www.free-decompiler.com/flash/issues/895 -[#884]: https://www.free-decompiler.com/flash/issues/884 -[#899]: https://www.free-decompiler.com/flash/issues/899 -[#903]: https://www.free-decompiler.com/flash/issues/903 -[#855]: https://www.free-decompiler.com/flash/issues/855 -[#850]: https://www.free-decompiler.com/flash/issues/850 -[#832]: https://www.free-decompiler.com/flash/issues/832 -[#904]: https://www.free-decompiler.com/flash/issues/904 -[#910]: https://www.free-decompiler.com/flash/issues/910 -[#922]: https://www.free-decompiler.com/flash/issues/922 -[#916]: https://www.free-decompiler.com/flash/issues/916 -[#938]: https://www.free-decompiler.com/flash/issues/938 -[#897]: https://www.free-decompiler.com/flash/issues/897 -[#470]: https://www.free-decompiler.com/flash/issues/470 -[#877]: https://www.free-decompiler.com/flash/issues/877 -[#878]: https://www.free-decompiler.com/flash/issues/878 -[#845]: https://www.free-decompiler.com/flash/issues/845 -[#883]: https://www.free-decompiler.com/flash/issues/883 -[#882]: https://www.free-decompiler.com/flash/issues/882 -[#760]: https://www.free-decompiler.com/flash/issues/760 -[#887]: https://www.free-decompiler.com/flash/issues/887 -[#842]: https://www.free-decompiler.com/flash/issues/842 -[#841]: https://www.free-decompiler.com/flash/issues/841 -[#772]: https://www.free-decompiler.com/flash/issues/772 -[#762]: https://www.free-decompiler.com/flash/issues/762 -[#862]: https://www.free-decompiler.com/flash/issues/862 -[#865]: https://www.free-decompiler.com/flash/issues/865 -[#613]: https://www.free-decompiler.com/flash/issues/613 -[#868]: https://www.free-decompiler.com/flash/issues/868 -[#713]: https://www.free-decompiler.com/flash/issues/713 -[#807]: https://www.free-decompiler.com/flash/issues/807 -[#728]: https://www.free-decompiler.com/flash/issues/728 -[#857]: https://www.free-decompiler.com/flash/issues/857 -[#860]: https://www.free-decompiler.com/flash/issues/860 -[#824]: https://www.free-decompiler.com/flash/issues/824 -[#809]: https://www.free-decompiler.com/flash/issues/809 -[#805]: https://www.free-decompiler.com/flash/issues/805 -[#825]: https://www.free-decompiler.com/flash/issues/825 -[#737]: https://www.free-decompiler.com/flash/issues/737 -[#350]: https://www.free-decompiler.com/flash/issues/350 -[#814]: https://www.free-decompiler.com/flash/issues/814 -[#816]: https://www.free-decompiler.com/flash/issues/816 -[#835]: https://www.free-decompiler.com/flash/issues/835 -[#836]: https://www.free-decompiler.com/flash/issues/836 -[#848]: https://www.free-decompiler.com/flash/issues/848 -[#817]: https://www.free-decompiler.com/flash/issues/817 -[#849]: https://www.free-decompiler.com/flash/issues/849 -[#852]: https://www.free-decompiler.com/flash/issues/852 -[#837]: https://www.free-decompiler.com/flash/issues/837 -[#811]: https://www.free-decompiler.com/flash/issues/811 -[#745]: https://www.free-decompiler.com/flash/issues/745 -[#803]: https://www.free-decompiler.com/flash/issues/803 -[#738]: https://www.free-decompiler.com/flash/issues/738 -[#742]: https://www.free-decompiler.com/flash/issues/742 -[#747]: https://www.free-decompiler.com/flash/issues/747 -[#749]: https://www.free-decompiler.com/flash/issues/749 -[#752]: https://www.free-decompiler.com/flash/issues/752 -[#753]: https://www.free-decompiler.com/flash/issues/753 -[#759]: https://www.free-decompiler.com/flash/issues/759 -[#766]: https://www.free-decompiler.com/flash/issues/766 -[#768]: https://www.free-decompiler.com/flash/issues/768 -[#773]: https://www.free-decompiler.com/flash/issues/773 -[#776]: https://www.free-decompiler.com/flash/issues/776 -[#783]: https://www.free-decompiler.com/flash/issues/783 -[#785]: https://www.free-decompiler.com/flash/issues/785 -[#787]: https://www.free-decompiler.com/flash/issues/787 -[#788]: https://www.free-decompiler.com/flash/issues/788 -[#790]: https://www.free-decompiler.com/flash/issues/790 -[#794]: https://www.free-decompiler.com/flash/issues/794 -[#798]: https://www.free-decompiler.com/flash/issues/798 -[#800]: https://www.free-decompiler.com/flash/issues/800 -[#676]: https://www.free-decompiler.com/flash/issues/676 -[#734]: https://www.free-decompiler.com/flash/issues/734 -[#687]: https://www.free-decompiler.com/flash/issues/687 -[#709]: https://www.free-decompiler.com/flash/issues/709 -[#732]: https://www.free-decompiler.com/flash/issues/732 -[#730]: https://www.free-decompiler.com/flash/issues/730 -[#735]: https://www.free-decompiler.com/flash/issues/735 -[#722]: https://www.free-decompiler.com/flash/issues/722 -[#725]: https://www.free-decompiler.com/flash/issues/725 -[#715]: https://www.free-decompiler.com/flash/issues/715 -[#635]: https://www.free-decompiler.com/flash/issues/635 -[#726]: https://www.free-decompiler.com/flash/issues/726 -[#716]: https://www.free-decompiler.com/flash/issues/716 -[#717]: https://www.free-decompiler.com/flash/issues/717 -[#718]: https://www.free-decompiler.com/flash/issues/718 -[#720]: https://www.free-decompiler.com/flash/issues/720 -[#719]: https://www.free-decompiler.com/flash/issues/719 -[#723]: https://www.free-decompiler.com/flash/issues/723 -[#288]: https://www.free-decompiler.com/flash/issues/288 -[#677]: https://www.free-decompiler.com/flash/issues/677 -[#389]: https://www.free-decompiler.com/flash/issues/389 -[#701]: https://www.free-decompiler.com/flash/issues/701 -[#707]: https://www.free-decompiler.com/flash/issues/707 -[#302]: https://www.free-decompiler.com/flash/issues/302 -[#685]: https://www.free-decompiler.com/flash/issues/685 -[#698]: https://www.free-decompiler.com/flash/issues/698 -[#710]: https://www.free-decompiler.com/flash/issues/710 -[#711]: https://www.free-decompiler.com/flash/issues/711 -[#681]: https://www.free-decompiler.com/flash/issues/681 -[#688]: https://www.free-decompiler.com/flash/issues/688 -[#691]: https://www.free-decompiler.com/flash/issues/691 -[#524]: https://www.free-decompiler.com/flash/issues/524 -[#663]: https://www.free-decompiler.com/flash/issues/663 -[#702]: https://www.free-decompiler.com/flash/issues/702 -[#539]: https://www.free-decompiler.com/flash/issues/539 -[#650]: https://www.free-decompiler.com/flash/issues/650 -[#680]: https://www.free-decompiler.com/flash/issues/680 -[#649]: https://www.free-decompiler.com/flash/issues/649 -[#656]: https://www.free-decompiler.com/flash/issues/656 -[#661]: https://www.free-decompiler.com/flash/issues/661 -[#664]: https://www.free-decompiler.com/flash/issues/664 -[#668]: https://www.free-decompiler.com/flash/issues/668 -[#674]: https://www.free-decompiler.com/flash/issues/674 -[#675]: https://www.free-decompiler.com/flash/issues/675 -[#632]: https://www.free-decompiler.com/flash/issues/632 -[#651]: https://www.free-decompiler.com/flash/issues/651 -[#678]: https://www.free-decompiler.com/flash/issues/678 -[#672]: https://www.free-decompiler.com/flash/issues/672 -[#684]: https://www.free-decompiler.com/flash/issues/684 -[#647]: https://www.free-decompiler.com/flash/issues/647 -[#648]: https://www.free-decompiler.com/flash/issues/648 -[#612]: https://www.free-decompiler.com/flash/issues/612 -[#623]: https://www.free-decompiler.com/flash/issues/623 -[#624]: https://www.free-decompiler.com/flash/issues/624 -[#627]: https://www.free-decompiler.com/flash/issues/627 -[#640]: https://www.free-decompiler.com/flash/issues/640 -[#595]: https://www.free-decompiler.com/flash/issues/595 -[#592]: https://www.free-decompiler.com/flash/issues/592 -[#585]: https://www.free-decompiler.com/flash/issues/585 -[#578]: https://www.free-decompiler.com/flash/issues/578 -[#501]: https://www.free-decompiler.com/flash/issues/501 -[#616]: https://www.free-decompiler.com/flash/issues/616 -[#559]: https://www.free-decompiler.com/flash/issues/559 -[#401]: https://www.free-decompiler.com/flash/issues/401 -[#593]: https://www.free-decompiler.com/flash/issues/593 -[#594]: https://www.free-decompiler.com/flash/issues/594 -[#579]: https://www.free-decompiler.com/flash/issues/579 -[#428]: https://www.free-decompiler.com/flash/issues/428 -[#337]: https://www.free-decompiler.com/flash/issues/337 -[#584]: https://www.free-decompiler.com/flash/issues/584 -[#576]: https://www.free-decompiler.com/flash/issues/576 -[#250]: https://www.free-decompiler.com/flash/issues/250 -[#580]: https://www.free-decompiler.com/flash/issues/580 -[#510]: https://www.free-decompiler.com/flash/issues/510 -[#583]: https://www.free-decompiler.com/flash/issues/583 -[#586]: https://www.free-decompiler.com/flash/issues/586 -[#574]: https://www.free-decompiler.com/flash/issues/574 -[#570]: https://www.free-decompiler.com/flash/issues/570 -[#563]: https://www.free-decompiler.com/flash/issues/563 -[#561]: https://www.free-decompiler.com/flash/issues/561 -[#509]: https://www.free-decompiler.com/flash/issues/509 -[#433]: https://www.free-decompiler.com/flash/issues/433 -[#557]: https://www.free-decompiler.com/flash/issues/557 -[#556]: https://www.free-decompiler.com/flash/issues/556 -[#504]: https://www.free-decompiler.com/flash/issues/504 -[#529]: https://www.free-decompiler.com/flash/issues/529 -[#538]: https://www.free-decompiler.com/flash/issues/538 -[#537]: https://www.free-decompiler.com/flash/issues/537 -[#540]: https://www.free-decompiler.com/flash/issues/540 -[#387]: https://www.free-decompiler.com/flash/issues/387 -[#552]: https://www.free-decompiler.com/flash/issues/552 -[#494]: https://www.free-decompiler.com/flash/issues/494 -[#513]: https://www.free-decompiler.com/flash/issues/513 -[#262]: https://www.free-decompiler.com/flash/issues/262 -[#499]: https://www.free-decompiler.com/flash/issues/499 -[#508]: https://www.free-decompiler.com/flash/issues/508 -[#305]: https://www.free-decompiler.com/flash/issues/305 -[#312]: https://www.free-decompiler.com/flash/issues/312 -[#503]: https://www.free-decompiler.com/flash/issues/503 -[#304]: https://www.free-decompiler.com/flash/issues/304 -[#306]: https://www.free-decompiler.com/flash/issues/306 -[#507]: https://www.free-decompiler.com/flash/issues/507 -[#424]: https://www.free-decompiler.com/flash/issues/424 -[#425]: https://www.free-decompiler.com/flash/issues/425 -[#478]: https://www.free-decompiler.com/flash/issues/478 -[#485]: https://www.free-decompiler.com/flash/issues/485 -[#517]: https://www.free-decompiler.com/flash/issues/517 -[#518]: https://www.free-decompiler.com/flash/issues/518 -[#361]: https://www.free-decompiler.com/flash/issues/361 -[#392]: https://www.free-decompiler.com/flash/issues/392 -[#516]: https://www.free-decompiler.com/flash/issues/516 -[#495]: https://www.free-decompiler.com/flash/issues/495 -[#496]: https://www.free-decompiler.com/flash/issues/496 -[#299]: https://www.free-decompiler.com/flash/issues/299 -[#303]: https://www.free-decompiler.com/flash/issues/303 -[#324]: https://www.free-decompiler.com/flash/issues/324 -[#346]: https://www.free-decompiler.com/flash/issues/346 -[#371]: https://www.free-decompiler.com/flash/issues/371 -[#426]: https://www.free-decompiler.com/flash/issues/426 -[#457]: https://www.free-decompiler.com/flash/issues/457 -[#458]: https://www.free-decompiler.com/flash/issues/458 -[#460]: https://www.free-decompiler.com/flash/issues/460 -[#462]: https://www.free-decompiler.com/flash/issues/462 -[#463]: https://www.free-decompiler.com/flash/issues/463 -[#465]: https://www.free-decompiler.com/flash/issues/465 -[#466]: https://www.free-decompiler.com/flash/issues/466 -[#369]: https://www.free-decompiler.com/flash/issues/369 -[#390]: https://www.free-decompiler.com/flash/issues/390 -[#453]: https://www.free-decompiler.com/flash/issues/453 -[#459]: https://www.free-decompiler.com/flash/issues/459 -[#461]: https://www.free-decompiler.com/flash/issues/461 -[#451]: https://www.free-decompiler.com/flash/issues/451 -[#454]: https://www.free-decompiler.com/flash/issues/454 -[#455]: https://www.free-decompiler.com/flash/issues/455 -[#474]: https://www.free-decompiler.com/flash/issues/474 -[#477]: https://www.free-decompiler.com/flash/issues/477 -[#481]: https://www.free-decompiler.com/flash/issues/481 -[#484]: https://www.free-decompiler.com/flash/issues/484 -[#493]: https://www.free-decompiler.com/flash/issues/493 -[#365]: https://www.free-decompiler.com/flash/issues/365 -[#366]: https://www.free-decompiler.com/flash/issues/366 -[#429]: https://www.free-decompiler.com/flash/issues/429 -[#447]: https://www.free-decompiler.com/flash/issues/447 -[#354]: https://www.free-decompiler.com/flash/issues/354 -[#438]: https://www.free-decompiler.com/flash/issues/438 -[#436]: https://www.free-decompiler.com/flash/issues/436 -[#446]: https://www.free-decompiler.com/flash/issues/446 -[#427]: https://www.free-decompiler.com/flash/issues/427 -[#405]: https://www.free-decompiler.com/flash/issues/405 -[#420]: https://www.free-decompiler.com/flash/issues/420 -[#421]: https://www.free-decompiler.com/flash/issues/421 -[#430]: https://www.free-decompiler.com/flash/issues/430 -[#397]: https://www.free-decompiler.com/flash/issues/397 -[#431]: https://www.free-decompiler.com/flash/issues/431 -[#169]: https://www.free-decompiler.com/flash/issues/169 -[#335]: https://www.free-decompiler.com/flash/issues/335 -[#404]: https://www.free-decompiler.com/flash/issues/404 -[#407]: https://www.free-decompiler.com/flash/issues/407 -[#399]: https://www.free-decompiler.com/flash/issues/399 -[#400]: https://www.free-decompiler.com/flash/issues/400 -[#398]: https://www.free-decompiler.com/flash/issues/398 -[#382]: https://www.free-decompiler.com/flash/issues/382 -[#396]: https://www.free-decompiler.com/flash/issues/396 -[#357]: https://www.free-decompiler.com/flash/issues/357 -[#391]: https://www.free-decompiler.com/flash/issues/391 -[#395]: https://www.free-decompiler.com/flash/issues/395 -[#334]: https://www.free-decompiler.com/flash/issues/334 -[#301]: https://www.free-decompiler.com/flash/issues/301 -[#383]: https://www.free-decompiler.com/flash/issues/383 -[#386]: https://www.free-decompiler.com/flash/issues/386 -[#367]: https://www.free-decompiler.com/flash/issues/367 -[#380]: https://www.free-decompiler.com/flash/issues/380 -[#292]: https://www.free-decompiler.com/flash/issues/292 -[#375]: https://www.free-decompiler.com/flash/issues/375 -[#378]: https://www.free-decompiler.com/flash/issues/378 -[#325]: https://www.free-decompiler.com/flash/issues/325 -[#210]: https://www.free-decompiler.com/flash/issues/210 -[#355]: https://www.free-decompiler.com/flash/issues/355 -[#313]: https://www.free-decompiler.com/flash/issues/313 -[#330]: https://www.free-decompiler.com/flash/issues/330 -[#332]: https://www.free-decompiler.com/flash/issues/332 -[#344]: https://www.free-decompiler.com/flash/issues/344 -[#295]: https://www.free-decompiler.com/flash/issues/295 -[#297]: https://www.free-decompiler.com/flash/issues/297 -[#307]: https://www.free-decompiler.com/flash/issues/307 -[#309]: https://www.free-decompiler.com/flash/issues/309 -[#310]: https://www.free-decompiler.com/flash/issues/310 -[#311]: https://www.free-decompiler.com/flash/issues/311 -[#327]: https://www.free-decompiler.com/flash/issues/327 -[#328]: https://www.free-decompiler.com/flash/issues/328 -[#333]: https://www.free-decompiler.com/flash/issues/333 -[#336]: https://www.free-decompiler.com/flash/issues/336 -[#338]: https://www.free-decompiler.com/flash/issues/338 -[#315]: https://www.free-decompiler.com/flash/issues/315 -[#123]: https://www.free-decompiler.com/flash/issues/123 -[#243]: https://www.free-decompiler.com/flash/issues/243 -[#326]: https://www.free-decompiler.com/flash/issues/326 -[#287]: https://www.free-decompiler.com/flash/issues/287 -[#290]: https://www.free-decompiler.com/flash/issues/290 -[#291]: https://www.free-decompiler.com/flash/issues/291 -[#294]: https://www.free-decompiler.com/flash/issues/294 -[#298]: https://www.free-decompiler.com/flash/issues/298 -[#296]: https://www.free-decompiler.com/flash/issues/296 -[#314]: https://www.free-decompiler.com/flash/issues/314 -[#316]: https://www.free-decompiler.com/flash/issues/316 -[#318]: https://www.free-decompiler.com/flash/issues/318 -[#319]: https://www.free-decompiler.com/flash/issues/319 -[#323]: https://www.free-decompiler.com/flash/issues/323 -[#223]: https://www.free-decompiler.com/flash/issues/223 -[#261]: https://www.free-decompiler.com/flash/issues/261 -[#269]: https://www.free-decompiler.com/flash/issues/269 -[#274]: https://www.free-decompiler.com/flash/issues/274 -[#275]: https://www.free-decompiler.com/flash/issues/275 -[#258]: https://www.free-decompiler.com/flash/issues/258 -[#267]: https://www.free-decompiler.com/flash/issues/267 -[#286]: https://www.free-decompiler.com/flash/issues/286 -[#233]: https://www.free-decompiler.com/flash/issues/233 -[#235]: https://www.free-decompiler.com/flash/issues/235 -[#263]: https://www.free-decompiler.com/flash/issues/263 -[#264]: https://www.free-decompiler.com/flash/issues/264 -[#265]: https://www.free-decompiler.com/flash/issues/265 -[#266]: https://www.free-decompiler.com/flash/issues/266 -[#281]: https://www.free-decompiler.com/flash/issues/281 -[#251]: https://www.free-decompiler.com/flash/issues/251 -[#257]: https://www.free-decompiler.com/flash/issues/257 -[#259]: https://www.free-decompiler.com/flash/issues/259 -[#260]: https://www.free-decompiler.com/flash/issues/260 -[#268]: https://www.free-decompiler.com/flash/issues/268 -[#272]: https://www.free-decompiler.com/flash/issues/272 -[#276]: https://www.free-decompiler.com/flash/issues/276 -[#220]: https://www.free-decompiler.com/flash/issues/220 -[#284]: https://www.free-decompiler.com/flash/issues/284 -[#232]: https://www.free-decompiler.com/flash/issues/232 -[#253]: https://www.free-decompiler.com/flash/issues/253 -[#137]: https://www.free-decompiler.com/flash/issues/137 -[#242]: https://www.free-decompiler.com/flash/issues/242 -[#244]: https://www.free-decompiler.com/flash/issues/244 -[#203]: https://www.free-decompiler.com/flash/issues/203 -[#225]: https://www.free-decompiler.com/flash/issues/225 -[#236]: https://www.free-decompiler.com/flash/issues/236 -[#245]: https://www.free-decompiler.com/flash/issues/245 -[#247]: https://www.free-decompiler.com/flash/issues/247 -[#248]: https://www.free-decompiler.com/flash/issues/248 -[#254]: https://www.free-decompiler.com/flash/issues/254 -[#255]: https://www.free-decompiler.com/flash/issues/255 -[#256]: https://www.free-decompiler.com/flash/issues/256 -[#241]: https://www.free-decompiler.com/flash/issues/241 -[#238]: https://www.free-decompiler.com/flash/issues/238 -[#239]: https://www.free-decompiler.com/flash/issues/239 -[#240]: https://www.free-decompiler.com/flash/issues/240 -[#237]: https://www.free-decompiler.com/flash/issues/237 -[#217]: https://www.free-decompiler.com/flash/issues/217 -[#219]: https://www.free-decompiler.com/flash/issues/219 -[#224]: https://www.free-decompiler.com/flash/issues/224 -[#121]: https://www.free-decompiler.com/flash/issues/121 -[#207]: https://www.free-decompiler.com/flash/issues/207 -[#151]: https://www.free-decompiler.com/flash/issues/151 -[#171]: https://www.free-decompiler.com/flash/issues/171 -[#206]: https://www.free-decompiler.com/flash/issues/206 -[#208]: https://www.free-decompiler.com/flash/issues/208 -[#209]: https://www.free-decompiler.com/flash/issues/209 -[#229]: https://www.free-decompiler.com/flash/issues/229 -[#213]: https://www.free-decompiler.com/flash/issues/213 -[#221]: https://www.free-decompiler.com/flash/issues/221 -[#226]: https://www.free-decompiler.com/flash/issues/226 -[#227]: https://www.free-decompiler.com/flash/issues/227 -[#230]: https://www.free-decompiler.com/flash/issues/230 -[#172]: https://www.free-decompiler.com/flash/issues/172 -[#174]: https://www.free-decompiler.com/flash/issues/174 -[#175]: https://www.free-decompiler.com/flash/issues/175 -[#212]: https://www.free-decompiler.com/flash/issues/212 -[#185]: https://www.free-decompiler.com/flash/issues/185 -[#186]: https://www.free-decompiler.com/flash/issues/186 -[#197]: https://www.free-decompiler.com/flash/issues/197 -[#216]: https://www.free-decompiler.com/flash/issues/216 -[#168]: https://www.free-decompiler.com/flash/issues/168 -[#176]: https://www.free-decompiler.com/flash/issues/176 -[#177]: https://www.free-decompiler.com/flash/issues/177 -[#202]: https://www.free-decompiler.com/flash/issues/202 -[#173]: https://www.free-decompiler.com/flash/issues/173 -[#190]: https://www.free-decompiler.com/flash/issues/190 -[#129]: https://www.free-decompiler.com/flash/issues/129 -[#153]: https://www.free-decompiler.com/flash/issues/153 -[#180]: https://www.free-decompiler.com/flash/issues/180 -[#136]: https://www.free-decompiler.com/flash/issues/136 -[#179]: https://www.free-decompiler.com/flash/issues/179 -[#144]: https://www.free-decompiler.com/flash/issues/144 -[#164]: https://www.free-decompiler.com/flash/issues/164 -[#167]: https://www.free-decompiler.com/flash/issues/167 -[#170]: https://www.free-decompiler.com/flash/issues/170 -[#178]: https://www.free-decompiler.com/flash/issues/178 -[#181]: https://www.free-decompiler.com/flash/issues/181 -[#182]: https://www.free-decompiler.com/flash/issues/182 -[#183]: https://www.free-decompiler.com/flash/issues/183 -[#184]: https://www.free-decompiler.com/flash/issues/184 -[#189]: https://www.free-decompiler.com/flash/issues/189 -[#191]: https://www.free-decompiler.com/flash/issues/191 -[#195]: https://www.free-decompiler.com/flash/issues/195 -[#196]: https://www.free-decompiler.com/flash/issues/196 -[#198]: https://www.free-decompiler.com/flash/issues/198 -[#200]: https://www.free-decompiler.com/flash/issues/200 -[#201]: https://www.free-decompiler.com/flash/issues/201 -[#166]: https://www.free-decompiler.com/flash/issues/166 -[#165]: https://www.free-decompiler.com/flash/issues/165 -[#63]: https://www.free-decompiler.com/flash/issues/63 -[#67]: https://www.free-decompiler.com/flash/issues/67 -[#117]: https://www.free-decompiler.com/flash/issues/117 -[#127]: https://www.free-decompiler.com/flash/issues/127 -[#134]: https://www.free-decompiler.com/flash/issues/134 -[#155]: https://www.free-decompiler.com/flash/issues/155 -[#142]: https://www.free-decompiler.com/flash/issues/142 -[#146]: https://www.free-decompiler.com/flash/issues/146 -[#130]: https://www.free-decompiler.com/flash/issues/130 -[#132]: https://www.free-decompiler.com/flash/issues/132 -[#145]: https://www.free-decompiler.com/flash/issues/145 -[#147]: https://www.free-decompiler.com/flash/issues/147 -[#148]: https://www.free-decompiler.com/flash/issues/148 -[#152]: https://www.free-decompiler.com/flash/issues/152 -[#156]: https://www.free-decompiler.com/flash/issues/156 -[#157]: https://www.free-decompiler.com/flash/issues/157 -[#158]: https://www.free-decompiler.com/flash/issues/158 -[#159]: https://www.free-decompiler.com/flash/issues/159 -[#160]: https://www.free-decompiler.com/flash/issues/160 -[#162]: https://www.free-decompiler.com/flash/issues/162 -[#163]: https://www.free-decompiler.com/flash/issues/163 -[#149]: https://www.free-decompiler.com/flash/issues/149 -[#150]: https://www.free-decompiler.com/flash/issues/150 -[#119]: https://www.free-decompiler.com/flash/issues/119 -[#101]: https://www.free-decompiler.com/flash/issues/101 -[#114]: https://www.free-decompiler.com/flash/issues/114 -[#135]: https://www.free-decompiler.com/flash/issues/135 -[#141]: https://www.free-decompiler.com/flash/issues/141 -[#102]: https://www.free-decompiler.com/flash/issues/102 -[#124]: https://www.free-decompiler.com/flash/issues/124 -[#128]: https://www.free-decompiler.com/flash/issues/128 -[#131]: https://www.free-decompiler.com/flash/issues/131 -[#104]: https://www.free-decompiler.com/flash/issues/104 -[#113]: https://www.free-decompiler.com/flash/issues/113 -[#133]: https://www.free-decompiler.com/flash/issues/133 -[#140]: https://www.free-decompiler.com/flash/issues/140 -[#108]: https://www.free-decompiler.com/flash/issues/108 -[#105]: https://www.free-decompiler.com/flash/issues/105 -[#109]: https://www.free-decompiler.com/flash/issues/109 -[#106]: https://www.free-decompiler.com/flash/issues/106 -[#107]: https://www.free-decompiler.com/flash/issues/107 -[#110]: https://www.free-decompiler.com/flash/issues/110 -[#103]: https://www.free-decompiler.com/flash/issues/103 -[#111]: https://www.free-decompiler.com/flash/issues/111 -[#96]: https://www.free-decompiler.com/flash/issues/96 -[#98]: https://www.free-decompiler.com/flash/issues/98 -[#99]: https://www.free-decompiler.com/flash/issues/99 -[#100]: https://www.free-decompiler.com/flash/issues/100 -[#85]: https://www.free-decompiler.com/flash/issues/85 -[#79]: https://www.free-decompiler.com/flash/issues/79 -[#92]: https://www.free-decompiler.com/flash/issues/92 -[#93]: https://www.free-decompiler.com/flash/issues/93 -[#94]: https://www.free-decompiler.com/flash/issues/94 -[#95]: https://www.free-decompiler.com/flash/issues/95 -[#86]: https://www.free-decompiler.com/flash/issues/86 -[#87]: https://www.free-decompiler.com/flash/issues/87 -[#88]: https://www.free-decompiler.com/flash/issues/88 -[#89]: https://www.free-decompiler.com/flash/issues/89 -[#82]: https://www.free-decompiler.com/flash/issues/82 -[#78]: https://www.free-decompiler.com/flash/issues/78 -[#81]: https://www.free-decompiler.com/flash/issues/81 -[#84]: https://www.free-decompiler.com/flash/issues/84 -[#83]: https://www.free-decompiler.com/flash/issues/83 -[#65]: https://www.free-decompiler.com/flash/issues/65 -[#48]: https://www.free-decompiler.com/flash/issues/48 -[#53]: https://www.free-decompiler.com/flash/issues/53 -[#66]: https://www.free-decompiler.com/flash/issues/66 -[#68]: https://www.free-decompiler.com/flash/issues/68 -[#69]: https://www.free-decompiler.com/flash/issues/69 -[#75]: https://www.free-decompiler.com/flash/issues/75 -[#73]: https://www.free-decompiler.com/flash/issues/73 -[#62]: https://www.free-decompiler.com/flash/issues/62 -[#72]: https://www.free-decompiler.com/flash/issues/72 -[#64]: https://www.free-decompiler.com/flash/issues/64 -[#38]: https://www.free-decompiler.com/flash/issues/38 -[#56]: https://www.free-decompiler.com/flash/issues/56 -[#57]: https://www.free-decompiler.com/flash/issues/57 -[#58]: https://www.free-decompiler.com/flash/issues/58 -[#45]: https://www.free-decompiler.com/flash/issues/45 -[#50]: https://www.free-decompiler.com/flash/issues/50 -[#51]: https://www.free-decompiler.com/flash/issues/51 -[#52]: https://www.free-decompiler.com/flash/issues/52 -[#47]: https://www.free-decompiler.com/flash/issues/47 -[#42]: https://www.free-decompiler.com/flash/issues/42 -[#39]: https://www.free-decompiler.com/flash/issues/39 -[#40]: https://www.free-decompiler.com/flash/issues/40 -[#44]: https://www.free-decompiler.com/flash/issues/44 -[#36]: https://www.free-decompiler.com/flash/issues/36 -[#43]: https://www.free-decompiler.com/flash/issues/43 -[#46]: https://www.free-decompiler.com/flash/issues/46 -[#3]: https://www.free-decompiler.com/flash/issues/3 -[#37]: https://www.free-decompiler.com/flash/issues/37 -[#34]: https://www.free-decompiler.com/flash/issues/34 -[#35]: https://www.free-decompiler.com/flash/issues/35 -[#32]: https://www.free-decompiler.com/flash/issues/32 +# Change Log +All notable changes to this project will be documented in this file. + +## [Unreleased] +### Added +- [#1240] AS search using multiple threads when parallel speedup is enabled +- [#1308] Search by all P-code files in AS3 +- [#1333] Exporting sprites as swf files +- [#1365] Allow to configure all types of configuration settings from command line +- [#1369] Allow zoom in sprite (and button) export + +### Fixed +- [#1327] P-code editing: error message and syntax highlighting fixed when instruction name contains upper cased letter +- [#1343] AS 1/2 direct editation critical bug +- [#1348] Cannot properly export frame with cyrillic symbols to SVG +- [#1354] Various FLA export problem fixes +- [#1367] Raw edit conditional type fix. +- [#1401] SVG export: duplicate pattern IDs fixed +- [#1402] SVG export: certain font characters not exported properly fixed + +## [10.0.0] - 2016-12-24 +### Added +- Iggy Files support - reading and (limited) editation of fonts, texts and AS3 - 64 bit variant only +- optional AS3 direct editation with Flex SDK +- AS3 p-code editing - metadata read/write support +- AS3 p-code editing - end of the block command like in RABCDasm +- AS3 p-code editing - popup docs for more than instructions +- Debugger - New columns for variable details - scope, flags, trait +- Debugger - Add watch feature +- AS3 decompilation - colliding trait/class names handling - show hash suffix with namespace index on such cases +- Deobfuscation Tool - Fix colliding trait/classes via toolbar command +- Auto rename identifiers option now fixes colliding trait/classes aswell +- [#1254] FLA export - detecting scripts on AS3 timeline +- [#907] FFDec Library JAR file has version inside it. +- [#1311], [#1313] actionScript source font size +- Display warning when library version and GUI version mismatch +- Changelog file +- [#1308] Search by all P-code files (AS 1/2 only) + +### Changed +- [#1189] AS3 - sort imports to have same order always +- GUI: AS3 P-code header show actual trait type and method type +- GUI: Script editing buttons now named "Edit ActionScript" and "Edit P-code" +- Set advance values button has confirm dialog with information +- [#1274] Linux package no longer requires Oracle Java only +- Library now packaged inside ZIP file + +### Fixed +- P-code docs formatting fix +- Export dialog - handling sprite and SWF frames correctly +- [#1275] debugger - show local variables fixes +- AS3 p-code editing - popup docs correctly displayed when label on line start +- [#1278] replacing DefineBits error +- [#1281] DefineFont 2/3 getting character advance value when replacing fix +- Set advance values button - Do not set advance if the char cannot be displayed in source font +- AS3 Goto declaration for single character names +- Identifier renaming for top level classes +- AS3 direct editation not correctly saving local register names +- [#1254] FLA export - placing AS3 classes to FLA directory instead of scripts dir +- Mac OS X installer fix (.pkg) +- [#1289] AS1/2 direct editation - variables used in inner functions must not be stored in local registers +- [#1283] AS3 Unbounded Vector - Vector<*> decompilation and direct editation fix +- [#1294] Font editation (DefineFont2/3) - correct switching of wide character codes +- [#1302] Callpropvoid instruction docblock not correct +- [#1309] recent files not getting updates +- [#1312] faster colliding usages finder +- [#1303] garbled text when exporting frame with text +- [#1314] user interface: button order +- Internal viewer shows red image when bitmap fill is not available (see issue [#1320]) +- [#1323] Audio playback fails + +## [9.0.0] - 2016-08-12 +### Added +- Instance metadata (AMF3) editing in PlaceObject4 +- [#1156] Flash Viewer - DefineScalingGrid support (9-slice scaling) +- [#1171] Export stroke scale to FLA +- FLA export - check invalid unicode characters +- [#1170] Extract from memory in commandline +- Reload one vs Reload all buttons +- ABC: Float and Float4 support +- AS3 p-code instruction documentation in GUI +- [#1241] Settings to show original bytes in hex view +- Search in dump view +- Jump to resources view from hex view +- Show warning on 32bit JRE + +### Changed +- [#1162] improved opening loaded SWF files +- Flash Viewer - skip frames when not on time +- [#1199] Automatically import alpha channel to JPEG3/4 from PNG + +### Fixed +- [#1151] Filters on texts fixed +- [#1128] Adding characters to font fixed (FontAlignZones not removed) +- [#1163] Clicking open->file makes program buggy +- Refresh tree after raw edit +- [#1172] Text double escape fix +- [#1174] Change language fix +- some AS2 deobfuscation fixes +- [#1183] Index out of bounds fix +- Implicit coersion on binary/unary opfix +- debugger: corect display variable values through getters +- Multiple XLF export fix +- [#1193] FLA export - text tag advance fix, one layer shape fix +- [#1193] FLA export - smoothed image detection, export raw JPEG data +- [#1193] Export space character to TTF correctly +- [#1200] Previous search text selected when quick find +- Flash viewer: aspect ratio on startup fix +- [#1198] Saving trait slot const value +- Zoom parameter commandline fixed +- [#1205] clipping fixed +- [#1194] Wrong sound effects in FLA +- [#1210] Frame Export fix +- Improved/fixed go to declaration in AS3 +- [#1217] PCode window not in same position as AS +- Hide memor search on non windows platform +- [#1244] Incorrect showing of NOP instructions +- [#1244] Remove unknown actions when deobfuscation is enabled, compole unknown instructions back +- [#1241] File content is different from hex view +- [#1247] Incorrectly handling remainingbytes for DefineCompactedFont +- [#1236] won't open fixed +- [#1251] SWF not same after export XML and import back +- [#1265] Error during export +- [#1268] Font export - Using second glyph when two glyphs for one character found +- [#1268] GFX compacted font - fixed advance values on export + +## [8.0.1] - 2016-02-20 +### Changed +- FFDec debug tab in advanced settings moved to other tabs + +### Fixed +- [#1161] AS1/2 deobfuscation broken +- AS1/2 Simplify expressions fix + +## [8.0.0] - 2016-02-18 +### Added +- Debugger - AS1/2 Show registers +- Debugger - display variables in the tree structure +- Debugger - set value of variable +- Debugger - AS1/2 View constantpool +- Debugger - P-code level debugging for both AS1/2 and AS3 +- Basic SVG import for shapes +- Simplify expression setting +- [#1118] Loading characters through ImportAssets - show as readonly +- [#409], [#1132], [SkinPart] metadata support - decompilation and direct editation in AS3 +- [#1134] compiling §§ instructions back while direct editation (§§goto is still missing) +- [#1121] Ability to save binary data by its name +- [#1052] Add object to existing frame +- Allow adding tag to main timeline +- AS1/2: Ctrl+click to declaration of variables, registers +- Allow trait specification in pcode import +- Icons for tag types in Dump view +- Show error message when a text tag is invalid (glyph index problem) +- AS3 direct editation - store local register names in debug info = allow to rename them + +### Changed +- New application icon and splash screen +- [#1145] AS3 better declaration type detection, better convert_x instruction handling +- Binary export - use .swf extension for swf files +- Better tree labels in generic tag editor (Raw edit) +- [#758] Allow zooming more than preview area in internal viewer + +### Fixed +- [#1096] FLA export - pretty print +- [#1104] AS1/2/3 Script Importat not working +- [#1107] Text Offset Incorrect fixed +- [#1106] New Shapes replace function fix +- [#1113] It takes too long to switch between rendered sprite +- [#1075] Lenght of DefineText in some cases +- [#1127] autoRenameIdentifiers is not supported in CLI mode +- [#1128] Letterspacing bug (after font embed): ignore letterspacing when character changed +- [#1103] Foreach variables fixes +- AS3 Switch fixes +- Default clause position in switch +- [#1133] Incorrect frame order for nested sprite +- [#1135] Handle try "to" in p-code correctly +- Font wideOffsets,wideCodes fixed in DefineFont2/3 +- AS3: super method call +- [#1138] All exported videos are the same file which may be broken +- [#1139],[#930] Windows Installer: Correct ActiveX download link, Download latest java from webpages +- [#1137] running flashplayer(debugger) executable in Linux/MacOs +- [#1144] Command line argument renameInvalidIdentifiers +- [#1145] double not (!!) not removed +- [#1147] Sprite is exported incorrectly +- [#1148] handing end of stream exception in abc reader, loc exception +- [#1152] Font info tag modified tag was not set => saved swf was corrupt +- [#1154] Some 32bit JRE problems - program won't start +- [#1145] Correct precedence handling on binary operators +- [#116] not resolving unusual tags in DefineSprite + +## [7.1.2] - 2015-12-03 +### Fixed +- AS3 debugger start halt fix +- AS1/2 debugger fix on nondebug enabled SWFs +- AS1/2 debugger fix for functions +- Debug menu item enabled fix +- AS3 local reg index fix +- Advanced settings calendar +- AVM2 instructions in hex view +- [#1070] Incorrect switch decompilation +- [#1098] Import XML fix + +## [7.1.1] - 2015-11-23 +### Fixed +- Critical debugger fix - widelines + +## [7.1.0] - 2015-11-23 +### Added +- AS1/2 debugger +- Breakpoint/IP marker on line beginning + +### Changed +- Starting debugger on demand +- Installer message about playerglobal is only warning now + +### Fixed +- [#1033], [#1083] AS3 deobfuscation issues +- [#1091] AS 1/2 direct editation saving + +## [7.0.1] - 2015-11-18 +### Fixed +- Debugger: Adding breakpoint if script initializer not displayed + +## [7.0.0] - 2015-11-18 +### Added +- AS3 Debugger - breakpoints, stepping, show variables +- Faster AS3 direct editation + +### Changed +- Better Configuration of flashplayer paths + +### Removed +- Removed old "debugger" buttons +- Removed search from browsers cache - inactual code + +### Fixed +- Many AS3 direct editation related bugs +- [#1076] export fix + +## [6.1.1] - 2015-10-30 +### Fixed +- Deobfuscate AS3 metadata +- [#1068] MorphShape with focal gradient fix, FLA XML export formatting fix +- [#1063] AS3 direct edit - script initializer fix, generating method names +- XML export/import fixes +- [#1019] Namespace imports fix +- AVM2 code execution fix +- [#1016] AS3 direct editation fixes +- [#1010] AS2 direct editation - internal and override is not a reserved word +- [#1008] pushshort instruction diassembly +- [#1004] this/super can be AS1/2 variable +- [#933] AS3 allow numbers as object literal keys + +## [6.1.0] - 2015-10-26 +### Added +- Open other loaded SWFs during playback (useful for loaders) +- Export uncompressed data from dump tree +- Print performance statistics from commandline +- [#1062] Editing/displaying script initializers +- Enable debugging on SWF file (commandline) + +### Changed +- Faster syntax highlighting +- Better AS1/2 deobfuscator +- [#418] AS3 deobfuscator improved + +### Fixed +- AS call method fix (first parameter is "this") +- [#1047] open all scripts folders +- [#812] decompile fail +- [#1056] deltaY missing when adding a new StraightEdgeRecord +- [#1057] Editing as in editor results in package name moving +- [#991] GUI export +- [#689] Ignore Case not correctly toggled +- [#1060] reversed and/or detection in some cases +- [#1037] isXML call + +## [6.0.2] - 2015-09-12 +### Added +- AS3: Display and direct edit trait Metadata +- Allow to specify tag type on image or shape import +- Convert image tags from commandline +- [#489] Hex decode very large integers +- Add new tags without show empty folders +- Dependent characters in basic tag info +- [#1007] replace bytearray in raw editing +- Italian translation + +### Changed +- AS2 parser - add string to constant pool if there is not enough space +- [#1044] AS2 - order scripts by physical location, name by offset + +### Removed +- Deprecated commandline parameters removed + +### Fixed +- JNA problems on some JDKs +- [#947] Marklevels errors ignored 17a94b7 +- [#953] Mac application permission fix (maybe) +- [#954] IndexOutOfBounds fix +- [#950] AddTrait setting modified fix +- [#945] AS1/2 directeditation fix - member named as global function +- [#957] AS1/2 IndexOutOfBounds fix +- [#956] Invalid jump offsets warning +- [#968] Sprites export with wrong coloring +- [#978] case sensitivity of filenames +- [#955] AS2 decompilation problem +- Image alpha fixes +- [#966] Go to document class +- [#991] scripts exporting +- [#999] save as fla +- [#1000] image export for malformed JPEG3 tags +- [#1017] store alchemy opcodes with wrong order +- [#1030] stack overflow fix + +## [6.0.1] - 2015-07-06 +### Added +- Special §§ instructions marked as red +- [#949] Replace alpha channel from commandline +- AS3 deobfuscation from commandline +- Option to ignore FlashCC/Alchemy packages + +### Changed +- [#944],[#991],[#939],[#942] AS3 deobfuscation improvements + +### Fixed +- AS1/2 deobfuscation fixed +- [#952] Not loading SWF without extension + +## [6.0.0] - 2015-07-04 +### Added +- New AS3 deobfuscation method +- Internal "preprocessor" §§ actions introduced - §§pop,§§push,... +- Allow reload FFDec when no SWF is opened +- [#858] Allow to set compression type in header +- [#905] Show codec details for sound items +- Better alchemy/DomainMemory instruction handling +- Better obfuscated names handling +- [#920] Export instance name to SVG +- [#921] Export html DefineEditText to SVG +- Open multiple files with drag and drop +- Better "multi packs" handling (Alchemy) +- SWF version 29 to flash player 18 mapping +- ImportAssets2 sha1 field +- [#924] Sprites to image from commandline +- AS1/2 direct editation big numbers fix +- Allow to add FILTERs and SHAPERECORDs in generic tag editor +- Enable close all menu when no swf is selected +- Restore modified state even when something goes wrong +- Some old tags added + +### Changed +- AS decompilation highly improved +- Better &&, || handling +- DoABCDefine renamed to DoABC2 +- Separated Sprite export settings + +### Deprecated +- Old AS1/2/3 deobfuscation method marked as deprecated (can be enabled back deep in the configuration) + +### Fixed +- Many decompilation problems - EmptyStack exception, Maximum recursion level reached, etc. +- Few menu issues +- [#895] Correct handling CMYK JPEG +- [#884] AS direct edit assignment +- [#899] Show script after AS3 direct editation +- Some AS1/2 parser problems +- [#903] FLA export - fix for missing fontname, lastframe +- [#855] AS3 direct edit - for..in variable declaration fix +- [#850] Constant initialization for same multinames +- [#832] AS3 direct edit - other ABCs resolving fix +- [#904] Cannot export images +- [#910] Missing instructions +- Opening not existent files on restoring last session +- [#922] Edit text leading +- Put image before shape on shape replace +- [#916] Replacing Shape corrupts SWF +- JRE setup parameters fixed +- [#938] Parallel speedup limit fix + +## [5.3.0] - 2015-05-25 +### Added +- Generic tag editor: improved table editing (import/export assets tags, etc.) + +### Changed +- Classic (nonribbon) UI improved - has same items as Ribbon UI +- Icons improvements +- Disabling menu items when work in progress + +### Fixed +- [#897] Classic UI fix + +## [5.2.0] - 2015-05-22 +### Added +- UI8 editbox for swf version in header panel +- Basic tag information panel + +### Changed +- AS1/2: Shown only the constant pool(s) in pcode editor +- Do not allow to chage tag tree selection, when current tag is under editing +- Faster bitmap export +- Using less memory when playing sounds +- Error message changed when the opened file is not swf + +### Fixed +- [#470] panels size after resizing from/to full screen +- [#877] A small glitch after search in AS +- [#878] small glitch after saving P-code or swf file +- [#470] glitch +- [#845] If frame consist 2 DoAction then it imports only first one +- pdf export (when no frame exists) +- text rendering (alpha channel was ignored), +- bmp export (paddings when width%2==1) +- [#883] -dumpSWF option does not work anymore +- [#882] Canvas export border size +- [#760] Internal viewer line linear gradient fill is not working +- [#887] error on export a special swf's P-CODE +- Extensions of exported images fixed + +## [5.1.0] - 2015-05-04 +### Added +- Allow to copy/move multiple tags, and dependencies +- [#842] For reconstruction if debug line info present +- [#841] Loop control for sound preview +- [#845] Import exported AS1/2 (DefineButton2&DefineSprite) button +- Scrollbar added to fontpanel +- SWF header editor +- Configure what object types to export in exportdialog + +### Changed +- Better gif exporter +- [#772]: closing loading dialog now cancels the loading of the swf +- [#762] export pcode with different extension + +### Fixed +- CRITICAL: Update System Bug causing updates not working +- [#862] AS3 asm: do not read beyond return/throw instructions +- [#865], [#613]: ribbon prefered width fix +- [#868] export path fix, allow to export buttons +- [#865] TagTree font size problem on high resolution screens +- [#713],[#807] Installer for 4.0+ fails to access Adobe Website +- [#728] Large fonts, [#857] add scroll on DefineFont3 + +## [5.0.2] - 2015-04-18 +### Added +- Reopen last session + +### Fixed +- ffdec.sh file line endings fixed + +## [5.0.1] - 2015-04-18 +### Fixed +- [#860]: Opening bundle (zip, swc, any binary file) files fixed + +## [5.0.0] - 2015-04-18 +### Added +- Color skins +- [#824] Mac OS X package +- [#809] Move left,right buttons for DefineTexts using translatex parameter +- [#805] Editor mode for DefineTexts +- [#825] Hotkeys for next/previous DefineText +- Export/Import symbol classes/export asset tags +- Frame export progress +- [#737] Single file script export +- Displaying changed AS3 scripts in GUI as bold +- Additional character info tags placed under character node +- New icons for other tags (metadata,fileattributes,setbackground,place/remove) +- Metadata tag editor + +### Changed +- Default color skin altered +- [#350] Allow only one running instance (Windows only, can be turned off) +- SWFs in zip based bundles (SWC for example) can be modified & saved +- Performace improvements +- More compact SWF-XML format +- Marking changed parentnodes as bold too + +### Fixed +- [#814] Exporting with scale problem +- [#816] P-code not shown after class initializer trait selection +- [#835] Static initializer improvements +- AS3 direct editing - local register decrement fix +- AS3 direct editing - maintain register order/names +- [#836] AS1/2/3 Correct expression precedence handling +- AS3 preincrement +- [#848] Correct toggling text switches +- [#817] AS1/2 for..in variable declaration +- [#849] Attribute member +- [#852] Ignore case for russian characters +- [#837] AS3 try..finally without catch + +## [4.1.1] - 2015-02-21 +### Added +- Export/Import XML added to ribbon menu +- Few GUI enhancements +- Undo tag changes context menu + +### Changed +- Java 8 now required + +### Removed +- Removed support for Java below 8 + +### Fixed +- [#811] export ActionScript + +## [4.1.0] - 2015-02-18 +### Added +- XML export/import +- confirmation dialogs added +- Add support for non-standard ABC-compressed SWF file +- [#745] Copy tag to another SWF +- [#803] Align text in DefineText + +### Changed +- performance improvements +- [#758] Zoom to fit is dynamic + +### Fixed +- [#738] Frame export +- [#742] Can't edit frames +- [#747] Move tag to adds extra frame +- [#749] Internal viewer Sprite fill color +- [#752] Sound is not stopped +- [#753] Reload swf +- [#759] Decompilation § symbol +- [#766] Can't extract all resources +- [#768] Super calls not being correctly recognized +- [#773] Scripts associated with ClipActions are not shown +- [#776] Stop working after setting "number of threads" to 0 +- [#783] No OK box when edited script or text was saved +- [#785] Text search. Remember last choise, Unicode case insensitive search +- [#787] Search in AS bug (when navigating to searched results) +- [#788] Add DefineCompactedFont Tag to gfx file +- [#790] Impossible to change letters under a font +- [#794] Font extraction fails sometimes +- [#798] Close file streams after export, exporting progress +- [#800] Unexpected deleted carrier return in DefineEditText +- Build fix on Linux +- Fis Startup Script for OpenJDK +- Other minor fixes + +## [4.0.5] - 2014-12-01 +### Added +- Escape control characters in strings, identifier names +- [#676] import text error messages / logging enhancement +- [#734] \xAB escapes, \uABCD escapes +- [#687] AS3 - allowing p-code comments on separate line +- [#709] Text Export to Single File with custom filename + +### Fixed +- [#732] Random freezing - JavactiveX library updated. +- [#730] Not working without ActiveX fix on Windows +- [#735] Automatic deobfuscation not correctly switched (required restart) + +## [4.0.4] - 2014-11-23 +### Changed +- better file cache, removing unneccessary temp files + +### Fixed +- obfuscated identifiers + +## [4.0.3] - 2014-11-23 +### Added +- [#722] Go to next/previous frame +- BMP file format export (images,frames,shapes) and import(images) + +### Fixed +- [#725] various AS direct editation bug fixes - namespace compilation, AS 1/2 strict equals, submethod scope, unbounded type +- [#715] namespace resolving fix +- [#635],[#726] placing cursor inside Unicode characters + +## [4.0.2] - 2014-11-22 +### Added +- show frame number during play +- flashplayer - show controls for DefineSprite +- goto frame +- [#716],[#717],[#718] Proxy - save SWF, replace, copy URL, filesizes, table design + +### Changed +- [#720]: edited shape tag is not marked as modified after replacing +- reorganized about dialog + +### Fixed +- [#719] null swf name in Proxy after cancelling rename dialog +- flashplayer - font display +- [#723]: saving swf with invalid referenced characters +- DefineCompactedFont paging +- [#288] Less memory usage during FLA export +- Corrected syntax hilighting for AS3 P-code + +## [4.0.1] - 2014-11-12 +### Fixed +- [#713] Installer can continue when no file can be downloaded +- Fixed shapes +- Checking for updates moved to separate thread + +## [4.0.0] - 2014-11-11 +### Added +- [#677] Zoom level in export settings +- internal viewer: linear/srgb gradients +- zooming buttons for flashplayer/internal viewer +- stroke scaling modes for canvas export +- create snapshot button +- [#389] Selecting font face on import +- [#701] Importing font from TTF file +- Reorganized font panel +- [#707] Debugger for logging messages +- [#302] AS3: Better Ctrl+Click handling with underline, more declaration targets +- [#685] Getting local register names from debug info can be disabled +- Adding new tags +- [#698] Allowing unicode letters in identifiers +- [#710] Information about deobfuscation in error comments +- One EXE for 32/64 bit, uses percentage memory. +- EXE SplashScreen +- New Improved Windows Installer (NSIS) - can install Java and FlashPlayer, download playerglobal.swc +- Config setting to load inner SWFs automatically +- Replace shape with image + +### Changed +- better FlashPlayer integration using JavactiveX library +- Faster building tag tree +- Faster timeline construction +- [#711] Improved folder view - faster and with correct context menu + +### Fixed +- AS2 deobfuscation fixes +- AS2 loops fix +- [#681] Linux script fixes +- AS2 constructor name fix +- [#688] AS3 direct edit fixes +- [#691] AS3 p-code reading/saving fix +- AS3 direct edit -submethod name resolve fix +- frames to html canvas fix +- [#524] Mask layer not applied when nonempty script layer +- [#663] AS3 imports fixes +- Font export of dot character +- Font panel Yes button fixed +- [#702] GFX font reading fix +- Better obfuscated names handling +- [#539] for(each) in declaration fixes + +## [3.0.0] - 2014-09-20 +### Added +- Separated GUI (GPL) and library (now LGPL) +- Editing obfuscated identifiers via new paragraph(§) syntax +- Timeline View with preview and object hilighting +- Show GFX data in dump view +- [#650] New parameter to replace binarydata, images, sounds, scripts from commandline +- Dump view - selecting node +- [#680] Loading subSWFs from binaryTags now optional (button/context menu) to avoid unnecessary memory consumption + +### Removed +- Removed deprecated commandline export formats (see --help) + +### Fixed +- FileAttributes tag reading fix +- [#649] GFX reading fixed +- [#656] Search in memory - 64 bit processes fix +- [#661] scripts not showing +- [#664] expanding fillStyles in raw edit +- [#668] add missing character fix, text tags fix +- [#674] texts hilighting initialization fix +- [#675] AS1/2 and/or operator compilation +- [#632] Locking file after opening (cannot save, etc.) +- [#651] Unnecessary removing expression killed in unreachable part +- [#678] Windows batch file paths fixed +- [#672] Disabling transparency slider on RGB only selection +- [#684] Sound streams inside DefineSprites, soundstream handling + +## [2.1.4] - 2014-08-23 +### Added +- AS1/2: New method for deobfuscation (can be switched off in settings) +- AS1/2: Using eval/set on invalid identifiers, quotes in function names/parameters + +### Fixed +- [#647] Skipping FileAttributesTag with Parallel speedup on +- [#648] Export from embedded SWF + +## [2.1.3] - 2014-08-18 +### Added +- Show "save" and "saveas" in application menu +- Saving data range in dump view +- Show actions, abcdata in dumpview (context menu on the tree node) +- [#612] show color in hex format + +### Changed +- Faster dump info collecting (less memory) +- Allow selecting multiple files in open file dialog + +### Fixed +- [#623] ffdec.sh UNIX file endings, executable +- [#624] search in embedded swf files +- [#632] AS1/2 Unnecessary GetVariable before NewObject +- [#627] filter swf not working +- LZMA saving +- Export pcode&hex from commandline +- [#640] text import fixed, ignore BOM + +## [2.1.2] - 2014-07-20 +### Added +- Dump view +- Context menu: Jump to character, raw edit all tags +- Catalan translation +- SWF header display + +### Fixed +- [#595] AS3 direct edit - Getter/Setter generation - caused FlashPlayer crashes +- [#592] AS3 Multiname resolving in P-code causing different bytecode +- [#585] AS3 moving popped values to output +- [#578] Always on top fixed on search results +- [#501] GotoFrame2 fix +- [#616] Frames to PNG export +- Export context menu +- [#559] Bitmap export opacity +- [#401] Placeobject 3/4 fix +- [#593] Return object newline +- [#594] Setting for curly brace + +## [2.1.1] - 2014-06-05 +### Added +- [#302] Find declaration (Ctrl+click, Ctrl+B), Find usages (Ctrl+U) - Works only for exactly same multinames, not local registers +- AS1/2 direct edit - global functions improvements +- AS1/2 negate operator, unary minus operator +- Opening SWFs in BinaryData tags +- AS1: Old string operators support, and/or, <> operator (editation) +- Statusbar loading animation improved +- [#579] AS3 direct editation - removing old class/methods from ABC +- remove character without the dependencies (remove only the place/remove tags) +- Running on system with no home directory +- [#428] PDF export (as images only) +- Commandline FlashPaper to PDF export +- Select frames / Characters commandline options + +### Changed +- [#337] quickfind visibility improved +- [#584] commandline script export - select whole packages (use .+ at the end of -selectas3class) + +### Fixed +- [#576] AS1/2 direct editation: DefineFunction2 fix +- AS1/2 property fix +- AS1/2 typeof operator fix +- [#250] line spacing fix +- PlaceObject 3-4 className +- [#579] AS3 direct editation bugfixes - property resolving, integer values +- Morphshape canvas export fix +- Canvas export fix - closing path +- [#580] Rename invalid identifiers commandline fix +- [#510] JSyntaxPane find and replace dialog wrap around fix +- No more frame caching during export => memory saving (like [#583]) +- [#586] DropShadow filter fix +- Canvas export colortransform fix + +## [2.1.0 update 2] - 2014-05-08 +### Added +- AS3 decompilation/editation: Vector initializers +- AS3 direct editation: more classes in one file + +### Fixed +- [#574] DefineSprite editing fix +- Various AS3 direct editation fixes + +## [2.1.0 update 1] - 2014-05-05 +### Added +- Portugese-brasilian translation + +### Changed +- HTML Canvas export improvements + +### Fixed +- Various AS3 direct editation bugs, like [#570] + +## [2.1.0] - 2014-05-01 +### Added +- AS3 direct editation (Experimental!) +- Frames SVG Export +- Shape/MorphShape/Frames HTML 5 Canvas Export +- [#559] morphshapes as animated SVG +- [#563] Single file text export/import +- Font WOFF export +- Advanced settings dialog with tabs, config names, descriptions + +### Fixed +- [#561], [#509], [#433]: AS3 EmptyStackException fix - correct hasnext2 arguments +- Internal viewer: Filters fix + +## [2.0.1 update 2] - 2014-04-05 +### Fixed +- [#557] AS3 null namespace fix - p-code not working + +## [2.0.1 update 1] - 2014-04-04 +### Fixed +- [#556] Goto main class on startup fix +- [#557] Nullpointer fix (private namespaces) + +## [2.0.1] - 2014-04-03 +### Added +- Thumbnail view +- Font TTF export +- Exporting frames: PNGs, AVI, GIF (via Internal flash viewer) +- Expand all context menu +- Internal viewer: Button mouse move and click handling +- Playing sounds without flash player +- Internal viewer: Sounds on stage +- All sounds to WAV export +- Internal viewer: Showing texts, dynamic text border/fill +- [#504]: Unicode characters in JSyntaxPane +- Internal viewer: showing object under cursor +- Folder icons +- Sound/Image format on command line. +- Removing placeobject tags +- Removing frames +- AS: "elseif" statements +- Code formatting: space before parenthesis + +### Changed +- Single frames animated. + +### Fixed +- [#529] limit the number of displayed binaryData bytes +- [#538] Interface are sometimes dynamic +- [#537] super is sometime preceded by a dot +- [#540] Saving SWF changes very large static uint values +- [#387] Frames preview bugged +- AS:loop mismatch fix on parallel speedup +- [#552] Some timeout exceptions +- [#494] Fixed nightly builds updates + +## [2.0.0] - 2014-03-02 +### Added +- Generic tag tree editor +- Timeline view (stub only) +- FLA export to CS5, CS5.5, CC format (previously only CS6 was supported) +- [#513]: command line option to extract swf from binary file +- Configurable code formatting (Indentation + brace position) +- [#262] Export FLA: Font character ranges export +- Configurable checking for updates + +### Changed +- Improved Internal Flash viewer - better shapes, morphshapes, DefineEditText tag, clipping, blend modes +- Improved commandline usage +- Automatic deobfuscation default value set to False (See News on webpages) +- Check for updates can be configured to inform about Nightly builds aswell + +### Deprecated +- Some commandline options are now deprecated, see --help + +### Fixed +- [#499] Cannot save via Proxy fixed +- [#504] font name reading fixed +- [#508] Support for OS without GUI +- [#305] Export FLA: empty sound layers +- [#312] Export FLA: Improved Shape/MorphShape fix +- [#503] Export FLA: Smoothing invalid shapes +- [#401] Invalid GFX tags in non GFX files +- [#304],[#306],[#507],[#424],[#425],[#478],[#485],[#517],[#518] Many direct AS1/2 editing issues +- [#361] FFDec icon is not visible on application start +- [#392] Video stream data fix +- [#516] AS3 P-code editor - Null name namespace handling + +## [1.8.1 update 1] - 2014-02-02 +### Fixed +- [#495] font embedding fix +- [#496] date format in new version dialog +- cosmetic changes + +## [1.8.1] - 2014-01-30 +### Added +- [#299] replace DefineBits images +- [#303] open folder with exported FLA +- [#324],[#346] SWC/zip/other binary file support +- [#371] detailed logging +- [#426] command line switch to rename identifiers +- [#457] clear recent opened files list +- [#458] save selected system font for swf fonts +- [#460] text editor: do not scroll to the end automatically +- [#462] font embedding dialog: show more sample characters +- [#463] global search in texts +- [#465] make font properties editable +- [#466] font preview + +### Changed +- [#369] new SVG and preview image rendering +- [#390] refresh font list without reloading the application +- [#453] update texts aftert adding new character to a font tag +- [#459] remember text panel splitter position +- [#461] font panel gui redesigned + +### Fixed +- [#451] dialog windows are not on the center of the screen +- [#454] Text syntax highlighting +- [#455],[#465] classic interface issues +- [#474] changeing language only available one time +- [#477] log window localization +- [#481] SVG export fix +- [#484] Oversized advance value after editing DefineText with DefineFont2 font +- [#493] missing search results + +## [1.8.0 update 1] - 2013-12-27 +### Added +- [#453] refresh (edit+save action) all texts button + +### Fixed +- Flash panel and font panel fixed + +## [1.8.0] - 2013-12-27 +### Added +- [#350] Allow to open multiple SWFs +- [#365] Filter fake SWFs during memory search +- [#366] Allow to sort the result list in memory search window +- [#429] Auto rename invalid identifiers setting +- [#447] Non-ribbon interface + +### Fixed +- [#354] Infinite decompilation fixed +- [#438] Case sensitive Command line arguments fixed +- [#436] Saving actionscript fixed +- [#446] Precedence issue fixed +- [#451] Dialogue window positions on a multi-monitor configuration fixed + +## [1.7.4 update 1] - 2013-12-05 +### Added +- [#426] Command line parameter for renaming invalid identifiers + +### Fixed +- [#427] Exception on linux fixed +- [#405], [#420], [#421] Some decompilation issues fixed +- [#430] Configuration default value problem fixed +- [#397], [#431] Deobfuscation stucked sometimes problem fixed + +## [1.7.4] - 2013-11-10 +### Added +- [#169] hexedit method body bytes +- [#335] last opened files +- [#404] Exporting P-code and Hex + console parameters +- [#407] register name is configurable +- Advanced settings +- Cancellable decompiling, exporting and searching + +### Fixed +- [#399], [#400] performance optimizations + +## [1.7.3 update 2] - 2013-09-29 +### Fixed +- [#398] AS3 p-code values with index 0 (null) + +## [1.7.3 update 1] - 2013-09-28 +### Added +- [#382] AS3: Adding new method + +## [1.7.3] - 2013-09-27 +### Added +- AS3: Multiname and namespace editing. +- [#382],[#396] AS3: Adding new trait (method/slot/const) +- AS3: Highlighting pair parenthesis/bracket +- AS3: Editing various new P-code parameters +- AS3: Highligting of trait names/types/parameters +- AS3: Global rename identifier for traits +- [#357] Playback controls for DefineSound +- [#391] AS3: Native methods mark +- [#395] Support for GFx ScaleForm SWFs (with fonts editing) +- Displaying fonts in internal viewer +- [#334], [#395] New Embed font dialog - selecting character ranges with preview +- Replacing characters in font (Yes/No to all dialog) + +### Changed +- AS3: New p-code syntax inspired by RABCDasm +- AS3: Editing whole trait in one textarea +- AS3: Removed messages about adding new constants +- AS3: Modified colors in editor +- [#301] Clearing error log causes icon to reset + +## [1.7.2 update 2] - 2013-09-13 +### Changed +- Updated translations + +### Fixed +- [#383] Firefox browser cache handling +- [#386] SWF resizing + +## [1.7.2 update 1] - 2013-09-11 +### Changed +- updated translations + +### Fixed +- [#383] Fixed cache loading when Firefox not used + +## [1.7.2] - 2013-09-11 +### Added +- [#357] Sounds Preview (Windows only) +- Movies preview (Windows only) +- Whole SWF display +- Preview controls (Play,Pause,Stop) +- Search SWFs in browsers cache (Firefox, Chrome) +- [#367] Memory search: Save selected files to disk +- Portugese translation + +### Changed +- [#380] Faster displaying DefineBitsLossless(2) images + +### Fixed +- [#292] Background color for Fonts preview fixed +- [#375] Replacing DefineBitsLossless image tag +- [#378] Refreshing language of JSyntaxPane +- MORPHGRADIENT reading fix + +## [1.7.1] - 2013-08-25 +### Added +- Loading SWFs from other processes memory (Windows only, sorry) +- [#325] Spanish translation +- [#210] Ukrainian and Dutch translation +- [#355] Chinese translation +- [#292] Change background color in SWF preview +- [#301] Clear errors log button +- [#313] Command line parameter for ignore all errors +- [#330] Protection agains adding same characters +- [#332] AS1/2 Showing elapsed times during commandline export +- [#344] Reload opened SWF +- Decompilation timeouts + +### Fixed +- [#295] Export FLA: wrong font +- [#297] Too bright titlebar button colors +- [#307] Export FLA: fixed empty textfields +- [#309] Export FLA: static text letter spacing detection +- [#310] Export FLA: Strokes +- [#311] Export FLA: BitmapFill +- [#327] AS1/2 Disassembly error stop application +- [#328] Fixed replacing images in DefineBitsJPEGX +- [#333] AS1/2 action reading +- [#336] Graph window is too small +- [#337] Quick search panel barely visible in same cases +- [#338] Expand/collapse icon in errorlog + +## [1.7.0 update 1] - 2013-08-11 +### Added +- [#315] German translation (partial) + +### Fixed +- [#123] Better context menu integration +- [#243],[#326] Better deobfuscation +- [#287] Typo in parallelSpeedUp parameter +- [#290],[#291] improved select language dialog +- [#294] minor GUI fixes +- [#298] Progressbar positition issues +- [#296] better export directory remembering +- [#314] Better deobfuscating filenames +- [#316] Readonly editor panes accepted Ctrl+Z/Y +- [#318] Export FLA: Shapes export fix +- [#319] AS3: Improved try..catch..finally decompilation +- [#323] AS3: Fixed default switch part + +## [1.7.0] - 2013-08-03 +### Added +- Listing contributors on about page +- [#223] AS2: Detecting uninitialized class fields +- [#250] Export FLA: Detecting static fields margin and spacing +- [#261] Export FLA: AS1/2 Frame scripts on first layer +- [#269] Commandline parameters for switching configuration +- [#274] AS3 Displaying elapsed time during commandline export +- [#275] AS3 Removing returnvoid as last statement + +### Changed +- New GUI based on Substance look and feel +- Menu changed to ribbon panel +- New round icon +- [#258] AS1/2: Improved chained assignments +- [#267] Starting program without choosing a file +- [#286] Saving to temp file first + +### Fixed +- [#123] Improved context menu integration on Windows +- [#233] Globally rename identifier deselects item in the tree +- [#235] Export FLA: Dynamic text fields coordinates +- [#243],[#263],[#264],[#265],[#266],[#281] Improved deobfuscation +- [#251] Export FLA: Fixed filter strength rounding +- [#257] Export FLA: Text field color and size issues +- [#259] Fixed images alpha +- [#260] Export FLA: Labels position +- [#268] AS1/2 Function parameter shown as register instead loc +- [#272] AS3 Class initializer editation fix +- [#276] Fixed anonymous/inline functions handling +- [#220] Improved editing fonts / texts +- [#284],... other small fixes + +## [1.6.7] - 2013-07-20 +### Added +- [#220] Selection of font to import characters from +- [#232] Automatically add .swf extension in saveas dialog +- [#253] Abort/Retry/Ignore dialog on errors with file saving + +### Changed +- Improved translations + +### Fixed +- [#137],[#242], [#243], [#244] AS1/2/3 fixed deobfuscation +- [#203] AS1/2 improved direct editing +- [#220] Adding characters to font fix +- [#225] AS1/2 object literal without name quotes +- [#236] AS1/2 Rename invalid identifiers issues +- [#245] AS3 Double space around "as" keyword +- [#247] AS3 Scrolling to main class at startup +- [#248] Memory issues (slowdown) +- [#254] Expressions as commands +- [#255] Windows 7 loading issues +- [#256] AS3 Object literal in return clause +- SWF text parsing (new lines) +- Labels size by locales + +## [1.6.6 update 2] - 2013-07-16 +### Fixed +- [#241] Program could not be started + +## [1.6.6 update 1] - 2013-07-16 +### Changed +- Better localization support + +### Fixed +- [#238],[#239],[#240] Fixed deobfuscation related problems +- [#237] Parentheses in AS1/2 add,subtract + +## [1.6.6] - 2013-07-16 +### Added +- [#217] Russian translation (focus) +- [#219] Hungarian translation (honfika) +- [#224] Swedish translation (Capasha) +- [#220] Adding characters to Fonts, displaying font info +- [#121] Search progress indication +- Error log + +### Changed +- [#203] Improved direct editing of AS1/2 +- [#207] Update SWF preview after switching external/internal flash player + +### Fixed +- [#151] Memory caching +- [#171] Skipping invalid AS3 code - newobject, newarray +- [#206] AS3 switch problem +- [#208] Renaming anonymous functions +- [#209],[#229] FLA export texts positions +- [#213],[#221] other decompilation issues +- [#225] AS object literal broken with ternar operator +- [#226] onClip indentation in FLA export +- [#227] gotoAndStop wrong frame index +- [#230] FLA export missing strokes +- Shapes viewer - missing strokes + +## [1.6.5 update 1] - 2013-07-09 +### Fixed +- [#151] Fixed caching in memory +- [#172] AS1/2 constant detection fix +- [#174] Renaming SymbolClass fix +- [#175],[#212] Fixed create directory issues on export +- [#185],[#186] on-clip actions indentation +- [#197] AS1/2 Missing storeregister before switch +- [#216] AS2 Fixed field order +- [#213] AS2 Fixed var fields quotes, switch nullpointer + +## [1.6.5] - 2013-07-08 +### Added +- Multilanguage support (currently English and Czech) +- [#151] Option for caching in memory instead of files +- [#168] Export selection in tree context menu +- [#176] option to show main class on startup +- [#177] saving window maximized state +- [#202] Removing tags other than DefineSprite + +### Changed +- [#173],[#190] Better renaming +- [#129], [#153] Better deobfuscation +- [#180] better error handling +- [#185],[#186] better displaying and exporting onclip actions + +### Fixed +- [#123] Better context menu integration +- [#136] FLA export - text sizes +- [#137],[#179] foreach issues (hasNext) +- [#144] Plain text export - empty line fix +- [#144] Not displaying texts +- [#164] DefineMorphShape issues +- [#167] Sprite tag appearing twice in export filename +- [#170] AS3 Try in loop +- [#172] loop detection fix +- [#175] use empty namespace +- [#178] AS subtract with negate +- [#181] AS3 missing quotes in object field +- [#182] missing namespace imports +- [#183] wrong stage size +- [#184] wrong video link +- [#189] Fixed three dots in tree +- [#191] Focalgradient fill fix +- [#195] AS2 issues +- [#196],[#197] switch issues +- [#198] DefineFont2 empty check +- [#200] DefineBitsLossLess fix +- [#201] Nonworking main window in Linux/MacOS (due toAssociation) + +## [1.6.4 update 1] - 2013-06-30 +### Fixed +- [#166] For loops detection +- [#165] AS3:direct lookupswitch support + +## [1.6.4] - 2013-06-30 +### Added +- [#63] Globally rename identifier +- [#67] Deobfuscation - rename identifiers according to type +- [#117] Drag & Drop SWF file to main window opens it +- [#123] Context menu integration on Windows +- [#127] Drag & Drop items from tree outside of application +- [#134] AS3: Find document class +- [#144] New lines in plain text export +- [#155] Remembering window size + splitbar positions between runs + +### Changed +- [#142] Using exportassets tag for tag names +- [#146] Display AS2 classes as tree of packages +- Better loop detection + +### Fixed +- [#129] AS1/2: not refreshing decompiled after rename +- [#130] Renaming SymbolClass identifiers too +- [#132] Renaming identifiers renamed strings +- [#136] Invalid text positions in FLA export +- [#145] Unicode support +- [#147] Escape filenames during obfuscated AS3 export +- [#148] Better package vs classname handling +- [#152] Empty if branches not inverted +- [#156] Better search handling (not freezing) +- [#157] AS3: Try statements in loops +- [#158] Graph repaint problem +- [#159] AS3: Improper rest parameter handling +- [#160] Commandline binaryData export +- [#162] DefineBitsJPEG2 image replacing +- [#163] Closing SWF file after loading +- other minor fixes + +## [1.6.3 update 2] - 2013-06-21 +### Changed +- [#149] Ifs with empty onTrue branches now inverted + +### Fixed +- [#150] Long line restriction removed + +## [1.6.3 update 1] - 2013-06-21 +### Fixed +- Memory limit decreased - FFDec was not working on 32 bit JVM. + +## [1.6.3] - 2013-06-20 +### Changed +- Parallel SpeedUp can be disabled in menu +- Better loop detection + +### Fixed +- [#119] Replacements file not found issue +- [#101] AS1/2 postincrement fix +- [#114],[#116],[#135],[#141] Fixed loop detection +- [#102] Fixed loop highlighting in export +- [#124] Flash player file path detection +- [#128] Improved imports +- [#135] CommentItem fix +- [#129],[#131] Better deobfuscation +- [#104] AS3 inc/dec local deobfuscation fix +- [#113],[#133],[#140] Memory limit increased + +## [1.6.2] - 2013-06-09 +### Added +- New loop detection algorithm + +### Changed +- [#108] - Faster loading and decompiling (Parallelism) +- Improved Internal flash viewer - shapes and morphshapes + +### Fixed +- Ternar operator fix +- [#102] Fixed Shapes to FLA export +- AS1/2 class detection fix +- [#105],[#104],[#101] fixed via new loop detection + +## [1.6.1] - 2013-06-03 +### Added +- Internal Flash Viewer - preview of flash parts (shapes,sprites,frames) without need of Flash Player. (Used on nonWindows platforms by default) +- [#109], [#106], [#107] some code improvements + +### Changed +- Application needs Java 1.7 to run + +### Removed +- Support for Java before 1.7 + +### Fixed +- [#102], [#110] AS3: Class highlight fix +- [#103] AS3:Fixed setslot handling +- [#104] AS3:Inc/Declocal nullpointer fix +- [#104] Multiple conditions in loop fix +- [#111] AS3:Object literal truncates line +- [#105] Better do while..break handling +- loop fixes + +## [1.6.0 update 1] - 2013-05-25 +### Added +- better FLA export + +### Fixed +- Many FLA export related bugs (like [#96]) +- [#98] Empty initializers do not cause empty lines now +- [#99] small logging issues +- [#100] large obfuscated code support + +## [1.6.0] - 2013-05-20 +### Added +- Export to FLA (Experimental BETA!) +- [#85] Search text in all ActionScripts +- SWF 11 support + +### Fixed +- [#79] ActionStartDrag constraint fix +- [#92] Inversed GreaterThan/LessThan +- [#93] AS1/2 fixed switch detection +- [#94] AS1/2 ActionTry - register cast fix +- [#95] Better script end handling + +## [1.5.2] - 2013-05-05 +### Added +- Improved automatic update system (changes log). +- Handling script traits as separate objects. +- [#86] open/save file dialog now accepts absolute paths in quotes + +### Fixed +- [#87] Not displaying image changes in DefineBitsLossLess1 & 2 +- [#88] Fixed graph building +- [#89] AS3: bracket in property name lead to missing dot +- [#82] printgraph issue + +## [1.5.1 update 1] - 2013-05-04 +### Added +- Exporting texts via commandline +- Exporting all via commandline + +### Fixed +- DefineText2 color parameter +- AS3 GetSlot,SetSlot +- [#78],[#81],[#82],[#84] Fixed deobfuscation, exceptions during printgraph,... +- [#83] Fixed images transparency (zlib fix) +- Fixed graphparts with only jump in it (obfuscators) +- MORPHGRADIENT FIX +- Trasparency in DefineBitsJPEG3 and 4 +- Displaying shapes,morphshapes and sprites with bitmaps + +## [1.5.1] - 2013-05-01 +### Added +- Support for larger switches (10+cases) +- Editing text tags +- [#65] Exporting text tags +- Removing sprites +- Replacing images + +### Fixed +- DefineMorphShape2 fix +- [#79] - AS1/2 class detection fix, wrong printgraph fix +- [#78] - script trait slots fix + +## [1.5.0 update 1] - 2013-04-21 +### Fixed +- Automatic deobfuscation config defaulted to Off for AS1/2. + +## [1.5.0] - 2013-04-20 +### Added +- Direct editing of ActionScript 1/2 code (Beta) +- AS1/2: ifFrameLoaded support +- Automatic deobfuscation can be disabled in the menu +- [#48] - Decompile only specified class (commandline option) +- [#53] - AS3: Displaying multiname indices in trait detail, displaying method indices +- [#66] - Decompressing LZMA via commandline +- [#68] - Exporting DefineBinaryData tags, assigning class names to characters (SymbolClass tag) +- [#69] - DoABC vs DoABCDefine tags decompilation +- [#75] - Comma separator in while/do..while conditions, better if..return handling +- AS1/2: parsing NaN,Infinity value (Fix for [#73]) + +### Changed +- New icons (edit/save/cancel and main menu) + +### Fixed +- [#62] - Errors on not defined character tags (import tag) +- [#72] - First ternary operator expression was always true +- Fixed many deobfuscation related bugs + +## [1.4.3 update 2] - 2013-04-10 +### Fixed +- [#64] - AS1/2 Resolving registers in ActionDefineFunction2 (super,this,...and parameters shown as registerxx) +- Try to fix lib/FlashPlayer.exe issue + +## [1.4.3 update 1] - 2013-04-06 +### Fixed +- [#38] - Indentation in const/var initializers, missing semicolon +- [#56] - Test output left in last release +- [#57] - Unknown instructions now do not log an exception (obfuscators do this) +- [#58] - Index out of bounds exception fix on methodinfo indices in imports detection. +- AS3 loops fix +- While true fix + +## [1.4.3] - 2013-04-04 +### Added +- AS1/2 Better deobfuscation + +### Fixed +- [#45] - Unicode characters fix +- [#50] - AS1/2 Function body deobfuscation fix +- [#51] - Displaying java class names instead of expressions +- [#52] - AS1/2 Better constantpool detection (deobfuscation) +- [#38] - AS3 indentation in initialized const/var value for newobject +- Fixed ImportAssets2 tag id + +## [1.4.2 update 1] - 2013-03-25 +### Fixed +- [#47] - wrong AS3 deobfuscation +- AS3 deobfuscation issues +- AS3 switch + +## [1.4.2] - 2013-03-24 +### Added +- [#42] - Displaying code as hex +- AS1/2: Renaming identifiers (deobfuscation) +- AS1/2,AS3: Better deobfuscation +- Storing configuration to user home +- Installer for Windows systems + +### Changed +- Graph button changed to icon. + +### Fixed +- [#39] - AS1/2 NewMethod..Pop fix +- [#40] - No logging + For..in..return decompilation +- [#44] - DefineFont2 fix +- [#36] - Multiname with invalid index +- [#43] - Ternary operator and more +- [#46] - Ifs with empty branches got ignored +- [#3] - Ignoring unknown opcodes +- Logging exceptions during export + +## [1.4.1] - 2013-03-10 +### Added +- Exporting sounds +- Better AS1/2 deobfuscation (disassembly & decompilation) + +### Fixed +- Exporting only first 1000 frames of the movie +- Decompiled code was not refreshed on AS1/2 changes +- Application no longer creates empty directories on export + +## [1.4.0 update 1] - 2013-03-04 +### Fixed +- [#37] - AS3: Reversed loop conditions + +## [1.4.0] - 2013-03-03 +### Added +- AS3: ignoring return void at the end of methods +- New icons - Silk icons +- AS3: Traits list sort button +- Better Graph display +- Frames view +- Exporting of movies (No audio) +- Some AS3 related Tests +- Homepage & Donate link in the menu + +### Changed +- Tree view instead of tabs +- AS1/2 and AS3 now share same decompiling method. + +### Fixed +- [#34] - Reversed loop conditions +- [#35] - Fixed unicode strings (Japanese) + +## [1.3.1] - 2013-02-23 +### Changed +- Flash player no longer uses SWT library + +### Fixed +- [#32] - AS2: Action255 bug +- [#31] - Erorrneous tags are now ignored +- DefineBitsLossLess 1&2 on 8bit colormapped images + +## [1.3.0] - 2013-02-17 +### Added +- Decompilation is more resistant to obfuscation +- Shapes SVG export +- AS2: Decompiling classes & interfaces +- Click&go feature - clicking actionscript source displays appropriate P-code instruction and vice-versa (both AS1/2 and AS3) +- AS3: Deobfuscation menu +- Graph button for displaying code flow Graph + +### Changed +- Complete new decompiling method in both AS1/2 and AS3 +- Application renamed from "JP ActionScript Decompiler" to "JPEXS Free Flash Decompiler". +- To edit source, Edit button must be pressed first (Due to click&go feature) + +### Fixed +- AS3: Method info editor fixed +- Edittext & Button displaying + +## [1.2.0] - 2013-01-19 +### Added +- Displaying various SWF objects (shapes, sprites,...) with flash player library (Windows only, sorry). +- Images display and export +- AS2: Exporting selection +- Progressbar during loading + +### Changed +- One merged window for AS1/2 and 3. +- Updated icons + +### Fixed +- AS3: xml attrib, switch in anonymous function (in AS2 too) + +## [1.1.0] - 2013-01-02 +### Added +- Checking for updates +- AS2: Exporting +- AS3: Decompiling whole scripts instead of just classes +- AS3: Exporting selected scripts +- AS3: Script search bar +- AS3: List of DoABCTags now has default "- all -" item +- AS3: Better imports, use namespaces +- AS3: XML related instructions +- AS3: Anonymous functions with names +- AS3: Better initialization of const values +- Logging exceptions to log.txt file + +### Fixed +- AS3: set_local..get_local, dup, chained assignments, highlighting, callsupervoid, typenames, with statement, loops + +## [1.0.1] - 2012-12-26 +### Added +- AS3: Runtime namespace resolving +- AS3: Arguments variable +- AS3: Better recognizing Pre/Post Increments/Decrements +- AS3: Better declarations + +### Fixed +- AS3: Fixed static variables + +## [1.0.0] - 2012-12-24 +### Added +- Support for LZMA compressed files +- AS3: Detecting local register types for declaration. +- AS3: Displaying inline functions +- AS3: Last save/open dir is remembered +- AS3: Better usage detection for multinames +- AS3: Commandline arguments for exporting +- AS3: Better chained assignments +- AS2: FSCommand2 instruction support +- Proxy: Mimetype application/octet-stream added +- Added executable for Windows users. + +### Changed +- AS3: GUI - Constants tab moved to the top +- AS3: Deobfuscation is now optional, can be accessed via menu + +### Fixed +- AS3: rest parameter, for..in, fail on large classes (due to sub limiter) +- Other minor fixes + +## [beta 1] - 2011-07-30 +### Added +- AS3: Automatic computing method body parameters (EXPERIMENTAL) +- AS3: Editing return type of methods +- AS3: Editing type and default value for variables/constants (Slot/Const traits) +- AS1/2: Few enhancements +- About dialog + +### Changed +- Gui: Updated Icons + +### Fixed +- AS 1/2: Fixed large bug causing Ifs to not decompile properly +- Proxy: Some minor fixes + +## [alpha 10] - 2011-07-13 +### Added +- AS3:Highlighting actual line +- AS3:Completing instruction names via Ctrl+Space +- AS3:Editing method parameters, method body parameters via tab panel +- AS3:ByteCode minor_version 17 supported - decimal datatypes +- AS3:Local variables and method parameters take name from debug information if present +- AS3:Automatic renaming of classes/methods when obfuscated names +- AS3:Better error messages (When cannot decompile obfuscated code) + +### Fixed +- AS3:Fixed Vector datatypes (TypeName multiname, applytype instruction) +- AS3:Hilighting fixes +- AS3:Fixed decrement/increment statements decompilation +- AS3:Decompiler now adds variable declarations on the beginning of decompiled method +- AS3:Try/catch statements fixed when debug information present +- AS3:Fixed for each statements +- AS3:Other minor fixes + +## [alpha 9] - 2011-07-02 +### Added +- AS3: Added disassembling of some new types of instructions +- AS3: Exporting source as PCode + +### Fixed +- AS3: Many other bugfixes... + +## [alpha 8] - 2010-09-19 +### Added +- AS3: Editing exceptions +- AS3: Finding usage of multinames from constant table + +### Changed +- AS1/2: Better GUI +- AS1/2: Better decompiling of Ifs, For..in + +## [alpha 7] - 2010-09-04 +### Added +- Initial public release + +[Unreleased]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version9.0.0...dev +[9.0.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version8.0.1...version9.0.0 +[8.0.1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version8.0.0...version8.0.1 +[8.0.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version7.1.2...version8.0.0 +[7.1.2]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version7.1.1...version7.1.2 +[7.1.1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version7.1.0...version7.1.1 +[7.1.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version7.0.1...version7.1.0 +[7.0.1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version7.0.0...version7.0.1 +[7.0.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version6.1.1...version7.0.0 +[6.1.1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version6.1.0...version6.1.1 +[6.1.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version6.0.2...version6.1.0 +[6.0.2]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version6.0.1...version6.0.2 +[6.0.1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version6.0.0...version6.0.1 +[6.0.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version5.3.0...version6.0.0 +[5.3.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version5.2.0...version5.3.0 +[5.2.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version5.1.0...version5.2.0 +[5.1.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version5.0.2...version5.1.0 +[5.0.2]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version5.0.1...version5.0.2 +[5.0.1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version5.0.0...version5.0.1 +[5.0.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version4.1.1...version5.0.0 +[4.1.1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version4.1.0...version4.1.1 +[4.1.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version4.0.5...version4.1.0 +[4.0.5]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version4.0.4...version4.0.5 +[4.0.4]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version4.0.3...version4.0.4 +[4.0.3]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version4.0.2...version4.0.3 +[4.0.2]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version4.0.1...version4.0.2 +[4.0.1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version4.0.0...version4.0.1 +[4.0.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version3.0.0...version4.0.0 +[3.0.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version2.1.4...version3.0.0 +[2.1.4]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version2.1.3...version2.1.4 +[2.1.3]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version2.1.2...version2.1.3 +[2.1.2]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version2.1.1...version2.1.2 +[2.1.1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version2.1.0u2...version2.1.1 +[2.1.0 update 2]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version2.1.0u1...version2.1.0u2 +[2.1.0 update 1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version2.1.0...version2.1.0u1 +[2.1.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version2.0.1u2...version2.1.0 +[2.0.1 update 2]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version2.0.1u1...version2.0.1u2 +[2.0.1 update 1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version2.0.1...version2.0.1u1 +[2.0.1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version2.0.0...version2.0.1 +[2.0.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.8.1u1...version2.0.0 +[1.8.1 update 1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.8.1...version1.8.1u1 +[1.8.1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.8.0u1...version1.8.1 +[1.8.0 update 1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.8.0...version1.8.0u1 +[1.8.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.7.4u1...version1.8.0 +[1.7.4 update 1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.7.4...version1.7.4u1 +[1.7.4]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.7.3u2...version1.7.4 +[1.7.3 update 2]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.7.3u1...version1.7.3u2 +[1.7.3 update 1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.7.3...version1.7.3u1 +[1.7.3]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.7.2u2...version1.7.3 +[1.7.2 update 2]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.7.2u1...version1.7.2u2 +[1.7.2 update 1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.7.2...version1.7.2u1 +[1.7.2]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.7.1...version1.7.2 +[1.7.1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.7.0u1...version1.7.1 +[1.7.0 update 1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.7.0...version1.7.0u1 +[1.7.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.6.7...version1.7.0 +[1.6.7]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.6.6u2...version1.6.7 +[1.6.6 update 2]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.6.6u1...version1.6.6u2 +[1.6.6 update 1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.6.6...version1.6.6u1 +[1.6.6]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.6.5u1...version1.6.6 +[1.6.5 update 1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.6.5...version1.6.5u1 +[1.6.5]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.6.4u1...version1.6.5 +[1.6.4 update 1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.6.4...version1.6.4u1 +[1.6.4]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.6.3u2...version1.6.4 +[1.6.3 update 2]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.6.3u1...version1.6.3u2 +[1.6.3 update 1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.6.3...version1.6.3u1 +[1.6.3]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.6.2...version1.6.3 +[1.6.2]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.6.1...version1.6.2 +[1.6.1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.6.0u1...version1.6.1 +[1.6.0 update 1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.6.0...version1.6.0u1 +[1.6.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.5.2...version1.6.0 +[1.5.2]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.5.1u1...version1.5.2 +[1.5.1 update 1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.5.1...version1.5.1u1 +[1.5.1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.5.0u1...version1.5.1 +[1.5.0 update 1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.5.0...version1.5.0u1 +[1.5.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.4.3u2...version1.5.0 +[1.4.3 update 2]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.4.3u1...version1.4.3u2 +[1.4.3 update 1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.4.3...version1.4.3u1 +[1.4.3]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.4.2u1...version1.4.3 +[1.4.2 update 1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.4.2...version1.4.2u1 +[1.4.2]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.4.1...version1.4.2 +[1.4.1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.4.0u1...version1.4.1 +[1.4.0 update 1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.4.0...version1.4.0u1 +[1.4.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.3.1...version1.4.0 +[1.3.1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.3.0...version1.3.1 +[1.3.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.2.0...version1.3.0 +[1.2.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.1.0...version1.2.0 +[1.1.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.0.1...version1.1.0 +[1.0.1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.0.0...version1.0.1 +[1.0.0]: https://github.com/jindrapetrik/jpexs-decompiler/compare/beta1...version1.0.0 +[beta 1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/alpha10...beta1 +[alpha 10]: https://github.com/jindrapetrik/jpexs-decompiler/compare/alpha9...alpha10 +[alpha 9]: https://github.com/jindrapetrik/jpexs-decompiler/compare/alpha8...alpha9 +[alpha 8]: https://github.com/jindrapetrik/jpexs-decompiler/compare/alpha7...alpha8 +[alpha 7]: https://github.com/jindrapetrik/jpexs-decompiler/releases/tag/alpha7 +[#1156]: https://www.free-decompiler.com/flash/issues/1156 +[#1171]: https://www.free-decompiler.com/flash/issues/1171 +[#1170]: https://www.free-decompiler.com/flash/issues/1170 +[#1241]: https://www.free-decompiler.com/flash/issues/1241 +[#1162]: https://www.free-decompiler.com/flash/issues/1162 +[#1199]: https://www.free-decompiler.com/flash/issues/1199 +[#1151]: https://www.free-decompiler.com/flash/issues/1151 +[#1128]: https://www.free-decompiler.com/flash/issues/1128 +[#1163]: https://www.free-decompiler.com/flash/issues/1163 +[#1172]: https://www.free-decompiler.com/flash/issues/1172 +[#1174]: https://www.free-decompiler.com/flash/issues/1174 +[#1183]: https://www.free-decompiler.com/flash/issues/1183 +[#1193]: https://www.free-decompiler.com/flash/issues/1193 +[#1200]: https://www.free-decompiler.com/flash/issues/1200 +[#1198]: https://www.free-decompiler.com/flash/issues/1198 +[#1205]: https://www.free-decompiler.com/flash/issues/1205 +[#1194]: https://www.free-decompiler.com/flash/issues/1194 +[#1210]: https://www.free-decompiler.com/flash/issues/1210 +[#1217]: https://www.free-decompiler.com/flash/issues/1217 +[#1244]: https://www.free-decompiler.com/flash/issues/1244 +[#1247]: https://www.free-decompiler.com/flash/issues/1247 +[#1236]: https://www.free-decompiler.com/flash/issues/1236 +[#1251]: https://www.free-decompiler.com/flash/issues/1251 +[#1265]: https://www.free-decompiler.com/flash/issues/1265 +[#1268]: https://www.free-decompiler.com/flash/issues/1268 +[#1161]: https://www.free-decompiler.com/flash/issues/1161 +[#1118]: https://www.free-decompiler.com/flash/issues/1118 +[#409]: https://www.free-decompiler.com/flash/issues/409 +[#1132]: https://www.free-decompiler.com/flash/issues/1132 +[#1134]: https://www.free-decompiler.com/flash/issues/1134 +[#1121]: https://www.free-decompiler.com/flash/issues/1121 +[#1052]: https://www.free-decompiler.com/flash/issues/1052 +[#1145]: https://www.free-decompiler.com/flash/issues/1145 +[#758]: https://www.free-decompiler.com/flash/issues/758 +[#1096]: https://www.free-decompiler.com/flash/issues/1096 +[#1104]: https://www.free-decompiler.com/flash/issues/1104 +[#1107]: https://www.free-decompiler.com/flash/issues/1107 +[#1106]: https://www.free-decompiler.com/flash/issues/1106 +[#1113]: https://www.free-decompiler.com/flash/issues/1113 +[#1075]: https://www.free-decompiler.com/flash/issues/1075 +[#1127]: https://www.free-decompiler.com/flash/issues/1127 +[#1103]: https://www.free-decompiler.com/flash/issues/1103 +[#1133]: https://www.free-decompiler.com/flash/issues/1133 +[#1135]: https://www.free-decompiler.com/flash/issues/1135 +[#1138]: https://www.free-decompiler.com/flash/issues/1138 +[#1139]: https://www.free-decompiler.com/flash/issues/1139 +[#930]: https://www.free-decompiler.com/flash/issues/930 +[#1137]: https://www.free-decompiler.com/flash/issues/1137 +[#1144]: https://www.free-decompiler.com/flash/issues/1144 +[#1147]: https://www.free-decompiler.com/flash/issues/1147 +[#1148]: https://www.free-decompiler.com/flash/issues/1148 +[#1152]: https://www.free-decompiler.com/flash/issues/1152 +[#1154]: https://www.free-decompiler.com/flash/issues/1154 +[#116]: https://www.free-decompiler.com/flash/issues/116 +[#1070]: https://www.free-decompiler.com/flash/issues/1070 +[#1098]: https://www.free-decompiler.com/flash/issues/1098 +[#1033]: https://www.free-decompiler.com/flash/issues/1033 +[#1083]: https://www.free-decompiler.com/flash/issues/1083 +[#1091]: https://www.free-decompiler.com/flash/issues/1091 +[#1076]: https://www.free-decompiler.com/flash/issues/1076 +[#1068]: https://www.free-decompiler.com/flash/issues/1068 +[#1063]: https://www.free-decompiler.com/flash/issues/1063 +[#1019]: https://www.free-decompiler.com/flash/issues/1019 +[#1016]: https://www.free-decompiler.com/flash/issues/1016 +[#1010]: https://www.free-decompiler.com/flash/issues/1010 +[#1008]: https://www.free-decompiler.com/flash/issues/1008 +[#1004]: https://www.free-decompiler.com/flash/issues/1004 +[#933]: https://www.free-decompiler.com/flash/issues/933 +[#1062]: https://www.free-decompiler.com/flash/issues/1062 +[#418]: https://www.free-decompiler.com/flash/issues/418 +[#1047]: https://www.free-decompiler.com/flash/issues/1047 +[#812]: https://www.free-decompiler.com/flash/issues/812 +[#1056]: https://www.free-decompiler.com/flash/issues/1056 +[#1057]: https://www.free-decompiler.com/flash/issues/1057 +[#991]: https://www.free-decompiler.com/flash/issues/991 +[#689]: https://www.free-decompiler.com/flash/issues/689 +[#1060]: https://www.free-decompiler.com/flash/issues/1060 +[#1037]: https://www.free-decompiler.com/flash/issues/1037 +[#489]: https://www.free-decompiler.com/flash/issues/489 +[#1007]: https://www.free-decompiler.com/flash/issues/1007 +[#1044]: https://www.free-decompiler.com/flash/issues/1044 +[#947]: https://www.free-decompiler.com/flash/issues/947 +[#953]: https://www.free-decompiler.com/flash/issues/953 +[#954]: https://www.free-decompiler.com/flash/issues/954 +[#950]: https://www.free-decompiler.com/flash/issues/950 +[#945]: https://www.free-decompiler.com/flash/issues/945 +[#957]: https://www.free-decompiler.com/flash/issues/957 +[#956]: https://www.free-decompiler.com/flash/issues/956 +[#968]: https://www.free-decompiler.com/flash/issues/968 +[#978]: https://www.free-decompiler.com/flash/issues/978 +[#955]: https://www.free-decompiler.com/flash/issues/955 +[#966]: https://www.free-decompiler.com/flash/issues/966 +[#999]: https://www.free-decompiler.com/flash/issues/999 +[#1000]: https://www.free-decompiler.com/flash/issues/1000 +[#1017]: https://www.free-decompiler.com/flash/issues/1017 +[#1030]: https://www.free-decompiler.com/flash/issues/1030 +[#949]: https://www.free-decompiler.com/flash/issues/949 +[#944]: https://www.free-decompiler.com/flash/issues/944 +[#939]: https://www.free-decompiler.com/flash/issues/939 +[#942]: https://www.free-decompiler.com/flash/issues/942 +[#952]: https://www.free-decompiler.com/flash/issues/952 +[#858]: https://www.free-decompiler.com/flash/issues/858 +[#905]: https://www.free-decompiler.com/flash/issues/905 +[#920]: https://www.free-decompiler.com/flash/issues/920 +[#921]: https://www.free-decompiler.com/flash/issues/921 +[#924]: https://www.free-decompiler.com/flash/issues/924 +[#895]: https://www.free-decompiler.com/flash/issues/895 +[#884]: https://www.free-decompiler.com/flash/issues/884 +[#899]: https://www.free-decompiler.com/flash/issues/899 +[#903]: https://www.free-decompiler.com/flash/issues/903 +[#855]: https://www.free-decompiler.com/flash/issues/855 +[#850]: https://www.free-decompiler.com/flash/issues/850 +[#832]: https://www.free-decompiler.com/flash/issues/832 +[#904]: https://www.free-decompiler.com/flash/issues/904 +[#910]: https://www.free-decompiler.com/flash/issues/910 +[#922]: https://www.free-decompiler.com/flash/issues/922 +[#916]: https://www.free-decompiler.com/flash/issues/916 +[#938]: https://www.free-decompiler.com/flash/issues/938 +[#897]: https://www.free-decompiler.com/flash/issues/897 +[#470]: https://www.free-decompiler.com/flash/issues/470 +[#877]: https://www.free-decompiler.com/flash/issues/877 +[#878]: https://www.free-decompiler.com/flash/issues/878 +[#845]: https://www.free-decompiler.com/flash/issues/845 +[#883]: https://www.free-decompiler.com/flash/issues/883 +[#882]: https://www.free-decompiler.com/flash/issues/882 +[#760]: https://www.free-decompiler.com/flash/issues/760 +[#887]: https://www.free-decompiler.com/flash/issues/887 +[#842]: https://www.free-decompiler.com/flash/issues/842 +[#841]: https://www.free-decompiler.com/flash/issues/841 +[#772]: https://www.free-decompiler.com/flash/issues/772 +[#762]: https://www.free-decompiler.com/flash/issues/762 +[#862]: https://www.free-decompiler.com/flash/issues/862 +[#865]: https://www.free-decompiler.com/flash/issues/865 +[#613]: https://www.free-decompiler.com/flash/issues/613 +[#868]: https://www.free-decompiler.com/flash/issues/868 +[#713]: https://www.free-decompiler.com/flash/issues/713 +[#807]: https://www.free-decompiler.com/flash/issues/807 +[#728]: https://www.free-decompiler.com/flash/issues/728 +[#857]: https://www.free-decompiler.com/flash/issues/857 +[#860]: https://www.free-decompiler.com/flash/issues/860 +[#824]: https://www.free-decompiler.com/flash/issues/824 +[#809]: https://www.free-decompiler.com/flash/issues/809 +[#805]: https://www.free-decompiler.com/flash/issues/805 +[#825]: https://www.free-decompiler.com/flash/issues/825 +[#737]: https://www.free-decompiler.com/flash/issues/737 +[#350]: https://www.free-decompiler.com/flash/issues/350 +[#814]: https://www.free-decompiler.com/flash/issues/814 +[#816]: https://www.free-decompiler.com/flash/issues/816 +[#835]: https://www.free-decompiler.com/flash/issues/835 +[#836]: https://www.free-decompiler.com/flash/issues/836 +[#848]: https://www.free-decompiler.com/flash/issues/848 +[#817]: https://www.free-decompiler.com/flash/issues/817 +[#849]: https://www.free-decompiler.com/flash/issues/849 +[#852]: https://www.free-decompiler.com/flash/issues/852 +[#837]: https://www.free-decompiler.com/flash/issues/837 +[#811]: https://www.free-decompiler.com/flash/issues/811 +[#745]: https://www.free-decompiler.com/flash/issues/745 +[#803]: https://www.free-decompiler.com/flash/issues/803 +[#738]: https://www.free-decompiler.com/flash/issues/738 +[#742]: https://www.free-decompiler.com/flash/issues/742 +[#747]: https://www.free-decompiler.com/flash/issues/747 +[#749]: https://www.free-decompiler.com/flash/issues/749 +[#752]: https://www.free-decompiler.com/flash/issues/752 +[#753]: https://www.free-decompiler.com/flash/issues/753 +[#759]: https://www.free-decompiler.com/flash/issues/759 +[#766]: https://www.free-decompiler.com/flash/issues/766 +[#768]: https://www.free-decompiler.com/flash/issues/768 +[#773]: https://www.free-decompiler.com/flash/issues/773 +[#776]: https://www.free-decompiler.com/flash/issues/776 +[#783]: https://www.free-decompiler.com/flash/issues/783 +[#785]: https://www.free-decompiler.com/flash/issues/785 +[#787]: https://www.free-decompiler.com/flash/issues/787 +[#788]: https://www.free-decompiler.com/flash/issues/788 +[#790]: https://www.free-decompiler.com/flash/issues/790 +[#794]: https://www.free-decompiler.com/flash/issues/794 +[#798]: https://www.free-decompiler.com/flash/issues/798 +[#800]: https://www.free-decompiler.com/flash/issues/800 +[#676]: https://www.free-decompiler.com/flash/issues/676 +[#734]: https://www.free-decompiler.com/flash/issues/734 +[#687]: https://www.free-decompiler.com/flash/issues/687 +[#709]: https://www.free-decompiler.com/flash/issues/709 +[#732]: https://www.free-decompiler.com/flash/issues/732 +[#730]: https://www.free-decompiler.com/flash/issues/730 +[#735]: https://www.free-decompiler.com/flash/issues/735 +[#722]: https://www.free-decompiler.com/flash/issues/722 +[#725]: https://www.free-decompiler.com/flash/issues/725 +[#715]: https://www.free-decompiler.com/flash/issues/715 +[#635]: https://www.free-decompiler.com/flash/issues/635 +[#726]: https://www.free-decompiler.com/flash/issues/726 +[#716]: https://www.free-decompiler.com/flash/issues/716 +[#717]: https://www.free-decompiler.com/flash/issues/717 +[#718]: https://www.free-decompiler.com/flash/issues/718 +[#720]: https://www.free-decompiler.com/flash/issues/720 +[#719]: https://www.free-decompiler.com/flash/issues/719 +[#723]: https://www.free-decompiler.com/flash/issues/723 +[#288]: https://www.free-decompiler.com/flash/issues/288 +[#677]: https://www.free-decompiler.com/flash/issues/677 +[#389]: https://www.free-decompiler.com/flash/issues/389 +[#701]: https://www.free-decompiler.com/flash/issues/701 +[#707]: https://www.free-decompiler.com/flash/issues/707 +[#302]: https://www.free-decompiler.com/flash/issues/302 +[#685]: https://www.free-decompiler.com/flash/issues/685 +[#698]: https://www.free-decompiler.com/flash/issues/698 +[#710]: https://www.free-decompiler.com/flash/issues/710 +[#711]: https://www.free-decompiler.com/flash/issues/711 +[#681]: https://www.free-decompiler.com/flash/issues/681 +[#688]: https://www.free-decompiler.com/flash/issues/688 +[#691]: https://www.free-decompiler.com/flash/issues/691 +[#524]: https://www.free-decompiler.com/flash/issues/524 +[#663]: https://www.free-decompiler.com/flash/issues/663 +[#702]: https://www.free-decompiler.com/flash/issues/702 +[#539]: https://www.free-decompiler.com/flash/issues/539 +[#650]: https://www.free-decompiler.com/flash/issues/650 +[#680]: https://www.free-decompiler.com/flash/issues/680 +[#649]: https://www.free-decompiler.com/flash/issues/649 +[#656]: https://www.free-decompiler.com/flash/issues/656 +[#661]: https://www.free-decompiler.com/flash/issues/661 +[#664]: https://www.free-decompiler.com/flash/issues/664 +[#668]: https://www.free-decompiler.com/flash/issues/668 +[#674]: https://www.free-decompiler.com/flash/issues/674 +[#675]: https://www.free-decompiler.com/flash/issues/675 +[#632]: https://www.free-decompiler.com/flash/issues/632 +[#651]: https://www.free-decompiler.com/flash/issues/651 +[#678]: https://www.free-decompiler.com/flash/issues/678 +[#672]: https://www.free-decompiler.com/flash/issues/672 +[#684]: https://www.free-decompiler.com/flash/issues/684 +[#647]: https://www.free-decompiler.com/flash/issues/647 +[#648]: https://www.free-decompiler.com/flash/issues/648 +[#612]: https://www.free-decompiler.com/flash/issues/612 +[#623]: https://www.free-decompiler.com/flash/issues/623 +[#624]: https://www.free-decompiler.com/flash/issues/624 +[#627]: https://www.free-decompiler.com/flash/issues/627 +[#640]: https://www.free-decompiler.com/flash/issues/640 +[#595]: https://www.free-decompiler.com/flash/issues/595 +[#592]: https://www.free-decompiler.com/flash/issues/592 +[#585]: https://www.free-decompiler.com/flash/issues/585 +[#578]: https://www.free-decompiler.com/flash/issues/578 +[#501]: https://www.free-decompiler.com/flash/issues/501 +[#616]: https://www.free-decompiler.com/flash/issues/616 +[#559]: https://www.free-decompiler.com/flash/issues/559 +[#401]: https://www.free-decompiler.com/flash/issues/401 +[#593]: https://www.free-decompiler.com/flash/issues/593 +[#594]: https://www.free-decompiler.com/flash/issues/594 +[#579]: https://www.free-decompiler.com/flash/issues/579 +[#428]: https://www.free-decompiler.com/flash/issues/428 +[#337]: https://www.free-decompiler.com/flash/issues/337 +[#584]: https://www.free-decompiler.com/flash/issues/584 +[#576]: https://www.free-decompiler.com/flash/issues/576 +[#250]: https://www.free-decompiler.com/flash/issues/250 +[#580]: https://www.free-decompiler.com/flash/issues/580 +[#510]: https://www.free-decompiler.com/flash/issues/510 +[#583]: https://www.free-decompiler.com/flash/issues/583 +[#586]: https://www.free-decompiler.com/flash/issues/586 +[#574]: https://www.free-decompiler.com/flash/issues/574 +[#570]: https://www.free-decompiler.com/flash/issues/570 +[#563]: https://www.free-decompiler.com/flash/issues/563 +[#561]: https://www.free-decompiler.com/flash/issues/561 +[#509]: https://www.free-decompiler.com/flash/issues/509 +[#433]: https://www.free-decompiler.com/flash/issues/433 +[#557]: https://www.free-decompiler.com/flash/issues/557 +[#556]: https://www.free-decompiler.com/flash/issues/556 +[#504]: https://www.free-decompiler.com/flash/issues/504 +[#529]: https://www.free-decompiler.com/flash/issues/529 +[#538]: https://www.free-decompiler.com/flash/issues/538 +[#537]: https://www.free-decompiler.com/flash/issues/537 +[#540]: https://www.free-decompiler.com/flash/issues/540 +[#387]: https://www.free-decompiler.com/flash/issues/387 +[#552]: https://www.free-decompiler.com/flash/issues/552 +[#494]: https://www.free-decompiler.com/flash/issues/494 +[#513]: https://www.free-decompiler.com/flash/issues/513 +[#262]: https://www.free-decompiler.com/flash/issues/262 +[#499]: https://www.free-decompiler.com/flash/issues/499 +[#508]: https://www.free-decompiler.com/flash/issues/508 +[#305]: https://www.free-decompiler.com/flash/issues/305 +[#312]: https://www.free-decompiler.com/flash/issues/312 +[#503]: https://www.free-decompiler.com/flash/issues/503 +[#304]: https://www.free-decompiler.com/flash/issues/304 +[#306]: https://www.free-decompiler.com/flash/issues/306 +[#507]: https://www.free-decompiler.com/flash/issues/507 +[#424]: https://www.free-decompiler.com/flash/issues/424 +[#425]: https://www.free-decompiler.com/flash/issues/425 +[#478]: https://www.free-decompiler.com/flash/issues/478 +[#485]: https://www.free-decompiler.com/flash/issues/485 +[#517]: https://www.free-decompiler.com/flash/issues/517 +[#518]: https://www.free-decompiler.com/flash/issues/518 +[#361]: https://www.free-decompiler.com/flash/issues/361 +[#392]: https://www.free-decompiler.com/flash/issues/392 +[#516]: https://www.free-decompiler.com/flash/issues/516 +[#495]: https://www.free-decompiler.com/flash/issues/495 +[#496]: https://www.free-decompiler.com/flash/issues/496 +[#299]: https://www.free-decompiler.com/flash/issues/299 +[#303]: https://www.free-decompiler.com/flash/issues/303 +[#324]: https://www.free-decompiler.com/flash/issues/324 +[#346]: https://www.free-decompiler.com/flash/issues/346 +[#371]: https://www.free-decompiler.com/flash/issues/371 +[#426]: https://www.free-decompiler.com/flash/issues/426 +[#457]: https://www.free-decompiler.com/flash/issues/457 +[#458]: https://www.free-decompiler.com/flash/issues/458 +[#460]: https://www.free-decompiler.com/flash/issues/460 +[#462]: https://www.free-decompiler.com/flash/issues/462 +[#463]: https://www.free-decompiler.com/flash/issues/463 +[#465]: https://www.free-decompiler.com/flash/issues/465 +[#466]: https://www.free-decompiler.com/flash/issues/466 +[#369]: https://www.free-decompiler.com/flash/issues/369 +[#390]: https://www.free-decompiler.com/flash/issues/390 +[#453]: https://www.free-decompiler.com/flash/issues/453 +[#459]: https://www.free-decompiler.com/flash/issues/459 +[#461]: https://www.free-decompiler.com/flash/issues/461 +[#451]: https://www.free-decompiler.com/flash/issues/451 +[#454]: https://www.free-decompiler.com/flash/issues/454 +[#455]: https://www.free-decompiler.com/flash/issues/455 +[#474]: https://www.free-decompiler.com/flash/issues/474 +[#477]: https://www.free-decompiler.com/flash/issues/477 +[#481]: https://www.free-decompiler.com/flash/issues/481 +[#484]: https://www.free-decompiler.com/flash/issues/484 +[#493]: https://www.free-decompiler.com/flash/issues/493 +[#365]: https://www.free-decompiler.com/flash/issues/365 +[#366]: https://www.free-decompiler.com/flash/issues/366 +[#429]: https://www.free-decompiler.com/flash/issues/429 +[#447]: https://www.free-decompiler.com/flash/issues/447 +[#354]: https://www.free-decompiler.com/flash/issues/354 +[#438]: https://www.free-decompiler.com/flash/issues/438 +[#436]: https://www.free-decompiler.com/flash/issues/436 +[#446]: https://www.free-decompiler.com/flash/issues/446 +[#427]: https://www.free-decompiler.com/flash/issues/427 +[#405]: https://www.free-decompiler.com/flash/issues/405 +[#420]: https://www.free-decompiler.com/flash/issues/420 +[#421]: https://www.free-decompiler.com/flash/issues/421 +[#430]: https://www.free-decompiler.com/flash/issues/430 +[#397]: https://www.free-decompiler.com/flash/issues/397 +[#431]: https://www.free-decompiler.com/flash/issues/431 +[#169]: https://www.free-decompiler.com/flash/issues/169 +[#335]: https://www.free-decompiler.com/flash/issues/335 +[#404]: https://www.free-decompiler.com/flash/issues/404 +[#407]: https://www.free-decompiler.com/flash/issues/407 +[#399]: https://www.free-decompiler.com/flash/issues/399 +[#400]: https://www.free-decompiler.com/flash/issues/400 +[#398]: https://www.free-decompiler.com/flash/issues/398 +[#382]: https://www.free-decompiler.com/flash/issues/382 +[#396]: https://www.free-decompiler.com/flash/issues/396 +[#357]: https://www.free-decompiler.com/flash/issues/357 +[#391]: https://www.free-decompiler.com/flash/issues/391 +[#395]: https://www.free-decompiler.com/flash/issues/395 +[#334]: https://www.free-decompiler.com/flash/issues/334 +[#301]: https://www.free-decompiler.com/flash/issues/301 +[#383]: https://www.free-decompiler.com/flash/issues/383 +[#386]: https://www.free-decompiler.com/flash/issues/386 +[#367]: https://www.free-decompiler.com/flash/issues/367 +[#380]: https://www.free-decompiler.com/flash/issues/380 +[#292]: https://www.free-decompiler.com/flash/issues/292 +[#375]: https://www.free-decompiler.com/flash/issues/375 +[#378]: https://www.free-decompiler.com/flash/issues/378 +[#325]: https://www.free-decompiler.com/flash/issues/325 +[#210]: https://www.free-decompiler.com/flash/issues/210 +[#355]: https://www.free-decompiler.com/flash/issues/355 +[#313]: https://www.free-decompiler.com/flash/issues/313 +[#330]: https://www.free-decompiler.com/flash/issues/330 +[#332]: https://www.free-decompiler.com/flash/issues/332 +[#344]: https://www.free-decompiler.com/flash/issues/344 +[#295]: https://www.free-decompiler.com/flash/issues/295 +[#297]: https://www.free-decompiler.com/flash/issues/297 +[#307]: https://www.free-decompiler.com/flash/issues/307 +[#309]: https://www.free-decompiler.com/flash/issues/309 +[#310]: https://www.free-decompiler.com/flash/issues/310 +[#311]: https://www.free-decompiler.com/flash/issues/311 +[#327]: https://www.free-decompiler.com/flash/issues/327 +[#328]: https://www.free-decompiler.com/flash/issues/328 +[#333]: https://www.free-decompiler.com/flash/issues/333 +[#336]: https://www.free-decompiler.com/flash/issues/336 +[#338]: https://www.free-decompiler.com/flash/issues/338 +[#315]: https://www.free-decompiler.com/flash/issues/315 +[#123]: https://www.free-decompiler.com/flash/issues/123 +[#243]: https://www.free-decompiler.com/flash/issues/243 +[#326]: https://www.free-decompiler.com/flash/issues/326 +[#287]: https://www.free-decompiler.com/flash/issues/287 +[#290]: https://www.free-decompiler.com/flash/issues/290 +[#291]: https://www.free-decompiler.com/flash/issues/291 +[#294]: https://www.free-decompiler.com/flash/issues/294 +[#298]: https://www.free-decompiler.com/flash/issues/298 +[#296]: https://www.free-decompiler.com/flash/issues/296 +[#314]: https://www.free-decompiler.com/flash/issues/314 +[#316]: https://www.free-decompiler.com/flash/issues/316 +[#318]: https://www.free-decompiler.com/flash/issues/318 +[#319]: https://www.free-decompiler.com/flash/issues/319 +[#323]: https://www.free-decompiler.com/flash/issues/323 +[#223]: https://www.free-decompiler.com/flash/issues/223 +[#261]: https://www.free-decompiler.com/flash/issues/261 +[#269]: https://www.free-decompiler.com/flash/issues/269 +[#274]: https://www.free-decompiler.com/flash/issues/274 +[#275]: https://www.free-decompiler.com/flash/issues/275 +[#258]: https://www.free-decompiler.com/flash/issues/258 +[#267]: https://www.free-decompiler.com/flash/issues/267 +[#286]: https://www.free-decompiler.com/flash/issues/286 +[#233]: https://www.free-decompiler.com/flash/issues/233 +[#235]: https://www.free-decompiler.com/flash/issues/235 +[#263]: https://www.free-decompiler.com/flash/issues/263 +[#264]: https://www.free-decompiler.com/flash/issues/264 +[#265]: https://www.free-decompiler.com/flash/issues/265 +[#266]: https://www.free-decompiler.com/flash/issues/266 +[#281]: https://www.free-decompiler.com/flash/issues/281 +[#251]: https://www.free-decompiler.com/flash/issues/251 +[#257]: https://www.free-decompiler.com/flash/issues/257 +[#259]: https://www.free-decompiler.com/flash/issues/259 +[#260]: https://www.free-decompiler.com/flash/issues/260 +[#268]: https://www.free-decompiler.com/flash/issues/268 +[#272]: https://www.free-decompiler.com/flash/issues/272 +[#276]: https://www.free-decompiler.com/flash/issues/276 +[#220]: https://www.free-decompiler.com/flash/issues/220 +[#284]: https://www.free-decompiler.com/flash/issues/284 +[#232]: https://www.free-decompiler.com/flash/issues/232 +[#253]: https://www.free-decompiler.com/flash/issues/253 +[#137]: https://www.free-decompiler.com/flash/issues/137 +[#242]: https://www.free-decompiler.com/flash/issues/242 +[#244]: https://www.free-decompiler.com/flash/issues/244 +[#203]: https://www.free-decompiler.com/flash/issues/203 +[#225]: https://www.free-decompiler.com/flash/issues/225 +[#236]: https://www.free-decompiler.com/flash/issues/236 +[#245]: https://www.free-decompiler.com/flash/issues/245 +[#247]: https://www.free-decompiler.com/flash/issues/247 +[#248]: https://www.free-decompiler.com/flash/issues/248 +[#254]: https://www.free-decompiler.com/flash/issues/254 +[#255]: https://www.free-decompiler.com/flash/issues/255 +[#256]: https://www.free-decompiler.com/flash/issues/256 +[#241]: https://www.free-decompiler.com/flash/issues/241 +[#238]: https://www.free-decompiler.com/flash/issues/238 +[#239]: https://www.free-decompiler.com/flash/issues/239 +[#240]: https://www.free-decompiler.com/flash/issues/240 +[#237]: https://www.free-decompiler.com/flash/issues/237 +[#217]: https://www.free-decompiler.com/flash/issues/217 +[#219]: https://www.free-decompiler.com/flash/issues/219 +[#224]: https://www.free-decompiler.com/flash/issues/224 +[#121]: https://www.free-decompiler.com/flash/issues/121 +[#207]: https://www.free-decompiler.com/flash/issues/207 +[#151]: https://www.free-decompiler.com/flash/issues/151 +[#171]: https://www.free-decompiler.com/flash/issues/171 +[#206]: https://www.free-decompiler.com/flash/issues/206 +[#208]: https://www.free-decompiler.com/flash/issues/208 +[#209]: https://www.free-decompiler.com/flash/issues/209 +[#229]: https://www.free-decompiler.com/flash/issues/229 +[#213]: https://www.free-decompiler.com/flash/issues/213 +[#221]: https://www.free-decompiler.com/flash/issues/221 +[#226]: https://www.free-decompiler.com/flash/issues/226 +[#227]: https://www.free-decompiler.com/flash/issues/227 +[#230]: https://www.free-decompiler.com/flash/issues/230 +[#172]: https://www.free-decompiler.com/flash/issues/172 +[#174]: https://www.free-decompiler.com/flash/issues/174 +[#175]: https://www.free-decompiler.com/flash/issues/175 +[#212]: https://www.free-decompiler.com/flash/issues/212 +[#185]: https://www.free-decompiler.com/flash/issues/185 +[#186]: https://www.free-decompiler.com/flash/issues/186 +[#197]: https://www.free-decompiler.com/flash/issues/197 +[#216]: https://www.free-decompiler.com/flash/issues/216 +[#168]: https://www.free-decompiler.com/flash/issues/168 +[#176]: https://www.free-decompiler.com/flash/issues/176 +[#177]: https://www.free-decompiler.com/flash/issues/177 +[#202]: https://www.free-decompiler.com/flash/issues/202 +[#173]: https://www.free-decompiler.com/flash/issues/173 +[#190]: https://www.free-decompiler.com/flash/issues/190 +[#129]: https://www.free-decompiler.com/flash/issues/129 +[#153]: https://www.free-decompiler.com/flash/issues/153 +[#180]: https://www.free-decompiler.com/flash/issues/180 +[#136]: https://www.free-decompiler.com/flash/issues/136 +[#179]: https://www.free-decompiler.com/flash/issues/179 +[#144]: https://www.free-decompiler.com/flash/issues/144 +[#164]: https://www.free-decompiler.com/flash/issues/164 +[#167]: https://www.free-decompiler.com/flash/issues/167 +[#170]: https://www.free-decompiler.com/flash/issues/170 +[#178]: https://www.free-decompiler.com/flash/issues/178 +[#181]: https://www.free-decompiler.com/flash/issues/181 +[#182]: https://www.free-decompiler.com/flash/issues/182 +[#183]: https://www.free-decompiler.com/flash/issues/183 +[#184]: https://www.free-decompiler.com/flash/issues/184 +[#189]: https://www.free-decompiler.com/flash/issues/189 +[#191]: https://www.free-decompiler.com/flash/issues/191 +[#195]: https://www.free-decompiler.com/flash/issues/195 +[#196]: https://www.free-decompiler.com/flash/issues/196 +[#198]: https://www.free-decompiler.com/flash/issues/198 +[#200]: https://www.free-decompiler.com/flash/issues/200 +[#201]: https://www.free-decompiler.com/flash/issues/201 +[#166]: https://www.free-decompiler.com/flash/issues/166 +[#165]: https://www.free-decompiler.com/flash/issues/165 +[#63]: https://www.free-decompiler.com/flash/issues/63 +[#67]: https://www.free-decompiler.com/flash/issues/67 +[#117]: https://www.free-decompiler.com/flash/issues/117 +[#127]: https://www.free-decompiler.com/flash/issues/127 +[#134]: https://www.free-decompiler.com/flash/issues/134 +[#155]: https://www.free-decompiler.com/flash/issues/155 +[#142]: https://www.free-decompiler.com/flash/issues/142 +[#146]: https://www.free-decompiler.com/flash/issues/146 +[#130]: https://www.free-decompiler.com/flash/issues/130 +[#132]: https://www.free-decompiler.com/flash/issues/132 +[#145]: https://www.free-decompiler.com/flash/issues/145 +[#147]: https://www.free-decompiler.com/flash/issues/147 +[#148]: https://www.free-decompiler.com/flash/issues/148 +[#152]: https://www.free-decompiler.com/flash/issues/152 +[#156]: https://www.free-decompiler.com/flash/issues/156 +[#157]: https://www.free-decompiler.com/flash/issues/157 +[#158]: https://www.free-decompiler.com/flash/issues/158 +[#159]: https://www.free-decompiler.com/flash/issues/159 +[#160]: https://www.free-decompiler.com/flash/issues/160 +[#162]: https://www.free-decompiler.com/flash/issues/162 +[#163]: https://www.free-decompiler.com/flash/issues/163 +[#149]: https://www.free-decompiler.com/flash/issues/149 +[#150]: https://www.free-decompiler.com/flash/issues/150 +[#119]: https://www.free-decompiler.com/flash/issues/119 +[#101]: https://www.free-decompiler.com/flash/issues/101 +[#114]: https://www.free-decompiler.com/flash/issues/114 +[#135]: https://www.free-decompiler.com/flash/issues/135 +[#141]: https://www.free-decompiler.com/flash/issues/141 +[#102]: https://www.free-decompiler.com/flash/issues/102 +[#124]: https://www.free-decompiler.com/flash/issues/124 +[#128]: https://www.free-decompiler.com/flash/issues/128 +[#131]: https://www.free-decompiler.com/flash/issues/131 +[#104]: https://www.free-decompiler.com/flash/issues/104 +[#113]: https://www.free-decompiler.com/flash/issues/113 +[#133]: https://www.free-decompiler.com/flash/issues/133 +[#140]: https://www.free-decompiler.com/flash/issues/140 +[#108]: https://www.free-decompiler.com/flash/issues/108 +[#105]: https://www.free-decompiler.com/flash/issues/105 +[#109]: https://www.free-decompiler.com/flash/issues/109 +[#106]: https://www.free-decompiler.com/flash/issues/106 +[#107]: https://www.free-decompiler.com/flash/issues/107 +[#110]: https://www.free-decompiler.com/flash/issues/110 +[#103]: https://www.free-decompiler.com/flash/issues/103 +[#111]: https://www.free-decompiler.com/flash/issues/111 +[#96]: https://www.free-decompiler.com/flash/issues/96 +[#98]: https://www.free-decompiler.com/flash/issues/98 +[#99]: https://www.free-decompiler.com/flash/issues/99 +[#100]: https://www.free-decompiler.com/flash/issues/100 +[#85]: https://www.free-decompiler.com/flash/issues/85 +[#79]: https://www.free-decompiler.com/flash/issues/79 +[#92]: https://www.free-decompiler.com/flash/issues/92 +[#93]: https://www.free-decompiler.com/flash/issues/93 +[#94]: https://www.free-decompiler.com/flash/issues/94 +[#95]: https://www.free-decompiler.com/flash/issues/95 +[#86]: https://www.free-decompiler.com/flash/issues/86 +[#87]: https://www.free-decompiler.com/flash/issues/87 +[#88]: https://www.free-decompiler.com/flash/issues/88 +[#89]: https://www.free-decompiler.com/flash/issues/89 +[#82]: https://www.free-decompiler.com/flash/issues/82 +[#78]: https://www.free-decompiler.com/flash/issues/78 +[#81]: https://www.free-decompiler.com/flash/issues/81 +[#84]: https://www.free-decompiler.com/flash/issues/84 +[#83]: https://www.free-decompiler.com/flash/issues/83 +[#65]: https://www.free-decompiler.com/flash/issues/65 +[#48]: https://www.free-decompiler.com/flash/issues/48 +[#53]: https://www.free-decompiler.com/flash/issues/53 +[#66]: https://www.free-decompiler.com/flash/issues/66 +[#68]: https://www.free-decompiler.com/flash/issues/68 +[#69]: https://www.free-decompiler.com/flash/issues/69 +[#75]: https://www.free-decompiler.com/flash/issues/75 +[#73]: https://www.free-decompiler.com/flash/issues/73 +[#62]: https://www.free-decompiler.com/flash/issues/62 +[#72]: https://www.free-decompiler.com/flash/issues/72 +[#64]: https://www.free-decompiler.com/flash/issues/64 +[#38]: https://www.free-decompiler.com/flash/issues/38 +[#56]: https://www.free-decompiler.com/flash/issues/56 +[#57]: https://www.free-decompiler.com/flash/issues/57 +[#58]: https://www.free-decompiler.com/flash/issues/58 +[#45]: https://www.free-decompiler.com/flash/issues/45 +[#50]: https://www.free-decompiler.com/flash/issues/50 +[#51]: https://www.free-decompiler.com/flash/issues/51 +[#52]: https://www.free-decompiler.com/flash/issues/52 +[#47]: https://www.free-decompiler.com/flash/issues/47 +[#42]: https://www.free-decompiler.com/flash/issues/42 +[#39]: https://www.free-decompiler.com/flash/issues/39 +[#40]: https://www.free-decompiler.com/flash/issues/40 +[#44]: https://www.free-decompiler.com/flash/issues/44 +[#36]: https://www.free-decompiler.com/flash/issues/36 +[#43]: https://www.free-decompiler.com/flash/issues/43 +[#46]: https://www.free-decompiler.com/flash/issues/46 +[#3]: https://www.free-decompiler.com/flash/issues/3 +[#37]: https://www.free-decompiler.com/flash/issues/37 +[#34]: https://www.free-decompiler.com/flash/issues/34 +[#35]: https://www.free-decompiler.com/flash/issues/35 +[#32]: https://www.free-decompiler.com/flash/issues/32 [#31]: https://www.free-decompiler.com/flash/issues/31 \ No newline at end of file diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/DecompilerPool.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/DecompilerPool.java index 4321d7334..0a8050cf8 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/DecompilerPool.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/DecompilerPool.java @@ -1,182 +1,182 @@ -/* - * Copyright (C) 2010-2016 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash; - -import com.jpexs.decompiler.flash.abc.ScriptPack; -import com.jpexs.decompiler.flash.abc.types.ConvertData; -import com.jpexs.decompiler.flash.abc.types.ScriptInfo; -import com.jpexs.decompiler.flash.action.ActionList; -import com.jpexs.decompiler.flash.cache.ScriptDecompiledListener; -import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; -import com.jpexs.decompiler.flash.helpers.HighlightedText; -import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter; -import com.jpexs.decompiler.flash.tags.base.ASMSource; -import com.jpexs.helpers.ImmediateFuture; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - * @author JPEXS - */ -public class DecompilerPool { - - private final ThreadPoolExecutor executor; - - public DecompilerPool() { - int threadCount = Configuration.getParallelThreadCount(); - executor = new ThreadPoolExecutor(threadCount, threadCount, - 0L, TimeUnit.MILLISECONDS, - new LinkedBlockingQueue<>()); - } - - public Future submitTask(ASMSource src, ActionList actions, ScriptDecompiledListener listener) { - Callable callable = new Callable() { - @Override - public HighlightedText call() throws Exception { - if (listener != null) { - listener.onStart(); - } - - HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), true); - writer.startFunction("!script"); - src.getActionScriptSource(writer, actions); - writer.endFunction(); - - HighlightedText result = new HighlightedText(writer); - SWF swf = src.getSwf(); - if (swf != null) { - swf.as2Cache.put(src, result); - } - - if (listener != null) { - listener.onComplete(result); - } - - return result; - } - }; - - return submit(callable); - } - - public Future submitTask(ScriptPack pack, ScriptDecompiledListener listener) { - Callable callable = new Callable() { - @Override - public HighlightedText call() throws Exception { - if (listener != null) { - listener.onStart(); - } - - int scriptIndex = pack.scriptIndex; - ScriptInfo script = null; - if (scriptIndex > -1) { - script = pack.abc.script_info.get(scriptIndex); - } - boolean parallel = Configuration.parallelSpeedUp.get(); - HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), true); - pack.toSource(writer, script == null ? null : script.traits.traits, new ConvertData(), ScriptExportMode.AS, parallel); - - HighlightedText result = new HighlightedText(writer); - SWF swf = pack.getSwf(); - if (swf != null) { - swf.as3Cache.put(pack, result); - } - - if (listener != null) { - listener.onComplete(result); - } - - return result; - } - }; - - return submit(callable); - } - - private Future submit(Callable callable) { - boolean parallel = Configuration.parallelSpeedUp.get(); - if (parallel) { - Future f = executor.submit(callable); - return f; - } else { - boolean cancelled = false; - Throwable throwable = null; - HighlightedText result = null; - try { - result = callable.call(); - } catch (InterruptedException ex) { - cancelled = true; - } catch (Exception ex) { - throwable = ex; - } - - return new ImmediateFuture<>(result, throwable, cancelled); - } - } - - public String getStat() { - return "core: " + executor.getCorePoolSize() - + " size: " + executor.getPoolSize() - + " largest: " + executor.getLargestPoolSize() - + " max: " + executor.getMaximumPoolSize() - + " active: " + executor.getActiveCount() - + " count: " + executor.getTaskCount() - + " completed: " + executor.getCompletedTaskCount(); - } - - public HighlightedText decompile(ASMSource src, ActionList actions) throws InterruptedException { - Future future = submitTask(src, actions, null); - try { - return future.get(); - } catch (InterruptedException ex) { - future.cancel(true); - throw ex; - } catch (ExecutionException ex) { - Logger.getLogger(DecompilerPool.class.getName()).log(Level.SEVERE, null, ex); - } - - return null; - } - - public HighlightedText decompile(ScriptPack pack) throws InterruptedException { - Future future = submitTask(pack, null); - try { - return future.get(); - } catch (InterruptedException ex) { - future.cancel(true); - throw ex; - } catch (ExecutionException ex) { - Logger.getLogger(DecompilerPool.class.getName()).log(Level.SEVERE, null, ex); - } - - return null; - } - - public void shutdown() throws InterruptedException { - executor.shutdown(); - if (!executor.awaitTermination(100, TimeUnit.SECONDS)) { - } - } -} +/* + * Copyright (C) 2010-2016 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash; + +import com.jpexs.decompiler.flash.abc.ScriptPack; +import com.jpexs.decompiler.flash.abc.types.ConvertData; +import com.jpexs.decompiler.flash.abc.types.ScriptInfo; +import com.jpexs.decompiler.flash.action.ActionList; +import com.jpexs.decompiler.flash.cache.ScriptDecompiledListener; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; +import com.jpexs.decompiler.flash.helpers.HighlightedText; +import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter; +import com.jpexs.decompiler.flash.tags.base.ASMSource; +import com.jpexs.helpers.ImmediateFuture; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author JPEXS + */ +public class DecompilerPool { + + private final ThreadPoolExecutor executor; + + public DecompilerPool() { + int threadCount = Configuration.getParallelThreadCount(); + executor = new ThreadPoolExecutor(threadCount, threadCount, + 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue<>()); + } + + public Future submitTask(ASMSource src, ActionList actions, ScriptDecompiledListener listener) { + Callable callable = new Callable() { + @Override + public HighlightedText call() throws Exception { + if (listener != null) { + listener.onStart(); + } + + HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), true); + writer.startFunction("!script"); + src.getActionScriptSource(writer, actions); + writer.endFunction(); + + HighlightedText result = new HighlightedText(writer); + SWF swf = src.getSwf(); + if (swf != null) { + swf.as2Cache.put(src, result); + } + + if (listener != null) { + listener.onComplete(result); + } + + return result; + } + }; + + return submit(callable); + } + + public Future submitTask(ScriptPack pack, ScriptDecompiledListener listener) { + Callable callable = new Callable() { + @Override + public HighlightedText call() throws Exception { + if (listener != null) { + listener.onStart(); + } + + int scriptIndex = pack.scriptIndex; + ScriptInfo script = null; + if (scriptIndex > -1) { + script = pack.abc.script_info.get(scriptIndex); + } + boolean parallel = Configuration.parallelSpeedUp.get(); + HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), true); + pack.toSource(writer, script == null ? null : script.traits.traits, new ConvertData(), ScriptExportMode.AS, parallel); + + HighlightedText result = new HighlightedText(writer); + SWF swf = pack.getSwf(); + if (swf != null) { + swf.as3Cache.put(pack, result); + } + + if (listener != null) { + listener.onComplete(result); + } + + return result; + } + }; + + return submit(callable); + } + + private Future submit(Callable callable) { + boolean parallel = Configuration.parallelSpeedUp.get(); + if (parallel) { + Future f = executor.submit(callable); + return f; + } else { + boolean cancelled = false; + Throwable throwable = null; + HighlightedText result = null; + try { + result = callable.call(); + } catch (InterruptedException ex) { + cancelled = true; + } catch (Exception ex) { + throwable = ex; + } + + return new ImmediateFuture<>(result, throwable, cancelled); + } + } + + public String getStat() { + return "core: " + executor.getCorePoolSize() + + " size: " + executor.getPoolSize() + + " largest: " + executor.getLargestPoolSize() + + " max: " + executor.getMaximumPoolSize() + + " active: " + executor.getActiveCount() + + " count: " + executor.getTaskCount() + + " completed: " + executor.getCompletedTaskCount(); + } + + public HighlightedText decompile(ASMSource src, ActionList actions) throws InterruptedException { + Future future = submitTask(src, actions, null); + try { + return future.get(); + } catch (InterruptedException ex) { + future.cancel(true); + throw ex; + } catch (ExecutionException ex) { + Logger.getLogger(DecompilerPool.class.getName()).log(Level.SEVERE, null, ex); + } + + return null; + } + + public HighlightedText decompile(ScriptPack pack) throws InterruptedException { + Future future = submitTask(pack, null); + try { + return future.get(); + } catch (InterruptedException ex) { + future.cancel(true); + throw ex; + } catch (ExecutionException ex) { + Logger.getLogger(DecompilerPool.class.getName()).log(Level.SEVERE, null, ex); + } + + return null; + } + + public void shutdown() throws InterruptedException { + executor.shutdown(); + if (!executor.awaitTermination(100, TimeUnit.SECONDS)) { + } + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/commonshape/SVGExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/commonshape/SVGExporter.java index 362c71b2e..9d68207f4 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/commonshape/SVGExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/commonshape/SVGExporter.java @@ -1,269 +1,269 @@ -/* - * Copyright (C) 2010-2016 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.exporters.commonshape; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.decompiler.flash.exporters.modes.FontExportMode; -import com.jpexs.decompiler.flash.tags.Tag; -import com.jpexs.decompiler.flash.types.RECT; -import com.jpexs.decompiler.flash.types.RGBA; -import com.jpexs.helpers.Helper; -import java.awt.Color; -import java.io.StringWriter; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Stack; -import java.util.logging.Level; -import java.util.logging.Logger; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; -import org.w3c.dom.Attr; -import org.w3c.dom.CDATASection; -import org.w3c.dom.DOMImplementation; -import org.w3c.dom.Document; -import org.w3c.dom.DocumentType; -import org.w3c.dom.Element; -import org.w3c.dom.Node; - -/** - * - * @author JPEXS - */ -public class SVGExporter { - - protected static final String sNamespace = "http://www.w3.org/2000/svg"; - - protected static final String xlinkNamespace = "http://www.w3.org/1999/xlink"; - - protected Document _svg; - - protected Element _svgDefs; - - protected CDATASection _svgStyle; - - protected Stack _svgGs = new Stack<>(); - - public List gradients; - - protected int lastPatternId; - - public Map exportedTags = new HashMap<>(); - - public Map> exportedChars = new HashMap<>(); - - private final Map lastIds = new HashMap<>(); - - private final HashSet fontFaces = new HashSet<>(); - - public boolean useTextTag = Configuration.textExportExportFontFace.get(); - - public SVGExporter(ExportRectangle bounds, double zoom) { - - DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); - try { - DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); - DOMImplementation impl = docBuilder.getDOMImplementation(); - DocumentType svgDocType = impl.createDocumentType("svg", "-//W3C//DTD SVG 1.0//EN", - "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"); - _svg = impl.createDocument(sNamespace, "svg", svgDocType); - Element svgRoot = _svg.getDocumentElement(); - svgRoot.setAttribute("xmlns:xlink", xlinkNamespace); - if (bounds != null) { - svgRoot.setAttribute("width", (bounds.getWidth() / SWF.unitDivisor) + "px"); - svgRoot.setAttribute("height", (bounds.getHeight() / SWF.unitDivisor) + "px"); - createDefGroup(bounds, null, zoom); - } - } catch (ParserConfigurationException ex) { - Logger.getLogger(SVGExporter.class.getName()).log(Level.SEVERE, null, ex); - } - gradients = new ArrayList<>(); - } - - private Element getDefs() { - if (_svgDefs == null) { - _svgDefs = _svg.createElement("defs"); - _svg.getDocumentElement().appendChild(_svgDefs); - } - return _svgDefs; - } - - private CDATASection getStyle() { - if (_svgStyle == null) { - Element style = _svg.createElement("style"); - _svgStyle = _svg.createCDATASection(""); - style.appendChild(_svgStyle); - getDefs().appendChild(style); - } - return _svgStyle; - } - - public final void createDefGroup(ExportRectangle bounds, String id) { - createDefGroup(bounds, id, 1); - } - - public final void createDefGroup(ExportRectangle bounds, String id, double zoom) { - Element g = _svg.createElement("g"); - if (bounds != null) { - Matrix mat = Matrix.getTranslateInstance(-bounds.xMin, -bounds.yMin); - mat.scale(zoom); - g.setAttribute("transform", mat.getSvgTransformationString(SWF.unitDivisor, 1)); - } - if (id != null) { - g.setAttribute("id", id); - } - if (_svgGs.size() == 0) { - _svg.getDocumentElement().appendChild(g); - } else { - getDefs().appendChild(g); - } - _svgGs.add(g); - } - - public boolean endGroup() { - Element g = _svgGs.pop(); - if (g.getChildNodes().getLength() == 0) { - g.getParentNode().removeChild(g); - return false; - } - - return true; - } - - public final Element createSubGroup(Matrix transform, String id) { - Element group = createSubGroup(id, "g"); - if (transform != null) { - group.setAttribute("transform", transform.getSvgTransformationString(SWF.unitDivisor, 1)); - } - - return group; - } - - public final Element createClipPath(Matrix transform, String id) { - Element group = createSubGroup(id, "clipPath"); - Node parent = group.getParentNode(); - if (parent instanceof Element) { - Element parentElement = (Element) parent; - group.setAttribute("transform", parentElement.getAttribute("transform")); - } - return group; - } - - private Element createSubGroup(String id, String tagName) { - Element group = _svg.createElement(tagName); - if (id != null) { - group.setAttribute("id", id); - } - _svgGs.peek().appendChild(group); - _svgGs.add(group); - return group; - } - - public void addToGroup(Node newChild) { - _svgGs.peek().appendChild(newChild); - } - - public void addToDefs(Node newChild) { - getDefs().appendChild(newChild); - } - - public Element createElement(String tagName) { - return _svg.createElement(tagName); - } - - public String getSVG() { - TransformerFactory transformerFactory = TransformerFactory.newInstance(); - StringWriter writer = new StringWriter(); - try { - Transformer transformer = transformerFactory.newTransformer(); - transformer.setOutputProperty(OutputKeys.INDENT, "yes"); - transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); - DOMSource source = new DOMSource(_svg); - StreamResult result = new StreamResult(writer); - transformer.transform(source, result); - } catch (TransformerException ex) { - Logger.getLogger(SVGExporter.class.getName()).log(Level.SEVERE, null, ex); - } - return writer.toString(); - } - - public void setBackGroundColor(Color backGroundColor) { - Attr attr = _svg.createAttribute("style"); - attr.setValue("background: " + new RGBA(backGroundColor).toHexARGB()); - } - - public Element addUse(Matrix transform, RECT boundRect, String href, String instanceName) { - Element image = _svg.createElement("use"); - if (transform != null) { - image.setAttribute("transform", transform.getSvgTransformationString(SWF.unitDivisor, 1)); - image.setAttribute("width", Double.toString(boundRect.getWidth() / (double) SWF.unitDivisor)); - image.setAttribute("height", Double.toString(boundRect.getHeight() / (double) SWF.unitDivisor)); - } - if (instanceName != null) { - image.setAttribute("id", instanceName); - } - image.setAttribute("xlink:href", "#" + href); - _svgGs.peek().appendChild(image); - return image; - } - - public void addStyle(String fontFace, byte[] data, FontExportMode mode) { - if (!fontFaces.contains(fontFace)) { - fontFaces.add(fontFace); - String base64Data = Helper.byteArrayToBase64String(data); - String value = getStyle().getTextContent(); - value += Helper.newLine; - value += " @font-face {" + Helper.newLine; - value += " font-family: \"" + fontFace + "\";" + Helper.newLine; - switch (mode) { - case TTF: - value += " src: url('data:font/truetype;base64," + base64Data + "') format(\"truetype\");" + Helper.newLine; - break; - case WOFF: - value += " src: url('data:font/woff;base64," + base64Data + "') format(\"woff\");" + Helper.newLine; - break; - } - value += " }" + Helper.newLine; - getStyle().setTextContent(value); - } - } - - public String getUniqueId(String prefix) { - Integer lastId = lastIds.get(prefix); - if (lastId == null) { - lastId = 0; - } else { - lastId++; - } - lastIds.put(prefix, lastId); - return prefix + lastId; - } - - protected static double roundPixels20(double pixels) { - return Math.round(pixels * 100) / 100.0; - } -} +/* + * Copyright (C) 2010-2016 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.exporters.commonshape; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.exporters.modes.FontExportMode; +import com.jpexs.decompiler.flash.tags.Tag; +import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.decompiler.flash.types.RGBA; +import com.jpexs.helpers.Helper; +import java.awt.Color; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Stack; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import org.w3c.dom.Attr; +import org.w3c.dom.CDATASection; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentType; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +/** + * + * @author JPEXS + */ +public class SVGExporter { + + protected static final String sNamespace = "http://www.w3.org/2000/svg"; + + protected static final String xlinkNamespace = "http://www.w3.org/1999/xlink"; + + protected Document _svg; + + protected Element _svgDefs; + + protected CDATASection _svgStyle; + + protected Stack _svgGs = new Stack<>(); + + public List gradients; + + protected int lastPatternId; + + public Map exportedTags = new HashMap<>(); + + public Map> exportedChars = new HashMap<>(); + + private final Map lastIds = new HashMap<>(); + + private final HashSet fontFaces = new HashSet<>(); + + public boolean useTextTag = Configuration.textExportExportFontFace.get(); + + public SVGExporter(ExportRectangle bounds, double zoom) { + + DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); + try { + DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); + DOMImplementation impl = docBuilder.getDOMImplementation(); + DocumentType svgDocType = impl.createDocumentType("svg", "-//W3C//DTD SVG 1.0//EN", + "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"); + _svg = impl.createDocument(sNamespace, "svg", svgDocType); + Element svgRoot = _svg.getDocumentElement(); + svgRoot.setAttribute("xmlns:xlink", xlinkNamespace); + if (bounds != null) { + svgRoot.setAttribute("width", (bounds.getWidth() / SWF.unitDivisor) + "px"); + svgRoot.setAttribute("height", (bounds.getHeight() / SWF.unitDivisor) + "px"); + createDefGroup(bounds, null, zoom); + } + } catch (ParserConfigurationException ex) { + Logger.getLogger(SVGExporter.class.getName()).log(Level.SEVERE, null, ex); + } + gradients = new ArrayList<>(); + } + + private Element getDefs() { + if (_svgDefs == null) { + _svgDefs = _svg.createElement("defs"); + _svg.getDocumentElement().appendChild(_svgDefs); + } + return _svgDefs; + } + + private CDATASection getStyle() { + if (_svgStyle == null) { + Element style = _svg.createElement("style"); + _svgStyle = _svg.createCDATASection(""); + style.appendChild(_svgStyle); + getDefs().appendChild(style); + } + return _svgStyle; + } + + public final void createDefGroup(ExportRectangle bounds, String id) { + createDefGroup(bounds, id, 1); + } + + public final void createDefGroup(ExportRectangle bounds, String id, double zoom) { + Element g = _svg.createElement("g"); + if (bounds != null) { + Matrix mat = Matrix.getTranslateInstance(-bounds.xMin, -bounds.yMin); + mat.scale(zoom); + g.setAttribute("transform", mat.getSvgTransformationString(SWF.unitDivisor, 1)); + } + if (id != null) { + g.setAttribute("id", id); + } + if (_svgGs.size() == 0) { + _svg.getDocumentElement().appendChild(g); + } else { + getDefs().appendChild(g); + } + _svgGs.add(g); + } + + public boolean endGroup() { + Element g = _svgGs.pop(); + if (g.getChildNodes().getLength() == 0) { + g.getParentNode().removeChild(g); + return false; + } + + return true; + } + + public final Element createSubGroup(Matrix transform, String id) { + Element group = createSubGroup(id, "g"); + if (transform != null) { + group.setAttribute("transform", transform.getSvgTransformationString(SWF.unitDivisor, 1)); + } + + return group; + } + + public final Element createClipPath(Matrix transform, String id) { + Element group = createSubGroup(id, "clipPath"); + Node parent = group.getParentNode(); + if (parent instanceof Element) { + Element parentElement = (Element) parent; + group.setAttribute("transform", parentElement.getAttribute("transform")); + } + return group; + } + + private Element createSubGroup(String id, String tagName) { + Element group = _svg.createElement(tagName); + if (id != null) { + group.setAttribute("id", id); + } + _svgGs.peek().appendChild(group); + _svgGs.add(group); + return group; + } + + public void addToGroup(Node newChild) { + _svgGs.peek().appendChild(newChild); + } + + public void addToDefs(Node newChild) { + getDefs().appendChild(newChild); + } + + public Element createElement(String tagName) { + return _svg.createElement(tagName); + } + + public String getSVG() { + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + StringWriter writer = new StringWriter(); + try { + Transformer transformer = transformerFactory.newTransformer(); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); + DOMSource source = new DOMSource(_svg); + StreamResult result = new StreamResult(writer); + transformer.transform(source, result); + } catch (TransformerException ex) { + Logger.getLogger(SVGExporter.class.getName()).log(Level.SEVERE, null, ex); + } + return writer.toString(); + } + + public void setBackGroundColor(Color backGroundColor) { + Attr attr = _svg.createAttribute("style"); + attr.setValue("background: " + new RGBA(backGroundColor).toHexARGB()); + } + + public Element addUse(Matrix transform, RECT boundRect, String href, String instanceName) { + Element image = _svg.createElement("use"); + if (transform != null) { + image.setAttribute("transform", transform.getSvgTransformationString(SWF.unitDivisor, 1)); + image.setAttribute("width", Double.toString(boundRect.getWidth() / (double) SWF.unitDivisor)); + image.setAttribute("height", Double.toString(boundRect.getHeight() / (double) SWF.unitDivisor)); + } + if (instanceName != null) { + image.setAttribute("id", instanceName); + } + image.setAttribute("xlink:href", "#" + href); + _svgGs.peek().appendChild(image); + return image; + } + + public void addStyle(String fontFace, byte[] data, FontExportMode mode) { + if (!fontFaces.contains(fontFace)) { + fontFaces.add(fontFace); + String base64Data = Helper.byteArrayToBase64String(data); + String value = getStyle().getTextContent(); + value += Helper.newLine; + value += " @font-face {" + Helper.newLine; + value += " font-family: \"" + fontFace + "\";" + Helper.newLine; + switch (mode) { + case TTF: + value += " src: url('data:font/truetype;base64," + base64Data + "') format(\"truetype\");" + Helper.newLine; + break; + case WOFF: + value += " src: url('data:font/woff;base64," + base64Data + "') format(\"woff\");" + Helper.newLine; + break; + } + value += " }" + Helper.newLine; + getStyle().setTextContent(value); + } + } + + public String getUniqueId(String prefix) { + Integer lastId = lastIds.get(prefix); + if (lastId == null) { + lastId = 0; + } else { + lastId++; + } + lastIds.put(prefix, lastId); + return prefix + lastId; + } + + protected static double roundPixels20(double pixels) { + return Math.round(pixels * 100) / 100.0; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/SVGMorphShapeExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/SVGMorphShapeExporter.java index 72680fc31..947f003ee 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/SVGMorphShapeExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/SVGMorphShapeExporter.java @@ -1,463 +1,463 @@ -/* - * Copyright (C) 2010-2016 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.exporters.morphshape; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; -import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; -import com.jpexs.decompiler.flash.tags.base.ImageTag; -import com.jpexs.decompiler.flash.tags.enums.ImageFormat; -import com.jpexs.decompiler.flash.types.ColorTransform; -import com.jpexs.decompiler.flash.types.FILLSTYLE; -import com.jpexs.decompiler.flash.types.GRADIENT; -import com.jpexs.decompiler.flash.types.GRADRECORD; -import com.jpexs.decompiler.flash.types.LINESTYLE2; -import com.jpexs.decompiler.flash.types.RGB; -import com.jpexs.decompiler.flash.types.RGBA; -import com.jpexs.decompiler.flash.types.SHAPE; -import com.jpexs.helpers.Helper; -import com.jpexs.helpers.SerializableImage; -import java.awt.Color; -import org.w3c.dom.Element; - -/** - * - * @author JPEXS, Claus Wahlers - */ -public class SVGMorphShapeExporter extends DefaultSVGMorphShapeExporter { - - protected Element path; - - protected int id; - - protected int lastPatternId; - - private final Color defaultColor; - - private final SWF swf; - - private final SVGExporter exporter; - - public SVGMorphShapeExporter(SWF swf, SHAPE shape, SHAPE endShape, int id, SVGExporter exporter, Color defaultColor, ColorTransform colorTransform, double zoom) { - super(shape, endShape, colorTransform, zoom); - this.swf = swf; - this.id = id; - this.defaultColor = defaultColor; - this.exporter = exporter; - } - - @Override - public void beginFill(RGB color, RGB colorEnd) { - if (color == null) { - color = new RGB(defaultColor == null ? Color.black : defaultColor); - } - if (colorEnd == null) { - colorEnd = new RGB(defaultColor == null ? Color.black : defaultColor); - } - finalizePath(); - path.setAttribute("stroke", "none"); - path.setAttribute("fill", color.toHexRGB()); - path.setAttribute("fill-rule", "evenodd"); - path.appendChild(createAnimateElement("fill", color.toHexRGB(), colorEnd.toHexRGB())); - if (color instanceof RGBA) { - RGBA colorA = (RGBA) color; - if (colorA.alpha != 255) { - path.setAttribute("fill-opacity", Float.toString(colorA.getAlphaFloat())); - } - RGBA colorAEnd = (RGBA) colorEnd; - path.appendChild(createAnimateElement("fill-opacity", colorA.getAlphaFloat(), colorAEnd.getAlphaFloat())); - } - } - - @Override - public void beginGradientFill(int type, GRADRECORD[] gradientRecords, GRADRECORD[] gradientRecordsEnd, Matrix matrix, Matrix matrixEnd, int spreadMethod, int interpolationMethod, float focalPointRatio, float focalPointRatioEnd) { - finalizePath(); - Element gradient = (type == FILLSTYLE.LINEAR_GRADIENT) - ? exporter.createElement("linearGradient") - : exporter.createElement("radialGradient"); - populateGradientElement(gradient, type, gradientRecords, gradientRecordsEnd, matrix, matrixEnd, spreadMethod, interpolationMethod, focalPointRatio); - int id = exporter.gradients.indexOf(gradient); - if (id < 0) { - // todo: filter same gradients - id = exporter.gradients.size(); - exporter.gradients.add(gradient); - } - gradient.setAttribute("id", "gradient" + id); - path.setAttribute("stroke", "none"); - path.setAttribute("fill", "url(#gradient" + id + ")"); - path.setAttribute("fill-rule", "evenodd"); - exporter.addToDefs(gradient); - } - - @Override - public void beginBitmapFill(int bitmapId, Matrix matrix, Matrix matrixEnd, boolean repeat, boolean smooth, ColorTransform colorTransform) { - finalizePath(); - ImageTag image = swf.getImage(bitmapId); - if (image != null) { - SerializableImage img = image.getImageCached(); - if (img != null) { - if (colorTransform != null) { - colorTransform.apply(img); - } - - int width = img.getWidth(); - int height = img.getHeight(); - lastPatternId++; - String patternId = "PatternID_" + id + "_" + lastPatternId; - ImageFormat format = image.getImageFormat(); - byte[] imageData = Helper.readStream(image.getImageData()); - String base64ImgData = Helper.byteArrayToBase64String(imageData); - path.setAttribute("style", "fill:url(#" + patternId + ")"); - Element pattern = exporter.createElement("pattern"); - pattern.setAttribute("id", patternId); - pattern.setAttribute("patternUnits", "userSpaceOnUse"); - pattern.setAttribute("overflow", "visible"); - pattern.setAttribute("width", "" + width); - pattern.setAttribute("height", "" + height); - pattern.setAttribute("viewBox", "0 0 " + width + " " + height); - if (matrix != null) { - matrix = matrix.clone(); - matrix.rotateSkew0 *= zoom / SWF.unitDivisor; - matrix.rotateSkew1 *= zoom / SWF.unitDivisor; - matrix.scaleX *= zoom / SWF.unitDivisor; - matrix.scaleY *= zoom / SWF.unitDivisor; - matrixEnd = matrixEnd.clone(); - matrixEnd.rotateSkew0 *= zoom / SWF.unitDivisor; - matrixEnd.rotateSkew1 *= zoom / SWF.unitDivisor; - matrixEnd.scaleX *= zoom / SWF.unitDivisor; - matrixEnd.scaleY *= zoom / SWF.unitDivisor; - addMatrixAnimation(pattern, "patternTransform", matrix, matrixEnd); - } - Element imageElement = exporter.createElement("image"); - imageElement.setAttribute("width", "" + width); - imageElement.setAttribute("height", "" + height); - imageElement.setAttribute("xlink:href", "data:image/" + format + ";base64," + base64ImgData); - pattern.appendChild(imageElement); - exporter.addToGroup(pattern); - } - } - } - - @Override - public void lineStyle(double thickness, double thicknessEnd, RGB color, RGB colorEnd, boolean pixelHinting, String scaleMode, int startCaps, int endCaps, int joints, float miterLimit) { - finalizePath(); - thickness *= zoom / SWF.unitDivisor; - thicknessEnd *= zoom / SWF.unitDivisor; - path.setAttribute("fill", "none"); - if (color != null) { - path.setAttribute("stroke", color.toHexRGB()); - path.appendChild(createAnimateElement("stroke", color.toHexRGB(), colorEnd.toHexRGB())); - } - path.setAttribute("stroke-width", Double.toString(thickness == 0 ? 1 : thickness)); - path.appendChild(createAnimateElement("stroke-width", thickness, thicknessEnd)); - - if (color instanceof RGBA) { - RGBA colorA = (RGBA) color; - if (colorA.alpha != 255) { - path.setAttribute("stroke-opacity", Float.toString(colorA.getAlphaFloat())); - } - RGBA colorAEnd = (RGBA) colorEnd; - path.appendChild(createAnimateElement("fill-opacity", colorA.getAlphaFloat(), colorAEnd.getAlphaFloat())); - } - switch (startCaps) { - case LINESTYLE2.NO_CAP: - path.setAttribute("stroke-linecap", "butt"); - break; - case LINESTYLE2.SQUARE_CAP: - path.setAttribute("stroke-linecap", "square"); - break; - default: - path.setAttribute("stroke-linecap", "round"); - break; - } - switch (joints) { - case LINESTYLE2.BEVEL_JOIN: - path.setAttribute("stroke-linejoin", "bevel"); - break; - case LINESTYLE2.ROUND_JOIN: - path.setAttribute("stroke-linejoin", "round"); - break; - default: - path.setAttribute("stroke-linejoin", "miter"); - if (miterLimit >= 1 && miterLimit != 4f) { - path.setAttribute("stroke-miterlimit", Double.toString(miterLimit)); - } - break; - } - } - - @Override - public void lineGradientStyle(int type, GRADRECORD[] gradientRecords, GRADRECORD[] gradientRecordsEnd, Matrix matrix, Matrix matrixEnd, int spreadMethod, int interpolationMethod, float focalPointRatio, float focalPointRatioEnd) { - path.removeAttribute("stroke-opacity"); - Element gradient = (type == FILLSTYLE.LINEAR_GRADIENT) - ? exporter.createElement("linearGradient") - : exporter.createElement("radialGradient"); - populateGradientElement(gradient, type, gradientRecords, gradientRecordsEnd, matrix, matrixEnd, spreadMethod, interpolationMethod, focalPointRatio); - int id = exporter.gradients.indexOf(gradient); - if (id < 0) { - // todo: filter same gradients - id = exporter.gradients.size(); - exporter.gradients.add(gradient); - } - gradient.setAttribute("id", "gradient" + id); - path.setAttribute("stroke", "url(#gradient" + id + ")"); - path.setAttribute("fill", "none"); - exporter.addToDefs(gradient); - } - - private Element createAnimateElement(String attributeName, Object startValue, Object endValue) { - Element animate = exporter.createElement("animate"); - animate.setAttribute("dur", "2s"); // todo - animate.setAttribute("repeatCount", "indefinite"); - animate.setAttribute("attributeName", attributeName); - animate.setAttribute("values", startValue + ";" + endValue); - return animate; - } - - @Override - protected void finalizePath() { - if (path != null && pathData != null && pathData.length() > 0) { - path.setAttribute("d", pathData.toString().trim()); - path.appendChild(createAnimateElement("d", pathData.toString().trim(), pathDataEnd.toString().trim())); - exporter.addToGroup(path); - } - path = exporter.createElement("path"); - super.finalizePath(); - } - - private void addMatrixAnimation(Element element, String attribute, Matrix matrix, Matrix matrixEnd) { - final int animationLength = 2; // todo - final String animationLengthStr = animationLength + "s"; - - element.setAttribute(attribute, matrix.getSvgTransformationString(SWF.unitDivisor / zoom, 1)); - - // QR decomposition - double translateX = roundPixels400(matrix.translateX * zoom / SWF.unitDivisor); - double translateY = roundPixels400(matrix.translateY * zoom / SWF.unitDivisor); - double a = matrix.scaleX; - double b = matrix.rotateSkew0; - double c = matrix.rotateSkew1; - double d = matrix.scaleY; - double r = Math.sqrt(a * a + b * b); - double det = a * d - b * c; - double rotate = roundPixels400(Math.signum(b) * Math.acos(a / r) * 180 / Math.PI); - double scaleX = roundPixels400(r); - double scaleY = roundPixels400(det / r); - double skewX = roundPixels400(Math.atan((a * c + b * d) / (r * r)) * 180 / Math.PI); - - double translateXEnd = roundPixels400(matrixEnd.translateX * zoom / SWF.unitDivisor); - double translateYEnd = roundPixels400(matrixEnd.translateY * zoom / SWF.unitDivisor); - a = matrixEnd.scaleX; - b = matrixEnd.rotateSkew0; - c = matrixEnd.rotateSkew1; - d = matrixEnd.scaleY; - double rEnd = Math.sqrt(a * a + b * b); - double detEnd = a * d - b * c; - double rotateEnd = roundPixels400(Math.signum(b) * Math.acos(a / rEnd) * 180 / Math.PI); - double scaleXEnd = roundPixels400(rEnd); - double scaleYEnd = roundPixels400(detEnd / rEnd); - double skewXEnd = roundPixels400(Math.atan((a * c + b * d) / (rEnd * rEnd)) * 180 / Math.PI); - - Element animateClear = exporter.createElement("animateTransform"); - animateClear.setAttribute("dur", animationLengthStr); - animateClear.setAttribute("repeatCount", "indefinite"); - animateClear.setAttribute("attributeName", attribute); - animateClear.setAttribute("type", "scale"); - animateClear.setAttribute("additive", "replace"); - animateClear.setAttribute("from", "1"); - animateClear.setAttribute("to", "1"); - - Element animateTranslate = exporter.createElement("animateTransform"); - animateTranslate.setAttribute("dur", animationLengthStr); - animateTranslate.setAttribute("repeatCount", "indefinite"); - animateTranslate.setAttribute("attributeName", attribute); - animateTranslate.setAttribute("type", "translate"); - animateTranslate.setAttribute("additive", "sum"); - animateTranslate.setAttribute("from", translateX + " " + translateY); - animateTranslate.setAttribute("to", translateXEnd + " " + translateYEnd); - - Element animateRotate = exporter.createElement("animateTransform"); - animateRotate.setAttribute("dur", animationLengthStr); - animateRotate.setAttribute("repeatCount", "indefinite"); - animateRotate.setAttribute("attributeName", attribute); - animateRotate.setAttribute("type", "rotate"); - animateRotate.setAttribute("additive", "sum"); - animateRotate.setAttribute("from", Double.toString(rotate)); - animateRotate.setAttribute("to", Double.toString(rotateEnd)); - - Element animateScale = exporter.createElement("animateTransform"); - animateScale.setAttribute("dur", animationLengthStr); - animateScale.setAttribute("repeatCount", "indefinite"); - animateScale.setAttribute("attributeName", attribute); - animateScale.setAttribute("type", "scale"); - animateScale.setAttribute("additive", "sum"); - animateScale.setAttribute("from", scaleX + " " + scaleY); - animateScale.setAttribute("to", scaleXEnd + " " + scaleYEnd); - - Element animateSkewX = exporter.createElement("animateTransform"); - animateSkewX.setAttribute("dur", animationLengthStr); - animateSkewX.setAttribute("repeatCount", "indefinite"); - animateSkewX.setAttribute("attributeName", attribute); - animateSkewX.setAttribute("type", "skewX"); - animateSkewX.setAttribute("additive", "sum"); - animateSkewX.setAttribute("from", Double.toString(skewX)); - animateSkewX.setAttribute("to", Double.toString(skewXEnd)); - - element.appendChild(animateClear); - element.appendChild(animateTranslate); - element.appendChild(animateRotate); - element.appendChild(animateScale); - element.appendChild(animateSkewX); - - /* - // LDU decomposition - - double translateX = roundPixels400(matrix.translateX * zoom / SWF.unitDivisor); - double translateY = roundPixels400(matrix.translateY * zoom / SWF.unitDivisor); - double a = matrix.scaleX; - double b = matrix.rotateSkew0; - double c = matrix.rotateSkew1; - double d = matrix.scaleY; - double det = a * d - b * c; - double skewY = roundPixels400(Math.atan2(b, a) * 180 / Math.PI); - double scaleX = roundPixels400(a); - double scaleY = roundPixels400(det / a); - double skewX = roundPixels400(Math.atan2(c, a) * 180 / Math.PI); - - double translateXEnd = roundPixels400(matrixEnd.translateX * zoom / SWF.unitDivisor); - double translateYEnd = roundPixels400(matrixEnd.translateY * zoom / SWF.unitDivisor); - a = matrixEnd.scaleX; - b = matrixEnd.rotateSkew0; - c = matrixEnd.rotateSkew1; - d = matrixEnd.scaleY; - double detEnd = a * d - b * c; - double skewYEnd = roundPixels400(Math.atan2(b, a) * 180 / Math.PI); - double scaleXEnd = roundPixels400(a); - double scaleYEnd = roundPixels400(detEnd / a); - double skewXEnd = roundPixels400(Math.atan2(c, a) * 180 / Math.PI); - - Element animateClear = exporter.createElement("animateTransform"); - animateClear.setAttribute("dur", animationLengthStr); - animateClear.setAttribute("repeatCount", "indefinite"); - animateClear.setAttribute("attributeName", attribute); - animateClear.setAttribute("type", "scale"); - animateClear.setAttribute("additive", "replace"); - animateClear.setAttribute("from", "1"); - animateClear.setAttribute("to", "1"); - - Element animateTranslate = exporter.createElement("animateTransform"); - animateTranslate.setAttribute("dur", animationLengthStr); - animateTranslate.setAttribute("repeatCount", "indefinite"); - animateTranslate.setAttribute("attributeName", attribute); - animateTranslate.setAttribute("type", "translate"); - animateTranslate.setAttribute("additive", "sum"); - animateTranslate.setAttribute("from", translateX + " " + translateY); - animateTranslate.setAttribute("to", translateXEnd + " " + translateYEnd); - - Element animateSkewY = exporter.createElement("animateTransform"); - animateSkewY.setAttribute("dur", animationLengthStr); - animateSkewY.setAttribute("repeatCount", "indefinite"); - animateSkewY.setAttribute("attributeName", attribute); - animateSkewY.setAttribute("type", "skewY"); - animateSkewY.setAttribute("additive", "sum"); - animateSkewY.setAttribute("from", Double.toString(skewY)); - animateSkewY.setAttribute("to", Double.toString(skewYEnd)); - - Element animateScale = exporter.createElement("animateTransform"); - animateScale.setAttribute("dur", animationLengthStr); - animateScale.setAttribute("repeatCount", "indefinite"); - animateScale.setAttribute("attributeName", attribute); - animateScale.setAttribute("type", "scale"); - animateScale.setAttribute("additive", "sum"); - animateScale.setAttribute("from", scaleX + " " + scaleY); - animateScale.setAttribute("to", scaleXEnd + " " + scaleYEnd); - - Element animateSkewX = exporter.createElement("animateTransform"); - animateSkewX.setAttribute("dur", animationLengthStr); - animateSkewX.setAttribute("repeatCount", "indefinite"); - animateSkewX.setAttribute("attributeName", attribute); - animateSkewX.setAttribute("type", "skewX"); - animateSkewX.setAttribute("additive", "sum"); - animateSkewX.setAttribute("from", Double.toString(skewX)); - animateSkewX.setAttribute("to", Double.toString(skewXEnd)); - - element.appendChild(animateClear); - element.appendChild(animateTranslate); - element.appendChild(animateSkewY); - element.appendChild(animateScale); - element.appendChild(animateSkewX);*/ - } - - protected void populateGradientElement(Element gradient, int type, GRADRECORD[] gradientRecords, GRADRECORD[] gradientRecordsEnd, Matrix matrix, Matrix matrixEnd, int spreadMethod, int interpolationMethod, float focalPointRatio) { - gradient.setAttribute("gradientUnits", "userSpaceOnUse"); - if (type == FILLSTYLE.LINEAR_GRADIENT) { - gradient.setAttribute("x1", "-819.2"); - gradient.setAttribute("x2", "819.2"); - } else { - gradient.setAttribute("r", "819.2"); - gradient.setAttribute("cx", "0"); - gradient.setAttribute("cy", "0"); - if (focalPointRatio != 0) { - gradient.setAttribute("fx", Double.toString(819.2 * focalPointRatio)); - gradient.setAttribute("fy", "0"); - } - } - switch (spreadMethod) { - case GRADIENT.SPREAD_PAD_MODE: - gradient.setAttribute("spreadMethod", "pad"); - break; - case GRADIENT.SPREAD_REFLECT_MODE: - gradient.setAttribute("spreadMethod", "reflect"); - break; - case GRADIENT.SPREAD_REPEAT_MODE: - gradient.setAttribute("spreadMethod", "repeat"); - break; - } - if (interpolationMethod == GRADIENT.INTERPOLATION_LINEAR_RGB_MODE) { - gradient.setAttribute("color-interpolation", "linearRGB"); - } - if (matrix != null) { - addMatrixAnimation(gradient, "gradientTransform", matrix, matrixEnd); - } - for (int i = 0; i < gradientRecords.length; i++) { - GRADRECORD record = gradientRecords[i]; - GRADRECORD recordEnd = gradientRecordsEnd[i]; - Element gradientEntry = exporter.createElement("stop"); - gradientEntry.setAttribute("offset", Double.toString(record.ratio / 255.0)); - gradientEntry.appendChild(createAnimateElement("offset", record.ratio / 255.0, recordEnd.ratio / 255.0)); - RGB color = record.color; - RGB colorEnd = recordEnd.color; - //if(colors.get(i) != 0) { - gradientEntry.setAttribute("stop-color", color.toHexRGB()); - gradientEntry.appendChild(createAnimateElement("stop-color", color.toHexRGB(), colorEnd.toHexRGB())); - //} - if (color instanceof RGBA) { - RGBA colorA = (RGBA) color; - if (colorA.alpha != 255) { - gradientEntry.setAttribute("stop-opacity", Float.toString(colorA.getAlphaFloat())); - } - RGBA colorAEnd = (RGBA) colorEnd; - gradientEntry.appendChild(createAnimateElement("stop-opacity", colorA.getAlphaFloat(), colorAEnd.getAlphaFloat())); - } - gradient.appendChild(gradientEntry); - } - } - - protected double roundPixels400(double pixels) { - return Math.round(pixels * 10000) / 10000.0; - } -} +/* + * Copyright (C) 2010-2016 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.exporters.morphshape; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; +import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; +import com.jpexs.decompiler.flash.tags.base.ImageTag; +import com.jpexs.decompiler.flash.tags.enums.ImageFormat; +import com.jpexs.decompiler.flash.types.ColorTransform; +import com.jpexs.decompiler.flash.types.FILLSTYLE; +import com.jpexs.decompiler.flash.types.GRADIENT; +import com.jpexs.decompiler.flash.types.GRADRECORD; +import com.jpexs.decompiler.flash.types.LINESTYLE2; +import com.jpexs.decompiler.flash.types.RGB; +import com.jpexs.decompiler.flash.types.RGBA; +import com.jpexs.decompiler.flash.types.SHAPE; +import com.jpexs.helpers.Helper; +import com.jpexs.helpers.SerializableImage; +import java.awt.Color; +import org.w3c.dom.Element; + +/** + * + * @author JPEXS, Claus Wahlers + */ +public class SVGMorphShapeExporter extends DefaultSVGMorphShapeExporter { + + protected Element path; + + protected int id; + + protected int lastPatternId; + + private final Color defaultColor; + + private final SWF swf; + + private final SVGExporter exporter; + + public SVGMorphShapeExporter(SWF swf, SHAPE shape, SHAPE endShape, int id, SVGExporter exporter, Color defaultColor, ColorTransform colorTransform, double zoom) { + super(shape, endShape, colorTransform, zoom); + this.swf = swf; + this.id = id; + this.defaultColor = defaultColor; + this.exporter = exporter; + } + + @Override + public void beginFill(RGB color, RGB colorEnd) { + if (color == null) { + color = new RGB(defaultColor == null ? Color.black : defaultColor); + } + if (colorEnd == null) { + colorEnd = new RGB(defaultColor == null ? Color.black : defaultColor); + } + finalizePath(); + path.setAttribute("stroke", "none"); + path.setAttribute("fill", color.toHexRGB()); + path.setAttribute("fill-rule", "evenodd"); + path.appendChild(createAnimateElement("fill", color.toHexRGB(), colorEnd.toHexRGB())); + if (color instanceof RGBA) { + RGBA colorA = (RGBA) color; + if (colorA.alpha != 255) { + path.setAttribute("fill-opacity", Float.toString(colorA.getAlphaFloat())); + } + RGBA colorAEnd = (RGBA) colorEnd; + path.appendChild(createAnimateElement("fill-opacity", colorA.getAlphaFloat(), colorAEnd.getAlphaFloat())); + } + } + + @Override + public void beginGradientFill(int type, GRADRECORD[] gradientRecords, GRADRECORD[] gradientRecordsEnd, Matrix matrix, Matrix matrixEnd, int spreadMethod, int interpolationMethod, float focalPointRatio, float focalPointRatioEnd) { + finalizePath(); + Element gradient = (type == FILLSTYLE.LINEAR_GRADIENT) + ? exporter.createElement("linearGradient") + : exporter.createElement("radialGradient"); + populateGradientElement(gradient, type, gradientRecords, gradientRecordsEnd, matrix, matrixEnd, spreadMethod, interpolationMethod, focalPointRatio); + int id = exporter.gradients.indexOf(gradient); + if (id < 0) { + // todo: filter same gradients + id = exporter.gradients.size(); + exporter.gradients.add(gradient); + } + gradient.setAttribute("id", "gradient" + id); + path.setAttribute("stroke", "none"); + path.setAttribute("fill", "url(#gradient" + id + ")"); + path.setAttribute("fill-rule", "evenodd"); + exporter.addToDefs(gradient); + } + + @Override + public void beginBitmapFill(int bitmapId, Matrix matrix, Matrix matrixEnd, boolean repeat, boolean smooth, ColorTransform colorTransform) { + finalizePath(); + ImageTag image = swf.getImage(bitmapId); + if (image != null) { + SerializableImage img = image.getImageCached(); + if (img != null) { + if (colorTransform != null) { + colorTransform.apply(img); + } + + int width = img.getWidth(); + int height = img.getHeight(); + lastPatternId++; + String patternId = "PatternID_" + id + "_" + lastPatternId; + ImageFormat format = image.getImageFormat(); + byte[] imageData = Helper.readStream(image.getImageData()); + String base64ImgData = Helper.byteArrayToBase64String(imageData); + path.setAttribute("style", "fill:url(#" + patternId + ")"); + Element pattern = exporter.createElement("pattern"); + pattern.setAttribute("id", patternId); + pattern.setAttribute("patternUnits", "userSpaceOnUse"); + pattern.setAttribute("overflow", "visible"); + pattern.setAttribute("width", "" + width); + pattern.setAttribute("height", "" + height); + pattern.setAttribute("viewBox", "0 0 " + width + " " + height); + if (matrix != null) { + matrix = matrix.clone(); + matrix.rotateSkew0 *= zoom / SWF.unitDivisor; + matrix.rotateSkew1 *= zoom / SWF.unitDivisor; + matrix.scaleX *= zoom / SWF.unitDivisor; + matrix.scaleY *= zoom / SWF.unitDivisor; + matrixEnd = matrixEnd.clone(); + matrixEnd.rotateSkew0 *= zoom / SWF.unitDivisor; + matrixEnd.rotateSkew1 *= zoom / SWF.unitDivisor; + matrixEnd.scaleX *= zoom / SWF.unitDivisor; + matrixEnd.scaleY *= zoom / SWF.unitDivisor; + addMatrixAnimation(pattern, "patternTransform", matrix, matrixEnd); + } + Element imageElement = exporter.createElement("image"); + imageElement.setAttribute("width", "" + width); + imageElement.setAttribute("height", "" + height); + imageElement.setAttribute("xlink:href", "data:image/" + format + ";base64," + base64ImgData); + pattern.appendChild(imageElement); + exporter.addToGroup(pattern); + } + } + } + + @Override + public void lineStyle(double thickness, double thicknessEnd, RGB color, RGB colorEnd, boolean pixelHinting, String scaleMode, int startCaps, int endCaps, int joints, float miterLimit) { + finalizePath(); + thickness *= zoom / SWF.unitDivisor; + thicknessEnd *= zoom / SWF.unitDivisor; + path.setAttribute("fill", "none"); + if (color != null) { + path.setAttribute("stroke", color.toHexRGB()); + path.appendChild(createAnimateElement("stroke", color.toHexRGB(), colorEnd.toHexRGB())); + } + path.setAttribute("stroke-width", Double.toString(thickness == 0 ? 1 : thickness)); + path.appendChild(createAnimateElement("stroke-width", thickness, thicknessEnd)); + + if (color instanceof RGBA) { + RGBA colorA = (RGBA) color; + if (colorA.alpha != 255) { + path.setAttribute("stroke-opacity", Float.toString(colorA.getAlphaFloat())); + } + RGBA colorAEnd = (RGBA) colorEnd; + path.appendChild(createAnimateElement("fill-opacity", colorA.getAlphaFloat(), colorAEnd.getAlphaFloat())); + } + switch (startCaps) { + case LINESTYLE2.NO_CAP: + path.setAttribute("stroke-linecap", "butt"); + break; + case LINESTYLE2.SQUARE_CAP: + path.setAttribute("stroke-linecap", "square"); + break; + default: + path.setAttribute("stroke-linecap", "round"); + break; + } + switch (joints) { + case LINESTYLE2.BEVEL_JOIN: + path.setAttribute("stroke-linejoin", "bevel"); + break; + case LINESTYLE2.ROUND_JOIN: + path.setAttribute("stroke-linejoin", "round"); + break; + default: + path.setAttribute("stroke-linejoin", "miter"); + if (miterLimit >= 1 && miterLimit != 4f) { + path.setAttribute("stroke-miterlimit", Double.toString(miterLimit)); + } + break; + } + } + + @Override + public void lineGradientStyle(int type, GRADRECORD[] gradientRecords, GRADRECORD[] gradientRecordsEnd, Matrix matrix, Matrix matrixEnd, int spreadMethod, int interpolationMethod, float focalPointRatio, float focalPointRatioEnd) { + path.removeAttribute("stroke-opacity"); + Element gradient = (type == FILLSTYLE.LINEAR_GRADIENT) + ? exporter.createElement("linearGradient") + : exporter.createElement("radialGradient"); + populateGradientElement(gradient, type, gradientRecords, gradientRecordsEnd, matrix, matrixEnd, spreadMethod, interpolationMethod, focalPointRatio); + int id = exporter.gradients.indexOf(gradient); + if (id < 0) { + // todo: filter same gradients + id = exporter.gradients.size(); + exporter.gradients.add(gradient); + } + gradient.setAttribute("id", "gradient" + id); + path.setAttribute("stroke", "url(#gradient" + id + ")"); + path.setAttribute("fill", "none"); + exporter.addToDefs(gradient); + } + + private Element createAnimateElement(String attributeName, Object startValue, Object endValue) { + Element animate = exporter.createElement("animate"); + animate.setAttribute("dur", "2s"); // todo + animate.setAttribute("repeatCount", "indefinite"); + animate.setAttribute("attributeName", attributeName); + animate.setAttribute("values", startValue + ";" + endValue); + return animate; + } + + @Override + protected void finalizePath() { + if (path != null && pathData != null && pathData.length() > 0) { + path.setAttribute("d", pathData.toString().trim()); + path.appendChild(createAnimateElement("d", pathData.toString().trim(), pathDataEnd.toString().trim())); + exporter.addToGroup(path); + } + path = exporter.createElement("path"); + super.finalizePath(); + } + + private void addMatrixAnimation(Element element, String attribute, Matrix matrix, Matrix matrixEnd) { + final int animationLength = 2; // todo + final String animationLengthStr = animationLength + "s"; + + element.setAttribute(attribute, matrix.getSvgTransformationString(SWF.unitDivisor / zoom, 1)); + + // QR decomposition + double translateX = roundPixels400(matrix.translateX * zoom / SWF.unitDivisor); + double translateY = roundPixels400(matrix.translateY * zoom / SWF.unitDivisor); + double a = matrix.scaleX; + double b = matrix.rotateSkew0; + double c = matrix.rotateSkew1; + double d = matrix.scaleY; + double r = Math.sqrt(a * a + b * b); + double det = a * d - b * c; + double rotate = roundPixels400(Math.signum(b) * Math.acos(a / r) * 180 / Math.PI); + double scaleX = roundPixels400(r); + double scaleY = roundPixels400(det / r); + double skewX = roundPixels400(Math.atan((a * c + b * d) / (r * r)) * 180 / Math.PI); + + double translateXEnd = roundPixels400(matrixEnd.translateX * zoom / SWF.unitDivisor); + double translateYEnd = roundPixels400(matrixEnd.translateY * zoom / SWF.unitDivisor); + a = matrixEnd.scaleX; + b = matrixEnd.rotateSkew0; + c = matrixEnd.rotateSkew1; + d = matrixEnd.scaleY; + double rEnd = Math.sqrt(a * a + b * b); + double detEnd = a * d - b * c; + double rotateEnd = roundPixels400(Math.signum(b) * Math.acos(a / rEnd) * 180 / Math.PI); + double scaleXEnd = roundPixels400(rEnd); + double scaleYEnd = roundPixels400(detEnd / rEnd); + double skewXEnd = roundPixels400(Math.atan((a * c + b * d) / (rEnd * rEnd)) * 180 / Math.PI); + + Element animateClear = exporter.createElement("animateTransform"); + animateClear.setAttribute("dur", animationLengthStr); + animateClear.setAttribute("repeatCount", "indefinite"); + animateClear.setAttribute("attributeName", attribute); + animateClear.setAttribute("type", "scale"); + animateClear.setAttribute("additive", "replace"); + animateClear.setAttribute("from", "1"); + animateClear.setAttribute("to", "1"); + + Element animateTranslate = exporter.createElement("animateTransform"); + animateTranslate.setAttribute("dur", animationLengthStr); + animateTranslate.setAttribute("repeatCount", "indefinite"); + animateTranslate.setAttribute("attributeName", attribute); + animateTranslate.setAttribute("type", "translate"); + animateTranslate.setAttribute("additive", "sum"); + animateTranslate.setAttribute("from", translateX + " " + translateY); + animateTranslate.setAttribute("to", translateXEnd + " " + translateYEnd); + + Element animateRotate = exporter.createElement("animateTransform"); + animateRotate.setAttribute("dur", animationLengthStr); + animateRotate.setAttribute("repeatCount", "indefinite"); + animateRotate.setAttribute("attributeName", attribute); + animateRotate.setAttribute("type", "rotate"); + animateRotate.setAttribute("additive", "sum"); + animateRotate.setAttribute("from", Double.toString(rotate)); + animateRotate.setAttribute("to", Double.toString(rotateEnd)); + + Element animateScale = exporter.createElement("animateTransform"); + animateScale.setAttribute("dur", animationLengthStr); + animateScale.setAttribute("repeatCount", "indefinite"); + animateScale.setAttribute("attributeName", attribute); + animateScale.setAttribute("type", "scale"); + animateScale.setAttribute("additive", "sum"); + animateScale.setAttribute("from", scaleX + " " + scaleY); + animateScale.setAttribute("to", scaleXEnd + " " + scaleYEnd); + + Element animateSkewX = exporter.createElement("animateTransform"); + animateSkewX.setAttribute("dur", animationLengthStr); + animateSkewX.setAttribute("repeatCount", "indefinite"); + animateSkewX.setAttribute("attributeName", attribute); + animateSkewX.setAttribute("type", "skewX"); + animateSkewX.setAttribute("additive", "sum"); + animateSkewX.setAttribute("from", Double.toString(skewX)); + animateSkewX.setAttribute("to", Double.toString(skewXEnd)); + + element.appendChild(animateClear); + element.appendChild(animateTranslate); + element.appendChild(animateRotate); + element.appendChild(animateScale); + element.appendChild(animateSkewX); + + /* + // LDU decomposition + + double translateX = roundPixels400(matrix.translateX * zoom / SWF.unitDivisor); + double translateY = roundPixels400(matrix.translateY * zoom / SWF.unitDivisor); + double a = matrix.scaleX; + double b = matrix.rotateSkew0; + double c = matrix.rotateSkew1; + double d = matrix.scaleY; + double det = a * d - b * c; + double skewY = roundPixels400(Math.atan2(b, a) * 180 / Math.PI); + double scaleX = roundPixels400(a); + double scaleY = roundPixels400(det / a); + double skewX = roundPixels400(Math.atan2(c, a) * 180 / Math.PI); + + double translateXEnd = roundPixels400(matrixEnd.translateX * zoom / SWF.unitDivisor); + double translateYEnd = roundPixels400(matrixEnd.translateY * zoom / SWF.unitDivisor); + a = matrixEnd.scaleX; + b = matrixEnd.rotateSkew0; + c = matrixEnd.rotateSkew1; + d = matrixEnd.scaleY; + double detEnd = a * d - b * c; + double skewYEnd = roundPixels400(Math.atan2(b, a) * 180 / Math.PI); + double scaleXEnd = roundPixels400(a); + double scaleYEnd = roundPixels400(detEnd / a); + double skewXEnd = roundPixels400(Math.atan2(c, a) * 180 / Math.PI); + + Element animateClear = exporter.createElement("animateTransform"); + animateClear.setAttribute("dur", animationLengthStr); + animateClear.setAttribute("repeatCount", "indefinite"); + animateClear.setAttribute("attributeName", attribute); + animateClear.setAttribute("type", "scale"); + animateClear.setAttribute("additive", "replace"); + animateClear.setAttribute("from", "1"); + animateClear.setAttribute("to", "1"); + + Element animateTranslate = exporter.createElement("animateTransform"); + animateTranslate.setAttribute("dur", animationLengthStr); + animateTranslate.setAttribute("repeatCount", "indefinite"); + animateTranslate.setAttribute("attributeName", attribute); + animateTranslate.setAttribute("type", "translate"); + animateTranslate.setAttribute("additive", "sum"); + animateTranslate.setAttribute("from", translateX + " " + translateY); + animateTranslate.setAttribute("to", translateXEnd + " " + translateYEnd); + + Element animateSkewY = exporter.createElement("animateTransform"); + animateSkewY.setAttribute("dur", animationLengthStr); + animateSkewY.setAttribute("repeatCount", "indefinite"); + animateSkewY.setAttribute("attributeName", attribute); + animateSkewY.setAttribute("type", "skewY"); + animateSkewY.setAttribute("additive", "sum"); + animateSkewY.setAttribute("from", Double.toString(skewY)); + animateSkewY.setAttribute("to", Double.toString(skewYEnd)); + + Element animateScale = exporter.createElement("animateTransform"); + animateScale.setAttribute("dur", animationLengthStr); + animateScale.setAttribute("repeatCount", "indefinite"); + animateScale.setAttribute("attributeName", attribute); + animateScale.setAttribute("type", "scale"); + animateScale.setAttribute("additive", "sum"); + animateScale.setAttribute("from", scaleX + " " + scaleY); + animateScale.setAttribute("to", scaleXEnd + " " + scaleYEnd); + + Element animateSkewX = exporter.createElement("animateTransform"); + animateSkewX.setAttribute("dur", animationLengthStr); + animateSkewX.setAttribute("repeatCount", "indefinite"); + animateSkewX.setAttribute("attributeName", attribute); + animateSkewX.setAttribute("type", "skewX"); + animateSkewX.setAttribute("additive", "sum"); + animateSkewX.setAttribute("from", Double.toString(skewX)); + animateSkewX.setAttribute("to", Double.toString(skewXEnd)); + + element.appendChild(animateClear); + element.appendChild(animateTranslate); + element.appendChild(animateSkewY); + element.appendChild(animateScale); + element.appendChild(animateSkewX);*/ + } + + protected void populateGradientElement(Element gradient, int type, GRADRECORD[] gradientRecords, GRADRECORD[] gradientRecordsEnd, Matrix matrix, Matrix matrixEnd, int spreadMethod, int interpolationMethod, float focalPointRatio) { + gradient.setAttribute("gradientUnits", "userSpaceOnUse"); + if (type == FILLSTYLE.LINEAR_GRADIENT) { + gradient.setAttribute("x1", "-819.2"); + gradient.setAttribute("x2", "819.2"); + } else { + gradient.setAttribute("r", "819.2"); + gradient.setAttribute("cx", "0"); + gradient.setAttribute("cy", "0"); + if (focalPointRatio != 0) { + gradient.setAttribute("fx", Double.toString(819.2 * focalPointRatio)); + gradient.setAttribute("fy", "0"); + } + } + switch (spreadMethod) { + case GRADIENT.SPREAD_PAD_MODE: + gradient.setAttribute("spreadMethod", "pad"); + break; + case GRADIENT.SPREAD_REFLECT_MODE: + gradient.setAttribute("spreadMethod", "reflect"); + break; + case GRADIENT.SPREAD_REPEAT_MODE: + gradient.setAttribute("spreadMethod", "repeat"); + break; + } + if (interpolationMethod == GRADIENT.INTERPOLATION_LINEAR_RGB_MODE) { + gradient.setAttribute("color-interpolation", "linearRGB"); + } + if (matrix != null) { + addMatrixAnimation(gradient, "gradientTransform", matrix, matrixEnd); + } + for (int i = 0; i < gradientRecords.length; i++) { + GRADRECORD record = gradientRecords[i]; + GRADRECORD recordEnd = gradientRecordsEnd[i]; + Element gradientEntry = exporter.createElement("stop"); + gradientEntry.setAttribute("offset", Double.toString(record.ratio / 255.0)); + gradientEntry.appendChild(createAnimateElement("offset", record.ratio / 255.0, recordEnd.ratio / 255.0)); + RGB color = record.color; + RGB colorEnd = recordEnd.color; + //if(colors.get(i) != 0) { + gradientEntry.setAttribute("stop-color", color.toHexRGB()); + gradientEntry.appendChild(createAnimateElement("stop-color", color.toHexRGB(), colorEnd.toHexRGB())); + //} + if (color instanceof RGBA) { + RGBA colorA = (RGBA) color; + if (colorA.alpha != 255) { + gradientEntry.setAttribute("stop-opacity", Float.toString(colorA.getAlphaFloat())); + } + RGBA colorAEnd = (RGBA) colorEnd; + gradientEntry.appendChild(createAnimateElement("stop-opacity", colorA.getAlphaFloat(), colorAEnd.getAlphaFloat())); + } + gradient.appendChild(gradientEntry); + } + } + + protected double roundPixels400(double pixels) { + return Math.round(pixels * 10000) / 10000.0; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/shape/SVGShapeExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/shape/SVGShapeExporter.java index 252012bab..e740ac8c2 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/shape/SVGShapeExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/shape/SVGShapeExporter.java @@ -1,264 +1,264 @@ -/* - * Copyright (C) 2010-2016 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.exporters.shape; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; -import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; -import com.jpexs.decompiler.flash.tags.base.ImageTag; -import com.jpexs.decompiler.flash.tags.enums.ImageFormat; -import com.jpexs.decompiler.flash.types.ColorTransform; -import com.jpexs.decompiler.flash.types.FILLSTYLE; -import com.jpexs.decompiler.flash.types.GRADIENT; -import com.jpexs.decompiler.flash.types.GRADRECORD; -import com.jpexs.decompiler.flash.types.LINESTYLE2; -import com.jpexs.decompiler.flash.types.RGB; -import com.jpexs.decompiler.flash.types.RGBA; -import com.jpexs.decompiler.flash.types.SHAPE; -import com.jpexs.helpers.Helper; -import com.jpexs.helpers.SerializableImage; -import java.awt.Color; -import org.w3c.dom.Element; - -/** - * - * @author JPEXS, Claus Wahlers - */ -public class SVGShapeExporter extends DefaultSVGShapeExporter { - - protected Element path; - - protected int id; - - protected int lastPatternId; - - private final Color defaultColor; - - private final SWF swf; - - private final SVGExporter exporter; - - public SVGShapeExporter(SWF swf, SHAPE shape, int id, SVGExporter exporter, Color defaultColor, ColorTransform colorTransform, double zoom) { - super(swf, shape, colorTransform, zoom); - this.swf = swf; - this.id = id; - this.defaultColor = defaultColor; - this.exporter = exporter; - } - - @Override - public void beginFill(RGB color) { - if (color == null && defaultColor != null) { - color = new RGB(defaultColor); - } - finalizePath(); - path.setAttribute("stroke", "none"); - if (color != null) { - path.setAttribute("fill", color.toHexRGB()); - } - path.setAttribute("fill-rule", "evenodd"); - if (color instanceof RGBA) { - RGBA colorA = (RGBA) color; - if (colorA.alpha != 255) { - path.setAttribute("fill-opacity", Float.toString(colorA.getAlphaFloat())); - } - } - } - - @Override - public void beginGradientFill(int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) { - finalizePath(); - Element gradient = (type == FILLSTYLE.LINEAR_GRADIENT) - ? exporter.createElement("linearGradient") - : exporter.createElement("radialGradient"); - populateGradientElement(gradient, type, gradientRecords, matrix, spreadMethod, interpolationMethod, focalPointRatio); - int id = exporter.gradients.indexOf(gradient); - if (id < 0) { - // todo: filter same gradients - id = exporter.gradients.size(); - exporter.gradients.add(gradient); - } - String gradientId = "gradient" + id; - gradient.setAttribute("id", gradientId); - path.setAttribute("stroke", "none"); - path.setAttribute("fill", "url(#" + gradientId + ")"); - path.setAttribute("fill-rule", "evenodd"); - exporter.addToDefs(gradient); - } - - @Override - public void beginBitmapFill(int bitmapId, Matrix matrix, boolean repeat, boolean smooth, ColorTransform colorTransform) { - finalizePath(); - ImageTag image = swf.getImage(bitmapId); - if (image != null) { - SerializableImage img = image.getImageCached(); - if (img != null) { - if (colorTransform != null) { - colorTransform.apply(img); - } - - int width = img.getWidth(); - int height = img.getHeight(); - lastPatternId++; - String patternId = "PatternID_" + id + "_" + lastPatternId; - ImageFormat format = image.getImageFormat(); - byte[] imageData = Helper.readStream(image.getImageData()); - String base64ImgData = Helper.byteArrayToBase64String(imageData); - path.setAttribute("style", "fill:url(#" + patternId + ")"); - Element pattern = exporter.createElement("pattern"); - pattern.setAttribute("id", patternId); - pattern.setAttribute("patternUnits", "userSpaceOnUse"); - pattern.setAttribute("overflow", "visible"); - pattern.setAttribute("width", "" + width); - pattern.setAttribute("height", "" + height); - pattern.setAttribute("viewBox", "0 0 " + width + " " + height); - if (matrix != null) { - pattern.setAttribute("patternTransform", matrix.getSvgTransformationString(SWF.unitDivisor / zoom, SWF.unitDivisor / zoom)); - } - Element imageElement = exporter.createElement("image"); - imageElement.setAttribute("width", "" + width); - imageElement.setAttribute("height", "" + height); - imageElement.setAttribute("xlink:href", "data:image/" + format + ";base64," + base64ImgData); - pattern.appendChild(imageElement); - exporter.addToGroup(pattern); - return; - } - } - - path.setAttribute("fill", "#ff0000"); - } - - @Override - public void lineStyle(double thickness, RGB color, boolean pixelHinting, String scaleMode, int startCaps, int endCaps, int joints, float miterLimit) { - finalizePath(); - thickness *= zoom / SWF.unitDivisor; - path.setAttribute("fill", "none"); - if (color != null) { - path.setAttribute("stroke", color.toHexRGB()); - } - path.setAttribute("stroke-width", Double.toString(thickness == 0 ? 1 : thickness)); - if (color instanceof RGBA) { - RGBA colorA = (RGBA) color; - if (colorA.alpha != 255) { - path.setAttribute("stroke-opacity", Float.toString(colorA.getAlphaFloat())); - } - } - switch (startCaps) { - case LINESTYLE2.NO_CAP: - path.setAttribute("stroke-linecap", "butt"); - break; - case LINESTYLE2.SQUARE_CAP: - path.setAttribute("stroke-linecap", "square"); - break; - default: - path.setAttribute("stroke-linecap", "round"); - break; - } - switch (joints) { - case LINESTYLE2.BEVEL_JOIN: - path.setAttribute("stroke-linejoin", "bevel"); - break; - case LINESTYLE2.ROUND_JOIN: - path.setAttribute("stroke-linejoin", "round"); - break; - default: - path.setAttribute("stroke-linejoin", "miter"); - if (miterLimit >= 1 && miterLimit != 4f) { - path.setAttribute("stroke-miterlimit", Double.toString(miterLimit)); - } - break; - } - } - - @Override - public void lineGradientStyle(int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) { - path.removeAttribute("stroke-opacity"); - Element gradient = (type == FILLSTYLE.LINEAR_GRADIENT) - ? exporter.createElement("linearGradient") - : exporter.createElement("radialGradient"); - populateGradientElement(gradient, type, gradientRecords, matrix, spreadMethod, interpolationMethod, focalPointRatio); - int id = exporter.gradients.indexOf(gradient); - if (id < 0) { - // todo: filter same gradients - id = exporter.gradients.size(); - exporter.gradients.add(gradient); - } - gradient.setAttribute("id", "gradient" + id); - path.setAttribute("stroke", "url(#gradient" + id + ")"); - path.setAttribute("fill", "none"); - exporter.addToDefs(gradient); - } - - @Override - protected void finalizePath() { - if (path != null && pathData != null && pathData.length() > 0) { - path.setAttribute("d", pathData.toString().trim()); - exporter.addToGroup(path); - } - path = exporter.createElement("path"); - super.finalizePath(); - } - - protected void populateGradientElement(Element gradient, int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) { - gradient.setAttribute("gradientUnits", "userSpaceOnUse"); - if (type == FILLSTYLE.LINEAR_GRADIENT) { - gradient.setAttribute("x1", "-819.2"); - gradient.setAttribute("x2", "819.2"); - } else { - gradient.setAttribute("r", "819.2"); - gradient.setAttribute("cx", "0"); - gradient.setAttribute("cy", "0"); - if (focalPointRatio != 0) { - gradient.setAttribute("fx", Double.toString(819.2 * focalPointRatio)); - gradient.setAttribute("fy", "0"); - } - } - switch (spreadMethod) { - case GRADIENT.SPREAD_PAD_MODE: - gradient.setAttribute("spreadMethod", "pad"); - break; - case GRADIENT.SPREAD_REFLECT_MODE: - gradient.setAttribute("spreadMethod", "reflect"); - break; - case GRADIENT.SPREAD_REPEAT_MODE: - gradient.setAttribute("spreadMethod", "repeat"); - break; - } - if (interpolationMethod == GRADIENT.INTERPOLATION_LINEAR_RGB_MODE) { - gradient.setAttribute("color-interpolation", "linearRGB"); - } - if (matrix != null) { - gradient.setAttribute("gradientTransform", matrix.getSvgTransformationString(SWF.unitDivisor / zoom, 1)); - } - for (int i = 0; i < gradientRecords.length; i++) { - GRADRECORD record = gradientRecords[i]; - Element gradientEntry = exporter.createElement("stop"); - gradientEntry.setAttribute("offset", Double.toString(record.ratio / 255.0)); - RGB color = record.color; - //if(colors.get(i) != 0) { - gradientEntry.setAttribute("stop-color", color.toHexRGB()); - //} - if (color instanceof RGBA) { - RGBA colorA = (RGBA) color; - if (colorA.alpha != 255) { - gradientEntry.setAttribute("stop-opacity", Float.toString(colorA.getAlphaFloat())); - } - } - gradient.appendChild(gradientEntry); - } - } -} +/* + * Copyright (C) 2010-2016 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.exporters.shape; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; +import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; +import com.jpexs.decompiler.flash.tags.base.ImageTag; +import com.jpexs.decompiler.flash.tags.enums.ImageFormat; +import com.jpexs.decompiler.flash.types.ColorTransform; +import com.jpexs.decompiler.flash.types.FILLSTYLE; +import com.jpexs.decompiler.flash.types.GRADIENT; +import com.jpexs.decompiler.flash.types.GRADRECORD; +import com.jpexs.decompiler.flash.types.LINESTYLE2; +import com.jpexs.decompiler.flash.types.RGB; +import com.jpexs.decompiler.flash.types.RGBA; +import com.jpexs.decompiler.flash.types.SHAPE; +import com.jpexs.helpers.Helper; +import com.jpexs.helpers.SerializableImage; +import java.awt.Color; +import org.w3c.dom.Element; + +/** + * + * @author JPEXS, Claus Wahlers + */ +public class SVGShapeExporter extends DefaultSVGShapeExporter { + + protected Element path; + + protected int id; + + protected int lastPatternId; + + private final Color defaultColor; + + private final SWF swf; + + private final SVGExporter exporter; + + public SVGShapeExporter(SWF swf, SHAPE shape, int id, SVGExporter exporter, Color defaultColor, ColorTransform colorTransform, double zoom) { + super(swf, shape, colorTransform, zoom); + this.swf = swf; + this.id = id; + this.defaultColor = defaultColor; + this.exporter = exporter; + } + + @Override + public void beginFill(RGB color) { + if (color == null && defaultColor != null) { + color = new RGB(defaultColor); + } + finalizePath(); + path.setAttribute("stroke", "none"); + if (color != null) { + path.setAttribute("fill", color.toHexRGB()); + } + path.setAttribute("fill-rule", "evenodd"); + if (color instanceof RGBA) { + RGBA colorA = (RGBA) color; + if (colorA.alpha != 255) { + path.setAttribute("fill-opacity", Float.toString(colorA.getAlphaFloat())); + } + } + } + + @Override + public void beginGradientFill(int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) { + finalizePath(); + Element gradient = (type == FILLSTYLE.LINEAR_GRADIENT) + ? exporter.createElement("linearGradient") + : exporter.createElement("radialGradient"); + populateGradientElement(gradient, type, gradientRecords, matrix, spreadMethod, interpolationMethod, focalPointRatio); + int id = exporter.gradients.indexOf(gradient); + if (id < 0) { + // todo: filter same gradients + id = exporter.gradients.size(); + exporter.gradients.add(gradient); + } + String gradientId = "gradient" + id; + gradient.setAttribute("id", gradientId); + path.setAttribute("stroke", "none"); + path.setAttribute("fill", "url(#" + gradientId + ")"); + path.setAttribute("fill-rule", "evenodd"); + exporter.addToDefs(gradient); + } + + @Override + public void beginBitmapFill(int bitmapId, Matrix matrix, boolean repeat, boolean smooth, ColorTransform colorTransform) { + finalizePath(); + ImageTag image = swf.getImage(bitmapId); + if (image != null) { + SerializableImage img = image.getImageCached(); + if (img != null) { + if (colorTransform != null) { + colorTransform.apply(img); + } + + int width = img.getWidth(); + int height = img.getHeight(); + lastPatternId++; + String patternId = "PatternID_" + id + "_" + lastPatternId; + ImageFormat format = image.getImageFormat(); + byte[] imageData = Helper.readStream(image.getImageData()); + String base64ImgData = Helper.byteArrayToBase64String(imageData); + path.setAttribute("style", "fill:url(#" + patternId + ")"); + Element pattern = exporter.createElement("pattern"); + pattern.setAttribute("id", patternId); + pattern.setAttribute("patternUnits", "userSpaceOnUse"); + pattern.setAttribute("overflow", "visible"); + pattern.setAttribute("width", "" + width); + pattern.setAttribute("height", "" + height); + pattern.setAttribute("viewBox", "0 0 " + width + " " + height); + if (matrix != null) { + pattern.setAttribute("patternTransform", matrix.getSvgTransformationString(SWF.unitDivisor / zoom, SWF.unitDivisor / zoom)); + } + Element imageElement = exporter.createElement("image"); + imageElement.setAttribute("width", "" + width); + imageElement.setAttribute("height", "" + height); + imageElement.setAttribute("xlink:href", "data:image/" + format + ";base64," + base64ImgData); + pattern.appendChild(imageElement); + exporter.addToGroup(pattern); + return; + } + } + + path.setAttribute("fill", "#ff0000"); + } + + @Override + public void lineStyle(double thickness, RGB color, boolean pixelHinting, String scaleMode, int startCaps, int endCaps, int joints, float miterLimit) { + finalizePath(); + thickness *= zoom / SWF.unitDivisor; + path.setAttribute("fill", "none"); + if (color != null) { + path.setAttribute("stroke", color.toHexRGB()); + } + path.setAttribute("stroke-width", Double.toString(thickness == 0 ? 1 : thickness)); + if (color instanceof RGBA) { + RGBA colorA = (RGBA) color; + if (colorA.alpha != 255) { + path.setAttribute("stroke-opacity", Float.toString(colorA.getAlphaFloat())); + } + } + switch (startCaps) { + case LINESTYLE2.NO_CAP: + path.setAttribute("stroke-linecap", "butt"); + break; + case LINESTYLE2.SQUARE_CAP: + path.setAttribute("stroke-linecap", "square"); + break; + default: + path.setAttribute("stroke-linecap", "round"); + break; + } + switch (joints) { + case LINESTYLE2.BEVEL_JOIN: + path.setAttribute("stroke-linejoin", "bevel"); + break; + case LINESTYLE2.ROUND_JOIN: + path.setAttribute("stroke-linejoin", "round"); + break; + default: + path.setAttribute("stroke-linejoin", "miter"); + if (miterLimit >= 1 && miterLimit != 4f) { + path.setAttribute("stroke-miterlimit", Double.toString(miterLimit)); + } + break; + } + } + + @Override + public void lineGradientStyle(int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) { + path.removeAttribute("stroke-opacity"); + Element gradient = (type == FILLSTYLE.LINEAR_GRADIENT) + ? exporter.createElement("linearGradient") + : exporter.createElement("radialGradient"); + populateGradientElement(gradient, type, gradientRecords, matrix, spreadMethod, interpolationMethod, focalPointRatio); + int id = exporter.gradients.indexOf(gradient); + if (id < 0) { + // todo: filter same gradients + id = exporter.gradients.size(); + exporter.gradients.add(gradient); + } + gradient.setAttribute("id", "gradient" + id); + path.setAttribute("stroke", "url(#gradient" + id + ")"); + path.setAttribute("fill", "none"); + exporter.addToDefs(gradient); + } + + @Override + protected void finalizePath() { + if (path != null && pathData != null && pathData.length() > 0) { + path.setAttribute("d", pathData.toString().trim()); + exporter.addToGroup(path); + } + path = exporter.createElement("path"); + super.finalizePath(); + } + + protected void populateGradientElement(Element gradient, int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) { + gradient.setAttribute("gradientUnits", "userSpaceOnUse"); + if (type == FILLSTYLE.LINEAR_GRADIENT) { + gradient.setAttribute("x1", "-819.2"); + gradient.setAttribute("x2", "819.2"); + } else { + gradient.setAttribute("r", "819.2"); + gradient.setAttribute("cx", "0"); + gradient.setAttribute("cy", "0"); + if (focalPointRatio != 0) { + gradient.setAttribute("fx", Double.toString(819.2 * focalPointRatio)); + gradient.setAttribute("fy", "0"); + } + } + switch (spreadMethod) { + case GRADIENT.SPREAD_PAD_MODE: + gradient.setAttribute("spreadMethod", "pad"); + break; + case GRADIENT.SPREAD_REFLECT_MODE: + gradient.setAttribute("spreadMethod", "reflect"); + break; + case GRADIENT.SPREAD_REPEAT_MODE: + gradient.setAttribute("spreadMethod", "repeat"); + break; + } + if (interpolationMethod == GRADIENT.INTERPOLATION_LINEAR_RGB_MODE) { + gradient.setAttribute("color-interpolation", "linearRGB"); + } + if (matrix != null) { + gradient.setAttribute("gradientTransform", matrix.getSvgTransformationString(SWF.unitDivisor / zoom, 1)); + } + for (int i = 0; i < gradientRecords.length; i++) { + GRADRECORD record = gradientRecords[i]; + Element gradientEntry = exporter.createElement("stop"); + gradientEntry.setAttribute("offset", Double.toString(record.ratio / 255.0)); + RGB color = record.color; + //if(colors.get(i) != 0) { + gradientEntry.setAttribute("stop-color", color.toHexRGB()); + //} + if (color instanceof RGBA) { + RGBA colorA = (RGBA) color; + if (colorA.alpha != 255) { + gradientEntry.setAttribute("stop-opacity", Float.toString(colorA.getAlphaFloat())); + } + } + gradient.appendChild(gradientEntry); + } + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ImageTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ImageTag.java index b5e9386e8..8e1b7b029 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ImageTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ImageTag.java @@ -1,281 +1,281 @@ -/* - * Copyright (C) 2010-2016 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags.base; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; -import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; -import com.jpexs.decompiler.flash.exporters.shape.BitmapExporter; -import com.jpexs.decompiler.flash.exporters.shape.CanvasShapeExporter; -import com.jpexs.decompiler.flash.exporters.shape.SVGShapeExporter; -import com.jpexs.decompiler.flash.helpers.ImageHelper; -import com.jpexs.decompiler.flash.tags.TagInfo; -import com.jpexs.decompiler.flash.tags.enums.ImageFormat; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.ColorTransform; -import com.jpexs.decompiler.flash.types.FILLSTYLE; -import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY; -import com.jpexs.decompiler.flash.types.LINESTYLE; -import com.jpexs.decompiler.flash.types.LINESTYLEARRAY; -import com.jpexs.decompiler.flash.types.MATRIX; -import com.jpexs.decompiler.flash.types.RECT; -import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord; -import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord; -import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord; -import com.jpexs.helpers.ByteArrayRange; -import com.jpexs.helpers.SerializableImage; -import java.awt.Dimension; -import java.awt.Shape; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Set; - -/** - * - * @author JPEXS - */ -public abstract class ImageTag extends DrawableTag { - - @SWFType(BasicType.UI16) - public int characterID; - - protected SerializableImage cachedImage; - - public ImageTag(SWF swf, int id, String name, ByteArrayRange data) { - super(swf, id, name, data); - } - - public abstract InputStream getOriginalImageData(); - - protected abstract SerializableImage getImage(); - - public abstract Dimension getImageDimension(); - - public abstract void setImage(byte[] data) throws IOException; - - public abstract ImageFormat getImageFormat(); - - public abstract ImageFormat getOriginalImageFormat(); - - public boolean importSupported() { - return true; - } - - public static ImageFormat getImageFormat(byte[] data) { - return getImageFormat(new ByteArrayRange(data)); - } - - public static ImageFormat getImageFormat(ByteArrayRange data) { - if (hasErrorHeader(data)) { - return ImageFormat.JPEG; - } - - if (data.getLength() > 2 && ((data.get(0) & 0xff) == 0xff) && ((data.get(1) & 0xff) == 0xd8)) { - return ImageFormat.JPEG; - } - - if (data.getLength() > 6 && ((data.get(0) & 0xff) == 0x47) && ((data.get(1) & 0xff) == 0x49) && ((data.get(2) & 0xff) == 0x46) && ((data.get(3) & 0xff) == 0x38) && ((data.get(4) & 0xff) == 0x39) && ((data.get(5) & 0xff) == 0x61)) { - return ImageFormat.GIF; - } - - if (data.getLength() > 8 && ((data.get(0) & 0xff) == 0x89) && ((data.get(1) & 0xff) == 0x50) && ((data.get(2) & 0xff) == 0x4e) && ((data.get(3) & 0xff) == 0x47) && ((data.get(4) & 0xff) == 0x0d) && ((data.get(5) & 0xff) == 0x0a) && ((data.get(6) & 0xff) == 0x1a) && ((data.get(7) & 0xff) == 0x0a)) { - return ImageFormat.PNG; - } - - return ImageFormat.UNKNOWN; - } - - public SerializableImage getImageCached() { - if (cachedImage != null) { - return cachedImage; - } - - SerializableImage image = getImage(); - if (Configuration.cacheImages.get()) { - cachedImage = image; - } - - return image; - } - - public InputStream getImageData() { - InputStream is = getOriginalImageData(); - if (is != null) { - return is; - } - - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ImageHelper.write(getImage().getBufferedImage(), getImageFormat(), baos); - return new ByteArrayInputStream(baos.toByteArray()); - } - - public static boolean hasErrorHeader(byte[] data) { - return hasErrorHeader(new ByteArrayRange(data)); - } - - public static boolean hasErrorHeader(ByteArrayRange data) { - if (data.getLength() > 4) { - if ((data.get(0) & 0xff) == 0xff && (data.get(1) & 0xff) == 0xd9 - && (data.get(2) & 0xff) == 0xff && (data.get(3) & 0xff) == 0xd8) { - return true; - } - } - return false; - } - - private SHAPEWITHSTYLE getShape() { - RECT rect = getRect(); - return getShape(rect, false); - } - - public SHAPEWITHSTYLE getShape(RECT rect, boolean fill) { - boolean translated = rect.Xmin != 0 || rect.Ymin != 0; - SHAPEWITHSTYLE shape = new SHAPEWITHSTYLE(); - shape.fillStyles = new FILLSTYLEARRAY(); - shape.fillStyles.fillStyles = new FILLSTYLE[1]; - FILLSTYLE fillStyle = new FILLSTYLE(); - fillStyle.fillStyleType = Configuration.shapeImportUseNonSmoothedFill.get() - ? FILLSTYLE.NON_SMOOTHED_REPEATING_BITMAP : FILLSTYLE.REPEATING_BITMAP; - fillStyle.bitmapId = getCharacterId(); - MATRIX matrix = new MATRIX(); - matrix.hasScale = true; - if (fill) { - RECT imageRect = getRect(); - matrix.scaleX = (int) ((((long) SWF.unitDivisor) << 16) * rect.getWidth() / imageRect.getWidth()); - matrix.scaleY = (int) ((((long) SWF.unitDivisor) << 16) * rect.getHeight() / imageRect.getHeight()); - } else { - matrix.scaleX = ((int) SWF.unitDivisor) << 16; - matrix.scaleY = matrix.scaleX; - } - if (translated) { - matrix.translateX = rect.Xmin; - matrix.translateY = rect.Ymin; - } - fillStyle.bitmapMatrix = matrix; - shape.fillStyles.fillStyles[0] = fillStyle; - - shape.lineStyles = new LINESTYLEARRAY(); - shape.lineStyles.lineStyles = new LINESTYLE[0]; - shape.shapeRecords = new ArrayList<>(); - StyleChangeRecord style = new StyleChangeRecord(); - style.stateFillStyle0 = true; - style.fillStyle0 = 1; - style.stateMoveTo = true; - if (translated) { - style.moveDeltaX = rect.Xmin; - style.moveDeltaY = rect.Ymin; - } - shape.shapeRecords.add(style); - StraightEdgeRecord top = new StraightEdgeRecord(); - top.generalLineFlag = true; - top.deltaX = rect.getWidth(); - StraightEdgeRecord right = new StraightEdgeRecord(); - right.generalLineFlag = true; - right.deltaY = rect.getHeight(); - StraightEdgeRecord bottom = new StraightEdgeRecord(); - bottom.generalLineFlag = true; - bottom.deltaX = -rect.getWidth(); - StraightEdgeRecord left = new StraightEdgeRecord(); - left.generalLineFlag = true; - left.deltaY = -rect.getHeight(); - shape.shapeRecords.add(top); - shape.shapeRecords.add(right); - shape.shapeRecords.add(bottom); - shape.shapeRecords.add(left); - shape.shapeRecords.add(new EndShapeRecord()); - return shape; - } - - @Override - public RECT getRect() { - return getRect(null); // parameter not used - } - - @Override - public RECT getRect(Set added) { - Dimension dimension = getImageDimension(); - int widthInTwips = (int) (dimension.getWidth() * SWF.unitDivisor); - int heightInTwips = (int) (dimension.getHeight() * SWF.unitDivisor); - return new RECT(0, widthInTwips, 0, heightInTwips); - } - - @Override - public int getUsedParameters() { - return 0; - } - - @Override - public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation, boolean stroked) { - return transformation.toTransform().createTransformedShape(getShape().getOutline(swf, stroked)); - } - - @Override - public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix strokeTransformation, Matrix absoluteTransformation, ColorTransform colorTransform) { - BitmapExporter.export(swf, getShape(), null, image, transformation, strokeTransformation, colorTransform); - } - - @Override - public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level) throws IOException { - SVGShapeExporter shapeExporter = new SVGShapeExporter(swf, getShape(), getCharacterId(), exporter, null, colorTransform, 1); - shapeExporter.export(); - } - - @Override - public void toHtmlCanvas(StringBuilder result, double unitDivisor) { - CanvasShapeExporter cse = new CanvasShapeExporter(null, unitDivisor, swf, getShape(), null, 0, 0); - cse.export(); - result.append(cse.getShapeData()); - } - - @Override - public int getNumFrames() { - return 1; - } - - @Override - public boolean isSingleFrame() { - return true; - } - - public void clearCache() { - cachedImage = null; - } - - @Override - public void getTagInfo(TagInfo tagInfo) { - super.getTagInfo(tagInfo); - Dimension dimension = getImageDimension(); - tagInfo.addInfo("general", "width", dimension.getWidth()); - tagInfo.addInfo("general", "height", dimension.getHeight()); - } - - @Override - public int getCharacterId() { - return characterID; - } - - @Override - public void setCharacterId(int characterId) { - this.characterID = characterId; - } -} +/* + * Copyright (C) 2010-2016 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags.base; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; +import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; +import com.jpexs.decompiler.flash.exporters.shape.BitmapExporter; +import com.jpexs.decompiler.flash.exporters.shape.CanvasShapeExporter; +import com.jpexs.decompiler.flash.exporters.shape.SVGShapeExporter; +import com.jpexs.decompiler.flash.helpers.ImageHelper; +import com.jpexs.decompiler.flash.tags.TagInfo; +import com.jpexs.decompiler.flash.tags.enums.ImageFormat; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.ColorTransform; +import com.jpexs.decompiler.flash.types.FILLSTYLE; +import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY; +import com.jpexs.decompiler.flash.types.LINESTYLE; +import com.jpexs.decompiler.flash.types.LINESTYLEARRAY; +import com.jpexs.decompiler.flash.types.MATRIX; +import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord; +import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord; +import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord; +import com.jpexs.helpers.ByteArrayRange; +import com.jpexs.helpers.SerializableImage; +import java.awt.Dimension; +import java.awt.Shape; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Set; + +/** + * + * @author JPEXS + */ +public abstract class ImageTag extends DrawableTag { + + @SWFType(BasicType.UI16) + public int characterID; + + protected SerializableImage cachedImage; + + public ImageTag(SWF swf, int id, String name, ByteArrayRange data) { + super(swf, id, name, data); + } + + public abstract InputStream getOriginalImageData(); + + protected abstract SerializableImage getImage(); + + public abstract Dimension getImageDimension(); + + public abstract void setImage(byte[] data) throws IOException; + + public abstract ImageFormat getImageFormat(); + + public abstract ImageFormat getOriginalImageFormat(); + + public boolean importSupported() { + return true; + } + + public static ImageFormat getImageFormat(byte[] data) { + return getImageFormat(new ByteArrayRange(data)); + } + + public static ImageFormat getImageFormat(ByteArrayRange data) { + if (hasErrorHeader(data)) { + return ImageFormat.JPEG; + } + + if (data.getLength() > 2 && ((data.get(0) & 0xff) == 0xff) && ((data.get(1) & 0xff) == 0xd8)) { + return ImageFormat.JPEG; + } + + if (data.getLength() > 6 && ((data.get(0) & 0xff) == 0x47) && ((data.get(1) & 0xff) == 0x49) && ((data.get(2) & 0xff) == 0x46) && ((data.get(3) & 0xff) == 0x38) && ((data.get(4) & 0xff) == 0x39) && ((data.get(5) & 0xff) == 0x61)) { + return ImageFormat.GIF; + } + + if (data.getLength() > 8 && ((data.get(0) & 0xff) == 0x89) && ((data.get(1) & 0xff) == 0x50) && ((data.get(2) & 0xff) == 0x4e) && ((data.get(3) & 0xff) == 0x47) && ((data.get(4) & 0xff) == 0x0d) && ((data.get(5) & 0xff) == 0x0a) && ((data.get(6) & 0xff) == 0x1a) && ((data.get(7) & 0xff) == 0x0a)) { + return ImageFormat.PNG; + } + + return ImageFormat.UNKNOWN; + } + + public SerializableImage getImageCached() { + if (cachedImage != null) { + return cachedImage; + } + + SerializableImage image = getImage(); + if (Configuration.cacheImages.get()) { + cachedImage = image; + } + + return image; + } + + public InputStream getImageData() { + InputStream is = getOriginalImageData(); + if (is != null) { + return is; + } + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ImageHelper.write(getImage().getBufferedImage(), getImageFormat(), baos); + return new ByteArrayInputStream(baos.toByteArray()); + } + + public static boolean hasErrorHeader(byte[] data) { + return hasErrorHeader(new ByteArrayRange(data)); + } + + public static boolean hasErrorHeader(ByteArrayRange data) { + if (data.getLength() > 4) { + if ((data.get(0) & 0xff) == 0xff && (data.get(1) & 0xff) == 0xd9 + && (data.get(2) & 0xff) == 0xff && (data.get(3) & 0xff) == 0xd8) { + return true; + } + } + return false; + } + + private SHAPEWITHSTYLE getShape() { + RECT rect = getRect(); + return getShape(rect, false); + } + + public SHAPEWITHSTYLE getShape(RECT rect, boolean fill) { + boolean translated = rect.Xmin != 0 || rect.Ymin != 0; + SHAPEWITHSTYLE shape = new SHAPEWITHSTYLE(); + shape.fillStyles = new FILLSTYLEARRAY(); + shape.fillStyles.fillStyles = new FILLSTYLE[1]; + FILLSTYLE fillStyle = new FILLSTYLE(); + fillStyle.fillStyleType = Configuration.shapeImportUseNonSmoothedFill.get() + ? FILLSTYLE.NON_SMOOTHED_REPEATING_BITMAP : FILLSTYLE.REPEATING_BITMAP; + fillStyle.bitmapId = getCharacterId(); + MATRIX matrix = new MATRIX(); + matrix.hasScale = true; + if (fill) { + RECT imageRect = getRect(); + matrix.scaleX = (int) ((((long) SWF.unitDivisor) << 16) * rect.getWidth() / imageRect.getWidth()); + matrix.scaleY = (int) ((((long) SWF.unitDivisor) << 16) * rect.getHeight() / imageRect.getHeight()); + } else { + matrix.scaleX = ((int) SWF.unitDivisor) << 16; + matrix.scaleY = matrix.scaleX; + } + if (translated) { + matrix.translateX = rect.Xmin; + matrix.translateY = rect.Ymin; + } + fillStyle.bitmapMatrix = matrix; + shape.fillStyles.fillStyles[0] = fillStyle; + + shape.lineStyles = new LINESTYLEARRAY(); + shape.lineStyles.lineStyles = new LINESTYLE[0]; + shape.shapeRecords = new ArrayList<>(); + StyleChangeRecord style = new StyleChangeRecord(); + style.stateFillStyle0 = true; + style.fillStyle0 = 1; + style.stateMoveTo = true; + if (translated) { + style.moveDeltaX = rect.Xmin; + style.moveDeltaY = rect.Ymin; + } + shape.shapeRecords.add(style); + StraightEdgeRecord top = new StraightEdgeRecord(); + top.generalLineFlag = true; + top.deltaX = rect.getWidth(); + StraightEdgeRecord right = new StraightEdgeRecord(); + right.generalLineFlag = true; + right.deltaY = rect.getHeight(); + StraightEdgeRecord bottom = new StraightEdgeRecord(); + bottom.generalLineFlag = true; + bottom.deltaX = -rect.getWidth(); + StraightEdgeRecord left = new StraightEdgeRecord(); + left.generalLineFlag = true; + left.deltaY = -rect.getHeight(); + shape.shapeRecords.add(top); + shape.shapeRecords.add(right); + shape.shapeRecords.add(bottom); + shape.shapeRecords.add(left); + shape.shapeRecords.add(new EndShapeRecord()); + return shape; + } + + @Override + public RECT getRect() { + return getRect(null); // parameter not used + } + + @Override + public RECT getRect(Set added) { + Dimension dimension = getImageDimension(); + int widthInTwips = (int) (dimension.getWidth() * SWF.unitDivisor); + int heightInTwips = (int) (dimension.getHeight() * SWF.unitDivisor); + return new RECT(0, widthInTwips, 0, heightInTwips); + } + + @Override + public int getUsedParameters() { + return 0; + } + + @Override + public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation, boolean stroked) { + return transformation.toTransform().createTransformedShape(getShape().getOutline(swf, stroked)); + } + + @Override + public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix strokeTransformation, Matrix absoluteTransformation, ColorTransform colorTransform) { + BitmapExporter.export(swf, getShape(), null, image, transformation, strokeTransformation, colorTransform); + } + + @Override + public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level) throws IOException { + SVGShapeExporter shapeExporter = new SVGShapeExporter(swf, getShape(), getCharacterId(), exporter, null, colorTransform, 1); + shapeExporter.export(); + } + + @Override + public void toHtmlCanvas(StringBuilder result, double unitDivisor) { + CanvasShapeExporter cse = new CanvasShapeExporter(null, unitDivisor, swf, getShape(), null, 0, 0); + cse.export(); + result.append(cse.getShapeData()); + } + + @Override + public int getNumFrames() { + return 1; + } + + @Override + public boolean isSingleFrame() { + return true; + } + + public void clearCache() { + cachedImage = null; + } + + @Override + public void getTagInfo(TagInfo tagInfo) { + super.getTagInfo(tagInfo); + Dimension dimension = getImageDimension(); + tagInfo.addInfo("general", "width", dimension.getWidth()); + tagInfo.addInfo("general", "height", dimension.getHeight()); + } + + @Override + public int getCharacterId() { + return characterID; + } + + @Override + public void setCharacterId(int characterId) { + this.characterID = characterId; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/MorphShapeTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/MorphShapeTag.java index a1061bed5..fe8438a83 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/MorphShapeTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/MorphShapeTag.java @@ -1,327 +1,327 @@ -/* - * Copyright (C) 2010-2016 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags.base; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; -import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; -import com.jpexs.decompiler.flash.exporters.morphshape.CanvasMorphShapeExporter; -import com.jpexs.decompiler.flash.exporters.morphshape.SVGMorphShapeExporter; -import com.jpexs.decompiler.flash.exporters.shape.BitmapExporter; -import com.jpexs.decompiler.flash.exporters.shape.SVGShapeExporter; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.ColorTransform; -import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY; -import com.jpexs.decompiler.flash.types.LINESTYLEARRAY; -import com.jpexs.decompiler.flash.types.MORPHFILLSTYLEARRAY; -import com.jpexs.decompiler.flash.types.MORPHLINESTYLEARRAY; -import com.jpexs.decompiler.flash.types.RECT; -import com.jpexs.decompiler.flash.types.SHAPE; -import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.decompiler.flash.types.shaperecords.CurvedEdgeRecord; -import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord; -import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD; -import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord; -import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord; -import com.jpexs.helpers.ByteArrayRange; -import com.jpexs.helpers.SerializableImage; -import java.awt.Shape; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -/** - * - * @author JPEXS - */ -public abstract class MorphShapeTag extends DrawableTag { - - public static final int MAX_RATIO = 65535; - - @SWFType(BasicType.UI16) - public int characterId; - - public RECT startBounds; - - public RECT endBounds; - - public MORPHFILLSTYLEARRAY morphFillStyles; - - public MORPHLINESTYLEARRAY morphLineStyles; - - public SHAPE startEdges; - - public SHAPE endEdges; - - public MorphShapeTag(SWF swf, int id, String name, ByteArrayRange data) { - super(swf, id, name, data); - } - - public abstract int getShapeNum(); - - @Override - public RECT getRect() { - return getRect(new HashSet<>()); - } - - @Override - public void getNeededCharacters(Set needed) { - morphFillStyles.getNeededCharacters(needed); - startEdges.getNeededCharacters(needed); - endEdges.getNeededCharacters(needed); - } - - @Override - public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { - boolean modified = false; - modified |= morphFillStyles.replaceCharacter(oldCharacterId, newCharacterId); - modified |= startEdges.replaceCharacter(oldCharacterId, newCharacterId); - modified |= endEdges.replaceCharacter(oldCharacterId, newCharacterId); - if (modified) { - setModified(true); - } - return modified; - } - - @Override - public boolean removeCharacter(int characterId) { - boolean modified = false; - modified |= morphFillStyles.removeCharacter(characterId); - modified |= startEdges.removeCharacter(characterId); - modified |= endEdges.removeCharacter(characterId); - if (modified) { - setModified(true); - } - return modified; - } - - @Override - public int getCharacterId() { - return characterId; - } - - @Override - public void setCharacterId(int characterId) { - this.characterId = characterId; - } - - @Override - public RECT getRect(Set added) { - RECT rect = new RECT(); - rect.Xmin = Math.min(startBounds.Xmin, endBounds.Xmin); - rect.Ymin = Math.min(startBounds.Ymin, endBounds.Ymin); - rect.Xmax = Math.max(startBounds.Xmax, endBounds.Xmax); - rect.Ymax = Math.max(startBounds.Ymax, endBounds.Ymax); - return rect; - } - - public RECT getStartBounds() { - return startBounds; - } - - public RECT getEndBounds() { - return endBounds; - } - - public MORPHFILLSTYLEARRAY getFillStyles() { - return morphFillStyles; - } - - public MORPHLINESTYLEARRAY getLineStyles() { - return morphLineStyles; - } - - public SHAPE getStartEdges() { - return startEdges; - } - - public SHAPE getEndEdges() { - return endEdges; - } - - public SHAPEWITHSTYLE getShapeAtRatio(int ratio) { - List finalRecords = new ArrayList<>(); - FILLSTYLEARRAY fillStyles = morphFillStyles.getFillStylesAt(ratio); - LINESTYLEARRAY lineStyles = morphLineStyles.getLineStylesAt(getShapeNum(), ratio); - - int startPosX = 0, startPosY = 0; - int endPosX = 0, endPosY = 0; - int posX = 0, posY = 0; - - for (int startIndex = 0, endIndex = 0; - startIndex < startEdges.shapeRecords.size() - && endIndex < endEdges.shapeRecords.size(); startIndex++, endIndex++) { - - SHAPERECORD edge1 = startEdges.shapeRecords.get(startIndex); - SHAPERECORD edge2 = endEdges.shapeRecords.get(endIndex); - if (edge1 instanceof StyleChangeRecord || edge2 instanceof StyleChangeRecord) { - StyleChangeRecord scr1; - if (edge1 instanceof StyleChangeRecord) { - scr1 = (StyleChangeRecord) edge1; - if (scr1.stateMoveTo) { - startPosX = scr1.moveDeltaX; - startPosY = scr1.moveDeltaY; - } - } else { - scr1 = new StyleChangeRecord(); - startIndex--; - } - StyleChangeRecord scr2; - if (edge2 instanceof StyleChangeRecord) { - scr2 = (StyleChangeRecord) edge2; - if (scr2.stateMoveTo) { - endPosX = scr2.moveDeltaX; - endPosY = scr2.moveDeltaY; - } - } else { - scr2 = new StyleChangeRecord(); - endIndex--; - } - StyleChangeRecord scr = scr1.clone(); - if (scr1.stateMoveTo || scr2.stateMoveTo) { - scr.moveDeltaX = startPosX + (endPosX - startPosX) * ratio / MAX_RATIO; - scr.moveDeltaY = startPosY + (endPosY - startPosY) * ratio / MAX_RATIO; - scr.stateMoveTo = scr.moveDeltaX != posX || scr.moveDeltaY != posY; - } - finalRecords.add(scr); - continue; - } - - if (edge1 instanceof EndShapeRecord) { - finalRecords.add(edge1); - break; - } - if (edge2 instanceof EndShapeRecord) { - finalRecords.add(edge2); - break; - } - - if (edge1 instanceof CurvedEdgeRecord || edge2 instanceof CurvedEdgeRecord) { - CurvedEdgeRecord cer1 = null; - if (edge1 instanceof CurvedEdgeRecord) { - cer1 = (CurvedEdgeRecord) edge1; - } else if (edge1 instanceof StraightEdgeRecord) { - cer1 = SHAPERECORD.straightToCurve((StraightEdgeRecord) edge1); - } - CurvedEdgeRecord cer2 = null; - if (edge2 instanceof CurvedEdgeRecord) { - cer2 = (CurvedEdgeRecord) edge2; - } else if (edge2 instanceof StraightEdgeRecord) { - cer2 = SHAPERECORD.straightToCurve((StraightEdgeRecord) edge2); - } - if ((cer2 == null) || (cer1 == null)) { - continue; - } - CurvedEdgeRecord cer = new CurvedEdgeRecord(); - cer.controlDeltaX = cer1.controlDeltaX + (cer2.controlDeltaX - cer1.controlDeltaX) * ratio / MAX_RATIO; - cer.controlDeltaY = cer1.controlDeltaY + (cer2.controlDeltaY - cer1.controlDeltaY) * ratio / MAX_RATIO; - cer.anchorDeltaX = cer1.anchorDeltaX + (cer2.anchorDeltaX - cer1.anchorDeltaX) * ratio / MAX_RATIO; - cer.anchorDeltaY = cer1.anchorDeltaY + (cer2.anchorDeltaY - cer1.anchorDeltaY) * ratio / MAX_RATIO; - startPosX += cer1.controlDeltaX + cer1.anchorDeltaX; - startPosY += cer1.controlDeltaY + cer1.anchorDeltaY; - endPosX += cer2.controlDeltaX + cer2.anchorDeltaX; - endPosY += cer2.controlDeltaY + cer2.anchorDeltaY; - posX += cer.controlDeltaX + cer.anchorDeltaX; - posY += cer.controlDeltaY + cer.anchorDeltaY; - finalRecords.add(cer); - } else { - StraightEdgeRecord ser1 = null; - if (edge1 instanceof StraightEdgeRecord) { - ser1 = (StraightEdgeRecord) edge1; - } - StraightEdgeRecord ser2 = null; - if (edge2 instanceof StraightEdgeRecord) { - ser2 = (StraightEdgeRecord) edge2; - } - if ((ser2 == null) || (ser1 == null)) { - continue; - } - StraightEdgeRecord ser = new StraightEdgeRecord(); - ser.generalLineFlag = true; - ser.vertLineFlag = false; - ser.deltaX = ser1.deltaX + (ser2.deltaX - ser1.deltaX) * ratio / MAX_RATIO; - ser.deltaY = ser1.deltaY + (ser2.deltaY - ser1.deltaY) * ratio / MAX_RATIO; - startPosX += ser1.deltaX; - startPosY += ser1.deltaY; - endPosX += ser2.deltaX; - endPosY += ser2.deltaY; - posX += ser.deltaX; - posY += ser.deltaX; - finalRecords.add(ser); - } - } - SHAPEWITHSTYLE shape = new SHAPEWITHSTYLE(); - shape.fillStyles = fillStyles; - shape.lineStyles = lineStyles; - shape.shapeRecords = finalRecords; - return shape; - } - - @Override - public int getUsedParameters() { - return PARAMETER_RATIO; - } - - @Override - public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix strokeTransformation, Matrix absoluteTransformation, ColorTransform colorTransform) { - SHAPEWITHSTYLE shape = getShapeAtRatio(ratio); - // morphShape using shapeNum=3, morphShape2 using shapeNum=4 - // todo: Currently the generated image is not cached, because the cache - // key contains the hashCode of the finalRecord object, and it is always - // recreated - BitmapExporter.export(swf, shape, null, image, transformation, strokeTransformation, colorTransform); - } - - @Override - public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level) { - if (ratio == -2) { - SHAPEWITHSTYLE beginShapes = getShapeAtRatio(0); - SHAPEWITHSTYLE endShapes = getShapeAtRatio(65535); - SVGMorphShapeExporter shapeExporter = new SVGMorphShapeExporter(swf, beginShapes, endShapes, getCharacterId(), exporter, null, colorTransform, 1); - shapeExporter.export(); - } else { - SHAPEWITHSTYLE shapes = getShapeAtRatio(ratio); - SVGShapeExporter shapeExporter = new SVGShapeExporter(swf, shapes, getCharacterId(), exporter, null, colorTransform, 1); - shapeExporter.export(); - } - } - - @Override - public int getNumFrames() { - return 65536; - } - - @Override - public boolean isSingleFrame() { - // Morpshape is a single frame specified with the ratio - return true; - } - - @Override - public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation, boolean stroked) { - return transformation.toTransform().createTransformedShape(getShapeAtRatio(ratio).getOutline(swf, stroked)); - } - - @Override - public void toHtmlCanvas(StringBuilder result, double unitDivisor) { - CanvasMorphShapeExporter cmse = new CanvasMorphShapeExporter(swf, getShapeAtRatio(0), getShapeAtRatio(MAX_RATIO), null, unitDivisor, 0, 0); - cmse.export(); - result.append(cmse.getShapeData()); - } -} +/* + * Copyright (C) 2010-2016 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags.base; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; +import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; +import com.jpexs.decompiler.flash.exporters.morphshape.CanvasMorphShapeExporter; +import com.jpexs.decompiler.flash.exporters.morphshape.SVGMorphShapeExporter; +import com.jpexs.decompiler.flash.exporters.shape.BitmapExporter; +import com.jpexs.decompiler.flash.exporters.shape.SVGShapeExporter; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.ColorTransform; +import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY; +import com.jpexs.decompiler.flash.types.LINESTYLEARRAY; +import com.jpexs.decompiler.flash.types.MORPHFILLSTYLEARRAY; +import com.jpexs.decompiler.flash.types.MORPHLINESTYLEARRAY; +import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.decompiler.flash.types.SHAPE; +import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.decompiler.flash.types.shaperecords.CurvedEdgeRecord; +import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord; +import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD; +import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord; +import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord; +import com.jpexs.helpers.ByteArrayRange; +import com.jpexs.helpers.SerializableImage; +import java.awt.Shape; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * + * @author JPEXS + */ +public abstract class MorphShapeTag extends DrawableTag { + + public static final int MAX_RATIO = 65535; + + @SWFType(BasicType.UI16) + public int characterId; + + public RECT startBounds; + + public RECT endBounds; + + public MORPHFILLSTYLEARRAY morphFillStyles; + + public MORPHLINESTYLEARRAY morphLineStyles; + + public SHAPE startEdges; + + public SHAPE endEdges; + + public MorphShapeTag(SWF swf, int id, String name, ByteArrayRange data) { + super(swf, id, name, data); + } + + public abstract int getShapeNum(); + + @Override + public RECT getRect() { + return getRect(new HashSet<>()); + } + + @Override + public void getNeededCharacters(Set needed) { + morphFillStyles.getNeededCharacters(needed); + startEdges.getNeededCharacters(needed); + endEdges.getNeededCharacters(needed); + } + + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + boolean modified = false; + modified |= morphFillStyles.replaceCharacter(oldCharacterId, newCharacterId); + modified |= startEdges.replaceCharacter(oldCharacterId, newCharacterId); + modified |= endEdges.replaceCharacter(oldCharacterId, newCharacterId); + if (modified) { + setModified(true); + } + return modified; + } + + @Override + public boolean removeCharacter(int characterId) { + boolean modified = false; + modified |= morphFillStyles.removeCharacter(characterId); + modified |= startEdges.removeCharacter(characterId); + modified |= endEdges.removeCharacter(characterId); + if (modified) { + setModified(true); + } + return modified; + } + + @Override + public int getCharacterId() { + return characterId; + } + + @Override + public void setCharacterId(int characterId) { + this.characterId = characterId; + } + + @Override + public RECT getRect(Set added) { + RECT rect = new RECT(); + rect.Xmin = Math.min(startBounds.Xmin, endBounds.Xmin); + rect.Ymin = Math.min(startBounds.Ymin, endBounds.Ymin); + rect.Xmax = Math.max(startBounds.Xmax, endBounds.Xmax); + rect.Ymax = Math.max(startBounds.Ymax, endBounds.Ymax); + return rect; + } + + public RECT getStartBounds() { + return startBounds; + } + + public RECT getEndBounds() { + return endBounds; + } + + public MORPHFILLSTYLEARRAY getFillStyles() { + return morphFillStyles; + } + + public MORPHLINESTYLEARRAY getLineStyles() { + return morphLineStyles; + } + + public SHAPE getStartEdges() { + return startEdges; + } + + public SHAPE getEndEdges() { + return endEdges; + } + + public SHAPEWITHSTYLE getShapeAtRatio(int ratio) { + List finalRecords = new ArrayList<>(); + FILLSTYLEARRAY fillStyles = morphFillStyles.getFillStylesAt(ratio); + LINESTYLEARRAY lineStyles = morphLineStyles.getLineStylesAt(getShapeNum(), ratio); + + int startPosX = 0, startPosY = 0; + int endPosX = 0, endPosY = 0; + int posX = 0, posY = 0; + + for (int startIndex = 0, endIndex = 0; + startIndex < startEdges.shapeRecords.size() + && endIndex < endEdges.shapeRecords.size(); startIndex++, endIndex++) { + + SHAPERECORD edge1 = startEdges.shapeRecords.get(startIndex); + SHAPERECORD edge2 = endEdges.shapeRecords.get(endIndex); + if (edge1 instanceof StyleChangeRecord || edge2 instanceof StyleChangeRecord) { + StyleChangeRecord scr1; + if (edge1 instanceof StyleChangeRecord) { + scr1 = (StyleChangeRecord) edge1; + if (scr1.stateMoveTo) { + startPosX = scr1.moveDeltaX; + startPosY = scr1.moveDeltaY; + } + } else { + scr1 = new StyleChangeRecord(); + startIndex--; + } + StyleChangeRecord scr2; + if (edge2 instanceof StyleChangeRecord) { + scr2 = (StyleChangeRecord) edge2; + if (scr2.stateMoveTo) { + endPosX = scr2.moveDeltaX; + endPosY = scr2.moveDeltaY; + } + } else { + scr2 = new StyleChangeRecord(); + endIndex--; + } + StyleChangeRecord scr = scr1.clone(); + if (scr1.stateMoveTo || scr2.stateMoveTo) { + scr.moveDeltaX = startPosX + (endPosX - startPosX) * ratio / MAX_RATIO; + scr.moveDeltaY = startPosY + (endPosY - startPosY) * ratio / MAX_RATIO; + scr.stateMoveTo = scr.moveDeltaX != posX || scr.moveDeltaY != posY; + } + finalRecords.add(scr); + continue; + } + + if (edge1 instanceof EndShapeRecord) { + finalRecords.add(edge1); + break; + } + if (edge2 instanceof EndShapeRecord) { + finalRecords.add(edge2); + break; + } + + if (edge1 instanceof CurvedEdgeRecord || edge2 instanceof CurvedEdgeRecord) { + CurvedEdgeRecord cer1 = null; + if (edge1 instanceof CurvedEdgeRecord) { + cer1 = (CurvedEdgeRecord) edge1; + } else if (edge1 instanceof StraightEdgeRecord) { + cer1 = SHAPERECORD.straightToCurve((StraightEdgeRecord) edge1); + } + CurvedEdgeRecord cer2 = null; + if (edge2 instanceof CurvedEdgeRecord) { + cer2 = (CurvedEdgeRecord) edge2; + } else if (edge2 instanceof StraightEdgeRecord) { + cer2 = SHAPERECORD.straightToCurve((StraightEdgeRecord) edge2); + } + if ((cer2 == null) || (cer1 == null)) { + continue; + } + CurvedEdgeRecord cer = new CurvedEdgeRecord(); + cer.controlDeltaX = cer1.controlDeltaX + (cer2.controlDeltaX - cer1.controlDeltaX) * ratio / MAX_RATIO; + cer.controlDeltaY = cer1.controlDeltaY + (cer2.controlDeltaY - cer1.controlDeltaY) * ratio / MAX_RATIO; + cer.anchorDeltaX = cer1.anchorDeltaX + (cer2.anchorDeltaX - cer1.anchorDeltaX) * ratio / MAX_RATIO; + cer.anchorDeltaY = cer1.anchorDeltaY + (cer2.anchorDeltaY - cer1.anchorDeltaY) * ratio / MAX_RATIO; + startPosX += cer1.controlDeltaX + cer1.anchorDeltaX; + startPosY += cer1.controlDeltaY + cer1.anchorDeltaY; + endPosX += cer2.controlDeltaX + cer2.anchorDeltaX; + endPosY += cer2.controlDeltaY + cer2.anchorDeltaY; + posX += cer.controlDeltaX + cer.anchorDeltaX; + posY += cer.controlDeltaY + cer.anchorDeltaY; + finalRecords.add(cer); + } else { + StraightEdgeRecord ser1 = null; + if (edge1 instanceof StraightEdgeRecord) { + ser1 = (StraightEdgeRecord) edge1; + } + StraightEdgeRecord ser2 = null; + if (edge2 instanceof StraightEdgeRecord) { + ser2 = (StraightEdgeRecord) edge2; + } + if ((ser2 == null) || (ser1 == null)) { + continue; + } + StraightEdgeRecord ser = new StraightEdgeRecord(); + ser.generalLineFlag = true; + ser.vertLineFlag = false; + ser.deltaX = ser1.deltaX + (ser2.deltaX - ser1.deltaX) * ratio / MAX_RATIO; + ser.deltaY = ser1.deltaY + (ser2.deltaY - ser1.deltaY) * ratio / MAX_RATIO; + startPosX += ser1.deltaX; + startPosY += ser1.deltaY; + endPosX += ser2.deltaX; + endPosY += ser2.deltaY; + posX += ser.deltaX; + posY += ser.deltaX; + finalRecords.add(ser); + } + } + SHAPEWITHSTYLE shape = new SHAPEWITHSTYLE(); + shape.fillStyles = fillStyles; + shape.lineStyles = lineStyles; + shape.shapeRecords = finalRecords; + return shape; + } + + @Override + public int getUsedParameters() { + return PARAMETER_RATIO; + } + + @Override + public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix strokeTransformation, Matrix absoluteTransformation, ColorTransform colorTransform) { + SHAPEWITHSTYLE shape = getShapeAtRatio(ratio); + // morphShape using shapeNum=3, morphShape2 using shapeNum=4 + // todo: Currently the generated image is not cached, because the cache + // key contains the hashCode of the finalRecord object, and it is always + // recreated + BitmapExporter.export(swf, shape, null, image, transformation, strokeTransformation, colorTransform); + } + + @Override + public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level) { + if (ratio == -2) { + SHAPEWITHSTYLE beginShapes = getShapeAtRatio(0); + SHAPEWITHSTYLE endShapes = getShapeAtRatio(65535); + SVGMorphShapeExporter shapeExporter = new SVGMorphShapeExporter(swf, beginShapes, endShapes, getCharacterId(), exporter, null, colorTransform, 1); + shapeExporter.export(); + } else { + SHAPEWITHSTYLE shapes = getShapeAtRatio(ratio); + SVGShapeExporter shapeExporter = new SVGShapeExporter(swf, shapes, getCharacterId(), exporter, null, colorTransform, 1); + shapeExporter.export(); + } + } + + @Override + public int getNumFrames() { + return 65536; + } + + @Override + public boolean isSingleFrame() { + // Morpshape is a single frame specified with the ratio + return true; + } + + @Override + public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation, boolean stroked) { + return transformation.toTransform().createTransformedShape(getShapeAtRatio(ratio).getOutline(swf, stroked)); + } + + @Override + public void toHtmlCanvas(StringBuilder result, double unitDivisor) { + CanvasMorphShapeExporter cmse = new CanvasMorphShapeExporter(swf, getShapeAtRatio(0), getShapeAtRatio(MAX_RATIO), null, unitDivisor, 0, 0); + cmse.export(); + result.append(cmse.getShapeData()); + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ShapeTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ShapeTag.java index e8aacc204..0b2132a18 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ShapeTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ShapeTag.java @@ -1,213 +1,213 @@ -/* - * Copyright (C) 2010-2016 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags.base; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; -import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; -import com.jpexs.decompiler.flash.exporters.shape.BitmapExporter; -import com.jpexs.decompiler.flash.exporters.shape.CanvasShapeExporter; -import com.jpexs.decompiler.flash.exporters.shape.PathExporter; -import com.jpexs.decompiler.flash.exporters.shape.SVGShapeExporter; -import com.jpexs.decompiler.flash.helpers.LazyObject; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.ColorTransform; -import com.jpexs.decompiler.flash.types.RECT; -import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.helpers.ByteArrayRange; -import com.jpexs.helpers.SerializableImage; -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.Shape; -import java.awt.geom.AffineTransform; -import java.awt.geom.GeneralPath; -import java.awt.geom.PathIterator; -import java.io.IOException; -import java.util.List; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - * @author JPEXS - */ -public abstract class ShapeTag extends DrawableTag implements LazyObject { - - @SWFType(BasicType.UI16) - public int shapeId; - - public RECT shapeBounds; - - public SHAPEWITHSTYLE shapes; - - protected ByteArrayRange shapeData; - - private final int markerSize = 10; - - public ShapeTag(SWF swf, int id, String name, ByteArrayRange data) { - super(swf, id, name, data); - } - - @Override - public void load() { - getShapes(); - } - - public abstract int getShapeNum(); - - public SHAPEWITHSTYLE getShapes() { - if (shapes == null && shapeData != null) { - try { - SWFInputStream sis = new SWFInputStream(swf, shapeData.getArray(), 0, shapeData.getPos() + shapeData.getLength()); - sis.seek(shapeData.getPos()); - shapes = sis.readSHAPEWITHSTYLE(getShapeNum(), false, "shapes"); - shapeData = null; // not needed anymore, give it to GC - } catch (IOException ex) { - Logger.getLogger(ShapeTag.class.getName()).log(Level.SEVERE, null, ex); - } - } - - return shapes; - } - - @Override - public void getNeededCharacters(Set needed) { - SHAPEWITHSTYLE shapes = getShapes(); - if (shapes != null) { - getShapes().getNeededCharacters(needed); - } - } - - @Override - public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { - boolean modified = getShapes().replaceCharacter(oldCharacterId, newCharacterId); - if (modified) { - setModified(true); - } - return modified; - } - - @Override - public boolean removeCharacter(int characterId) { - boolean modified = getShapes().removeCharacter(characterId); - if (modified) { - setModified(true); - } - return modified; - } - - @Override - public RECT getRect(Set added) { - return shapeBounds; - } - - @Override - public RECT getRect() { - return getRect(null); // parameter not used - } - - @Override - public int getUsedParameters() { - return 0; - } - - @Override - public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation, boolean stroked) { - return transformation.toTransform().createTransformedShape(getShapes().getOutline(swf, stroked)); - } - - @Override - public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix strokeTransformation, Matrix absoluteTransformation, ColorTransform colorTransform) { - BitmapExporter.export(swf, getShapes(), null, image, transformation, strokeTransformation, colorTransform); - if (Configuration._debugMode.get()) { // show control points - List paths = PathExporter.export(swf, getShapes()); - double[] coords = new double[6]; - AffineTransform at = transformation.toTransform(); - at.preConcatenate(AffineTransform.getScaleInstance(1 / SWF.unitDivisor, 1 / SWF.unitDivisor)); - - // get the graphics from the inner image object, because it creates a new Graphics object - Graphics2D graphics = (Graphics2D) image.getBufferedImage().getGraphics(); - graphics.setPaint(Color.black); - for (GeneralPath path : paths) { - PathIterator iterator = path.getPathIterator(at); - while (!iterator.isDone()) { - int type = iterator.currentSegment(coords); - double x = coords[0]; - double y = coords[1]; - switch (type) { - case PathIterator.SEG_MOVETO: - graphics.drawRect((int) (x - markerSize / 2), (int) (y - markerSize / 2), markerSize, markerSize); - break; - case PathIterator.SEG_LINETO: - graphics.drawRect((int) (x - markerSize / 2), (int) (y - markerSize / 2), markerSize, markerSize); - break; - case PathIterator.SEG_QUADTO: - graphics.drawRect((int) (x - markerSize / 2), (int) (y - markerSize / 2), markerSize, markerSize); - x = coords[2]; - y = coords[3]; - graphics.drawRect((int) (x - markerSize / 2), (int) (y - markerSize / 2), markerSize, markerSize); - break; - case PathIterator.SEG_CUBICTO: - System.out.print("CUBICTO NOT SUPPORTED. "); - break; - case PathIterator.SEG_CLOSE: - System.out.print("CLOSE NOT SUPPORTED. "); - break; - } - iterator.next(); - } - } - } - } - - @Override - public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level) throws IOException { - SVGShapeExporter shapeExporter = new SVGShapeExporter(swf, getShapes(), getCharacterId(), exporter, null, colorTransform, 1); - shapeExporter.export(); - } - - @Override - public void toHtmlCanvas(StringBuilder result, double unitDivisor) { - CanvasShapeExporter cse = new CanvasShapeExporter(null, unitDivisor, swf, getShapes(), null, 0, 0); - cse.export(); - result.append(cse.getShapeData()); - } - - @Override - public int getNumFrames() { - return 1; - } - - @Override - public boolean isSingleFrame() { - return true; - } - - @Override - public int getCharacterId() { - return shapeId; - } - - @Override - public void setCharacterId(int characterId) { - this.shapeId = characterId; - } -} +/* + * Copyright (C) 2010-2016 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags.base; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; +import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; +import com.jpexs.decompiler.flash.exporters.shape.BitmapExporter; +import com.jpexs.decompiler.flash.exporters.shape.CanvasShapeExporter; +import com.jpexs.decompiler.flash.exporters.shape.PathExporter; +import com.jpexs.decompiler.flash.exporters.shape.SVGShapeExporter; +import com.jpexs.decompiler.flash.helpers.LazyObject; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.ColorTransform; +import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.helpers.ByteArrayRange; +import com.jpexs.helpers.SerializableImage; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.GeneralPath; +import java.awt.geom.PathIterator; +import java.io.IOException; +import java.util.List; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author JPEXS + */ +public abstract class ShapeTag extends DrawableTag implements LazyObject { + + @SWFType(BasicType.UI16) + public int shapeId; + + public RECT shapeBounds; + + public SHAPEWITHSTYLE shapes; + + protected ByteArrayRange shapeData; + + private final int markerSize = 10; + + public ShapeTag(SWF swf, int id, String name, ByteArrayRange data) { + super(swf, id, name, data); + } + + @Override + public void load() { + getShapes(); + } + + public abstract int getShapeNum(); + + public SHAPEWITHSTYLE getShapes() { + if (shapes == null && shapeData != null) { + try { + SWFInputStream sis = new SWFInputStream(swf, shapeData.getArray(), 0, shapeData.getPos() + shapeData.getLength()); + sis.seek(shapeData.getPos()); + shapes = sis.readSHAPEWITHSTYLE(getShapeNum(), false, "shapes"); + shapeData = null; // not needed anymore, give it to GC + } catch (IOException ex) { + Logger.getLogger(ShapeTag.class.getName()).log(Level.SEVERE, null, ex); + } + } + + return shapes; + } + + @Override + public void getNeededCharacters(Set needed) { + SHAPEWITHSTYLE shapes = getShapes(); + if (shapes != null) { + getShapes().getNeededCharacters(needed); + } + } + + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + boolean modified = getShapes().replaceCharacter(oldCharacterId, newCharacterId); + if (modified) { + setModified(true); + } + return modified; + } + + @Override + public boolean removeCharacter(int characterId) { + boolean modified = getShapes().removeCharacter(characterId); + if (modified) { + setModified(true); + } + return modified; + } + + @Override + public RECT getRect(Set added) { + return shapeBounds; + } + + @Override + public RECT getRect() { + return getRect(null); // parameter not used + } + + @Override + public int getUsedParameters() { + return 0; + } + + @Override + public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation, boolean stroked) { + return transformation.toTransform().createTransformedShape(getShapes().getOutline(swf, stroked)); + } + + @Override + public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix strokeTransformation, Matrix absoluteTransformation, ColorTransform colorTransform) { + BitmapExporter.export(swf, getShapes(), null, image, transformation, strokeTransformation, colorTransform); + if (Configuration._debugMode.get()) { // show control points + List paths = PathExporter.export(swf, getShapes()); + double[] coords = new double[6]; + AffineTransform at = transformation.toTransform(); + at.preConcatenate(AffineTransform.getScaleInstance(1 / SWF.unitDivisor, 1 / SWF.unitDivisor)); + + // get the graphics from the inner image object, because it creates a new Graphics object + Graphics2D graphics = (Graphics2D) image.getBufferedImage().getGraphics(); + graphics.setPaint(Color.black); + for (GeneralPath path : paths) { + PathIterator iterator = path.getPathIterator(at); + while (!iterator.isDone()) { + int type = iterator.currentSegment(coords); + double x = coords[0]; + double y = coords[1]; + switch (type) { + case PathIterator.SEG_MOVETO: + graphics.drawRect((int) (x - markerSize / 2), (int) (y - markerSize / 2), markerSize, markerSize); + break; + case PathIterator.SEG_LINETO: + graphics.drawRect((int) (x - markerSize / 2), (int) (y - markerSize / 2), markerSize, markerSize); + break; + case PathIterator.SEG_QUADTO: + graphics.drawRect((int) (x - markerSize / 2), (int) (y - markerSize / 2), markerSize, markerSize); + x = coords[2]; + y = coords[3]; + graphics.drawRect((int) (x - markerSize / 2), (int) (y - markerSize / 2), markerSize, markerSize); + break; + case PathIterator.SEG_CUBICTO: + System.out.print("CUBICTO NOT SUPPORTED. "); + break; + case PathIterator.SEG_CLOSE: + System.out.print("CLOSE NOT SUPPORTED. "); + break; + } + iterator.next(); + } + } + } + } + + @Override + public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level) throws IOException { + SVGShapeExporter shapeExporter = new SVGShapeExporter(swf, getShapes(), getCharacterId(), exporter, null, colorTransform, 1); + shapeExporter.export(); + } + + @Override + public void toHtmlCanvas(StringBuilder result, double unitDivisor) { + CanvasShapeExporter cse = new CanvasShapeExporter(null, unitDivisor, swf, getShapes(), null, 0, 0); + cse.export(); + result.append(cse.getShapeData()); + } + + @Override + public int getNumFrames() { + return 1; + } + + @Override + public boolean isSingleFrame() { + return true; + } + + @Override + public int getCharacterId() { + return shapeId; + } + + @Override + public void setCharacterId(int characterId) { + this.shapeId = characterId; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/TextTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/TextTag.java index 2fec40855..f743c20ea 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/TextTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/TextTag.java @@ -1,785 +1,785 @@ -/* - * Copyright (C) 2010-2016 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags.base; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.decompiler.flash.exporters.FontExporter; -import com.jpexs.decompiler.flash.exporters.commonshape.ExportRectangle; -import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; -import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; -import com.jpexs.decompiler.flash.exporters.modes.FontExportMode; -import com.jpexs.decompiler.flash.exporters.shape.BitmapExporter; -import com.jpexs.decompiler.flash.exporters.shape.CanvasShapeExporter; -import com.jpexs.decompiler.flash.exporters.shape.SVGShapeExporter; -import com.jpexs.decompiler.flash.helpers.HighlightedText; -import com.jpexs.decompiler.flash.importers.TextImportResizeTextBoundsMode; -import com.jpexs.decompiler.flash.tags.text.JustifyAlignGlyphEntry; -import com.jpexs.decompiler.flash.tags.text.TextAlign; -import com.jpexs.decompiler.flash.tags.text.TextParseException; -import com.jpexs.decompiler.flash.types.ColorTransform; -import com.jpexs.decompiler.flash.types.DynamicTextGlyphEntry; -import com.jpexs.decompiler.flash.types.FILLSTYLE; -import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY; -import com.jpexs.decompiler.flash.types.GLYPHENTRY; -import com.jpexs.decompiler.flash.types.LINESTYLE; -import com.jpexs.decompiler.flash.types.LINESTYLEARRAY; -import com.jpexs.decompiler.flash.types.MATRIX; -import com.jpexs.decompiler.flash.types.RECT; -import com.jpexs.decompiler.flash.types.RGB; -import com.jpexs.decompiler.flash.types.RGBA; -import com.jpexs.decompiler.flash.types.SHAPE; -import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE; -import com.jpexs.decompiler.flash.types.TEXTRECORD; -import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord; -import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD; -import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord; -import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord; -import com.jpexs.helpers.ByteArrayRange; -import com.jpexs.helpers.Helper; -import com.jpexs.helpers.SerializableImage; -import java.awt.Color; -import java.awt.Font; -import java.awt.FontMetrics; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Rectangle; -import java.awt.Shape; -import java.awt.font.LineMetrics; -import java.awt.font.TextAttribute; -import java.awt.image.BufferedImage; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; -import org.w3c.dom.Element; - -/** - * - * @author JPEXS - */ -public abstract class TextTag extends DrawableTag { - - public TextTag(SWF swf, int id, String name, ByteArrayRange data) { - super(swf, id, name, data); - } - - public abstract MATRIX getTextMatrix(); - - public abstract List getTexts(); - - public abstract List getFontIds(); - - public abstract HighlightedText getFormattedText(boolean ignoreLetterSpacing); - - // use the texts from the "texts" argument when it is not null - public abstract boolean setFormattedText(MissingCharacterHandler missingCharHandler, String formattedText, String[] texts) throws TextParseException; - - public abstract void updateTextBounds(); - - public abstract boolean alignText(TextAlign textAlign); - - public abstract boolean translateText(int diff); - - public abstract RECT getBounds(); - - public abstract void setBounds(RECT r); - - public abstract ExportRectangle calculateTextBounds(); - - @Override - public RECT getRect() { - return getRect(null); // parameter not used - } - - private static void updateRect(RECT ret, int x, int y) { - if (x < ret.Xmin) { - ret.Xmin = x; - } - if (x > ret.Xmax) { - ret.Xmax = x; - } - if (y < ret.Ymin) { - ret.Ymin = y; - } - if (y > ret.Ymax) { - ret.Ymax = y; - } - } - - public static void alignText(SWF swf, List textRecords, TextAlign textAlign) { - // Remove Justify align entries - for (TEXTRECORD tr : textRecords) { - for (int i = 0; i < tr.glyphEntries.size(); i++) { - GLYPHENTRY ge = tr.glyphEntries.get(i); - if (ge instanceof JustifyAlignGlyphEntry) { - JustifyAlignGlyphEntry jge = (JustifyAlignGlyphEntry) ge; - ge = new GLYPHENTRY(); - ge.glyphAdvance = jge.originalAdvance; - ge.glyphIndex = jge.glyphIndex; - tr.glyphEntries.set(i, ge); - } - } - } - - int xMin = Integer.MAX_VALUE; - int maxWidth = 0; - for (TEXTRECORD tr : textRecords) { - int xOffset = tr.styleFlagsHasXOffset ? tr.xOffset : 0; - if (xOffset < xMin) { - xMin = xOffset; - } - - int width = tr.getTotalAdvance(); - - if (width > maxWidth) { - maxWidth = width; - } - } - - FontTag font = null; - - for (TEXTRECORD tr : textRecords) { - if (tr.styleFlagsHasFont) { - FontTag font2 = swf.getFont(tr.fontId); - if (font2 != null) { - font = font2; - } - } - - int width = tr.getTotalAdvance(); - switch (textAlign) { - case LEFT: - tr.xOffset = xMin; - tr.styleFlagsHasXOffset = true; - break; - case CENTER: - tr.xOffset = xMin + (maxWidth - width) / 2; - tr.styleFlagsHasXOffset = true; - break; - case RIGHT: - tr.xOffset = xMin + maxWidth - width; - tr.styleFlagsHasXOffset = true; - break; - case JUSTIFY: - tr.xOffset = xMin; - tr.styleFlagsHasXOffset = true; - - if (font != null) { - int diff = maxWidth - width; - if (diff > 0) { - int spaces = 0; - int spaces2 = 0; - int state = 0; - List glyphEntries = new ArrayList<>(); - List glyphEntries2 = new ArrayList<>(); - for (GLYPHENTRY ge : tr.glyphEntries) { - char ch = font.glyphToChar(ge.glyphIndex); - boolean whitespace = Character.isWhitespace(ch); - switch (state) { - case 0: - if (!whitespace) { - state = 1; - } - break; - case 1: - if (whitespace) { - spaces2++; - glyphEntries2.add(ge); - } else { - spaces += spaces2; - spaces2 = 0; - glyphEntries.addAll(glyphEntries2); - glyphEntries2.clear(); - } - break; - } - } - - if (spaces > 0 && glyphEntries.size() > 0) { - int fix = diff / spaces; - int remaining = diff - fix * spaces; - for (GLYPHENTRY ge : glyphEntries) { - int diff2 = fix; - if (remaining-- > 0) { - diff2++; - } - - JustifyAlignGlyphEntry jge = new JustifyAlignGlyphEntry(); - jge.originalAdvance = ge.glyphAdvance; - jge.glyphAdvance = ge.glyphAdvance + diff2; - jge.glyphIndex = ge.glyphIndex; - int idx = tr.glyphEntries.indexOf(ge); - tr.glyphEntries.set(idx, jge); - } - } - } - } - break; - } - } - } - - public static Map getTextRecordsAttributes(List list, SWF swf) { - Map att = new HashMap<>(); - RECT textBounds = new RECT(Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE); - FontTag font = null; - int x = 0; - int y = 0; - int textHeight = 12; - int lineSpacing = 0; - double leading = 0; - double ascent = 0; - double descent = 0; - double lineDistance = 0; - - List glyphs = null; - boolean firstLine = true; - double top = 0; - List allLeftMargins = new ArrayList<>(); - List allLetterSpacings = new ArrayList<>(); - FontMetrics fontMetrics; - BufferedImage bi = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB); - Graphics graphics = bi.getGraphics(); - Font aFont = null; - int currentLeftMargin; - for (int r = 0; r < list.size(); r++) { - TEXTRECORD rec = list.get(r); - if (rec.styleFlagsHasFont) { - FontTag font2 = swf.getFont(rec.fontId); - if (font2 != null) { - font = font2; - } - textHeight = rec.textHeight; - if (font == null) { - Logger.getLogger(TextTag.class.getName()).log(Level.SEVERE, "Font with id=" + rec.fontId + " was not found."); - continue; - } - - glyphs = font.getGlyphShapeTable(); - - if (!font.hasLayout()) { - String fontName = FontTag.getFontNameWithFallback(font.getFontNameIntag()); - aFont = new Font(fontName, font.getFontStyle(), (int) (textHeight / SWF.unitDivisor)); - - Map attr = new HashMap<>(); - - attr.put(TextAttribute.KERNING, TextAttribute.KERNING_ON); - attr.put(TextAttribute.LIGATURES, TextAttribute.LIGATURES_ON); - aFont = aFont.deriveFont(attr); - - fontMetrics = graphics.getFontMetrics(aFont); - LineMetrics lm = fontMetrics.getLineMetrics("A", graphics); - ascent = lm.getAscent(); - descent = lm.getDescent(); - leading = lm.getLeading(); - lineDistance = ascent + descent; - } else { - leading = ((double) font.getLeading() * textHeight / 1024.0 / font.getDivider() / SWF.unitDivisor); - ascent = ((double) font.getAscent() * textHeight / 1024.0 / font.getDivider() / SWF.unitDivisor); - descent = ((double) font.getDescent() * textHeight / 1024.0 / font.getDivider() / SWF.unitDivisor); - lineDistance = ascent + descent; - } - } - currentLeftMargin = 0; - if (rec.styleFlagsHasXOffset) { - x = rec.xOffset; - currentLeftMargin = x; - } - if (rec.styleFlagsHasYOffset) { - if (!firstLine) { - top += ascent + descent; - int topint = (int) (Math.round(top) * SWF.unitDivisor); - lineSpacing = rec.yOffset - topint; - top += lineSpacing / SWF.unitDivisor; - } else { - top = ascent; - } - y = rec.yOffset; - } - - firstLine = false; - allLeftMargins.add(currentLeftMargin); - - if (glyphs == null) { - Logger.getLogger(TextTag.class.getName()).log(Level.SEVERE, "Glyphs not found."); - continue; - } - - int letterSpacing = Integer.MAX_VALUE; - for (int e = 0; e < rec.glyphEntries.size(); e++) { - GLYPHENTRY entry = rec.glyphEntries.get(e); - GLYPHENTRY nextEntry = null; - if (e < rec.glyphEntries.size() - 1) { - nextEntry = rec.glyphEntries.get(e + 1); - } - RECT rect = SHAPERECORD.getBounds(glyphs.get(entry.glyphIndex).shapeRecords); - rect.Xmax = (int) Math.round(((double) rect.Xmax * textHeight) / (font.getDivider() * 1024)); - rect.Xmin = (int) Math.round(((double) rect.Xmin * textHeight) / (font.getDivider() * 1024)); - rect.Ymax = (int) Math.round(((double) rect.Ymax * textHeight) / (font.getDivider() * 1024)); - rect.Ymin = (int) Math.round(((double) rect.Ymin * textHeight) / (font.getDivider() * 1024)); - updateRect(textBounds, x + rect.Xmin, y + rect.Ymin); - updateRect(textBounds, x + rect.Xmax, y + rect.Ymax); - int adv = entry.glyphAdvance; - - int defaultAdvance; - if (font.hasLayout()) { - int kerningAdjustment = 0; - if (nextEntry != null) { - kerningAdjustment = font.getGlyphKerningAdjustment(entry.glyphIndex, nextEntry.glyphIndex); - } - defaultAdvance = (int) (Math.round(textHeight * (font.getGlyphAdvance(entry.glyphIndex) + kerningAdjustment) / (1024.0 * font.getDivider()))); - } else { - defaultAdvance = (int) Math.round(SWF.unitDivisor * FontTag.getSystemFontAdvance(aFont, font.glyphToChar(entry.glyphIndex), nextEntry == null ? null : font.glyphToChar(nextEntry.glyphIndex))); - } - int newLetterSpacing = adv - defaultAdvance; - if (e == 0 || e == rec.glyphEntries.size() - 1) { - if (rec.glyphEntries.size() == 1) { - letterSpacing = 0; - } - } else if (newLetterSpacing < letterSpacing) { - letterSpacing = newLetterSpacing; - } - x += adv; - } - allLetterSpacings.add(letterSpacing); - } - att.put("indent", 0); //? - att.put("rightMargin", 0); //? - att.put("lineSpacing", lineSpacing); - att.put("textBounds", textBounds); - att.put("allLeftMargins", allLeftMargins); - att.put("allLetterSpacings", allLetterSpacings); - return att; - } - - public static SHAPE getBorderShape(RGB borderColor, RGB fillColor, RECT rect) { - SHAPEWITHSTYLE shape = new SHAPEWITHSTYLE(); - shape.fillStyles = new FILLSTYLEARRAY(); - if (fillColor != null) { - shape.fillStyles.fillStyles = new FILLSTYLE[1]; - FILLSTYLE fillStyle = new FILLSTYLE(); - fillStyle.fillStyleType = FILLSTYLE.SOLID; - fillStyle.color = fillColor; - shape.fillStyles.fillStyles[0] = fillStyle; - } else { - shape.fillStyles.fillStyles = new FILLSTYLE[0]; - } - shape.lineStyles = new LINESTYLEARRAY(); - shape.lineStyles.lineStyles = new LINESTYLE[1]; - LINESTYLE lineStyle = new LINESTYLE(); - lineStyle.color = borderColor; - lineStyle.width = 20; - shape.lineStyles.lineStyles[0] = lineStyle; - shape.shapeRecords = new ArrayList<>(); - StyleChangeRecord style = new StyleChangeRecord(); - style.lineStyle = 1; - style.stateLineStyle = true; - if (fillColor != null) { - style.stateFillStyle0 = true; - style.fillStyle0 = 1; - } - style.stateMoveTo = true; - shape.shapeRecords.add(style); - StraightEdgeRecord top = new StraightEdgeRecord(); - top.generalLineFlag = true; - top.deltaX = rect.getWidth(); - StraightEdgeRecord right = new StraightEdgeRecord(); - right.generalLineFlag = true; - right.deltaY = rect.getHeight(); - StraightEdgeRecord bottom = new StraightEdgeRecord(); - bottom.generalLineFlag = true; - bottom.deltaX = -rect.getWidth(); - StraightEdgeRecord left = new StraightEdgeRecord(); - left.generalLineFlag = true; - left.deltaY = -rect.getHeight(); - shape.shapeRecords.add(top); - shape.shapeRecords.add(right); - shape.shapeRecords.add(bottom); - shape.shapeRecords.add(left); - shape.shapeRecords.add(new EndShapeRecord()); - return shape; - } - - public static void drawBorder(SWF swf, SerializableImage image, RGB borderColor, RGB fillColor, RECT rect, MATRIX textMatrix, Matrix transformation, ColorTransform colorTransform) { - Graphics2D g = (Graphics2D) image.getGraphics(); - Matrix mat = transformation.clone(); - mat = mat.concatenate(new Matrix(textMatrix)); - BitmapExporter.export(swf, getBorderShape(borderColor, fillColor, rect), null, image, mat, mat, colorTransform); - } - - public static void drawBorderHtmlCanvas(SWF swf, StringBuilder result, RGB borderColor, RGB fillColor, RECT rect, MATRIX textMatrix, ColorTransform colorTransform, double unitDivisor) { - Matrix mat = new Matrix(textMatrix); - result.append("\tctx.save();\r\n"); - result.append("\tctx.transform(").append(mat.scaleX).append(",").append(mat.rotateSkew0).append(",").append(mat.rotateSkew1).append(",").append(mat.scaleY).append(",").append(mat.translateX).append(",").append(mat.translateY).append(");\r\n"); - SHAPE shape = getBorderShape(borderColor, fillColor, rect); - CanvasShapeExporter cse = new CanvasShapeExporter(null, unitDivisor, swf, shape, colorTransform, 0, 0); - cse.export(); - result.append(cse.getShapeData()); - result.append("\tctx.restore();\r\n"); - } - - public static void drawBorderSVG(SWF swf, SVGExporter exporter, RGB borderColor, RGB fillColor, RECT rect, MATRIX textMatrix, ColorTransform colorTransform, double zoom) { - exporter.createSubGroup(new Matrix(textMatrix), null); - SHAPE shape = getBorderShape(borderColor, fillColor, rect); - SVGShapeExporter shapeExporter = new SVGShapeExporter(swf, shape, 0, exporter, null, colorTransform, zoom); - shapeExporter.export(); - exporter.endGroup(); - } - - public static void staticTextToImage(SWF swf, List textRecords, int numText, SerializableImage image, MATRIX textMatrix, Matrix transformation, ColorTransform colorTransform) { - int textColor = 0; - FontTag font = null; - int textHeight = 12; - int x = 0; - int y = 0; - List glyphs = null; - Matrix mat0 = transformation.clone(); - mat0 = mat0.concatenate(new Matrix(textMatrix)); - for (TEXTRECORD rec : textRecords) { - if (rec.styleFlagsHasColor) { - if (numText == 2) { - textColor = rec.textColorA.toInt(); - } else { - textColor = rec.textColor.toInt(); - } - - if (colorTransform != null) { - textColor = colorTransform.apply(textColor); - } - } - if (rec.styleFlagsHasFont) { - FontTag font2 = swf.getFont(rec.fontId); - if (font2 != null) { - font = font2; - } - glyphs = font == null ? null : font.getGlyphShapeTable(); - textHeight = rec.textHeight; - } - if (rec.styleFlagsHasXOffset) { - x = rec.xOffset; - } - if (rec.styleFlagsHasYOffset) { - y = rec.yOffset; - } - - double divider = font == null ? 1 : font.getDivider(); - double rat = textHeight / 1024.0 / divider; - - Matrix matScale = Matrix.getScaleInstance(rat); - Color textColor2 = new Color(textColor, true); - for (GLYPHENTRY entry : rec.glyphEntries) { - matScale.translateX = x; - matScale.translateY = y; - - Matrix mat = mat0.concatenate(matScale); - SHAPE shape = null; - if (entry.glyphIndex != -1 && glyphs != null) { - // shapeNum: 1 - shape = glyphs.get(entry.glyphIndex); - } else if (entry instanceof DynamicTextGlyphEntry) { - DynamicTextGlyphEntry dynamicEntry = (DynamicTextGlyphEntry) entry; - if (dynamicEntry.fontFace != null) { - FontTag fnt = swf.getFontByName(dynamicEntry.fontFace); - if (fnt != null && entry.glyphIndex != -1) { - shape = fnt.getGlyphShapeTable().get(entry.glyphIndex); - } else { - shape = SHAPERECORD.fontCharacterToSHAPE(new Font(dynamicEntry.fontFace, dynamicEntry.fontStyle, 12), (int) Math.round(divider * 1024), dynamicEntry.character); - } - } - } - - if (shape != null) { - BitmapExporter.export(swf, shape, textColor2, image, mat, mat, colorTransform); - if (SHAPERECORD.DRAW_BOUNDING_BOX) { - RGB borderColor = new RGBA(Color.black); - RGB fillColor = new RGBA(new Color(255, 255, 255, 0)); - RECT bounds = shape.getBounds(); - mat = Matrix.getTranslateInstance(bounds.Xmin, bounds.Ymin).preConcatenate(mat); - TextTag.drawBorder(swf, image, borderColor, fillColor, bounds, new MATRIX(), mat, colorTransform); - } - } - - x += entry.glyphAdvance; - } - } - } - - public static ExportRectangle calculateTextBounds(SWF swf, List textRecords, MATRIX textMatrix) { - FontTag font = null; - int textHeight = 12; - int x = 0; - int y = 0; - List glyphs = null; - ExportRectangle result = null; - for (TEXTRECORD rec : textRecords) { - if (rec.styleFlagsHasFont) { - font = swf.getFont(rec.fontId); - glyphs = font == null ? null : font.getGlyphShapeTable(); - textHeight = rec.textHeight; - } - if (rec.styleFlagsHasXOffset) { - x = rec.xOffset; - } - if (rec.styleFlagsHasYOffset) { - y = rec.yOffset; - } - - double rat = textHeight / 1024.0 / (font == null ? 1 : font.getDivider()); - - for (GLYPHENTRY entry : rec.glyphEntries) { - Matrix mat = new Matrix(); - mat = mat.concatenate(new Matrix(textMatrix)); - Matrix matTr = Matrix.getTranslateInstance(x, y); - mat = mat.concatenate(matTr); - mat = mat.concatenate(Matrix.getScaleInstance(rat)); - if (entry.glyphIndex != -1 && glyphs != null) { - // shapeNum: 1 - SHAPE shape = glyphs.get(entry.glyphIndex); - RECT glyphBounds = shape.getBounds(); - int glyphWidth = glyphBounds.getWidth(); - int glyphHeight = glyphBounds.getHeight(); - glyphBounds.Xmin -= glyphWidth / 2; - glyphBounds.Ymin -= glyphHeight / 2; - glyphBounds.Xmax += glyphWidth; - glyphBounds.Ymax += glyphHeight; - if (glyphBounds.Xmax > glyphBounds.Xmin && glyphBounds.Ymax > glyphBounds.Ymin) { - ExportRectangle rect = mat.transform(new ExportRectangle(glyphBounds)); - if (result == null) { - result = rect; - } else { - result.xMin = Math.min(result.xMin, rect.xMin); - result.yMin = Math.min(result.yMin, rect.yMin); - result.xMax = Math.max(result.xMax, rect.xMax); - result.yMax = Math.max(result.yMax, rect.yMax); - } - } - x += entry.glyphAdvance; - } - } - } - - return result; - } - - protected void updateTextBounds(RECT textBounds) { - TextImportResizeTextBoundsMode resizeMode = Configuration.textImportResizeTextBoundsMode.get(); - if (resizeMode != null && (resizeMode.equals(TextImportResizeTextBoundsMode.GROW_ONLY) || resizeMode.equals(TextImportResizeTextBoundsMode.GROW_AND_SHRINK))) { - ExportRectangle newBounds = calculateTextBounds(); - if (newBounds != null) { - int xMin = (int) Math.floor(newBounds.xMin); - int yMin = (int) Math.floor(newBounds.yMin); - int xMax = (int) Math.ceil(newBounds.xMax); - int yMax = (int) Math.ceil(newBounds.yMax); - if (resizeMode.equals(TextImportResizeTextBoundsMode.GROW_ONLY)) { - textBounds.Xmin = Math.min(xMin, textBounds.Xmin); - textBounds.Ymin = Math.min(yMin, textBounds.Ymin); - textBounds.Xmax = Math.max(xMax, textBounds.Xmax); - textBounds.Ymax = Math.max(yMax, textBounds.Ymax); - } else if (resizeMode.equals(TextImportResizeTextBoundsMode.GROW_AND_SHRINK)) { - textBounds.Xmin = xMin; - textBounds.Ymin = yMin; - textBounds.Xmax = xMax; - textBounds.Ymax = yMax; - } - } - } - } - - public static void staticTextToHtmlCanvas(double unitDivisor, SWF swf, List textRecords, int numText, StringBuilder result, RECT bounds, MATRIX textMatrix, ColorTransform colorTransform) { - int textColor = 0; - FontTag font = null; - int fontId = -1; - int textHeight = 12; - int x = 0; - int y = 0; - - List glyphs = new ArrayList<>(); - for (TEXTRECORD rec : textRecords) { - if (rec.styleFlagsHasColor) { - if (numText == 2) { - textColor = rec.textColorA.toInt(); - } else { - textColor = rec.textColor.toInt(); - } - - if (colorTransform != null) { - textColor = colorTransform.apply(textColor); - } - } - if (rec.styleFlagsHasFont) { - font = swf.getFont(rec.fontId); - fontId = rec.fontId; - glyphs = font.getGlyphShapeTable(); - textHeight = rec.textHeight; - } - if (rec.styleFlagsHasXOffset) { - x = rec.xOffset; - } - if (rec.styleFlagsHasYOffset) { - y = rec.yOffset; - } - - double rat = textHeight / 1024.0 / font.getDivider(); - - result.append("\tvar textColor = ").append(CanvasShapeExporter.color(textColor)).append(";\r\n"); - for (GLYPHENTRY entry : rec.glyphEntries) { - Matrix mat = (new Matrix(textMatrix).concatenate(Matrix.getTranslateInstance(x, y))).concatenate(Matrix.getScaleInstance(rat)); - if (entry.glyphIndex != -1) { - // shapeNum: 1 - result.append("\tctx.save();\r\n"); - result.append("\tctx.transform(").append(mat.scaleX).append(",").append(mat.rotateSkew0).append(",").append(mat.rotateSkew1).append(",").append(mat.scaleY).append(",").append(mat.translateX).append(",").append(mat.translateY).append(");\r\n"); - result.append("\tfont").append(fontId).append("(ctx,\"").append(("" + font.glyphToChar(entry.glyphIndex)).replace("\\", "\\\\").replace("\"", "\\\"")).append("\",textColor);\r\n"); - result.append("\tctx.restore();\r\n"); - x += entry.glyphAdvance; - } - } - } - } - - public static void staticTextToSVG(SWF swf, List textRecords, int numText, SVGExporter exporter, RECT bounds, MATRIX textMatrix, ColorTransform colorTransform, double zoom) { - int textColor = 0; - FontTag font = null; - int textHeight = 12; - int x = 0; - int y = 0; - List glyphs = new ArrayList<>(); - for (TEXTRECORD rec : textRecords) { - if (rec.styleFlagsHasColor) { - if (numText == 2) { - textColor = rec.textColorA.toInt(); - } else { - textColor = rec.textColor.toInt(); - } - - if (colorTransform != null) { - textColor = colorTransform.apply(textColor); - } - } - if (rec.styleFlagsHasFont) { - font = swf.getFont(rec.fontId); - glyphs = font.getGlyphShapeTable(); - textHeight = rec.textHeight; - } - int offsetX = 0; - int offsetY = 0; - if (rec.styleFlagsHasXOffset) { - offsetX = rec.xOffset; - x = offsetX; - } - if (rec.styleFlagsHasYOffset) { - offsetY = rec.yOffset; - y = offsetY; - } - - double rat = textHeight / 1024.0 / font.getDivider(); - - exporter.createSubGroup(new Matrix(textMatrix), null); - if (exporter.useTextTag) { - StringBuilder text = new StringBuilder(); - int totalAdvance = 0; - for (GLYPHENTRY entry : rec.glyphEntries) { - if (entry.glyphIndex != -1) { - char ch = font.glyphToChar(entry.glyphIndex); - text.append(ch); - totalAdvance += entry.glyphAdvance; - } - } - - boolean hasOffset = offsetX != 0 || offsetY != 0; - if (hasOffset) { - exporter.createSubGroup(Matrix.getTranslateInstance(offsetX, offsetY), null); - } - - Element textElement = exporter.createElement("text"); - textElement.setAttribute("font-size", Double.toString(rat * 1024)); - textElement.setAttribute("font-family", font.getFontNameIntag()); - textElement.setAttribute("textLength", Double.toString(totalAdvance / SWF.unitDivisor)); - textElement.setAttribute("lengthAdjust", "spacing"); - textElement.setTextContent(text.toString()); - - RGBA colorA = new RGBA(textColor); - textElement.setAttribute("fill", colorA.toHexRGB()); - if (colorA.alpha != 255) { - textElement.setAttribute("fill-opacity", Float.toString(colorA.getAlphaFloat())); - } - - exporter.addToGroup(textElement); - FontExportMode fontExportMode = FontExportMode.WOFF; - exporter.addStyle(font.getFontNameIntag(), new FontExporter().exportFont(font, fontExportMode), fontExportMode); - - if (hasOffset) { - exporter.endGroup(); - } - } else { - for (GLYPHENTRY entry : rec.glyphEntries) { - Matrix mat = Matrix.getTranslateInstance(x, y).concatenate(Matrix.getScaleInstance(rat)); - if (entry.glyphIndex != -1) { - // shapeNum: 1 - SHAPE shape = glyphs.get(entry.glyphIndex); - char ch = font.glyphToChar(entry.glyphIndex); - - String charId = null; - Map chs; - if (exporter.exportedChars.containsKey(font)) { - chs = exporter.exportedChars.get(font); - if (chs.containsKey(entry.glyphIndex)) { - charId = chs.get(entry.glyphIndex); - } - } else { - chs = new HashMap<>(); - exporter.exportedChars.put(font, chs); - } - - if (charId == null) { - charId = exporter.getUniqueId(Helper.getValidHtmlId("font_" + font.getFontNameIntag() + "_" + ch)); - exporter.createDefGroup(null, charId); - SVGShapeExporter shapeExporter = new SVGShapeExporter(swf, shape, 0, exporter, null, colorTransform, zoom); - shapeExporter.export(); - if (!exporter.endGroup()) { - charId = ""; - } - - chs.put(entry.glyphIndex, charId); - } - - if (!"".equals(charId)) { - Element charImage = exporter.addUse(mat, bounds, charId, null); - RGBA colorA = new RGBA(textColor); - charImage.setAttribute("fill", colorA.toHexRGB()); - if (colorA.alpha != 255) { - charImage.setAttribute("fill-opacity", Float.toString(colorA.getAlphaFloat())); - } - } - - x += entry.glyphAdvance; - } - } - } - exporter.endGroup(); - } - } - - @Override - public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation, boolean stroked) { - RECT r = getBounds(); - Shape shp = new Rectangle.Double(r.Xmin, r.Ymin, r.getWidth(), r.getHeight()); - return transformation.toTransform().createTransformedShape(shp); //TODO: match character shapes (?) - } -} +/* + * Copyright (C) 2010-2016 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags.base; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.exporters.FontExporter; +import com.jpexs.decompiler.flash.exporters.commonshape.ExportRectangle; +import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; +import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; +import com.jpexs.decompiler.flash.exporters.modes.FontExportMode; +import com.jpexs.decompiler.flash.exporters.shape.BitmapExporter; +import com.jpexs.decompiler.flash.exporters.shape.CanvasShapeExporter; +import com.jpexs.decompiler.flash.exporters.shape.SVGShapeExporter; +import com.jpexs.decompiler.flash.helpers.HighlightedText; +import com.jpexs.decompiler.flash.importers.TextImportResizeTextBoundsMode; +import com.jpexs.decompiler.flash.tags.text.JustifyAlignGlyphEntry; +import com.jpexs.decompiler.flash.tags.text.TextAlign; +import com.jpexs.decompiler.flash.tags.text.TextParseException; +import com.jpexs.decompiler.flash.types.ColorTransform; +import com.jpexs.decompiler.flash.types.DynamicTextGlyphEntry; +import com.jpexs.decompiler.flash.types.FILLSTYLE; +import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY; +import com.jpexs.decompiler.flash.types.GLYPHENTRY; +import com.jpexs.decompiler.flash.types.LINESTYLE; +import com.jpexs.decompiler.flash.types.LINESTYLEARRAY; +import com.jpexs.decompiler.flash.types.MATRIX; +import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.decompiler.flash.types.RGB; +import com.jpexs.decompiler.flash.types.RGBA; +import com.jpexs.decompiler.flash.types.SHAPE; +import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE; +import com.jpexs.decompiler.flash.types.TEXTRECORD; +import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord; +import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD; +import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord; +import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord; +import com.jpexs.helpers.ByteArrayRange; +import com.jpexs.helpers.Helper; +import com.jpexs.helpers.SerializableImage; +import java.awt.Color; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.font.LineMetrics; +import java.awt.font.TextAttribute; +import java.awt.image.BufferedImage; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.w3c.dom.Element; + +/** + * + * @author JPEXS + */ +public abstract class TextTag extends DrawableTag { + + public TextTag(SWF swf, int id, String name, ByteArrayRange data) { + super(swf, id, name, data); + } + + public abstract MATRIX getTextMatrix(); + + public abstract List getTexts(); + + public abstract List getFontIds(); + + public abstract HighlightedText getFormattedText(boolean ignoreLetterSpacing); + + // use the texts from the "texts" argument when it is not null + public abstract boolean setFormattedText(MissingCharacterHandler missingCharHandler, String formattedText, String[] texts) throws TextParseException; + + public abstract void updateTextBounds(); + + public abstract boolean alignText(TextAlign textAlign); + + public abstract boolean translateText(int diff); + + public abstract RECT getBounds(); + + public abstract void setBounds(RECT r); + + public abstract ExportRectangle calculateTextBounds(); + + @Override + public RECT getRect() { + return getRect(null); // parameter not used + } + + private static void updateRect(RECT ret, int x, int y) { + if (x < ret.Xmin) { + ret.Xmin = x; + } + if (x > ret.Xmax) { + ret.Xmax = x; + } + if (y < ret.Ymin) { + ret.Ymin = y; + } + if (y > ret.Ymax) { + ret.Ymax = y; + } + } + + public static void alignText(SWF swf, List textRecords, TextAlign textAlign) { + // Remove Justify align entries + for (TEXTRECORD tr : textRecords) { + for (int i = 0; i < tr.glyphEntries.size(); i++) { + GLYPHENTRY ge = tr.glyphEntries.get(i); + if (ge instanceof JustifyAlignGlyphEntry) { + JustifyAlignGlyphEntry jge = (JustifyAlignGlyphEntry) ge; + ge = new GLYPHENTRY(); + ge.glyphAdvance = jge.originalAdvance; + ge.glyphIndex = jge.glyphIndex; + tr.glyphEntries.set(i, ge); + } + } + } + + int xMin = Integer.MAX_VALUE; + int maxWidth = 0; + for (TEXTRECORD tr : textRecords) { + int xOffset = tr.styleFlagsHasXOffset ? tr.xOffset : 0; + if (xOffset < xMin) { + xMin = xOffset; + } + + int width = tr.getTotalAdvance(); + + if (width > maxWidth) { + maxWidth = width; + } + } + + FontTag font = null; + + for (TEXTRECORD tr : textRecords) { + if (tr.styleFlagsHasFont) { + FontTag font2 = swf.getFont(tr.fontId); + if (font2 != null) { + font = font2; + } + } + + int width = tr.getTotalAdvance(); + switch (textAlign) { + case LEFT: + tr.xOffset = xMin; + tr.styleFlagsHasXOffset = true; + break; + case CENTER: + tr.xOffset = xMin + (maxWidth - width) / 2; + tr.styleFlagsHasXOffset = true; + break; + case RIGHT: + tr.xOffset = xMin + maxWidth - width; + tr.styleFlagsHasXOffset = true; + break; + case JUSTIFY: + tr.xOffset = xMin; + tr.styleFlagsHasXOffset = true; + + if (font != null) { + int diff = maxWidth - width; + if (diff > 0) { + int spaces = 0; + int spaces2 = 0; + int state = 0; + List glyphEntries = new ArrayList<>(); + List glyphEntries2 = new ArrayList<>(); + for (GLYPHENTRY ge : tr.glyphEntries) { + char ch = font.glyphToChar(ge.glyphIndex); + boolean whitespace = Character.isWhitespace(ch); + switch (state) { + case 0: + if (!whitespace) { + state = 1; + } + break; + case 1: + if (whitespace) { + spaces2++; + glyphEntries2.add(ge); + } else { + spaces += spaces2; + spaces2 = 0; + glyphEntries.addAll(glyphEntries2); + glyphEntries2.clear(); + } + break; + } + } + + if (spaces > 0 && glyphEntries.size() > 0) { + int fix = diff / spaces; + int remaining = diff - fix * spaces; + for (GLYPHENTRY ge : glyphEntries) { + int diff2 = fix; + if (remaining-- > 0) { + diff2++; + } + + JustifyAlignGlyphEntry jge = new JustifyAlignGlyphEntry(); + jge.originalAdvance = ge.glyphAdvance; + jge.glyphAdvance = ge.glyphAdvance + diff2; + jge.glyphIndex = ge.glyphIndex; + int idx = tr.glyphEntries.indexOf(ge); + tr.glyphEntries.set(idx, jge); + } + } + } + } + break; + } + } + } + + public static Map getTextRecordsAttributes(List list, SWF swf) { + Map att = new HashMap<>(); + RECT textBounds = new RECT(Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE); + FontTag font = null; + int x = 0; + int y = 0; + int textHeight = 12; + int lineSpacing = 0; + double leading = 0; + double ascent = 0; + double descent = 0; + double lineDistance = 0; + + List glyphs = null; + boolean firstLine = true; + double top = 0; + List allLeftMargins = new ArrayList<>(); + List allLetterSpacings = new ArrayList<>(); + FontMetrics fontMetrics; + BufferedImage bi = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB); + Graphics graphics = bi.getGraphics(); + Font aFont = null; + int currentLeftMargin; + for (int r = 0; r < list.size(); r++) { + TEXTRECORD rec = list.get(r); + if (rec.styleFlagsHasFont) { + FontTag font2 = swf.getFont(rec.fontId); + if (font2 != null) { + font = font2; + } + textHeight = rec.textHeight; + if (font == null) { + Logger.getLogger(TextTag.class.getName()).log(Level.SEVERE, "Font with id=" + rec.fontId + " was not found."); + continue; + } + + glyphs = font.getGlyphShapeTable(); + + if (!font.hasLayout()) { + String fontName = FontTag.getFontNameWithFallback(font.getFontNameIntag()); + aFont = new Font(fontName, font.getFontStyle(), (int) (textHeight / SWF.unitDivisor)); + + Map attr = new HashMap<>(); + + attr.put(TextAttribute.KERNING, TextAttribute.KERNING_ON); + attr.put(TextAttribute.LIGATURES, TextAttribute.LIGATURES_ON); + aFont = aFont.deriveFont(attr); + + fontMetrics = graphics.getFontMetrics(aFont); + LineMetrics lm = fontMetrics.getLineMetrics("A", graphics); + ascent = lm.getAscent(); + descent = lm.getDescent(); + leading = lm.getLeading(); + lineDistance = ascent + descent; + } else { + leading = ((double) font.getLeading() * textHeight / 1024.0 / font.getDivider() / SWF.unitDivisor); + ascent = ((double) font.getAscent() * textHeight / 1024.0 / font.getDivider() / SWF.unitDivisor); + descent = ((double) font.getDescent() * textHeight / 1024.0 / font.getDivider() / SWF.unitDivisor); + lineDistance = ascent + descent; + } + } + currentLeftMargin = 0; + if (rec.styleFlagsHasXOffset) { + x = rec.xOffset; + currentLeftMargin = x; + } + if (rec.styleFlagsHasYOffset) { + if (!firstLine) { + top += ascent + descent; + int topint = (int) (Math.round(top) * SWF.unitDivisor); + lineSpacing = rec.yOffset - topint; + top += lineSpacing / SWF.unitDivisor; + } else { + top = ascent; + } + y = rec.yOffset; + } + + firstLine = false; + allLeftMargins.add(currentLeftMargin); + + if (glyphs == null) { + Logger.getLogger(TextTag.class.getName()).log(Level.SEVERE, "Glyphs not found."); + continue; + } + + int letterSpacing = Integer.MAX_VALUE; + for (int e = 0; e < rec.glyphEntries.size(); e++) { + GLYPHENTRY entry = rec.glyphEntries.get(e); + GLYPHENTRY nextEntry = null; + if (e < rec.glyphEntries.size() - 1) { + nextEntry = rec.glyphEntries.get(e + 1); + } + RECT rect = SHAPERECORD.getBounds(glyphs.get(entry.glyphIndex).shapeRecords); + rect.Xmax = (int) Math.round(((double) rect.Xmax * textHeight) / (font.getDivider() * 1024)); + rect.Xmin = (int) Math.round(((double) rect.Xmin * textHeight) / (font.getDivider() * 1024)); + rect.Ymax = (int) Math.round(((double) rect.Ymax * textHeight) / (font.getDivider() * 1024)); + rect.Ymin = (int) Math.round(((double) rect.Ymin * textHeight) / (font.getDivider() * 1024)); + updateRect(textBounds, x + rect.Xmin, y + rect.Ymin); + updateRect(textBounds, x + rect.Xmax, y + rect.Ymax); + int adv = entry.glyphAdvance; + + int defaultAdvance; + if (font.hasLayout()) { + int kerningAdjustment = 0; + if (nextEntry != null) { + kerningAdjustment = font.getGlyphKerningAdjustment(entry.glyphIndex, nextEntry.glyphIndex); + } + defaultAdvance = (int) (Math.round(textHeight * (font.getGlyphAdvance(entry.glyphIndex) + kerningAdjustment) / (1024.0 * font.getDivider()))); + } else { + defaultAdvance = (int) Math.round(SWF.unitDivisor * FontTag.getSystemFontAdvance(aFont, font.glyphToChar(entry.glyphIndex), nextEntry == null ? null : font.glyphToChar(nextEntry.glyphIndex))); + } + int newLetterSpacing = adv - defaultAdvance; + if (e == 0 || e == rec.glyphEntries.size() - 1) { + if (rec.glyphEntries.size() == 1) { + letterSpacing = 0; + } + } else if (newLetterSpacing < letterSpacing) { + letterSpacing = newLetterSpacing; + } + x += adv; + } + allLetterSpacings.add(letterSpacing); + } + att.put("indent", 0); //? + att.put("rightMargin", 0); //? + att.put("lineSpacing", lineSpacing); + att.put("textBounds", textBounds); + att.put("allLeftMargins", allLeftMargins); + att.put("allLetterSpacings", allLetterSpacings); + return att; + } + + public static SHAPE getBorderShape(RGB borderColor, RGB fillColor, RECT rect) { + SHAPEWITHSTYLE shape = new SHAPEWITHSTYLE(); + shape.fillStyles = new FILLSTYLEARRAY(); + if (fillColor != null) { + shape.fillStyles.fillStyles = new FILLSTYLE[1]; + FILLSTYLE fillStyle = new FILLSTYLE(); + fillStyle.fillStyleType = FILLSTYLE.SOLID; + fillStyle.color = fillColor; + shape.fillStyles.fillStyles[0] = fillStyle; + } else { + shape.fillStyles.fillStyles = new FILLSTYLE[0]; + } + shape.lineStyles = new LINESTYLEARRAY(); + shape.lineStyles.lineStyles = new LINESTYLE[1]; + LINESTYLE lineStyle = new LINESTYLE(); + lineStyle.color = borderColor; + lineStyle.width = 20; + shape.lineStyles.lineStyles[0] = lineStyle; + shape.shapeRecords = new ArrayList<>(); + StyleChangeRecord style = new StyleChangeRecord(); + style.lineStyle = 1; + style.stateLineStyle = true; + if (fillColor != null) { + style.stateFillStyle0 = true; + style.fillStyle0 = 1; + } + style.stateMoveTo = true; + shape.shapeRecords.add(style); + StraightEdgeRecord top = new StraightEdgeRecord(); + top.generalLineFlag = true; + top.deltaX = rect.getWidth(); + StraightEdgeRecord right = new StraightEdgeRecord(); + right.generalLineFlag = true; + right.deltaY = rect.getHeight(); + StraightEdgeRecord bottom = new StraightEdgeRecord(); + bottom.generalLineFlag = true; + bottom.deltaX = -rect.getWidth(); + StraightEdgeRecord left = new StraightEdgeRecord(); + left.generalLineFlag = true; + left.deltaY = -rect.getHeight(); + shape.shapeRecords.add(top); + shape.shapeRecords.add(right); + shape.shapeRecords.add(bottom); + shape.shapeRecords.add(left); + shape.shapeRecords.add(new EndShapeRecord()); + return shape; + } + + public static void drawBorder(SWF swf, SerializableImage image, RGB borderColor, RGB fillColor, RECT rect, MATRIX textMatrix, Matrix transformation, ColorTransform colorTransform) { + Graphics2D g = (Graphics2D) image.getGraphics(); + Matrix mat = transformation.clone(); + mat = mat.concatenate(new Matrix(textMatrix)); + BitmapExporter.export(swf, getBorderShape(borderColor, fillColor, rect), null, image, mat, mat, colorTransform); + } + + public static void drawBorderHtmlCanvas(SWF swf, StringBuilder result, RGB borderColor, RGB fillColor, RECT rect, MATRIX textMatrix, ColorTransform colorTransform, double unitDivisor) { + Matrix mat = new Matrix(textMatrix); + result.append("\tctx.save();\r\n"); + result.append("\tctx.transform(").append(mat.scaleX).append(",").append(mat.rotateSkew0).append(",").append(mat.rotateSkew1).append(",").append(mat.scaleY).append(",").append(mat.translateX).append(",").append(mat.translateY).append(");\r\n"); + SHAPE shape = getBorderShape(borderColor, fillColor, rect); + CanvasShapeExporter cse = new CanvasShapeExporter(null, unitDivisor, swf, shape, colorTransform, 0, 0); + cse.export(); + result.append(cse.getShapeData()); + result.append("\tctx.restore();\r\n"); + } + + public static void drawBorderSVG(SWF swf, SVGExporter exporter, RGB borderColor, RGB fillColor, RECT rect, MATRIX textMatrix, ColorTransform colorTransform, double zoom) { + exporter.createSubGroup(new Matrix(textMatrix), null); + SHAPE shape = getBorderShape(borderColor, fillColor, rect); + SVGShapeExporter shapeExporter = new SVGShapeExporter(swf, shape, 0, exporter, null, colorTransform, zoom); + shapeExporter.export(); + exporter.endGroup(); + } + + public static void staticTextToImage(SWF swf, List textRecords, int numText, SerializableImage image, MATRIX textMatrix, Matrix transformation, ColorTransform colorTransform) { + int textColor = 0; + FontTag font = null; + int textHeight = 12; + int x = 0; + int y = 0; + List glyphs = null; + Matrix mat0 = transformation.clone(); + mat0 = mat0.concatenate(new Matrix(textMatrix)); + for (TEXTRECORD rec : textRecords) { + if (rec.styleFlagsHasColor) { + if (numText == 2) { + textColor = rec.textColorA.toInt(); + } else { + textColor = rec.textColor.toInt(); + } + + if (colorTransform != null) { + textColor = colorTransform.apply(textColor); + } + } + if (rec.styleFlagsHasFont) { + FontTag font2 = swf.getFont(rec.fontId); + if (font2 != null) { + font = font2; + } + glyphs = font == null ? null : font.getGlyphShapeTable(); + textHeight = rec.textHeight; + } + if (rec.styleFlagsHasXOffset) { + x = rec.xOffset; + } + if (rec.styleFlagsHasYOffset) { + y = rec.yOffset; + } + + double divider = font == null ? 1 : font.getDivider(); + double rat = textHeight / 1024.0 / divider; + + Matrix matScale = Matrix.getScaleInstance(rat); + Color textColor2 = new Color(textColor, true); + for (GLYPHENTRY entry : rec.glyphEntries) { + matScale.translateX = x; + matScale.translateY = y; + + Matrix mat = mat0.concatenate(matScale); + SHAPE shape = null; + if (entry.glyphIndex != -1 && glyphs != null) { + // shapeNum: 1 + shape = glyphs.get(entry.glyphIndex); + } else if (entry instanceof DynamicTextGlyphEntry) { + DynamicTextGlyphEntry dynamicEntry = (DynamicTextGlyphEntry) entry; + if (dynamicEntry.fontFace != null) { + FontTag fnt = swf.getFontByName(dynamicEntry.fontFace); + if (fnt != null && entry.glyphIndex != -1) { + shape = fnt.getGlyphShapeTable().get(entry.glyphIndex); + } else { + shape = SHAPERECORD.fontCharacterToSHAPE(new Font(dynamicEntry.fontFace, dynamicEntry.fontStyle, 12), (int) Math.round(divider * 1024), dynamicEntry.character); + } + } + } + + if (shape != null) { + BitmapExporter.export(swf, shape, textColor2, image, mat, mat, colorTransform); + if (SHAPERECORD.DRAW_BOUNDING_BOX) { + RGB borderColor = new RGBA(Color.black); + RGB fillColor = new RGBA(new Color(255, 255, 255, 0)); + RECT bounds = shape.getBounds(); + mat = Matrix.getTranslateInstance(bounds.Xmin, bounds.Ymin).preConcatenate(mat); + TextTag.drawBorder(swf, image, borderColor, fillColor, bounds, new MATRIX(), mat, colorTransform); + } + } + + x += entry.glyphAdvance; + } + } + } + + public static ExportRectangle calculateTextBounds(SWF swf, List textRecords, MATRIX textMatrix) { + FontTag font = null; + int textHeight = 12; + int x = 0; + int y = 0; + List glyphs = null; + ExportRectangle result = null; + for (TEXTRECORD rec : textRecords) { + if (rec.styleFlagsHasFont) { + font = swf.getFont(rec.fontId); + glyphs = font == null ? null : font.getGlyphShapeTable(); + textHeight = rec.textHeight; + } + if (rec.styleFlagsHasXOffset) { + x = rec.xOffset; + } + if (rec.styleFlagsHasYOffset) { + y = rec.yOffset; + } + + double rat = textHeight / 1024.0 / (font == null ? 1 : font.getDivider()); + + for (GLYPHENTRY entry : rec.glyphEntries) { + Matrix mat = new Matrix(); + mat = mat.concatenate(new Matrix(textMatrix)); + Matrix matTr = Matrix.getTranslateInstance(x, y); + mat = mat.concatenate(matTr); + mat = mat.concatenate(Matrix.getScaleInstance(rat)); + if (entry.glyphIndex != -1 && glyphs != null) { + // shapeNum: 1 + SHAPE shape = glyphs.get(entry.glyphIndex); + RECT glyphBounds = shape.getBounds(); + int glyphWidth = glyphBounds.getWidth(); + int glyphHeight = glyphBounds.getHeight(); + glyphBounds.Xmin -= glyphWidth / 2; + glyphBounds.Ymin -= glyphHeight / 2; + glyphBounds.Xmax += glyphWidth; + glyphBounds.Ymax += glyphHeight; + if (glyphBounds.Xmax > glyphBounds.Xmin && glyphBounds.Ymax > glyphBounds.Ymin) { + ExportRectangle rect = mat.transform(new ExportRectangle(glyphBounds)); + if (result == null) { + result = rect; + } else { + result.xMin = Math.min(result.xMin, rect.xMin); + result.yMin = Math.min(result.yMin, rect.yMin); + result.xMax = Math.max(result.xMax, rect.xMax); + result.yMax = Math.max(result.yMax, rect.yMax); + } + } + x += entry.glyphAdvance; + } + } + } + + return result; + } + + protected void updateTextBounds(RECT textBounds) { + TextImportResizeTextBoundsMode resizeMode = Configuration.textImportResizeTextBoundsMode.get(); + if (resizeMode != null && (resizeMode.equals(TextImportResizeTextBoundsMode.GROW_ONLY) || resizeMode.equals(TextImportResizeTextBoundsMode.GROW_AND_SHRINK))) { + ExportRectangle newBounds = calculateTextBounds(); + if (newBounds != null) { + int xMin = (int) Math.floor(newBounds.xMin); + int yMin = (int) Math.floor(newBounds.yMin); + int xMax = (int) Math.ceil(newBounds.xMax); + int yMax = (int) Math.ceil(newBounds.yMax); + if (resizeMode.equals(TextImportResizeTextBoundsMode.GROW_ONLY)) { + textBounds.Xmin = Math.min(xMin, textBounds.Xmin); + textBounds.Ymin = Math.min(yMin, textBounds.Ymin); + textBounds.Xmax = Math.max(xMax, textBounds.Xmax); + textBounds.Ymax = Math.max(yMax, textBounds.Ymax); + } else if (resizeMode.equals(TextImportResizeTextBoundsMode.GROW_AND_SHRINK)) { + textBounds.Xmin = xMin; + textBounds.Ymin = yMin; + textBounds.Xmax = xMax; + textBounds.Ymax = yMax; + } + } + } + } + + public static void staticTextToHtmlCanvas(double unitDivisor, SWF swf, List textRecords, int numText, StringBuilder result, RECT bounds, MATRIX textMatrix, ColorTransform colorTransform) { + int textColor = 0; + FontTag font = null; + int fontId = -1; + int textHeight = 12; + int x = 0; + int y = 0; + + List glyphs = new ArrayList<>(); + for (TEXTRECORD rec : textRecords) { + if (rec.styleFlagsHasColor) { + if (numText == 2) { + textColor = rec.textColorA.toInt(); + } else { + textColor = rec.textColor.toInt(); + } + + if (colorTransform != null) { + textColor = colorTransform.apply(textColor); + } + } + if (rec.styleFlagsHasFont) { + font = swf.getFont(rec.fontId); + fontId = rec.fontId; + glyphs = font.getGlyphShapeTable(); + textHeight = rec.textHeight; + } + if (rec.styleFlagsHasXOffset) { + x = rec.xOffset; + } + if (rec.styleFlagsHasYOffset) { + y = rec.yOffset; + } + + double rat = textHeight / 1024.0 / font.getDivider(); + + result.append("\tvar textColor = ").append(CanvasShapeExporter.color(textColor)).append(";\r\n"); + for (GLYPHENTRY entry : rec.glyphEntries) { + Matrix mat = (new Matrix(textMatrix).concatenate(Matrix.getTranslateInstance(x, y))).concatenate(Matrix.getScaleInstance(rat)); + if (entry.glyphIndex != -1) { + // shapeNum: 1 + result.append("\tctx.save();\r\n"); + result.append("\tctx.transform(").append(mat.scaleX).append(",").append(mat.rotateSkew0).append(",").append(mat.rotateSkew1).append(",").append(mat.scaleY).append(",").append(mat.translateX).append(",").append(mat.translateY).append(");\r\n"); + result.append("\tfont").append(fontId).append("(ctx,\"").append(("" + font.glyphToChar(entry.glyphIndex)).replace("\\", "\\\\").replace("\"", "\\\"")).append("\",textColor);\r\n"); + result.append("\tctx.restore();\r\n"); + x += entry.glyphAdvance; + } + } + } + } + + public static void staticTextToSVG(SWF swf, List textRecords, int numText, SVGExporter exporter, RECT bounds, MATRIX textMatrix, ColorTransform colorTransform, double zoom) { + int textColor = 0; + FontTag font = null; + int textHeight = 12; + int x = 0; + int y = 0; + List glyphs = new ArrayList<>(); + for (TEXTRECORD rec : textRecords) { + if (rec.styleFlagsHasColor) { + if (numText == 2) { + textColor = rec.textColorA.toInt(); + } else { + textColor = rec.textColor.toInt(); + } + + if (colorTransform != null) { + textColor = colorTransform.apply(textColor); + } + } + if (rec.styleFlagsHasFont) { + font = swf.getFont(rec.fontId); + glyphs = font.getGlyphShapeTable(); + textHeight = rec.textHeight; + } + int offsetX = 0; + int offsetY = 0; + if (rec.styleFlagsHasXOffset) { + offsetX = rec.xOffset; + x = offsetX; + } + if (rec.styleFlagsHasYOffset) { + offsetY = rec.yOffset; + y = offsetY; + } + + double rat = textHeight / 1024.0 / font.getDivider(); + + exporter.createSubGroup(new Matrix(textMatrix), null); + if (exporter.useTextTag) { + StringBuilder text = new StringBuilder(); + int totalAdvance = 0; + for (GLYPHENTRY entry : rec.glyphEntries) { + if (entry.glyphIndex != -1) { + char ch = font.glyphToChar(entry.glyphIndex); + text.append(ch); + totalAdvance += entry.glyphAdvance; + } + } + + boolean hasOffset = offsetX != 0 || offsetY != 0; + if (hasOffset) { + exporter.createSubGroup(Matrix.getTranslateInstance(offsetX, offsetY), null); + } + + Element textElement = exporter.createElement("text"); + textElement.setAttribute("font-size", Double.toString(rat * 1024)); + textElement.setAttribute("font-family", font.getFontNameIntag()); + textElement.setAttribute("textLength", Double.toString(totalAdvance / SWF.unitDivisor)); + textElement.setAttribute("lengthAdjust", "spacing"); + textElement.setTextContent(text.toString()); + + RGBA colorA = new RGBA(textColor); + textElement.setAttribute("fill", colorA.toHexRGB()); + if (colorA.alpha != 255) { + textElement.setAttribute("fill-opacity", Float.toString(colorA.getAlphaFloat())); + } + + exporter.addToGroup(textElement); + FontExportMode fontExportMode = FontExportMode.WOFF; + exporter.addStyle(font.getFontNameIntag(), new FontExporter().exportFont(font, fontExportMode), fontExportMode); + + if (hasOffset) { + exporter.endGroup(); + } + } else { + for (GLYPHENTRY entry : rec.glyphEntries) { + Matrix mat = Matrix.getTranslateInstance(x, y).concatenate(Matrix.getScaleInstance(rat)); + if (entry.glyphIndex != -1) { + // shapeNum: 1 + SHAPE shape = glyphs.get(entry.glyphIndex); + char ch = font.glyphToChar(entry.glyphIndex); + + String charId = null; + Map chs; + if (exporter.exportedChars.containsKey(font)) { + chs = exporter.exportedChars.get(font); + if (chs.containsKey(entry.glyphIndex)) { + charId = chs.get(entry.glyphIndex); + } + } else { + chs = new HashMap<>(); + exporter.exportedChars.put(font, chs); + } + + if (charId == null) { + charId = exporter.getUniqueId(Helper.getValidHtmlId("font_" + font.getFontNameIntag() + "_" + ch)); + exporter.createDefGroup(null, charId); + SVGShapeExporter shapeExporter = new SVGShapeExporter(swf, shape, 0, exporter, null, colorTransform, zoom); + shapeExporter.export(); + if (!exporter.endGroup()) { + charId = ""; + } + + chs.put(entry.glyphIndex, charId); + } + + if (!"".equals(charId)) { + Element charImage = exporter.addUse(mat, bounds, charId, null); + RGBA colorA = new RGBA(textColor); + charImage.setAttribute("fill", colorA.toHexRGB()); + if (colorA.alpha != 255) { + charImage.setAttribute("fill-opacity", Float.toString(colorA.getAlphaFloat())); + } + } + + x += entry.glyphAdvance; + } + } + } + exporter.endGroup(); + } + } + + @Override + public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation, boolean stroked) { + RECT r = getBounds(); + Shape shp = new Rectangle.Double(r.Xmin, r.Ymin, r.getWidth(), r.getHeight()); + return transformation.toTransform().createTransformedShape(shp); //TODO: match character shapes (?) + } +} diff --git a/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java b/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java index b9dcbc0ff..97e1b99a2 100644 --- a/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java +++ b/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java @@ -1,902 +1,902 @@ -/* - * Copyright (C) 2010-2016 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.gui; - -import com.jpexs.debugger.flash.DebugConnectionListener; -import com.jpexs.debugger.flash.DebugMessageListener; -import com.jpexs.debugger.flash.Debugger; -import com.jpexs.debugger.flash.DebuggerCommands; -import com.jpexs.debugger.flash.DebuggerConnection; -import com.jpexs.debugger.flash.Variable; -import com.jpexs.debugger.flash.VariableFlags; -import com.jpexs.debugger.flash.VariableType; -import com.jpexs.debugger.flash.messages.in.InAskBreakpoints; -import com.jpexs.debugger.flash.messages.in.InBreakAt; -import com.jpexs.debugger.flash.messages.in.InBreakAtExt; -import com.jpexs.debugger.flash.messages.in.InBreakReason; -import com.jpexs.debugger.flash.messages.in.InCallFunction; -import com.jpexs.debugger.flash.messages.in.InConstantPool; -import com.jpexs.debugger.flash.messages.in.InContinue; -import com.jpexs.debugger.flash.messages.in.InFrame; -import com.jpexs.debugger.flash.messages.in.InGetSwd; -import com.jpexs.debugger.flash.messages.in.InGetSwf; -import com.jpexs.debugger.flash.messages.in.InGetVariable; -import com.jpexs.debugger.flash.messages.in.InNumScript; -import com.jpexs.debugger.flash.messages.in.InProcessTag; -import com.jpexs.debugger.flash.messages.in.InScript; -import com.jpexs.debugger.flash.messages.in.InSetBreakpoint; -import com.jpexs.debugger.flash.messages.in.InSwfInfo; -import com.jpexs.debugger.flash.messages.in.InTrace; -import com.jpexs.debugger.flash.messages.in.InVersion; -import com.jpexs.debugger.flash.messages.out.OutAddWatch2; -import com.jpexs.debugger.flash.messages.out.OutGetBreakReason; -import com.jpexs.debugger.flash.messages.out.OutGetSwd; -import com.jpexs.debugger.flash.messages.out.OutGetSwf; -import com.jpexs.debugger.flash.messages.out.OutPlay; -import com.jpexs.debugger.flash.messages.out.OutProcessedTag; -import com.jpexs.debugger.flash.messages.out.OutRewind; -import com.jpexs.debugger.flash.messages.out.OutSwfInfo; -import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.decompiler.graph.DottedChain; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeSet; -import java.util.logging.ConsoleHandler; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * - * @author JPEXS - */ -public class DebuggerHandler implements DebugConnectionListener { - - private boolean connected = false; - - private DebuggerCommands commands = null; - - private List swfs = new ArrayList<>(); - - private boolean paused = true; - - private Map modulePaths = new HashMap<>(); - - private Map moduleToSwfIndex = new HashMap<>(); - - private Map scriptToModule = new HashMap<>(); - - private Map moduleToTraitIndex = new HashMap<>(); - - private Map moduleToClassIndex = new HashMap<>(); - - private Map moduleToMethodIndex = new HashMap<>(); - - private Map> toAddBPointMap = new HashMap<>(); - - private Map> confirmedPointMap = new HashMap<>(); - - private Map> invalidBreakPointMap = new HashMap<>(); - - private Map> toRemoveBPointMap = new HashMap<>(); - - private int breakIp = -1; - - private String breakScriptName = null; - - public static class ActionScriptException extends Exception { - - private String errorClass; - - public ActionScriptException(String errorClass, String message) { - super(message); - this.errorClass = errorClass; - } - - public ActionScriptException(String errorClsMessage) { - this(errorClsMessage.substring(0, errorClsMessage.indexOf(": ")), errorClsMessage.substring(errorClsMessage.indexOf(": ") + 2)); - } - - public String getErrorClass() { - return errorClass; - } - } - - public int getBreakIp() { - if (!isPaused()) { - return -1; - } - return breakIp; - } - - public String getBreakScriptName() { - if (!isPaused()) { - return "-"; - } - return breakScriptName; - } - - public InGetVariable getVariable(long parentId, String varName, boolean children) { - try { - return commands.getVariable(parentId, varName, true, children); - } catch (IOException ex) { - return null; - } - } - - public void setVariable(long parentId, String varName, int valueType, Object value) { - try { - String svalue = ""; - switch (valueType) { - case VariableType.STRING: - svalue = "" + value; - break; - case VariableType.NUMBER: - svalue = "" + value; - break; - case VariableType.BOOLEAN: - svalue = ((Boolean) value) ? "true" : "false"; - break; - case VariableType.UNDEFINED: - svalue = "undefined"; - break; - case VariableType.NULL: - svalue = "undefined"; - break; - } - commands.setVariable(parentId, varName, valueType, svalue); - } catch (IOException ex) { - //ignore - } - } - - public synchronized void removeBreakPoint(String scriptName, int line) { - if (isBreakpointInvalid(scriptName, line)) { - invalidBreakPointMap.get(scriptName).remove(line); - if (invalidBreakPointMap.get(scriptName).isEmpty()) { - invalidBreakPointMap.remove(scriptName); - } - return; - } - if (isBreakpointToAdd(scriptName, line)) { - toAddBPointMap.get(scriptName).remove(line); - if (toAddBPointMap.get(scriptName).isEmpty()) { - toAddBPointMap.remove(scriptName); - } - } else if (isBreakpointConfirmed(scriptName, line)) { - if (!toRemoveBPointMap.containsKey(scriptName)) { - toRemoveBPointMap.put(scriptName, new TreeSet<>()); - } - toRemoveBPointMap.get(scriptName).add(line); - } - try { - sendBreakPoints(false); - } catch (IOException ex) { - //ignore - } - } - - private int watchTag = 1; - - public synchronized com.jpexs.debugger.flash.DebuggerCommands.Watch addWatch(Variable v, long v_id, boolean watchRead, boolean watchWrite) { - int tag = watchTag++; - try { - return commands.addWatch(v_id, v.name, (watchRead ? OutAddWatch2.FLAG_READ : 0) | (watchWrite ? OutAddWatch2.FLAG_WRITE : 0), tag); - } catch (IOException ex) { - return null; - } - } - - public synchronized Set getBreakPoints(String scriptName, boolean onlyValid) { - Set lines = new TreeSet<>(); - if (confirmedPointMap.containsKey(scriptName)) { - lines.addAll(confirmedPointMap.get(scriptName)); - } - if (toAddBPointMap.containsKey(scriptName)) { - lines.addAll(toAddBPointMap.get(scriptName)); - } - if (!onlyValid && invalidBreakPointMap.containsKey(scriptName)) { - lines.addAll(invalidBreakPointMap.get(scriptName)); - } - return lines; - } - - public synchronized void clearBreakPoints() { - for (String scriptName : confirmedPointMap.keySet()) { - if (!toAddBPointMap.containsKey(scriptName)) { - toAddBPointMap.put(scriptName, new TreeSet<>()); - } - toAddBPointMap.get(scriptName).addAll(confirmedPointMap.get(scriptName)); - } - for (String scriptName : invalidBreakPointMap.keySet()) { - if (!toAddBPointMap.containsKey(scriptName)) { - toAddBPointMap.put(scriptName, new TreeSet<>()); - } - toAddBPointMap.get(scriptName).addAll(invalidBreakPointMap.get(scriptName)); - } - confirmedPointMap.clear(); - invalidBreakPointMap.clear(); - } - - public synchronized Map> getAllBreakPoints(boolean validOnly) { - Map> ret = new HashMap<>(); - for (String scriptName : confirmedPointMap.keySet()) { - Set lines = new TreeSet<>(); - lines.addAll(confirmedPointMap.get(scriptName)); - ret.put(scriptName, lines); - } - for (String scriptName : toAddBPointMap.keySet()) { - if (!ret.containsKey(scriptName)) { - ret.put(scriptName, new TreeSet<>()); - } - ret.get(scriptName).addAll(toAddBPointMap.get(scriptName)); - } - if (!validOnly) { - for (String scriptName : invalidBreakPointMap.keySet()) { - if (!ret.containsKey(scriptName)) { - ret.put(scriptName, new TreeSet<>()); - } - ret.get(scriptName).addAll(invalidBreakPointMap.get(scriptName)); - } - } - return ret; - } - - public boolean addBreakPoint(String scriptName, int line) { - synchronized (this) { - Logger.getLogger(DebuggerHandler.class - .getName()).log(Level.FINE, "adding bp " + scriptName + ":" + line); - if (isBreakpointToRemove(scriptName, line)) { - toRemoveBPointMap.get(scriptName).remove(line); - if (toRemoveBPointMap.get(scriptName).isEmpty()) { - toRemoveBPointMap.remove(scriptName); - - } - } - - if (isBreakpointConfirmed(scriptName, line)) { - Logger.getLogger(DebuggerHandler.class.getName()).log(Level.FINE, "bp " + scriptName + ":" + line + " already confirmed"); - return true; - - } - if (isBreakpointInvalid(scriptName, line)) { - Logger.getLogger(DebuggerHandler.class.getName()).log(Level.FINE, "bp " + scriptName + ":" + line + " already invalid"); - return false; - } - if (!toAddBPointMap.containsKey(scriptName)) { - toAddBPointMap.put(scriptName, new TreeSet<>()); - } - toAddBPointMap.get(scriptName).add(line); - Logger - .getLogger(DebuggerHandler.class - .getName()).log(Level.FINE, "bp " + scriptName + ":" + line + " added to todo"); - } - try { - sendBreakPoints(false); - } catch (IOException ex) { - //ignored - } - - return true; - } - - public synchronized boolean isBreakpointConfirmed(String scriptName, int line) { - return confirmedPointMap.containsKey(scriptName) && confirmedPointMap.get(scriptName).contains(line); - } - - public synchronized boolean isBreakpointToAdd(String scriptName, int line) { - return toAddBPointMap.containsKey(scriptName) && toAddBPointMap.get(scriptName).contains(line); - } - - public synchronized boolean isBreakpointToRemove(String scriptName, int line) { - return toRemoveBPointMap.containsKey(scriptName) && toRemoveBPointMap.get(scriptName).contains(line); - } - - public synchronized boolean isBreakpointInvalid(String scriptName, int line) { - return invalidBreakPointMap.containsKey(scriptName) && invalidBreakPointMap.get(scriptName).contains(line); - } - - private synchronized void markBreakPointInvalid(String scriptName, int line) { - if (!invalidBreakPointMap.containsKey(scriptName)) { - invalidBreakPointMap.put(scriptName, new TreeSet<>()); - } - invalidBreakPointMap.get(scriptName).add(line); - } - - private InFrame frame; - - private InConstantPool pool; - - private InBreakAtExt breakInfo; - - private InBreakReason breakReason; - - private final List breakListeners = new ArrayList<>(); - - private final List traceListeners = new ArrayList<>(); - - private final List clisteners = new ArrayList<>(); - - public String moduleToString(int file) { - if (!modulePaths.containsKey(file)) { - return "unknown"; - } - return modulePaths.get(file); - } - - public synchronized InBreakAtExt getBreakInfo() { - if (!paused) { - return null; - } - return breakInfo; - } - - public synchronized InBreakReason getBreakReason() { - if (!paused) { - return null; - } - return breakReason; - } - - public static interface ConnectionListener { - - public void connected(); - - public void disconnected(); - } - - public static interface TraceListener { - - public void trace(String... val); - } - - public static interface BreakListener { - - public void breakAt(String scriptName, int line, int classIndex, int traitIndex, int methodIndex); - - public void doContinue(); - } - - public void addBreakListener(BreakListener l) { - breakListeners.add(l); - } - - public void addTraceListener(TraceListener l) { - traceListeners.add(l); - } - - public void removeTraceListener(TraceListener l) { - traceListeners.remove(l); - } - - public void removeBreakListener(BreakListener l) { - breakListeners.remove(l); - } - - public void addConnectionListener(ConnectionListener l) { - clisteners.add(l); - } - - public void removeConnectionListener(ConnectionListener l) { - clisteners.remove(l); - } - - public synchronized void refreshFrame() { - if (!paused) { - return; - } - try { - frame = commands.getFrame(0); - pool = commands.getConstantPool(0); - } catch (IOException ex) { - //ignore - } - } - - public synchronized InFrame getFrame() { - if (!paused) { - return null; - } - return frame; - } - - public synchronized int moduleIdOf(String pack) { - if (scriptToModule.containsKey(pack)) { - return scriptToModule.get(pack); - } - return -1; - } - - public boolean isPaused() { - if (!isConnected()) { - return false; - } - synchronized (this) { - return paused; - } - } - - public List getSwfs() { - return swfs; - } - - public void disconnect() { - frame = null; - pool = null; - breakInfo = null; - breakReason = null; - connected = false; - if (commands != null) { - commands.disconnect(); - } - commands = null; - synchronized (this) { - for (String scriptName : confirmedPointMap.keySet()) { - if (!toAddBPointMap.containsKey(scriptName)) { - toAddBPointMap.put(scriptName, new TreeSet<>()); - } - toAddBPointMap.get(scriptName).addAll(confirmedPointMap.get(scriptName)); - } - confirmedPointMap.clear(); - for (String scriptName : invalidBreakPointMap.keySet()) { - if (!toAddBPointMap.containsKey(scriptName)) { - toAddBPointMap.put(scriptName, new TreeSet<>()); - } - toAddBPointMap.get(scriptName).addAll(invalidBreakPointMap.get(scriptName)); - } - invalidBreakPointMap.clear(); - } - for (ConnectionListener l : clisteners) { - l.disconnected(); - } - } - - public synchronized boolean isConnected() { - return connected; - } - - public DebuggerCommands getCommands() throws IOException { - if (!isConnected() || commands == null) { - throw new IOException("Not connected"); - } - return commands; - } - - private static void enlog(Class cls) { - Level level = Level.FINEST; - - Logger mylog = Logger.getLogger(cls.getName()); - mylog.setLevel(level); - ConsoleHandler ch = new ConsoleHandler(); - ch.setLevel(level); - mylog.addHandler(ch); - } - - @Override - public void failedListen(IOException ex) { - View.execInEventDispatch(new Runnable() { - @Override - public void run() { - disconnect(); - Main.stopRun(); - Main.stopWork(); - View.showMessageDialog(Main.getMainFrame().getPanel(), AppStrings.translate("error.debug.listen").replace("%port%", "" + Debugger.DEBUG_PORT)); - Main.getMainFrame().getPanel().updateMenu(); - } - }); - - } - - @Override - public void connected(DebuggerConnection con) { - clearBreakPoints(); - - Main.startWork(AppStrings.translate("work.debugging"), null); - - synchronized (this) { - paused = false; - } - - Main.getMainFrame().getPanel().updateMenu(); - - //enlog(DebuggerConnection.class); - //enlog(DebuggerCommands.class); - //enlog(DebuggerHandler.class); - try { - con.getMessage(InVersion.class); - } catch (IOException ex) { - Logger.getLogger(DebuggerHandler.class.getName()).log(Level.SEVERE, null, ex); - } - - //Respon to InProcessTag with OutProcessedTag - con.addMessageListener(new DebugMessageListener() { - @Override - public void message(InProcessTag message) { - try { - con.writeMessage(new OutProcessedTag(con)); - } catch (IOException ex) { - //disconnect(); - //ignore - } - } - }); - - swfs.clear(); - - Map moduleNames = new HashMap<>(); - - final Pattern patAS3 = Pattern.compile("^(.*);(.*);(.*)\\.as$"); - final Pattern patAS3PCode = Pattern.compile("^#PCODE abc:([0-9]+),script:([0-9]+),class:(-?[0-9]+),trait:(-?[0-9]+),method:([0-9]+),body:([0-9]+);(.*)$"); - - try { - - con.addMessageListener(new DebugMessageListener() { - @Override - public void message(InNumScript t) { - con.dropMessage(t); - } - }); - - modulePaths = new HashMap<>(); - scriptToModule = new HashMap<>(); - - con.addMessageListener(new DebugMessageListener() { - @Override - public void message(InScript sc) { - moduleNames.put(sc.module, sc.name); - moduleToSwfIndex.put(sc.module, sc.swfIndex); - int file = sc.module; - String name = sc.name; - String[] parts = name.split(";"); - - Matcher m; - if ((m = patAS3.matcher(name)).matches()) { - String clsNameWithSuffix = m.group(3); - String pkg = m.group(2).replace("\\", "."); - m = patAS3PCode.matcher(name); - - if (m.matches()) { - moduleToClassIndex.put(file, Integer.parseInt(m.group(3))); - moduleToTraitIndex.put(file, Integer.parseInt(m.group(4))); - moduleToMethodIndex.put(file, Integer.parseInt(m.group(5))); - name = DottedChain.parseWithSuffix(pkg).addWithSuffix(clsNameWithSuffix).toString(); - name = "#PCODE abc:" + m.group(1) + ",body:" + m.group(6) + ";" + name; - } else { - name = DottedChain.parseWithSuffix(pkg).addWithSuffix(clsNameWithSuffix).toString(); - } - } - modulePaths.put(file, name); - scriptToModule.put(name, file); - con.dropMessage(sc); - } - }); - - /*int numScript = con.getMessage(InNumScript.class).num; - for (int i = 0; i < numScript; i++) { - InScript sc = con.getMessage(InScript.class); - moduleNames.put(sc.module, sc.name); - }*/ - //Pattern patMainFrame = Pattern.compile("^Actions for Scene ([0-9]+): Frame ([0-9]+) of Layer Name .*$"); - //Pattern patSymbol = Pattern.compile("^Actions for Symbol ([0-9]+): Frame ([0-9]+) of Layer Name .*$"); - //Pattern patAS2 = Pattern.compile("^([^:]+): .*\\.as$"); - //con.getMessage(InSetBreakpoint.class); - commands = new DebuggerCommands(con); - - commands.stopWarning(); - commands.setStopOnFault(); - commands.setEnumerateOverride(); - commands.setNotifyFailure(); - commands.setInvokeSetters(); - commands.setSwfLoadNotify(); - commands.setGetterTimeout(1500); - commands.setSetterTimeout(5000); - - boolean isAS3 = (Main.getMainFrame().getPanel().getCurrentSwf().isAS3()); - con.isAS3 = isAS3; - - //Widelines - only AS3, it hangs in AS1/2 and SWD does not support UI32 lines - if (isAS3) { - con.wideLines = commands.getOption("wide_line_player", "false").equals("true"); - if (con.wideLines) { - commands.setOption("wide_line_debugger", "on"); - } - } - commands.squelch(true); - - con.writeMessage(new OutSwfInfo(con, 0)); - con.addMessageListener(new DebugMessageListener() { - @Override - public void message(InSwfInfo t) { - for (InSwfInfo.SwfInfo s : t.swfInfos) { - swfs.add(s); - View.execInEventDispatch(new Runnable() { - @Override - public void run() { - try { - con.sendMessage(new OutGetSwf(con, (int) s.index), InGetSwf.class); - con.sendMessage(new OutGetSwd(con, (int) s.index), InGetSwd.class); - } catch (IOException ex) { - //ignore - } - } - }); - } - con.dropMessage(t); - } - }); - - InSetBreakpoint isb = con.getMessage(InSetBreakpoint.class); - synchronized (this) { - for (int i = 0; i < isb.files.size(); i++) { - String sname = moduleNames.get(isb.files.get(i)); - if (!confirmedPointMap.containsKey(sname)) { - confirmedPointMap.put(sname, new TreeSet<>()); - } - if (toAddBPointMap.containsKey(sname)) { - toAddBPointMap.get(sname).remove(isb.lines.get(i)); - if (toAddBPointMap.get(sname).isEmpty()) { - toAddBPointMap.remove(sname); - } - } - confirmedPointMap.get(sname).add(isb.lines.get(i)); - Logger.getLogger(DebuggerHandler.class.getName()).log(Level.INFO, "Breakpoint {0}:{1} submitted successfully", new Object[]{sname, isb.lines.get(i)}); - } - } - - synchronized (this) { - connected = true; - } - con.addMessageListener(new DebugMessageListener() { - @Override - public void message(InAskBreakpoints message) { - - } - }); - con.addMessageListener(new DebugMessageListener() { - @Override - public void message(InContinue msg) { - synchronized (DebuggerHandler.this) { - paused = false; - Logger.getLogger(DebuggerHandler.class.getName()).log(Level.FINE, "continued"); - } - for (BreakListener bl : breakListeners) { - bl.doContinue(); - } - } - }); - con.addMessageListener(new DebugMessageListener() { - @Override - public void message(InBreakAt message) { - synchronized (DebuggerHandler.this) { - paused = true; - Logger.getLogger(DebuggerHandler.class.getName()).log(Level.FINE, "paused"); - - } - - try { - breakInfo = con.getMessage(InBreakAtExt.class); - breakReason = con.sendMessage(new OutGetBreakReason(con), InBreakReason.class); - - String newBreakScriptName = "unknown"; - if (modulePaths.containsKey(message.file)) { - newBreakScriptName = modulePaths.get(message.file); - - } else if (breakReason.reason != InBreakReason.REASON_SCRIPT_LOADED) { - Logger.getLogger(DebuggerCommands.class.getName()).log(Level.SEVERE, "Invalid file: {0}", message.file); - return; - } - - final String[] reasonNames = new String[]{"unknown", "breakpoint", "watch", "fault", "stopRequest", "step", "halt", "scriptLoaded"}; - String reason = breakReason.reason < reasonNames.length ? reasonNames[breakReason.reason] : reasonNames[0]; - - Logger.getLogger(DebuggerHandler.class.getName()).log(Level.FINE, "break at {0}:{1}, reason: {2}", new Object[]{newBreakScriptName, message.line, reason}); - - sendBreakPoints(false); - synchronized (DebuggerHandler.this) { - breakScriptName = newBreakScriptName; - breakIp = message.line; - } - - if (breakReason.reason == InBreakReason.REASON_SCRIPT_LOADED) { - if (!Configuration.debugHalt.get()) { - commands.sendContinue(); - return; - } - Main.startWork(AppStrings.translate("work.halted"), null); - } else { - Main.startWork(AppStrings.translate("work.breakat") + newBreakScriptName + ":" + message.line + " " + AppStrings.translate("debug.break.reason." + reason), null); - } - frame = commands.getFrame(0); - pool = commands.getConstantPool(0); - - for (BreakListener l : breakListeners) { - l.breakAt(newBreakScriptName, message.line, - moduleToClassIndex.containsKey(message.file) ? moduleToClassIndex.get(message.file) : -1, - moduleToTraitIndex.containsKey(message.file) ? moduleToTraitIndex.get(message.file) : -1, - moduleToMethodIndex.containsKey(message.file) ? moduleToMethodIndex.get(message.file) : -1 - ); - } - - } catch (IOException ex) { - //ignore - } - - } - }); - - for (ConnectionListener l : clisteners) { - l.connected(); - } - - con.addMessageListener(new DebugMessageListener() { - @Override - public void message(InTrace tr) { - for (TraceListener l : traceListeners) { - l.trace(tr.text); - } - } - }); - - if (!isAS3) { - Logger.getLogger(DebuggerHandler.class.getName()).log(Level.FINER, "End of connect - sending continue"); - con.writeMessage(new OutRewind(con)); - con.writeMessage(new OutPlay(con)); - commands.sendContinue(); - } - - } catch (IOException ex) { - - synchronized (this) { - connected = false; - } - } - } - - private void sendBreakPoints(boolean force) throws IOException { - if (!force && !isPaused()) { - Logger.getLogger(DebuggerHandler.class.getName()).log(Level.FINEST, "not sending bps, not paused"); - return; - } - synchronized (this) { - for (String scriptName : toRemoveBPointMap.keySet()) { - int file = moduleIdOf(scriptName); - if (file > -1) { - for (int line : toRemoveBPointMap.get(scriptName)) { - if (isBreakpointConfirmed(scriptName, line)) { - commands.removeBreakPoint(file, line); - confirmedPointMap.get(scriptName).remove(line); - if (confirmedPointMap.get(scriptName).isEmpty()) { - confirmedPointMap.remove(scriptName); - } - } - Logger.getLogger(DebuggerHandler.class.getName()).log(Level.INFO, "Breakpoint {0}:{1} removed", new Object[]{scriptName, line}); - } - } - } - toRemoveBPointMap.clear(); - - for (String scriptName : toAddBPointMap.keySet()) { - int file = moduleIdOf(scriptName); - if (file > -1) { - for (int line : toAddBPointMap.get(scriptName)) { - if (commands.addBreakPoint(file, line)) { - Logger.getLogger(DebuggerHandler.class.getName()).log(Level.INFO, "Breakpoint {0}:{1} submitted successfully", new Object[]{scriptName, line}); - if (!confirmedPointMap.containsKey(scriptName)) { - confirmedPointMap.put(scriptName, new TreeSet<>()); - } - confirmedPointMap.get(scriptName).add(line); - } else { - Logger.getLogger(DebuggerHandler.class.getName()).log(Level.INFO, "Breakpoint {0}:{1} unable to submit", new Object[]{scriptName, line}); - markBreakPointInvalid(scriptName, line); - } - } - } else { - for (int line : toAddBPointMap.get(scriptName)) { - markBreakPointInvalid(scriptName, line); - } - } - } - toAddBPointMap.clear(); - - } - Logger.getLogger(DebuggerHandler.class.getName()).log(Level.FINEST, "sending bps finished"); - - } - - public synchronized InConstantPool getConstantPool() { - if (!paused) { - return null; - } - return pool; - } - - public synchronized InCallFunction callMethod(Variable object, String methodName, List args) throws ActionScriptException { - return callFunction(false, methodName, object, args); - } - - public synchronized InCallFunction callMethod(String object, String methodName, List args) throws ActionScriptException { - InGetVariable igv = getVariable(0, object, false); - return callMethod(igv.parent, methodName, args); - } - - private static String typeAsStr(Object value) { - if (value == null) { - return "null"; - } - if ((value instanceof Long) || (value instanceof Integer)) { - return "int"; - } - if (value instanceof Number) { - return "Number"; - } - if (value instanceof String) { - return "String"; - } - if (value instanceof Variable) { - Variable v = (Variable) value; - return v.getTypeAsStr(); - } - return "String"; - } - - private static String valueAsStr(Object value) { - if (value == null) { - return "null"; - } - if (value instanceof Double) { - double doubleValue = ((Double) value).doubleValue(); - long longValue = (long) doubleValue; - if (doubleValue == longValue) { - return Long.toString(longValue); - } - } - - if (value instanceof Variable) { - Variable v = (Variable) value; - return valueAsStr(v.value); - } - return "" + value; - } - - public synchronized InCallFunction callFunction(boolean isConstructor, String funcName, Variable thisValue, List args) throws ActionScriptException { - List argTypes = new ArrayList<>(); - List argValues = new ArrayList<>(); - for (Object value : args) { - argTypes.add(typeAsStr(value)); - argValues.add(valueAsStr(value)); - } - String thisType = typeAsStr(thisValue); - String thisValueStr = valueAsStr(thisValue); - try { - InCallFunction icf = commands.callFunction(isConstructor, funcName, thisType, thisValueStr, argTypes, argValues); - if (!icf.variables.isEmpty()) { - if ((icf.variables.get(0).flags & VariableFlags.IS_EXCEPTION) > 0) { - throw new ActionScriptException("" + icf.variables.get(0).value); - } - } - return icf; - } catch (IOException e) { - - } - return null; - } -} +/* + * Copyright (C) 2010-2016 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.gui; + +import com.jpexs.debugger.flash.DebugConnectionListener; +import com.jpexs.debugger.flash.DebugMessageListener; +import com.jpexs.debugger.flash.Debugger; +import com.jpexs.debugger.flash.DebuggerCommands; +import com.jpexs.debugger.flash.DebuggerConnection; +import com.jpexs.debugger.flash.Variable; +import com.jpexs.debugger.flash.VariableFlags; +import com.jpexs.debugger.flash.VariableType; +import com.jpexs.debugger.flash.messages.in.InAskBreakpoints; +import com.jpexs.debugger.flash.messages.in.InBreakAt; +import com.jpexs.debugger.flash.messages.in.InBreakAtExt; +import com.jpexs.debugger.flash.messages.in.InBreakReason; +import com.jpexs.debugger.flash.messages.in.InCallFunction; +import com.jpexs.debugger.flash.messages.in.InConstantPool; +import com.jpexs.debugger.flash.messages.in.InContinue; +import com.jpexs.debugger.flash.messages.in.InFrame; +import com.jpexs.debugger.flash.messages.in.InGetSwd; +import com.jpexs.debugger.flash.messages.in.InGetSwf; +import com.jpexs.debugger.flash.messages.in.InGetVariable; +import com.jpexs.debugger.flash.messages.in.InNumScript; +import com.jpexs.debugger.flash.messages.in.InProcessTag; +import com.jpexs.debugger.flash.messages.in.InScript; +import com.jpexs.debugger.flash.messages.in.InSetBreakpoint; +import com.jpexs.debugger.flash.messages.in.InSwfInfo; +import com.jpexs.debugger.flash.messages.in.InTrace; +import com.jpexs.debugger.flash.messages.in.InVersion; +import com.jpexs.debugger.flash.messages.out.OutAddWatch2; +import com.jpexs.debugger.flash.messages.out.OutGetBreakReason; +import com.jpexs.debugger.flash.messages.out.OutGetSwd; +import com.jpexs.debugger.flash.messages.out.OutGetSwf; +import com.jpexs.debugger.flash.messages.out.OutPlay; +import com.jpexs.debugger.flash.messages.out.OutProcessedTag; +import com.jpexs.debugger.flash.messages.out.OutRewind; +import com.jpexs.debugger.flash.messages.out.OutSwfInfo; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.graph.DottedChain; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; +import java.util.logging.ConsoleHandler; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * + * @author JPEXS + */ +public class DebuggerHandler implements DebugConnectionListener { + + private boolean connected = false; + + private DebuggerCommands commands = null; + + private List swfs = new ArrayList<>(); + + private boolean paused = true; + + private Map modulePaths = new HashMap<>(); + + private Map moduleToSwfIndex = new HashMap<>(); + + private Map scriptToModule = new HashMap<>(); + + private Map moduleToTraitIndex = new HashMap<>(); + + private Map moduleToClassIndex = new HashMap<>(); + + private Map moduleToMethodIndex = new HashMap<>(); + + private Map> toAddBPointMap = new HashMap<>(); + + private Map> confirmedPointMap = new HashMap<>(); + + private Map> invalidBreakPointMap = new HashMap<>(); + + private Map> toRemoveBPointMap = new HashMap<>(); + + private int breakIp = -1; + + private String breakScriptName = null; + + public static class ActionScriptException extends Exception { + + private String errorClass; + + public ActionScriptException(String errorClass, String message) { + super(message); + this.errorClass = errorClass; + } + + public ActionScriptException(String errorClsMessage) { + this(errorClsMessage.substring(0, errorClsMessage.indexOf(": ")), errorClsMessage.substring(errorClsMessage.indexOf(": ") + 2)); + } + + public String getErrorClass() { + return errorClass; + } + } + + public int getBreakIp() { + if (!isPaused()) { + return -1; + } + return breakIp; + } + + public String getBreakScriptName() { + if (!isPaused()) { + return "-"; + } + return breakScriptName; + } + + public InGetVariable getVariable(long parentId, String varName, boolean children) { + try { + return commands.getVariable(parentId, varName, true, children); + } catch (IOException ex) { + return null; + } + } + + public void setVariable(long parentId, String varName, int valueType, Object value) { + try { + String svalue = ""; + switch (valueType) { + case VariableType.STRING: + svalue = "" + value; + break; + case VariableType.NUMBER: + svalue = "" + value; + break; + case VariableType.BOOLEAN: + svalue = ((Boolean) value) ? "true" : "false"; + break; + case VariableType.UNDEFINED: + svalue = "undefined"; + break; + case VariableType.NULL: + svalue = "undefined"; + break; + } + commands.setVariable(parentId, varName, valueType, svalue); + } catch (IOException ex) { + //ignore + } + } + + public synchronized void removeBreakPoint(String scriptName, int line) { + if (isBreakpointInvalid(scriptName, line)) { + invalidBreakPointMap.get(scriptName).remove(line); + if (invalidBreakPointMap.get(scriptName).isEmpty()) { + invalidBreakPointMap.remove(scriptName); + } + return; + } + if (isBreakpointToAdd(scriptName, line)) { + toAddBPointMap.get(scriptName).remove(line); + if (toAddBPointMap.get(scriptName).isEmpty()) { + toAddBPointMap.remove(scriptName); + } + } else if (isBreakpointConfirmed(scriptName, line)) { + if (!toRemoveBPointMap.containsKey(scriptName)) { + toRemoveBPointMap.put(scriptName, new TreeSet<>()); + } + toRemoveBPointMap.get(scriptName).add(line); + } + try { + sendBreakPoints(false); + } catch (IOException ex) { + //ignore + } + } + + private int watchTag = 1; + + public synchronized com.jpexs.debugger.flash.DebuggerCommands.Watch addWatch(Variable v, long v_id, boolean watchRead, boolean watchWrite) { + int tag = watchTag++; + try { + return commands.addWatch(v_id, v.name, (watchRead ? OutAddWatch2.FLAG_READ : 0) | (watchWrite ? OutAddWatch2.FLAG_WRITE : 0), tag); + } catch (IOException ex) { + return null; + } + } + + public synchronized Set getBreakPoints(String scriptName, boolean onlyValid) { + Set lines = new TreeSet<>(); + if (confirmedPointMap.containsKey(scriptName)) { + lines.addAll(confirmedPointMap.get(scriptName)); + } + if (toAddBPointMap.containsKey(scriptName)) { + lines.addAll(toAddBPointMap.get(scriptName)); + } + if (!onlyValid && invalidBreakPointMap.containsKey(scriptName)) { + lines.addAll(invalidBreakPointMap.get(scriptName)); + } + return lines; + } + + public synchronized void clearBreakPoints() { + for (String scriptName : confirmedPointMap.keySet()) { + if (!toAddBPointMap.containsKey(scriptName)) { + toAddBPointMap.put(scriptName, new TreeSet<>()); + } + toAddBPointMap.get(scriptName).addAll(confirmedPointMap.get(scriptName)); + } + for (String scriptName : invalidBreakPointMap.keySet()) { + if (!toAddBPointMap.containsKey(scriptName)) { + toAddBPointMap.put(scriptName, new TreeSet<>()); + } + toAddBPointMap.get(scriptName).addAll(invalidBreakPointMap.get(scriptName)); + } + confirmedPointMap.clear(); + invalidBreakPointMap.clear(); + } + + public synchronized Map> getAllBreakPoints(boolean validOnly) { + Map> ret = new HashMap<>(); + for (String scriptName : confirmedPointMap.keySet()) { + Set lines = new TreeSet<>(); + lines.addAll(confirmedPointMap.get(scriptName)); + ret.put(scriptName, lines); + } + for (String scriptName : toAddBPointMap.keySet()) { + if (!ret.containsKey(scriptName)) { + ret.put(scriptName, new TreeSet<>()); + } + ret.get(scriptName).addAll(toAddBPointMap.get(scriptName)); + } + if (!validOnly) { + for (String scriptName : invalidBreakPointMap.keySet()) { + if (!ret.containsKey(scriptName)) { + ret.put(scriptName, new TreeSet<>()); + } + ret.get(scriptName).addAll(invalidBreakPointMap.get(scriptName)); + } + } + return ret; + } + + public boolean addBreakPoint(String scriptName, int line) { + synchronized (this) { + Logger.getLogger(DebuggerHandler.class + .getName()).log(Level.FINE, "adding bp " + scriptName + ":" + line); + if (isBreakpointToRemove(scriptName, line)) { + toRemoveBPointMap.get(scriptName).remove(line); + if (toRemoveBPointMap.get(scriptName).isEmpty()) { + toRemoveBPointMap.remove(scriptName); + + } + } + + if (isBreakpointConfirmed(scriptName, line)) { + Logger.getLogger(DebuggerHandler.class.getName()).log(Level.FINE, "bp " + scriptName + ":" + line + " already confirmed"); + return true; + + } + if (isBreakpointInvalid(scriptName, line)) { + Logger.getLogger(DebuggerHandler.class.getName()).log(Level.FINE, "bp " + scriptName + ":" + line + " already invalid"); + return false; + } + if (!toAddBPointMap.containsKey(scriptName)) { + toAddBPointMap.put(scriptName, new TreeSet<>()); + } + toAddBPointMap.get(scriptName).add(line); + Logger + .getLogger(DebuggerHandler.class + .getName()).log(Level.FINE, "bp " + scriptName + ":" + line + " added to todo"); + } + try { + sendBreakPoints(false); + } catch (IOException ex) { + //ignored + } + + return true; + } + + public synchronized boolean isBreakpointConfirmed(String scriptName, int line) { + return confirmedPointMap.containsKey(scriptName) && confirmedPointMap.get(scriptName).contains(line); + } + + public synchronized boolean isBreakpointToAdd(String scriptName, int line) { + return toAddBPointMap.containsKey(scriptName) && toAddBPointMap.get(scriptName).contains(line); + } + + public synchronized boolean isBreakpointToRemove(String scriptName, int line) { + return toRemoveBPointMap.containsKey(scriptName) && toRemoveBPointMap.get(scriptName).contains(line); + } + + public synchronized boolean isBreakpointInvalid(String scriptName, int line) { + return invalidBreakPointMap.containsKey(scriptName) && invalidBreakPointMap.get(scriptName).contains(line); + } + + private synchronized void markBreakPointInvalid(String scriptName, int line) { + if (!invalidBreakPointMap.containsKey(scriptName)) { + invalidBreakPointMap.put(scriptName, new TreeSet<>()); + } + invalidBreakPointMap.get(scriptName).add(line); + } + + private InFrame frame; + + private InConstantPool pool; + + private InBreakAtExt breakInfo; + + private InBreakReason breakReason; + + private final List breakListeners = new ArrayList<>(); + + private final List traceListeners = new ArrayList<>(); + + private final List clisteners = new ArrayList<>(); + + public String moduleToString(int file) { + if (!modulePaths.containsKey(file)) { + return "unknown"; + } + return modulePaths.get(file); + } + + public synchronized InBreakAtExt getBreakInfo() { + if (!paused) { + return null; + } + return breakInfo; + } + + public synchronized InBreakReason getBreakReason() { + if (!paused) { + return null; + } + return breakReason; + } + + public static interface ConnectionListener { + + public void connected(); + + public void disconnected(); + } + + public static interface TraceListener { + + public void trace(String... val); + } + + public static interface BreakListener { + + public void breakAt(String scriptName, int line, int classIndex, int traitIndex, int methodIndex); + + public void doContinue(); + } + + public void addBreakListener(BreakListener l) { + breakListeners.add(l); + } + + public void addTraceListener(TraceListener l) { + traceListeners.add(l); + } + + public void removeTraceListener(TraceListener l) { + traceListeners.remove(l); + } + + public void removeBreakListener(BreakListener l) { + breakListeners.remove(l); + } + + public void addConnectionListener(ConnectionListener l) { + clisteners.add(l); + } + + public void removeConnectionListener(ConnectionListener l) { + clisteners.remove(l); + } + + public synchronized void refreshFrame() { + if (!paused) { + return; + } + try { + frame = commands.getFrame(0); + pool = commands.getConstantPool(0); + } catch (IOException ex) { + //ignore + } + } + + public synchronized InFrame getFrame() { + if (!paused) { + return null; + } + return frame; + } + + public synchronized int moduleIdOf(String pack) { + if (scriptToModule.containsKey(pack)) { + return scriptToModule.get(pack); + } + return -1; + } + + public boolean isPaused() { + if (!isConnected()) { + return false; + } + synchronized (this) { + return paused; + } + } + + public List getSwfs() { + return swfs; + } + + public void disconnect() { + frame = null; + pool = null; + breakInfo = null; + breakReason = null; + connected = false; + if (commands != null) { + commands.disconnect(); + } + commands = null; + synchronized (this) { + for (String scriptName : confirmedPointMap.keySet()) { + if (!toAddBPointMap.containsKey(scriptName)) { + toAddBPointMap.put(scriptName, new TreeSet<>()); + } + toAddBPointMap.get(scriptName).addAll(confirmedPointMap.get(scriptName)); + } + confirmedPointMap.clear(); + for (String scriptName : invalidBreakPointMap.keySet()) { + if (!toAddBPointMap.containsKey(scriptName)) { + toAddBPointMap.put(scriptName, new TreeSet<>()); + } + toAddBPointMap.get(scriptName).addAll(invalidBreakPointMap.get(scriptName)); + } + invalidBreakPointMap.clear(); + } + for (ConnectionListener l : clisteners) { + l.disconnected(); + } + } + + public synchronized boolean isConnected() { + return connected; + } + + public DebuggerCommands getCommands() throws IOException { + if (!isConnected() || commands == null) { + throw new IOException("Not connected"); + } + return commands; + } + + private static void enlog(Class cls) { + Level level = Level.FINEST; + + Logger mylog = Logger.getLogger(cls.getName()); + mylog.setLevel(level); + ConsoleHandler ch = new ConsoleHandler(); + ch.setLevel(level); + mylog.addHandler(ch); + } + + @Override + public void failedListen(IOException ex) { + View.execInEventDispatch(new Runnable() { + @Override + public void run() { + disconnect(); + Main.stopRun(); + Main.stopWork(); + View.showMessageDialog(Main.getMainFrame().getPanel(), AppStrings.translate("error.debug.listen").replace("%port%", "" + Debugger.DEBUG_PORT)); + Main.getMainFrame().getPanel().updateMenu(); + } + }); + + } + + @Override + public void connected(DebuggerConnection con) { + clearBreakPoints(); + + Main.startWork(AppStrings.translate("work.debugging"), null); + + synchronized (this) { + paused = false; + } + + Main.getMainFrame().getPanel().updateMenu(); + + //enlog(DebuggerConnection.class); + //enlog(DebuggerCommands.class); + //enlog(DebuggerHandler.class); + try { + con.getMessage(InVersion.class); + } catch (IOException ex) { + Logger.getLogger(DebuggerHandler.class.getName()).log(Level.SEVERE, null, ex); + } + + //Respon to InProcessTag with OutProcessedTag + con.addMessageListener(new DebugMessageListener() { + @Override + public void message(InProcessTag message) { + try { + con.writeMessage(new OutProcessedTag(con)); + } catch (IOException ex) { + //disconnect(); + //ignore + } + } + }); + + swfs.clear(); + + Map moduleNames = new HashMap<>(); + + final Pattern patAS3 = Pattern.compile("^(.*);(.*);(.*)\\.as$"); + final Pattern patAS3PCode = Pattern.compile("^#PCODE abc:([0-9]+),script:([0-9]+),class:(-?[0-9]+),trait:(-?[0-9]+),method:([0-9]+),body:([0-9]+);(.*)$"); + + try { + + con.addMessageListener(new DebugMessageListener() { + @Override + public void message(InNumScript t) { + con.dropMessage(t); + } + }); + + modulePaths = new HashMap<>(); + scriptToModule = new HashMap<>(); + + con.addMessageListener(new DebugMessageListener() { + @Override + public void message(InScript sc) { + moduleNames.put(sc.module, sc.name); + moduleToSwfIndex.put(sc.module, sc.swfIndex); + int file = sc.module; + String name = sc.name; + String[] parts = name.split(";"); + + Matcher m; + if ((m = patAS3.matcher(name)).matches()) { + String clsNameWithSuffix = m.group(3); + String pkg = m.group(2).replace("\\", "."); + m = patAS3PCode.matcher(name); + + if (m.matches()) { + moduleToClassIndex.put(file, Integer.parseInt(m.group(3))); + moduleToTraitIndex.put(file, Integer.parseInt(m.group(4))); + moduleToMethodIndex.put(file, Integer.parseInt(m.group(5))); + name = DottedChain.parseWithSuffix(pkg).addWithSuffix(clsNameWithSuffix).toString(); + name = "#PCODE abc:" + m.group(1) + ",body:" + m.group(6) + ";" + name; + } else { + name = DottedChain.parseWithSuffix(pkg).addWithSuffix(clsNameWithSuffix).toString(); + } + } + modulePaths.put(file, name); + scriptToModule.put(name, file); + con.dropMessage(sc); + } + }); + + /*int numScript = con.getMessage(InNumScript.class).num; + for (int i = 0; i < numScript; i++) { + InScript sc = con.getMessage(InScript.class); + moduleNames.put(sc.module, sc.name); + }*/ + //Pattern patMainFrame = Pattern.compile("^Actions for Scene ([0-9]+): Frame ([0-9]+) of Layer Name .*$"); + //Pattern patSymbol = Pattern.compile("^Actions for Symbol ([0-9]+): Frame ([0-9]+) of Layer Name .*$"); + //Pattern patAS2 = Pattern.compile("^([^:]+): .*\\.as$"); + //con.getMessage(InSetBreakpoint.class); + commands = new DebuggerCommands(con); + + commands.stopWarning(); + commands.setStopOnFault(); + commands.setEnumerateOverride(); + commands.setNotifyFailure(); + commands.setInvokeSetters(); + commands.setSwfLoadNotify(); + commands.setGetterTimeout(1500); + commands.setSetterTimeout(5000); + + boolean isAS3 = (Main.getMainFrame().getPanel().getCurrentSwf().isAS3()); + con.isAS3 = isAS3; + + //Widelines - only AS3, it hangs in AS1/2 and SWD does not support UI32 lines + if (isAS3) { + con.wideLines = commands.getOption("wide_line_player", "false").equals("true"); + if (con.wideLines) { + commands.setOption("wide_line_debugger", "on"); + } + } + commands.squelch(true); + + con.writeMessage(new OutSwfInfo(con, 0)); + con.addMessageListener(new DebugMessageListener() { + @Override + public void message(InSwfInfo t) { + for (InSwfInfo.SwfInfo s : t.swfInfos) { + swfs.add(s); + View.execInEventDispatch(new Runnable() { + @Override + public void run() { + try { + con.sendMessage(new OutGetSwf(con, (int) s.index), InGetSwf.class); + con.sendMessage(new OutGetSwd(con, (int) s.index), InGetSwd.class); + } catch (IOException ex) { + //ignore + } + } + }); + } + con.dropMessage(t); + } + }); + + InSetBreakpoint isb = con.getMessage(InSetBreakpoint.class); + synchronized (this) { + for (int i = 0; i < isb.files.size(); i++) { + String sname = moduleNames.get(isb.files.get(i)); + if (!confirmedPointMap.containsKey(sname)) { + confirmedPointMap.put(sname, new TreeSet<>()); + } + if (toAddBPointMap.containsKey(sname)) { + toAddBPointMap.get(sname).remove(isb.lines.get(i)); + if (toAddBPointMap.get(sname).isEmpty()) { + toAddBPointMap.remove(sname); + } + } + confirmedPointMap.get(sname).add(isb.lines.get(i)); + Logger.getLogger(DebuggerHandler.class.getName()).log(Level.INFO, "Breakpoint {0}:{1} submitted successfully", new Object[]{sname, isb.lines.get(i)}); + } + } + + synchronized (this) { + connected = true; + } + con.addMessageListener(new DebugMessageListener() { + @Override + public void message(InAskBreakpoints message) { + + } + }); + con.addMessageListener(new DebugMessageListener() { + @Override + public void message(InContinue msg) { + synchronized (DebuggerHandler.this) { + paused = false; + Logger.getLogger(DebuggerHandler.class.getName()).log(Level.FINE, "continued"); + } + for (BreakListener bl : breakListeners) { + bl.doContinue(); + } + } + }); + con.addMessageListener(new DebugMessageListener() { + @Override + public void message(InBreakAt message) { + synchronized (DebuggerHandler.this) { + paused = true; + Logger.getLogger(DebuggerHandler.class.getName()).log(Level.FINE, "paused"); + + } + + try { + breakInfo = con.getMessage(InBreakAtExt.class); + breakReason = con.sendMessage(new OutGetBreakReason(con), InBreakReason.class); + + String newBreakScriptName = "unknown"; + if (modulePaths.containsKey(message.file)) { + newBreakScriptName = modulePaths.get(message.file); + + } else if (breakReason.reason != InBreakReason.REASON_SCRIPT_LOADED) { + Logger.getLogger(DebuggerCommands.class.getName()).log(Level.SEVERE, "Invalid file: {0}", message.file); + return; + } + + final String[] reasonNames = new String[]{"unknown", "breakpoint", "watch", "fault", "stopRequest", "step", "halt", "scriptLoaded"}; + String reason = breakReason.reason < reasonNames.length ? reasonNames[breakReason.reason] : reasonNames[0]; + + Logger.getLogger(DebuggerHandler.class.getName()).log(Level.FINE, "break at {0}:{1}, reason: {2}", new Object[]{newBreakScriptName, message.line, reason}); + + sendBreakPoints(false); + synchronized (DebuggerHandler.this) { + breakScriptName = newBreakScriptName; + breakIp = message.line; + } + + if (breakReason.reason == InBreakReason.REASON_SCRIPT_LOADED) { + if (!Configuration.debugHalt.get()) { + commands.sendContinue(); + return; + } + Main.startWork(AppStrings.translate("work.halted"), null); + } else { + Main.startWork(AppStrings.translate("work.breakat") + newBreakScriptName + ":" + message.line + " " + AppStrings.translate("debug.break.reason." + reason), null); + } + frame = commands.getFrame(0); + pool = commands.getConstantPool(0); + + for (BreakListener l : breakListeners) { + l.breakAt(newBreakScriptName, message.line, + moduleToClassIndex.containsKey(message.file) ? moduleToClassIndex.get(message.file) : -1, + moduleToTraitIndex.containsKey(message.file) ? moduleToTraitIndex.get(message.file) : -1, + moduleToMethodIndex.containsKey(message.file) ? moduleToMethodIndex.get(message.file) : -1 + ); + } + + } catch (IOException ex) { + //ignore + } + + } + }); + + for (ConnectionListener l : clisteners) { + l.connected(); + } + + con.addMessageListener(new DebugMessageListener() { + @Override + public void message(InTrace tr) { + for (TraceListener l : traceListeners) { + l.trace(tr.text); + } + } + }); + + if (!isAS3) { + Logger.getLogger(DebuggerHandler.class.getName()).log(Level.FINER, "End of connect - sending continue"); + con.writeMessage(new OutRewind(con)); + con.writeMessage(new OutPlay(con)); + commands.sendContinue(); + } + + } catch (IOException ex) { + + synchronized (this) { + connected = false; + } + } + } + + private void sendBreakPoints(boolean force) throws IOException { + if (!force && !isPaused()) { + Logger.getLogger(DebuggerHandler.class.getName()).log(Level.FINEST, "not sending bps, not paused"); + return; + } + synchronized (this) { + for (String scriptName : toRemoveBPointMap.keySet()) { + int file = moduleIdOf(scriptName); + if (file > -1) { + for (int line : toRemoveBPointMap.get(scriptName)) { + if (isBreakpointConfirmed(scriptName, line)) { + commands.removeBreakPoint(file, line); + confirmedPointMap.get(scriptName).remove(line); + if (confirmedPointMap.get(scriptName).isEmpty()) { + confirmedPointMap.remove(scriptName); + } + } + Logger.getLogger(DebuggerHandler.class.getName()).log(Level.INFO, "Breakpoint {0}:{1} removed", new Object[]{scriptName, line}); + } + } + } + toRemoveBPointMap.clear(); + + for (String scriptName : toAddBPointMap.keySet()) { + int file = moduleIdOf(scriptName); + if (file > -1) { + for (int line : toAddBPointMap.get(scriptName)) { + if (commands.addBreakPoint(file, line)) { + Logger.getLogger(DebuggerHandler.class.getName()).log(Level.INFO, "Breakpoint {0}:{1} submitted successfully", new Object[]{scriptName, line}); + if (!confirmedPointMap.containsKey(scriptName)) { + confirmedPointMap.put(scriptName, new TreeSet<>()); + } + confirmedPointMap.get(scriptName).add(line); + } else { + Logger.getLogger(DebuggerHandler.class.getName()).log(Level.INFO, "Breakpoint {0}:{1} unable to submit", new Object[]{scriptName, line}); + markBreakPointInvalid(scriptName, line); + } + } + } else { + for (int line : toAddBPointMap.get(scriptName)) { + markBreakPointInvalid(scriptName, line); + } + } + } + toAddBPointMap.clear(); + + } + Logger.getLogger(DebuggerHandler.class.getName()).log(Level.FINEST, "sending bps finished"); + + } + + public synchronized InConstantPool getConstantPool() { + if (!paused) { + return null; + } + return pool; + } + + public synchronized InCallFunction callMethod(Variable object, String methodName, List args) throws ActionScriptException { + return callFunction(false, methodName, object, args); + } + + public synchronized InCallFunction callMethod(String object, String methodName, List args) throws ActionScriptException { + InGetVariable igv = getVariable(0, object, false); + return callMethod(igv.parent, methodName, args); + } + + private static String typeAsStr(Object value) { + if (value == null) { + return "null"; + } + if ((value instanceof Long) || (value instanceof Integer)) { + return "int"; + } + if (value instanceof Number) { + return "Number"; + } + if (value instanceof String) { + return "String"; + } + if (value instanceof Variable) { + Variable v = (Variable) value; + return v.getTypeAsStr(); + } + return "String"; + } + + private static String valueAsStr(Object value) { + if (value == null) { + return "null"; + } + if (value instanceof Double) { + double doubleValue = ((Double) value).doubleValue(); + long longValue = (long) doubleValue; + if (doubleValue == longValue) { + return Long.toString(longValue); + } + } + + if (value instanceof Variable) { + Variable v = (Variable) value; + return valueAsStr(v.value); + } + return "" + value; + } + + public synchronized InCallFunction callFunction(boolean isConstructor, String funcName, Variable thisValue, List args) throws ActionScriptException { + List argTypes = new ArrayList<>(); + List argValues = new ArrayList<>(); + for (Object value : args) { + argTypes.add(typeAsStr(value)); + argValues.add(valueAsStr(value)); + } + String thisType = typeAsStr(thisValue); + String thisValueStr = valueAsStr(thisValue); + try { + InCallFunction icf = commands.callFunction(isConstructor, funcName, thisType, thisValueStr, argTypes, argValues); + if (!icf.variables.isEmpty()) { + if ((icf.variables.get(0).flags & VariableFlags.IS_EXCEPTION) > 0) { + throw new ActionScriptException("" + icf.variables.get(0).value); + } + } + return icf; + } catch (IOException e) { + + } + return null; + } +} diff --git a/src/com/jpexs/decompiler/flash/gui/ExportDialog.java b/src/com/jpexs/decompiler/flash/gui/ExportDialog.java index 9734d6e89..bcd7eed72 100644 --- a/src/com/jpexs/decompiler/flash/gui/ExportDialog.java +++ b/src/com/jpexs/decompiler/flash/gui/ExportDialog.java @@ -1,386 +1,386 @@ -/* - * Copyright (C) 2010-2016 JPEXS - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.jpexs.decompiler.flash.gui; - -import com.jpexs.decompiler.flash.abc.ScriptPack; -import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.decompiler.flash.exporters.modes.BinaryDataExportMode; -import com.jpexs.decompiler.flash.exporters.modes.ButtonExportMode; -import com.jpexs.decompiler.flash.exporters.modes.FontExportMode; -import com.jpexs.decompiler.flash.exporters.modes.FrameExportMode; -import com.jpexs.decompiler.flash.exporters.modes.ImageExportMode; -import com.jpexs.decompiler.flash.exporters.modes.MorphShapeExportMode; -import com.jpexs.decompiler.flash.exporters.modes.MovieExportMode; -import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; -import com.jpexs.decompiler.flash.exporters.modes.ShapeExportMode; -import com.jpexs.decompiler.flash.exporters.modes.SoundExportMode; -import com.jpexs.decompiler.flash.exporters.modes.SpriteExportMode; -import com.jpexs.decompiler.flash.exporters.modes.SymbolClassExportMode; -import com.jpexs.decompiler.flash.exporters.modes.TextExportMode; -import com.jpexs.decompiler.flash.gui.tagtree.TagTreeModel; -import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag; -import com.jpexs.decompiler.flash.tags.DefineSpriteTag; -import com.jpexs.decompiler.flash.tags.DefineVideoStreamTag; -import com.jpexs.decompiler.flash.tags.base.ASMSource; -import com.jpexs.decompiler.flash.tags.base.ButtonTag; -import com.jpexs.decompiler.flash.tags.base.FontTag; -import com.jpexs.decompiler.flash.tags.base.ImageTag; -import com.jpexs.decompiler.flash.tags.base.MorphShapeTag; -import com.jpexs.decompiler.flash.tags.base.ShapeTag; -import com.jpexs.decompiler.flash.tags.base.SoundTag; -import com.jpexs.decompiler.flash.tags.base.SymbolClassTypeTag; -import com.jpexs.decompiler.flash.tags.base.TextTag; -import com.jpexs.decompiler.flash.timeline.Frame; -import com.jpexs.decompiler.flash.treeitems.TreeItem; -import java.awt.BorderLayout; -import java.awt.Container; -import java.awt.Dimension; -import java.awt.FlowLayout; -import java.awt.event.ActionEvent; -import java.util.Arrays; -import java.util.List; -import javax.swing.JButton; -import javax.swing.JCheckBox; -import javax.swing.JComboBox; -import javax.swing.JLabel; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JTextField; - -/** - * - * @author JPEXS - */ -public class ExportDialog extends AppDialog { - - private int result = ERROR_OPTION; - - String[] optionNames = { - TagTreeModel.FOLDER_SHAPES, - TagTreeModel.FOLDER_TEXTS, - TagTreeModel.FOLDER_IMAGES, - TagTreeModel.FOLDER_MOVIES, - TagTreeModel.FOLDER_SOUNDS, - TagTreeModel.FOLDER_SCRIPTS, - TagTreeModel.FOLDER_BINARY_DATA, - TagTreeModel.FOLDER_FRAMES, - TagTreeModel.FOLDER_SPRITES, - TagTreeModel.FOLDER_BUTTONS, - TagTreeModel.FOLDER_FONTS, - TagTreeModel.FOLDER_MORPHSHAPES, - "symbolclass" - }; - - //Display options only when these classes found - Class[][] objClasses = { - {ShapeTag.class}, - {TextTag.class}, - {ImageTag.class}, - {DefineVideoStreamTag.class}, - {SoundTag.class}, - {ASMSource.class, ScriptPack.class}, - {DefineBinaryDataTag.class}, - {Frame.class}, - {Frame.class}, - {ButtonTag.class}, - {FontTag.class}, - {MorphShapeTag.class}, - {SymbolClassTypeTag.class}, - }; - - //Enum classes for values - Class[] optionClasses = { - ShapeExportMode.class, - TextExportMode.class, - ImageExportMode.class, - MovieExportMode.class, - SoundExportMode.class, - ScriptExportMode.class, - BinaryDataExportMode.class, - FrameExportMode.class, - SpriteExportMode.class, - ButtonExportMode.class, - FontExportMode.class, - MorphShapeExportMode.class, - SymbolClassExportMode.class, - }; - - Class[] zoomClasses = { - ShapeExportMode.class, - MorphShapeExportMode.class, - TextExportMode.class, - FrameExportMode.class, - SpriteExportMode.class, - ButtonExportMode.class, - }; - - private final JComboBox[] combos; - - private final JCheckBox[] checkBoxes; - - private final JCheckBox selectAllCheckBox; - - private JTextField zoomTextField = new JTextField(); - - public E getValue(Class option) { - for (int i = 0; i < optionClasses.length; i++) { - if (option == optionClasses[i]) { - E[] values = option.getEnumConstants(); - return values[combos[i].getSelectedIndex()]; - } - } - - return null; - } - - public boolean isOptionEnabled(Class option) { - for (int i = 0; i < optionClasses.length; i++) { - if (option == optionClasses[i]) { - return checkBoxes[i].isSelected(); - } - } - - return false; - } - - public double getZoom() { - return Double.parseDouble(zoomTextField.getText()) / 100; - } - - private void saveConfig() { - StringBuilder cfg = new StringBuilder(); - for (int i = 0; i < optionNames.length; i++) { - int selIndex = combos[i].getSelectedIndex(); - Class c = optionClasses[i]; - Object[] vals = c.getEnumConstants(); - String key = optionNames[i] + "." + vals[selIndex].toString().toLowerCase(); - if (i > 0) { - cfg.append(","); - } - cfg.append(key); - } - - Configuration.lastSelectedExportZoom.set(Double.parseDouble(zoomTextField.getText()) / 100); - Configuration.lastSelectedExportFormats.set(cfg.toString()); - } - - private boolean optionCanHandle(int optionIndex, Object e) { - for (int i = 0; i < objClasses[optionIndex].length; i++) { - Class c = objClasses[optionIndex][i]; - if (c.isInstance(e)) { - if (c == Frame.class) { //Frame class can be SWF frame or Sprite frame - Frame f = (Frame) e; - boolean isSprite = (f.timeline.timelined instanceof DefineSpriteTag); - boolean spritesWanted = optionClasses[optionIndex] == SpriteExportMode.class; - if (spritesWanted == isSprite) { //both true or both false - return true; - } - } else { - return true; - } - } - } - return false; - } - - public ExportDialog(List exportables) { - setTitle(translate("dialog.title")); - setResizable(false); - - Container cnt = getContentPane(); - cnt.setLayout(new BorderLayout()); - JPanel comboPanel = new JPanel(null); - int labWidth = 0; - boolean[] exportableExistsArray = new boolean[optionNames.length]; - for (int i = 0; i < optionNames.length; i++) { - boolean exportableExists = false; - if (exportables == null) { - exportableExists = true; - } else { - for (TreeItem e : exportables) { - if (optionCanHandle(i, e)) { - exportableExists = true; - } - } - } - - if (!exportableExists) { - continue; - } - - exportableExistsArray[i] = true; - - JLabel label = new JLabel(translate(optionNames[i])); - if (label.getPreferredSize().width > labWidth) { - labWidth = label.getPreferredSize().width; - } - } - - String exportFormatsStr = Configuration.lastSelectedExportFormats.get(); - if ("".equals(exportFormatsStr)) { - exportFormatsStr = null; - } - - String[] exportFormatsArr = new String[0]; - if (exportFormatsStr != null) { - if (exportFormatsStr.contains(",")) { - exportFormatsArr = exportFormatsStr.split(","); - } else { - exportFormatsArr = new String[]{exportFormatsStr}; - } - - } - - int comboWidth = 200; - int checkBoxWidth; - int top = 10; - - List exportFormats = Arrays.asList(exportFormatsArr); - combos = new JComboBox[optionNames.length]; - checkBoxes = new JCheckBox[optionNames.length]; - selectAllCheckBox = new JCheckBox(); - checkBoxWidth = selectAllCheckBox.getPreferredSize().width; - selectAllCheckBox.setBounds(10 + labWidth + 10 + comboWidth + 10, top, checkBoxWidth, selectAllCheckBox.getPreferredSize().height); - selectAllCheckBox.setSelected(true); - selectAllCheckBox.addActionListener((ActionEvent e) -> { - boolean selected = selectAllCheckBox.isSelected(); - for (JCheckBox checkBox : checkBoxes) { - if (checkBox != null) { - checkBox.setSelected(selected); - } - } - }); - comboPanel.add(selectAllCheckBox); - top += selectAllCheckBox.getHeight(); - - boolean zoomable = false; - for (int i = 0; i < optionNames.length; i++) { - Class c = optionClasses[i]; - Object[] vals = c.getEnumConstants(); - String[] names = new String[vals.length]; - int itemIndex = -1; - for (int j = 0; j < vals.length; j++) { - - String key = optionNames[i] + "." + vals[j].toString().toLowerCase(); - if (exportFormats.contains(key)) { - itemIndex = j; - } - names[j] = translate(key); - } - - combos[i] = new JComboBox<>(names); - if (itemIndex > -1) { - combos[i].setSelectedIndex(itemIndex); - } - - combos[i].setBounds(10 + labWidth + 10, top, comboWidth, combos[i].getPreferredSize().height); - - checkBoxes[i] = new JCheckBox(); - checkBoxes[i].setBounds(10 + labWidth + 10 + comboWidth + 10, top, checkBoxWidth, checkBoxes[i].getPreferredSize().height); - checkBoxes[i].setSelected(true); - - if (!exportableExistsArray[i]) { - continue; - } - - if (Arrays.asList(zoomClasses).contains(c)) { - zoomable = true; - } - - JLabel lab = new JLabel(translate(optionNames[i])); - lab.setBounds(10, top, lab.getPreferredSize().width, lab.getPreferredSize().height); - comboPanel.add(lab); - comboPanel.add(checkBoxes[i]); - comboPanel.add(combos[i]); - top += combos[i].getHeight(); - } - - int zoomWidth = 50; - if (zoomable) { - top += 2; - JLabel zlab = new JLabel(translate("zoom")); - zlab.setBounds(10, top + 4, zlab.getPreferredSize().width, zlab.getPreferredSize().height); - zoomTextField.setBounds(10 + labWidth + 10, top, zoomWidth, zoomTextField.getPreferredSize().height); - JLabel pctLabel = new JLabel(translate("zoom.percent")); - pctLabel.setBounds(10 + labWidth + 10 + zoomWidth + 5, top + 4, 20, pctLabel.getPreferredSize().height); - - comboPanel.add(zlab); - comboPanel.add(zoomTextField); - comboPanel.add(pctLabel); - top += zoomTextField.getHeight(); - } - - Dimension dim = new Dimension(10 + labWidth + 10 + checkBoxWidth + 10 + comboWidth + 10, top + 10); - comboPanel.setMinimumSize(dim); - comboPanel.setPreferredSize(dim); - cnt.add(comboPanel, BorderLayout.CENTER); - - JPanel buttonsPanel = new JPanel(new FlowLayout()); - JButton okButton = new JButton(translate("button.ok")); - okButton.addActionListener(this::okButtonActionPerformed); - - JButton cancelButton = new JButton(translate("button.cancel")); - cancelButton.addActionListener(this::cancelButtonActionPerformed); - - buttonsPanel.add(okButton); - buttonsPanel.add(cancelButton); - - cnt.add(buttonsPanel, BorderLayout.SOUTH); - pack(); - View.centerScreen(this); - View.setWindowIcon(this); - getRootPane().setDefaultButton(okButton); - setModal(true); - String pct = "" + Configuration.lastSelectedExportZoom.get() * 100; - if (pct.endsWith(".0")) { - pct = pct.substring(0, pct.length() - 2); - } - - zoomTextField.setText(pct); - } - - @Override - public void setVisible(boolean b) { - if (b) { - result = ERROR_OPTION; - } - super.setVisible(b); - } - - private void okButtonActionPerformed(ActionEvent evt) { - result = OK_OPTION; - try { - saveConfig(); - } catch (NumberFormatException nfe) { - JOptionPane.showMessageDialog(ExportDialog.this, translate("zoom.invalid"), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE); - zoomTextField.requestFocusInWindow(); - return; - } - - setVisible(false); - } - - private void cancelButtonActionPerformed(ActionEvent evt) { - result = CANCEL_OPTION; - setVisible(false); - } - - public int showExportDialog() { - setVisible(true); - return result; - } -} +/* + * Copyright (C) 2010-2016 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.jpexs.decompiler.flash.gui; + +import com.jpexs.decompiler.flash.abc.ScriptPack; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.exporters.modes.BinaryDataExportMode; +import com.jpexs.decompiler.flash.exporters.modes.ButtonExportMode; +import com.jpexs.decompiler.flash.exporters.modes.FontExportMode; +import com.jpexs.decompiler.flash.exporters.modes.FrameExportMode; +import com.jpexs.decompiler.flash.exporters.modes.ImageExportMode; +import com.jpexs.decompiler.flash.exporters.modes.MorphShapeExportMode; +import com.jpexs.decompiler.flash.exporters.modes.MovieExportMode; +import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; +import com.jpexs.decompiler.flash.exporters.modes.ShapeExportMode; +import com.jpexs.decompiler.flash.exporters.modes.SoundExportMode; +import com.jpexs.decompiler.flash.exporters.modes.SpriteExportMode; +import com.jpexs.decompiler.flash.exporters.modes.SymbolClassExportMode; +import com.jpexs.decompiler.flash.exporters.modes.TextExportMode; +import com.jpexs.decompiler.flash.gui.tagtree.TagTreeModel; +import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag; +import com.jpexs.decompiler.flash.tags.DefineSpriteTag; +import com.jpexs.decompiler.flash.tags.DefineVideoStreamTag; +import com.jpexs.decompiler.flash.tags.base.ASMSource; +import com.jpexs.decompiler.flash.tags.base.ButtonTag; +import com.jpexs.decompiler.flash.tags.base.FontTag; +import com.jpexs.decompiler.flash.tags.base.ImageTag; +import com.jpexs.decompiler.flash.tags.base.MorphShapeTag; +import com.jpexs.decompiler.flash.tags.base.ShapeTag; +import com.jpexs.decompiler.flash.tags.base.SoundTag; +import com.jpexs.decompiler.flash.tags.base.SymbolClassTypeTag; +import com.jpexs.decompiler.flash.tags.base.TextTag; +import com.jpexs.decompiler.flash.timeline.Frame; +import com.jpexs.decompiler.flash.treeitems.TreeItem; +import java.awt.BorderLayout; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.event.ActionEvent; +import java.util.Arrays; +import java.util.List; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JTextField; + +/** + * + * @author JPEXS + */ +public class ExportDialog extends AppDialog { + + private int result = ERROR_OPTION; + + String[] optionNames = { + TagTreeModel.FOLDER_SHAPES, + TagTreeModel.FOLDER_TEXTS, + TagTreeModel.FOLDER_IMAGES, + TagTreeModel.FOLDER_MOVIES, + TagTreeModel.FOLDER_SOUNDS, + TagTreeModel.FOLDER_SCRIPTS, + TagTreeModel.FOLDER_BINARY_DATA, + TagTreeModel.FOLDER_FRAMES, + TagTreeModel.FOLDER_SPRITES, + TagTreeModel.FOLDER_BUTTONS, + TagTreeModel.FOLDER_FONTS, + TagTreeModel.FOLDER_MORPHSHAPES, + "symbolclass" + }; + + //Display options only when these classes found + Class[][] objClasses = { + {ShapeTag.class}, + {TextTag.class}, + {ImageTag.class}, + {DefineVideoStreamTag.class}, + {SoundTag.class}, + {ASMSource.class, ScriptPack.class}, + {DefineBinaryDataTag.class}, + {Frame.class}, + {Frame.class}, + {ButtonTag.class}, + {FontTag.class}, + {MorphShapeTag.class}, + {SymbolClassTypeTag.class}, + }; + + //Enum classes for values + Class[] optionClasses = { + ShapeExportMode.class, + TextExportMode.class, + ImageExportMode.class, + MovieExportMode.class, + SoundExportMode.class, + ScriptExportMode.class, + BinaryDataExportMode.class, + FrameExportMode.class, + SpriteExportMode.class, + ButtonExportMode.class, + FontExportMode.class, + MorphShapeExportMode.class, + SymbolClassExportMode.class, + }; + + Class[] zoomClasses = { + ShapeExportMode.class, + MorphShapeExportMode.class, + TextExportMode.class, + FrameExportMode.class, + SpriteExportMode.class, + ButtonExportMode.class, + }; + + private final JComboBox[] combos; + + private final JCheckBox[] checkBoxes; + + private final JCheckBox selectAllCheckBox; + + private JTextField zoomTextField = new JTextField(); + + public E getValue(Class option) { + for (int i = 0; i < optionClasses.length; i++) { + if (option == optionClasses[i]) { + E[] values = option.getEnumConstants(); + return values[combos[i].getSelectedIndex()]; + } + } + + return null; + } + + public boolean isOptionEnabled(Class option) { + for (int i = 0; i < optionClasses.length; i++) { + if (option == optionClasses[i]) { + return checkBoxes[i].isSelected(); + } + } + + return false; + } + + public double getZoom() { + return Double.parseDouble(zoomTextField.getText()) / 100; + } + + private void saveConfig() { + StringBuilder cfg = new StringBuilder(); + for (int i = 0; i < optionNames.length; i++) { + int selIndex = combos[i].getSelectedIndex(); + Class c = optionClasses[i]; + Object[] vals = c.getEnumConstants(); + String key = optionNames[i] + "." + vals[selIndex].toString().toLowerCase(); + if (i > 0) { + cfg.append(","); + } + cfg.append(key); + } + + Configuration.lastSelectedExportZoom.set(Double.parseDouble(zoomTextField.getText()) / 100); + Configuration.lastSelectedExportFormats.set(cfg.toString()); + } + + private boolean optionCanHandle(int optionIndex, Object e) { + for (int i = 0; i < objClasses[optionIndex].length; i++) { + Class c = objClasses[optionIndex][i]; + if (c.isInstance(e)) { + if (c == Frame.class) { //Frame class can be SWF frame or Sprite frame + Frame f = (Frame) e; + boolean isSprite = (f.timeline.timelined instanceof DefineSpriteTag); + boolean spritesWanted = optionClasses[optionIndex] == SpriteExportMode.class; + if (spritesWanted == isSprite) { //both true or both false + return true; + } + } else { + return true; + } + } + } + return false; + } + + public ExportDialog(List exportables) { + setTitle(translate("dialog.title")); + setResizable(false); + + Container cnt = getContentPane(); + cnt.setLayout(new BorderLayout()); + JPanel comboPanel = new JPanel(null); + int labWidth = 0; + boolean[] exportableExistsArray = new boolean[optionNames.length]; + for (int i = 0; i < optionNames.length; i++) { + boolean exportableExists = false; + if (exportables == null) { + exportableExists = true; + } else { + for (TreeItem e : exportables) { + if (optionCanHandle(i, e)) { + exportableExists = true; + } + } + } + + if (!exportableExists) { + continue; + } + + exportableExistsArray[i] = true; + + JLabel label = new JLabel(translate(optionNames[i])); + if (label.getPreferredSize().width > labWidth) { + labWidth = label.getPreferredSize().width; + } + } + + String exportFormatsStr = Configuration.lastSelectedExportFormats.get(); + if ("".equals(exportFormatsStr)) { + exportFormatsStr = null; + } + + String[] exportFormatsArr = new String[0]; + if (exportFormatsStr != null) { + if (exportFormatsStr.contains(",")) { + exportFormatsArr = exportFormatsStr.split(","); + } else { + exportFormatsArr = new String[]{exportFormatsStr}; + } + + } + + int comboWidth = 200; + int checkBoxWidth; + int top = 10; + + List exportFormats = Arrays.asList(exportFormatsArr); + combos = new JComboBox[optionNames.length]; + checkBoxes = new JCheckBox[optionNames.length]; + selectAllCheckBox = new JCheckBox(); + checkBoxWidth = selectAllCheckBox.getPreferredSize().width; + selectAllCheckBox.setBounds(10 + labWidth + 10 + comboWidth + 10, top, checkBoxWidth, selectAllCheckBox.getPreferredSize().height); + selectAllCheckBox.setSelected(true); + selectAllCheckBox.addActionListener((ActionEvent e) -> { + boolean selected = selectAllCheckBox.isSelected(); + for (JCheckBox checkBox : checkBoxes) { + if (checkBox != null) { + checkBox.setSelected(selected); + } + } + }); + comboPanel.add(selectAllCheckBox); + top += selectAllCheckBox.getHeight(); + + boolean zoomable = false; + for (int i = 0; i < optionNames.length; i++) { + Class c = optionClasses[i]; + Object[] vals = c.getEnumConstants(); + String[] names = new String[vals.length]; + int itemIndex = -1; + for (int j = 0; j < vals.length; j++) { + + String key = optionNames[i] + "." + vals[j].toString().toLowerCase(); + if (exportFormats.contains(key)) { + itemIndex = j; + } + names[j] = translate(key); + } + + combos[i] = new JComboBox<>(names); + if (itemIndex > -1) { + combos[i].setSelectedIndex(itemIndex); + } + + combos[i].setBounds(10 + labWidth + 10, top, comboWidth, combos[i].getPreferredSize().height); + + checkBoxes[i] = new JCheckBox(); + checkBoxes[i].setBounds(10 + labWidth + 10 + comboWidth + 10, top, checkBoxWidth, checkBoxes[i].getPreferredSize().height); + checkBoxes[i].setSelected(true); + + if (!exportableExistsArray[i]) { + continue; + } + + if (Arrays.asList(zoomClasses).contains(c)) { + zoomable = true; + } + + JLabel lab = new JLabel(translate(optionNames[i])); + lab.setBounds(10, top, lab.getPreferredSize().width, lab.getPreferredSize().height); + comboPanel.add(lab); + comboPanel.add(checkBoxes[i]); + comboPanel.add(combos[i]); + top += combos[i].getHeight(); + } + + int zoomWidth = 50; + if (zoomable) { + top += 2; + JLabel zlab = new JLabel(translate("zoom")); + zlab.setBounds(10, top + 4, zlab.getPreferredSize().width, zlab.getPreferredSize().height); + zoomTextField.setBounds(10 + labWidth + 10, top, zoomWidth, zoomTextField.getPreferredSize().height); + JLabel pctLabel = new JLabel(translate("zoom.percent")); + pctLabel.setBounds(10 + labWidth + 10 + zoomWidth + 5, top + 4, 20, pctLabel.getPreferredSize().height); + + comboPanel.add(zlab); + comboPanel.add(zoomTextField); + comboPanel.add(pctLabel); + top += zoomTextField.getHeight(); + } + + Dimension dim = new Dimension(10 + labWidth + 10 + checkBoxWidth + 10 + comboWidth + 10, top + 10); + comboPanel.setMinimumSize(dim); + comboPanel.setPreferredSize(dim); + cnt.add(comboPanel, BorderLayout.CENTER); + + JPanel buttonsPanel = new JPanel(new FlowLayout()); + JButton okButton = new JButton(translate("button.ok")); + okButton.addActionListener(this::okButtonActionPerformed); + + JButton cancelButton = new JButton(translate("button.cancel")); + cancelButton.addActionListener(this::cancelButtonActionPerformed); + + buttonsPanel.add(okButton); + buttonsPanel.add(cancelButton); + + cnt.add(buttonsPanel, BorderLayout.SOUTH); + pack(); + View.centerScreen(this); + View.setWindowIcon(this); + getRootPane().setDefaultButton(okButton); + setModal(true); + String pct = "" + Configuration.lastSelectedExportZoom.get() * 100; + if (pct.endsWith(".0")) { + pct = pct.substring(0, pct.length() - 2); + } + + zoomTextField.setText(pct); + } + + @Override + public void setVisible(boolean b) { + if (b) { + result = ERROR_OPTION; + } + super.setVisible(b); + } + + private void okButtonActionPerformed(ActionEvent evt) { + result = OK_OPTION; + try { + saveConfig(); + } catch (NumberFormatException nfe) { + JOptionPane.showMessageDialog(ExportDialog.this, translate("zoom.invalid"), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE); + zoomTextField.requestFocusInWindow(); + return; + } + + setVisible(false); + } + + private void cancelButtonActionPerformed(ActionEvent evt) { + result = CANCEL_OPTION; + setVisible(false); + } + + public int showExportDialog() { + setVisible(true); + return result; + } +} diff --git a/src/com/jpexs/decompiler/flash/gui/abc/TraitsListItem.java b/src/com/jpexs/decompiler/flash/gui/abc/TraitsListItem.java index 5575b7397..720918a55 100644 --- a/src/com/jpexs/decompiler/flash/gui/abc/TraitsListItem.java +++ b/src/com/jpexs/decompiler/flash/gui/abc/TraitsListItem.java @@ -1,137 +1,137 @@ -/* - * Copyright (C) 2010-2016 JPEXS - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.jpexs.decompiler.flash.gui.abc; - -import com.jpexs.decompiler.flash.abc.ABC; -import com.jpexs.decompiler.flash.abc.types.ConvertData; -import com.jpexs.decompiler.flash.abc.types.traits.Trait; -import com.jpexs.decompiler.flash.abc.types.traits.TraitType; -import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; -import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter; -import com.jpexs.decompiler.flash.helpers.NulWriter; -import com.jpexs.decompiler.flash.search.ABCSearchResult; -import java.util.ArrayList; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - * @author JPEXS - */ -public class TraitsListItem { - - private final TraitType type; - - private final boolean isStatic; - - private final ABC abc; - - private final int classIndex; - - private final int index; - - private final int scriptIndex; - - public static String STR_INSTANCE_INITIALIZER = ABCSearchResult.STR_INSTANCE_INITIALIZER; - - public static String STR_CLASS_INITIALIZER = ABCSearchResult.STR_CLASS_INITIALIZER; - - public static String STR_SCRIPT_INITIALIZER = ABCSearchResult.STR_SCRIPT_INITIALIZER; - - public TraitsListItem(TraitType type, int index, boolean isStatic, ABC abc, int classIndex, int scriptIndex) { - this.type = type; - this.index = index; - this.isStatic = isStatic; - this.abc = abc; - this.classIndex = classIndex; - this.scriptIndex = scriptIndex; - } - - public int getGlobalTraitId() { - return abc.getGlobalTraitId(type, isStatic, classIndex, index); - } - - public String toStringName() { - - if (type == TraitType.INITIALIZER) { - if (!isStatic) { - return "__" + STR_INSTANCE_INITIALIZER; - } else { - return "__" + STR_CLASS_INITIALIZER; - } - } - if (type == TraitType.SCRIPT_INITIALIZER) { - return "__" + STR_SCRIPT_INITIALIZER; - } - if (isStatic) { - return abc.class_info.get(classIndex).static_traits.traits.get(index).getName(abc).getName(abc.constants, null, false, true); - } else { - return abc.instance_info.get(classIndex).instance_traits.traits.get(index).getName(abc).getName(abc.constants, null, false, true); - } - } - - @Override - public String toString() { - String s = ""; - try { - if (type == TraitType.SCRIPT_INITIALIZER) { - s = STR_SCRIPT_INITIALIZER; - } else if (type == TraitType.INITIALIZER) { - if (!isStatic) { - s = STR_INSTANCE_INITIALIZER; - } else { - s = STR_CLASS_INITIALIZER; - } - } else if (isStatic) { - ConvertData convertData = new ConvertData(); - Trait trait = abc.class_info.get(classIndex).static_traits.traits.get(index); - trait.convertHeader(null, convertData, "", abc, true, ScriptExportMode.AS, scriptIndex, classIndex, new NulWriter(), new ArrayList<>(), false); - HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), false); - trait.toStringHeader(null, convertData, "", abc, true, ScriptExportMode.AS, scriptIndex, classIndex, writer, new ArrayList<>(), false); - s = writer.toString(); - } else { - ConvertData convertData = new ConvertData(); - Trait trait = abc.instance_info.get(classIndex).instance_traits.traits.get(index); - trait.convertHeader(null, convertData, "", abc, false, ScriptExportMode.AS, scriptIndex, classIndex, new NulWriter(), new ArrayList<>(), false); - HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), false); - trait.toStringHeader(null, convertData, "", abc, false, ScriptExportMode.AS, scriptIndex, classIndex, writer, new ArrayList<>(), false); - s = writer.toString(); - } - } catch (InterruptedException ex) { - Logger.getLogger(TraitsListItem.class.getName()).log(Level.SEVERE, null, ex); - } - s = s.replaceAll("[ \r\n]+", " "); - return s; - } - - public TraitType getType() { - return type; - } - - public boolean isStatic() { - return isStatic; - } - - public int getClassIndex() { - return classIndex; - } - - public int getIndex() { - return index; - } -} +/* + * Copyright (C) 2010-2016 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.jpexs.decompiler.flash.gui.abc; + +import com.jpexs.decompiler.flash.abc.ABC; +import com.jpexs.decompiler.flash.abc.types.ConvertData; +import com.jpexs.decompiler.flash.abc.types.traits.Trait; +import com.jpexs.decompiler.flash.abc.types.traits.TraitType; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; +import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter; +import com.jpexs.decompiler.flash.helpers.NulWriter; +import com.jpexs.decompiler.flash.search.ABCSearchResult; +import java.util.ArrayList; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author JPEXS + */ +public class TraitsListItem { + + private final TraitType type; + + private final boolean isStatic; + + private final ABC abc; + + private final int classIndex; + + private final int index; + + private final int scriptIndex; + + public static String STR_INSTANCE_INITIALIZER = ABCSearchResult.STR_INSTANCE_INITIALIZER; + + public static String STR_CLASS_INITIALIZER = ABCSearchResult.STR_CLASS_INITIALIZER; + + public static String STR_SCRIPT_INITIALIZER = ABCSearchResult.STR_SCRIPT_INITIALIZER; + + public TraitsListItem(TraitType type, int index, boolean isStatic, ABC abc, int classIndex, int scriptIndex) { + this.type = type; + this.index = index; + this.isStatic = isStatic; + this.abc = abc; + this.classIndex = classIndex; + this.scriptIndex = scriptIndex; + } + + public int getGlobalTraitId() { + return abc.getGlobalTraitId(type, isStatic, classIndex, index); + } + + public String toStringName() { + + if (type == TraitType.INITIALIZER) { + if (!isStatic) { + return "__" + STR_INSTANCE_INITIALIZER; + } else { + return "__" + STR_CLASS_INITIALIZER; + } + } + if (type == TraitType.SCRIPT_INITIALIZER) { + return "__" + STR_SCRIPT_INITIALIZER; + } + if (isStatic) { + return abc.class_info.get(classIndex).static_traits.traits.get(index).getName(abc).getName(abc.constants, null, false, true); + } else { + return abc.instance_info.get(classIndex).instance_traits.traits.get(index).getName(abc).getName(abc.constants, null, false, true); + } + } + + @Override + public String toString() { + String s = ""; + try { + if (type == TraitType.SCRIPT_INITIALIZER) { + s = STR_SCRIPT_INITIALIZER; + } else if (type == TraitType.INITIALIZER) { + if (!isStatic) { + s = STR_INSTANCE_INITIALIZER; + } else { + s = STR_CLASS_INITIALIZER; + } + } else if (isStatic) { + ConvertData convertData = new ConvertData(); + Trait trait = abc.class_info.get(classIndex).static_traits.traits.get(index); + trait.convertHeader(null, convertData, "", abc, true, ScriptExportMode.AS, scriptIndex, classIndex, new NulWriter(), new ArrayList<>(), false); + HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), false); + trait.toStringHeader(null, convertData, "", abc, true, ScriptExportMode.AS, scriptIndex, classIndex, writer, new ArrayList<>(), false); + s = writer.toString(); + } else { + ConvertData convertData = new ConvertData(); + Trait trait = abc.instance_info.get(classIndex).instance_traits.traits.get(index); + trait.convertHeader(null, convertData, "", abc, false, ScriptExportMode.AS, scriptIndex, classIndex, new NulWriter(), new ArrayList<>(), false); + HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), false); + trait.toStringHeader(null, convertData, "", abc, false, ScriptExportMode.AS, scriptIndex, classIndex, writer, new ArrayList<>(), false); + s = writer.toString(); + } + } catch (InterruptedException ex) { + Logger.getLogger(TraitsListItem.class.getName()).log(Level.SEVERE, null, ex); + } + s = s.replaceAll("[ \r\n]+", " "); + return s; + } + + public TraitType getType() { + return type; + } + + public boolean isStatic() { + return isStatic; + } + + public int getClassIndex() { + return classIndex; + } + + public int getIndex() { + return index; + } +} diff --git a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_zh.properties b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_zh.properties index 669f23a6e..811de2324 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_zh.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_zh.properties @@ -1,734 +1,734 @@ -# Copyright (C) 2010-2016 JPEXS -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -menu.file = \u6587\u4ef6 -menu.file.open = \u6253\u5f00... -menu.file.save = \u4fdd\u5b58 -menu.file.saveas = \u53e6\u5b58\u4e3a... -menu.file.export.fla = \u5bfc\u51fa\u5230 FLA -menu.file.export.all = \u5bfc\u51fa\u6240\u6709 -menu.file.export.selection = \u5bfc\u51fa\u6240\u9009 -menu.file.exit = \u9000\u51fa - -menu.tools = \u5de5\u5177 -menu.tools.searchas = \u5728\u6240\u6709AS\u4ee3\u7801\u4e2d\u641c\u7d22... -menu.tools.proxy = \u4ee3\u7406 -menu.tools.deobfuscation = \u53cd\u6df7\u6dc6 -menu.tools.deobfuscation.pcode = P\u4ee3\u7801\u53cd\u6df7\u6dc6... -menu.tools.deobfuscation.globalrename = \u5168\u5c40\u91cd\u547d\u540d\u6807\u8bc6\u7b26 -menu.tools.deobfuscation.renameinvalid = \u91cd\u547d\u540d\u65e0\u6548\u6807\u8bc6\u7b26 -menu.tools.gotoDocumentClass = \u8df3\u8f6c\u5230\u4e3b\u7c7b - -menu.settings = \u8bbe\u7f6e -menu.settings.autodeobfuscation = \u81ea\u52a8\u53cd\u6df7\u6dc6 -menu.settings.internalflashviewer = \u4f7f\u7528\u5185\u90e8Flash\u64ad\u653e\u5668 -menu.settings.parallelspeedup = \u591a\u7ebf\u7a0b\u52a0\u901f -menu.settings.disabledecompilation = \u7981\u7528\u53cd\u7f16\u8bd1 (\u4ec5\u53cd\u6c47\u7f16) -menu.settings.addtocontextmenu = \u6dfb\u52a0FFDec\u5230SWF\u6587\u4ef6\u83dc\u5355 -menu.settings.language = \u66f4\u6539\u8bed\u8a00 -menu.settings.cacheOnDisk = \u4f7f\u7528\u786c\u76d8\u4f5c\u7f13\u5b58 -menu.settings.gotoMainClassOnStartup = \u52a0\u8f7d\u5b8c\u6bd5\u540e\u9ad8\u4eae\u4e3b\u7c7b - -menu.help = \u5e2e\u52a9 -menu.help.checkupdates = \u68c0\u67e5\u66f4\u65b0... -menu.help.helpus = \u5e2e\u52a9\u6211\u4eec! -menu.help.homepage = \u8bbf\u95ee\u4e3b\u9875 -menu.help.about = \u5173\u4e8e... - -contextmenu.remove = \u5220\u9664 - -button.save = \u4fdd\u5b58 -button.edit = \u7f16\u8f91 -button.cancel = \u53d6\u6d88 -button.replace = \u66ff\u6362... - -notavailonthisplatform = \u9884\u89c8\u8be5\u5bf9\u8c61\u662f\u5426\u53ef\u7528\u4e8e\u5f53\u524d\u5e73\u53f0. (\u4ec5Windows) - -swfpreview = SWF \u9884\u89c8 -swfpreview.internal = SWF \u9884\u89c8(\u4f7f\u7528\u5185\u7f6e\u64ad\u653e\u5668) - -parameters = \u53c2\u6570 - -rename.enternew = \u8bf7\u8f93\u5165\u65b0\u540d\u79f0: - -rename.finished.identifier = \u6807\u8bc6\u7b26\u5df2\u88ab\u91cd\u547d\u540d. -rename.finished.multiname = %count% \u4e2a multiname \u5df2\u88ab\u91cd\u547d\u540d. - -node.texts = \u6587\u672c -node.images = \u56fe\u50cf -node.movies = \u89c6\u9891 -node.sounds = \u58f0\u97f3 -node.binaryData = \u4e8c\u8fdb\u5236\u6570\u636e -node.fonts = \u5b57\u4f53 -node.sprites = \u7cbe\u7075 -node.shapes = \u56fe\u5f62 -node.morphshapes = \u53d8\u5f62\u5f62\u72b6 -node.buttons = \u6309\u94ae -node.frames = \u5e27 -node.scripts = \u811a\u672c - -message.warning = \u8b66\u544a -message.confirm.experimental = \u4e0b\u9762\u7684\u64cd\u4f5c\u53ef\u80fd\u4f1a\u635f\u574fSWF\u6587\u4ef6\uff0c\u5e76\u5c06\u5bfc\u81f4\u65e0\u6cd5\u64ad\u653e\u3002\r\n\u60a8\u5fc5\u987b\u6e05\u695a\u5730\u8ba4\u8bc6\u5230\u8fd9\u9879\u98ce\u9669\uff0c\u662f\u5426\u7ee7\u7eed\uff1f -message.confirm.parallel = \u591a\u7ebf\u7a0b\uff0c\u53ef\u4ee5\u52a0\u5feb\u52a0\u8f7d\u53ca\u53cd\u7f16\u8bd1\u901f\u5ea6\uff0c\u4f46\u4f1a\u6d88\u8017\u66f4\u591a\u7684\u5185\u5b58\u3002 -message.confirm.on = \u60a8\u786e\u5b9a\u8981\u5f00\u542f\u5417\uff1f -message.confirm.off = \u60a8\u786e\u5b9a\u8981\u5173\u95ed\u5417\uff1f -message.confirm = \u786e\u8ba4 - -message.confirm.autodeobfuscate = \u81ea\u52a8\u53cd\u6df7\u6dc6\u662f\u4e00\u79cd\u80fd\u53cd\u7f16\u8bd1\u88ab\u6df7\u6dc6\u4ee3\u7801\u7684\u529f\u80fd\u3002\r\n \u53cd\u6df7\u6dc6\u5c06\u5bfc\u81f4\u53cd\u7f16\u8bd1\u7684\u901f\u5ea6\u8f83\u6162\uff0c\u5e76\u53ef\u80fd\u4f1a\u7565\u8fc7\u51fa\u73b0\u7684\u201c\u6b7b\u4ee3\u7801\u201d\u3002\r\n \u5982\u679c\u60a8\u786e\u8ba4\u6587\u4ef6\u4e2d\u7684\u4ee3\u7801\u6ca1\u6709\u88ab\u6df7\u6dc6\uff0c\u5efa\u8bae\u60a8\u5173\u95ed\u8be5\u9009\u9879\u3002 - -message.parallel = \u591a\u7ebf\u7a0b -message.trait.saved = \u5df2\u6210\u529f\u4fdd\u5b58Trait - -message.constant.new.string = \u5728\u5e38\u91cf\u8868\u4e2d\u627e\u4e0d\u5230\u5b57\u7b26\u4e32 "%value%" \uff0c\u9700\u8981\u6dfb\u52a0\u5417\uff1f -message.constant.new.string.title = \u6dfb\u52a0\u5b57\u7b26\u4e32 -message.constant.new.integer = \u5728\u5e38\u91cf\u8868\u4e2d\u627e\u4e0d\u5230\u6574\u6570 "%value%" \uff0c\u9700\u8981\u6dfb\u52a0\u5417\uff1f -message.constant.new.integer.title = \u6dfb\u52a0\u6574\u6570 -message.constant.new.unsignedinteger = \u5728\u5e38\u91cf\u8868\u4e2d\u627e\u4e0d\u5230\u65e0\u7b26\u53f7\u6574\u6570 "%value%" \uff0c\u9700\u8981\u6dfb\u52a0\u5417\uff1f -message.constant.new.unsignedinteger.title = \u6dfb\u52a0\u65e0\u7b26\u53f7\u6574\u6570 -message.constant.new.double = \u5728\u5e38\u91cf\u8868\u4e2d\u627e\u4e0d\u5230\u53cc\u5b57\u8282 "%value%" \uff0c\u9700\u8981\u6dfb\u52a0\u5417\uff1f -message.constant.new.double.title = \u6dfb\u52a0\u53cc\u5b57\u8282 - -work.buffering = \u7f13\u51b2 -work.waitingfordissasembly = \u7b49\u5f85\u53cd\u6c47\u7f16 -work.gettinghilights = \u83b7\u53d6\u9ad8\u4eae -work.disassembling = \u53cd\u6c47\u7f16 -work.exporting = \u5bfc\u51fa\u4e2d -work.searching = \u641c\u7d22\u4e2d -work.renaming = \u91cd\u547d\u540d\u4e2d -work.exporting.fla = \u5bfc\u51fa FLA \u4e2d -work.renaming.identifiers = \u91cd\u547d\u540d\u6807\u8bc6\u7b26\u4e2d -work.deobfuscating = \u53cd\u6df7\u6dc6\u4e2d -work.decompiling = \u53cd\u7f16\u8bd1\u4e2d -work.gettingvariables = \u83b7\u53d6\u53d8\u91cf -work.reading.swf = \u8bfb\u5165 SWF \u4e2d -work.creatingwindow = \u521b\u5efa\u7a97\u4f53 -work.buildingscripttree = \u5efa\u7acb\u811a\u672c\u6811 - -work.deobfuscating.complete = \u53cd\u6df7\u6dc6\u5b8c\u6210 - -message.search.notfound = \u6ca1\u6709\u627e\u5230\u5b57\u7b26\u4e32 "%searchtext%" . -message.search.notfound.title = \u6ca1\u6709\u627e\u5230 - -message.rename.notfound.multiname = \u5728\u5149\u6807\u4e0b\u65b9\u6ca1\u6709\u627e\u5230multiname -message.rename.notfound.identifier = \u5728\u5149\u6807\u4e0b\u65b9\u6ca1\u6709\u627e\u5230\u6807\u8bc6\u7b26 -message.rename.notfound.title = \u6ca1\u6709\u627e\u5230 -message.rename.renamed = \u6807\u8bc6\u7b26\u91cd\u547d\u540d\u6570\uff1a %count% - -filter.images = \u56fe\u7247 (%extensions%) -filter.fla = %version% \u6587\u4ef6 (*.fla) -filter.xfl = %version% \u672a\u538b\u7f29\u6587\u4ef6 (*.xfl) -filter.swf = SWF \u6587\u4ef6 (*.swf) - -error = \u9519\u8bef -error.image.invalid = \u65e0\u6548\u56fe\u7247. - -error.text.invalid = \u65e0\u6548\u6587\u672c: %text% \u5728 %line% \u884c -error.file.save = \u65e0\u6cd5\u4fdd\u5b58\u6587\u4ef6 -error.file.write = \u65e0\u6cd5\u5199\u6587\u4ef6 -error.export = \u5bfc\u51fa\u65f6\u9519\u8bef - -export.select.directory = \u8bf7\u9009\u62e9\u5bfc\u51fa\u76ee\u5f55 -export.finishedin = \u5bfc\u51fa\u5b8c\u6210\uff0c\u8017\u8d39\u65f6\u95f4 %time% - -update.check.title = \u786e\u8ba4\u66f4\u65b0 -update.check.nonewversion = \u65e0\u53ef\u7528\u66f4\u65b0. - -message.helpus = \u8bf7\u8bbf\u95ee\r\n%url%\r\n\u83b7\u5f97\u76f8\u5173\u7ec6\u8282. -message.homepage = \u8bbf\u95ee\u4e3b\u9875\uff1a \r\n%url% - -proxy = \u4ee3\u7406 -proxy.start = \u5f00\u59cb\u4ee3\u7406 -proxy.stop = \u505c\u6b62\u4ee3\u7406 -proxy.show = \u663e\u793a\u4ee3\u7406 -exit = \u9000\u51fa - -panel.disassembled = P\u4ee3\u7801\u8d44\u6e90 -panel.decompiled = AS\u8d44\u6e90 - -search.info = \u641c\u7d22 "%text%" : -search.script = \u811a\u672c - -constants = \u5e38\u91cf -traits = Traits - -pleasewait = \u8bf7\u7a0d\u7b49 - -abc.detail.methodtrait = Method/Getter/Setter Trait -abc.detail.unsupported = - -abc.detail.slotconsttrait = Slot/Const Trait -abc.detail.traitname = \u540d\u79f0: - -abc.detail.body.params.maxstack = \u6700\u5927\u5806\u6808: -abc.detail.body.params.localregcount = \u672c\u5730\u5bc4\u5b58\u5668\u8ba1\u6570: -abc.detail.body.params.minscope = \u6700\u5c0f\u8303\u56f4\u6df1\u5ea6: -abc.detail.body.params.maxscope = \u6700\u5927\u8303\u56f4\u6df1\u5ea6: -abc.detail.body.params.autofill = \u4fdd\u5b58\u65f6\u4ee3\u7801\u81ea\u52a8\u586b\u5145 (\u5168\u5c40\u8bbe\u7f6e) -abc.detail.body.params.autofill.experimental = ...\u5b9e\u9a8c\u7684 - -abc.detail.methodinfo.methodindex = \u65b9\u6cd5\u7d22\u5f15: -abc.detail.methodinfo.parameters = \u53c2\u6570: -abc.detail.methodinfo.returnvalue = \u8fd4\u56de\u503c\u7c7b\u578b: - -error.methodinfo.params = \u65b9\u6cd5\u4fe1\u606f\u7684\u53c2\u6570\u9519\u8bef -error.methodinfo.returnvalue = \u65b9\u6cd5\u4fe1\u606f\u7684\u8fd4\u56de\u503c\u7c7b\u578b\u9519\u8bef - -abc.detail.methodinfo = \u65b9\u6cd5\u4fe1\u606f -abc.detail.body.code = \u65b9\u6cd5\u4e3b\u4f53\u4ee3\u7801 -abc.detail.body.params = \u65b9\u6cd5\u4e3b\u4f53\u53c2\u6570 - -abc.detail.slotconst.typevalue = \u7c7b\u578b\u548c\u503c: - -error.slotconst.typevalue = SlotConst\u7c7b\u578b\u503c\u9519\u8bef - -message.autofill.failed = \u65e0\u6cd5\u81ea\u52a8\u83b7\u5f97\u4e3b\u4f53\u53c2\u6570\u72b6\u6001\u4ee3\u7801\u3002\r\n\u8bf7\u5173\u95ed\u81ea\u52a8\u586b\u5145\u529f\u80fd\u540e\u518d\u8bd5\u4e00\u6b21. -info.selecttrait = \u8bf7\u9009\u62e9\u7c7b\uff0c\u7136\u540e\u70b9\u51fb\u8fdb\u884cActionScript\u6e90\u7684\u7f16\u8f91. - -button.viewgraph = \u6d4f\u89c8\u56fe\u5f62 -button.viewhex = \u6d4f\u89c8\u5341\u516d\u8fdb\u5236 - -action.edit.experimental = (\u5b9e\u9a8c\u7684) - -message.action.saved = \u4fdd\u5b58\u4ee3\u7801\u6210\u529f - -error.action.save = %error% \u5728 %line% \u884c - -message.confirm.remove = \u60a8\u786e\u5b9a\u8981\u5220\u9664 %item% \n \u4ee5\u53ca\u6240\u6709\u4f9d\u8d56\u5b83\u7684\u5bf9\u8c61\u5417\uff1f - -#after version 1.6.5u1: - -button.ok = \u786e\u5b9a -button.cancel = \u53d6\u6d88 - -font.name = \u5b57\u4f53\u540d\u79f0: -font.isbold = \u52a0\u7c97: -font.isitalic = \u659c\u4f53: -font.ascent = \u4e0a\u6807: -font.descent = \u4e0b\u6807: -font.leading = Leading: -font.characters = \u5b57\u7b26\u96c6: -font.characters.add = \u6dfb\u52a0\u5b57\u7b26\u96c6: -value.unknown = ? - -yes = \u662f -no = \u5426 - -errors.present = \u5728\u65e5\u5fd7\u4e2d\u8bb0\u5f55\u4e86\u9519\u8bef\uff0c\u70b9\u51fb\u67e5\u770b\u3002 -errors.none = \u5728\u65e5\u5fd7\u4e2d\u6ca1\u6709\u53d1\u73b0\u9519\u8bef\u3002 - -#after version 1.6.6: - -dialog.message.title = \u6d88\u606f -dialog.select.title = \u9009\u62e9\u4e00\u4e2a\u9009\u9879 - -button.yes = \u662f -button.no = \u5426 - -FileChooser.openButtonText = \u6253\u5f00 -FileChooser.openButtonToolTipText = \u6253\u5f00 -FileChooser.lookInLabelText = \u6d4f\u89c8: -FileChooser.acceptAllFileFilterText = \u6240\u6709\u6587\u4ef6 -FileChooser.filesOfTypeLabelText = \u6587\u4ef6\u7c7b\u578b: -FileChooser.fileNameLabelText = \u6587\u4ef6\u540d: -FileChooser.listViewButtonToolTipText = \u5217\u8868 -FileChooser.listViewButtonAccessibleName = \u5217\u8868 -FileChooser.detailsViewButtonToolTipText = \u8be6\u7ec6\u4fe1\u606f -FileChooser.detailsViewButtonAccessibleName = \u8be6\u7ec6\u4fe1\u606f -FileChooser.upFolderToolTipText = \u4e0a\u7ea7\u76ee\u5f55 -FileChooser.upFolderAccessibleName = \u4e0a\u7ea7\u76ee\u5f55 -FileChooser.homeFolderToolTipText = \u4e3b\u76ee\u5f55 -FileChooser.homeFolderAccessibleName = \u4e3b\u76ee\u5f55 -FileChooser.fileNameHeaderText = \u540d\u79f0 -FileChooser.fileSizeHeaderText = \u5927\u5c0f -FileChooser.fileTypeHeaderText = \u7c7b\u578b -FileChooser.fileDateHeaderText = \u65e5\u671f -FileChooser.fileAttrHeaderText = \u5c5e\u6027 -FileChooser.openDialogTitleText = \u6253\u5f00 -FileChooser.directoryDescriptionText = \u76ee\u5f55 -FileChooser.directoryOpenButtonText = \u6253\u5f00 -FileChooser.directoryOpenButtonToolTipText = \u6253\u5f00\u9009\u5b9a\u7684\u76ee\u5f55 -FileChooser.fileDescriptionText = \u901a\u7528\u6587\u4ef6 -FileChooser.helpButtonText = \u5e2e\u52a9 -FileChooser.helpButtonToolTipText = \u6587\u4ef6\u9009\u62e9\u5668\u5e2e\u52a9 -FileChooser.newFolderAccessibleName = \u65b0\u5efa\u6587\u4ef6\u5939 -FileChooser.newFolderErrorText = \u5efa\u7acb\u65b0\u6587\u4ef6\u5939\u65f6\u51fa\u9519 -FileChooser.newFolderToolTipText = \u65b0\u5efa\u6587\u4ef6\u5939 -FileChooser.other.newFolder = \u65b0\u6587\u4ef6\u5939 -FileChooser.other.newFolder.subsequent = \u65b0\u6587\u4ef6\u5939.{0} -FileChooser.win32.newFolder = \u65b0\u6587\u4ef6\u5939 -FileChooser.win32.newFolder.subsequent = \u65b0\u6587\u4ef6\u5939 ({0}) -FileChooser.saveButtonText = \u4fdd\u5b58 -FileChooser.saveButtonToolTipText = \u4fdd\u5b58\u9009\u5b9a\u6587\u4ef6 -FileChooser.saveDialogTitleText = \u4fdd\u5b58 -FileChooser.saveInLabelText = \u4fdd\u5b58\u5230: -FileChooser.updateButtonText = \u5237\u65b0 -FileChooser.updateButtonToolTipText = \u5237\u65b0\u76ee\u5f55\u5217\u8868 - -#after version 1.6.6u2: - -FileChooser.detailsViewActionLabel.textAndMnemonic = \u8be6\u7ec6\u4fe1\u606f -FileChooser.detailsViewButtonToolTip.textAndMnemonic = \u8be6\u7ec6\u4fe1\u606f -FileChooser.fileAttrHeader.textAndMnemonic = \u5c5e\u6027 -FileChooser.fileDateHeader.textAndMnemonic = Modified -FileChooser.fileNameHeader.textAndMnemonic = \u540d\u79f0 -FileChooser.fileNameLabel.textAndMnemonic = \u6587\u4ef6\u540d: -FileChooser.fileSizeHeader.textAndMnemonic = \u5927\u5c0f -FileChooser.fileTypeHeader.textAndMnemonic = \u7c7b\u578b -FileChooser.filesOfTypeLabel.textAndMnemonic = \u6587\u4ef6\u7c7b\u578b: -FileChooser.folderNameLabel.textAndMnemonic = \u76ee\u5f55\u540d: -FileChooser.homeFolderToolTip.textAndMnemonic = \u4e3b\u76ee\u5f55 -FileChooser.listViewActionLabel.textAndMnemonic = \u5217\u8868 -FileChooser.listViewButtonToolTip.textAndMnemonic = \u5217\u8868 -FileChooser.lookInLabel.textAndMnemonic = \u6d4f\u89c8: -FileChooser.newFolderActionLabel.textAndMnemonic = \u65b0\u6587\u4ef6\u5939 -FileChooser.newFolderToolTip.textAndMnemonic = \u65b0\u5efa\u6587\u4ef6\u5939 -FileChooser.refreshActionLabel.textAndMnemonic = \u5237\u65b0 -FileChooser.saveInLabel.textAndMnemonic = \u4fdd\u5b58\u5230: -FileChooser.upFolderToolTip.textAndMnemonic = \u4e0a\u7ea7\u76ee\u5f55 -FileChooser.viewMenuButtonAccessibleName = \u6d4f\u89c8\u83dc\u5355 -FileChooser.viewMenuButtonToolTipText = \u6d4f\u89c8\u83dc\u5355 -FileChooser.viewMenuLabel.textAndMnemonic = \u6d4f\u89c8 -FileChooser.newFolderActionLabelText = \u65b0\u6587\u4ef6\u5939 -FileChooser.listViewActionLabelText = \u5217\u8868 -FileChooser.detailsViewActionLabelText = \u8be6\u7ec6\u4fe1\u606f -FileChooser.refreshActionLabelText = \u5237\u65b0 -FileChooser.sortMenuLabelText = \u6392\u5217\u56fe\u6807 -FileChooser.viewMenuLabelText = \u6d4f\u89c8 -FileChooser.fileSizeKiloBytes = {0} KB -FileChooser.fileSizeMegaBytes = {0} MB -FileChooser.fileSizeGigaBytes = {0} GB -FileChooser.folderNameLabelText = \u76ee\u5f55\u540d: - -error.occured = \u53d1\u751f\u9519\u8bef : %error% -button.abort = \u7ec8\u6b62 -button.retry = \u91cd\u8bd5 -button.ignore = \u5ffd\u7565 - -font.source = \u6e90\u5b57\u4f53: - -#after version 1.6.7: - -menu.export = \u5bfc\u51fa -menu.general = \u901a\u7528 -menu.language = \u8bed\u8a00 - -startup.welcometo = \u6b22\u8fce\u4f7f\u7528 -startup.selectopen = \u4f7f\u7528\u4e0a\u65b9\u9762\u677f\u7684\u6253\u5f00\u56fe\u6807\u6216\u8005\u62d6\u52a8SWF\u6587\u4ef6\u5230\u5f53\u524d\u7a97\u53e3\u4ee5\u5f00\u59cb\u3002 - -error.font.nocharacter = \u9009\u62e9\u7684\u6e90\u5b57\u4f53\u4e0d\u5305\u542b\u5b57\u7b26 "%char%". - -warning.initializers = \u9759\u6001\u5b57\u6bb5\u548c\u5e38\u91cf\u901a\u5e38\u5728\u521d\u59cb\u5316\u65f6\u88ab\u521d\u59cb\u5316\uff0c\n\u5728\u6b64\u7f16\u8f91\u901a\u5e38\u662f\u4e0d\u591f\u7684\uff01 - -#after version 1.7.0u1: - -menu.tools.searchMemory = \u641c\u7d22\u5185\u5b58\u4e2d\u7684SWF -menu.file.reload = \u91cd\u8f7d -message.confirm.reload = \u8be5\u52a8\u4f5c\u5c06\u4f1a\u4e22\u5931\u6240\u6709\u672a\u4fdd\u5b58\u7684\u6539\u52a8\uff0c\u5e76\u91cd\u65b0\u52a0\u8f7d\u5f53\u524dSWF\u6587\u4ef6\u3002\n\u662f\u5426\u7ee7\u7eed\uff1f - -dialog.selectbkcolor.title = \u8bf7\u9009\u62e9SWF\u663e\u793a\u7684\u80cc\u666f\u8272 -button.selectbkcolor.hint = \u9009\u62e9\u80cc\u666f\u8272 - -ColorChooser.okText = \u786e\u5b9a -ColorChooser.cancelText = \u53d6\u6d88 -ColorChooser.resetText = \u91cd\u7f6e -ColorChooser.previewText = \u9884\u89c8 -ColorChooser.swatchesNameText = \u8c03\u8272\u677f -ColorChooser.swatchesRecentText = \u6700\u8fd1: -ColorChooser.sampleText = \u793a\u4f8b\u6587\u5b57 \u793a\u4f8b\u6587\u672c - -#after version 1.7.1: - -preview.play = \u64ad\u653e -preview.pause = \u6682\u505c -preview.stop = \u505c\u6b62 - -message.confirm.removemultiple = \u60a8\u786e\u5b9a\u8981\u79fb\u9664 %count% \u4e2a\u9879\u76ee\uff0c\n\u4ee5\u53ca\u5176\u6240\u6709\u7684\u4f9d\u8d56\u5bf9\u8c61\u5417\uff1f - -menu.tools.searchCache = \u641c\u7d22\u6d4f\u89c8\u5668\u7f13\u5b58 - -#after version 1.7.2u2 - -error.trait.exists = Trait \u6240\u7528\u7684\u540d\u79f0 \u201c%name%\u201d\u5df2\u5b58\u5728\u3002 -button.addtrait = \u6dfb\u52a0 Trait -button.font.embed = \u5d4c\u5165... -button.yes.all = \u5168\u662f -button.no.all = \u5168\u5426 -message.font.add.exists = \u5b57\u7b26 %char% \u5df2\u5b58\u5728\u3002\n\u60a8\u662f\u5426\u8981\u66ff\u6362\uff1f - -filter.gfx = ScaleForm GFx \u6587\u4ef6 (*.gfx) -filter.supported = \u6240\u6709\u652f\u6301\u6587\u4ef6\u7c7b\u578b -work.canceled = \u5df2\u53d6\u6d88 -work.restoringControlFlow = \u6062\u590d\u63a7\u5236\u5668\u6d41\u7a0b -menu.advancedsettings.advancedsettings = \u9ad8\u7ea7\u8bbe\u7f6e -menu.recentFiles = \u6700\u8fd1\u6587\u4ef6 - -#after version 1.7.4 -work.restoringControlFlow.complete = \u63a7\u5236\u5668\u6d41\u7a0b\u5df2\u6062\u590d -message.confirm.recentFileNotFound = \u627e\u4e0d\u5230\u6587\u4ef6\u3002\u662f\u5426\u4ece\u6700\u8fd1\u6587\u4ef6\u5217\u8868\u79fb\u9664\uff1f -contextmenu.closeSwf = \u5173\u95ed SWF -menu.settings.autoRenameIdentifiers = \u81ea\u52a8\u91cd\u547d\u540d\u6807\u8bc6 -menu.file.saveasexe = \u53e6\u5b58\u4e3aexe... -filter.exe = \u53ef\u6267\u884c\u6587\u4ef6(*.exe) - -#after version 1.8.0 -font.updateTexts = \u66f4\u65b0\u6587\u672c - -#after version 1.8.0u1 -menu.file.close = \u5173\u95ed -menu.file.closeAll = \u5168\u90e8\u5173\u95ed -menu.tools.otherTools = \u5176\u4ed6 -menu.tools.otherTools.clearRecentFiles = \u6e05\u9664\u6700\u8fd1\u6587\u4ef6 -fontName.name = \u5b57\u4f53\u663e\u793a\u540d\u79f0: -fontName.copyright = \u5b57\u4f53\u7248\u6743: -button.preview = \u9884\u89c8 -button.reset = \u91cd\u7f6e -errors.info = \u6709\u4fe1\u606f\u65e5\u5fd7\u3002\u70b9\u51fb\u67e5\u770b\u3002 -errors.warning = \u6709\u8b66\u544a\u65e5\u5fd7\u3002\u70b9\u51fb\u67e5\u770b\u3002 - -decompilationError = \u53cd\u7f16\u8bd1\u9519\u8bef - -disassemblingProgress.toString = \u5230\u5b57\u7b26\u4e32 -disassemblingProgress.reading = \u8bfb\u53d6\u4e2d -disassemblingProgress.deobfuscating = \u6df7\u6dc6 - -contextmenu.moveTag = \u79fb\u52a8\u6807\u7b7e\u5230 - -filter.swc = SWC\u7ec4\u4ef6\u6587\u4ef6 (*.swc) -filter.zip = ZIP\u538b\u7f29\u6587\u4ef6 (*.zip) -filter.binary = \u4e8c\u8fdb\u5236\u67e5\u627e - \u6240\u6709\u6587\u4ef6 (*.*) - -open.error = \u9519\u8bef -open.error.fileNotFound = \u672a\u627e\u5230\u6587\u4ef6 -open.error.cannotOpen = \u65e0\u6cd5\u6253\u5f00\u6587\u4ef6 - -node.others = \u5176\u4ed6 - -#after version 1.8.1 -menu.tools.search = \u6587\u672c\u67e5\u627e - -#after version 1.8.1u1 -menu.tools.timeline = \u65f6\u95f4\u8f74 - -dialog.selectcolor.title = \u9009\u62e9\u989c\u8272 -button.selectcolor.hint = \u70b9\u51fb\u9009\u62e9\u989c\u8272 - -#default item name, will be used in following sentences -generictag.array.item = \u9879\u76ee -generictag.array.insertbeginning = \u5728\u4e00\u5f00\u59cb\u63d2\u5165 %item% -generictag.array.insertbefore = \u63d2\u5165 %item% \u4e4b\u524d -generictag.array.remove = \u79fb\u9664 %item% -generictag.array.insertafter = \u63d2\u5165 %item% \u4e4b\u540e -generictag.array.insertend = \u5728\u7ed3\u675f\u63d2\u5165 %item% - -#after version 2.0.0 -contextmenu.expandAll = \u5168\u90e8\u5c55\u5f00 - -filter.sounds = \u652f\u6301\u7684\u58f0\u97f3\u683c\u5f0f (*.wav, *.mp3) -filter.sounds.wav = Wave\u6587\u4ef6\u683c\u5f0f (*.wav) -filter.sounds.mp3 = MP3\u538b\u7f29\u683c\u5f0f (*.mp3) - -error.sound.invalid = \u65e0\u6548\u6587\u4ef6\u3002 - -button.prev = \u4e0a\u4e00\u9875 -button.next = \u4e0b\u4e00\u9875 - -#after version 2.1.0 -message.action.playerglobal.title = \u9700\u8981PlayerGlobal\u652f\u6301\u5e93 -message.action.playerglobal.needed = \u82e5\u8981\u76f4\u63a5\u7f16\u8f91AS3\u811a\u672c, \u9700\u8981\u4eceAdobe\u4e3b\u9875\u4e0b\u8f7d\u4e00\u4e2a"PlayerGlobal.swc"\u7684\u652f\u6301\u5e93\u3002\r\n%adobehomepage%\r\n\u70b9\u51fb\u201c\u786e\u5b9a\u201d\u8f6c\u5230\u4e0b\u8f7d\u9875\u9762\u3002 -message.action.playerglobal.place = \u4e0b\u8f7d\u652f\u6301\u5e93PlayerGlobal(.swc),\u5e76\u653e\u5165\u8be5\u6587\u4ef6\u5939\u3002\r\n%libpath%\r\n \u70b9\u51fb\u201c\u786e\u5b9a\u201d\u7ee7\u7eed\u3002 - -message.confirm.experimental.function = \u6b64\u529f\u80fd\u4e3a\u5b9e\u9a8c\u6027\uff01\u8fd9\u610f\u5473\u7740\u7ed3\u679c\u5e76\u4e0d\u53ef\u9760\u5e76\u4e14\u4fdd\u5b58\u4e4b\u540e\u65e0\u6cd5\u6b63\u5e38\u8fd0\u884c\u3002 -message.confirm.donotshowagain = \u4e0d\u518d\u663e\u793a - -menu.import = \u5bfc\u5165 -menu.file.import.text = \u5bfc\u5165\u6587\u672c -import.select.directory = \u9009\u62e9\u5bfc\u5165\u76ee\u5f55 -error.text.import = \u5bfc\u5165\u6587\u672c\u9519\u8bef\u3002\u7ee7\u7eed\uff1f - -#after version 2.1.1 -contextmenu.removeWithDependencies = \u79fb\u9664\u4f9d\u8d56 - -abc.action.find-usages = \u67e5\u627e\u5f15\u7528 -abc.action.find-declaration = \u67e5\u627e\u58f0\u660e - -contextmenu.rawEdit = RAW\u7f16\u8f91 -contextmenu.jumpToCharacter = \u8f6c\u5230\u5b57\u7b26 - -menu.settings.dumpView = \u67e5\u770b\u8f6c\u50a8 - -menu.view = \u67e5\u770b -menu.file.view.resources = \u8d44\u6e90 -menu.file.view.hex = \u4e8c\u8fdb\u5236 - -node.header = \u6587\u4ef6\u5934 - -header.signature = \u6587\u4ef6\u6807\u8bc6: -header.compression = \u538b\u7f29\u6a21\u5f0f: -header.compression.lzma = LZMA -header.compression.zlib = ZLIB -header.compression.none = \u65e0\u538b\u7f29 -header.version = SWF\u7248\u672c: -header.gfx = GFX: -header.filesize = \u6587\u4ef6\u5927\u5c0f -header.framerate = \u5e27\u7387: -header.framecount = \u5e27\u6570: -header.displayrect = \u663e\u793a\u533a\u57df: -header.displayrect.value.twips = %xmin%,%ymin% => %xmax%,%ymax% twips -header.displayrect.value.pixels = %xmin%,%ymin% => %xmax%,%ymax% pixels - -#after version 2.1.2 -contextmenu.saveToFile = \u53e6\u5b58\u4e3a\u6587\u4ef6 -contextmenu.parseActions = \u89e3\u6790\u52a8\u4f5c -contextmenu.parseABC = \u89e3\u6790ABC -contextmenu.parseInstructions = \u89e3\u6790AVM2\u6307\u4ee4 - -#after version 2.1.3 -menu.deobfuscation = \u53cd\u6df7\u6dc6 -menu.file.deobfuscation.old = \u65e7\u6837\u5f0f -menu.file.deobfuscation.new = \u65b0\u6837\u5f0f - -#after version 2.1.4 -contextmenu.openswfinside = \u6253\u5f00 SWF \u5185\u90e8 -binarydata.swfInside = \u5b83\u770b\u8d77\u6765\u50cf\u6709\u8fd9\u4e2a\u4e8c\u8fdb\u5236\u6570\u636e\u6807\u7b7e\u5185\u7684 SWF\u3002\u70b9\u51fb\u6b64\u5904\u5c06\u5176\u52a0\u8f7d\u4e3a\u5b50\u6811\u3002 - -#after version 3.0.0 -button.zoomin.hint = \u653e\u5927 -button.zoomout.hint = \u7f29\u5c0f -button.zoomfit.hint = \u7f29\u653e\u5230\u9002\u5408 -button.zoomnone.hint = \u7f29\u653e\u5230 1:1 -button.snapshot.hint = \u6355\u83b7\u5feb\u7167\u5230\u526a\u8d34\u677f - -editorTruncateWarning = \u5728\u8c03\u8bd5\u6a21\u5f0f\u4e0b\u6587\u672c\u88ab\u622a\u65ad\u5728 %chars% \u4f4d\u7f6e\u3002 - -#Font name which is presented in the SWF Font tag -font.name.intag = \u5728\u6807\u7b7e\u5b57\u4f53\u540d\u79f0: - -menu.debugger = \u8c03\u8bd5\u5668 -menu.debugger.switch = \u8c03\u8bd5\u5668 -menu.debugger.replacetrace = \u66ff\u6362\u8ddf\u8e2a\u8c03\u7528 -menu.debugger.showlog = \u663e\u793a\u65e5\u5fd7 - -message.debugger = \u8be5 SWF \u8c03\u8bd5\u5668\u53ea\u80fd\u7528\u4e8e\u6253\u5370\u8bb0\u5f55\u6d88\u606f\u7684\u7a97\u53e3\uff0c\u6d4f\u89c8\u5668\u63a7\u5236\u53f0\u6216\u8b66\u62a5\u3002\r\n\u5b83\u4e0d\u662f\u8bbe\u8ba1\u7528\u4e8e\u529f\u80fd\uff0c\u5982\u6b65\u5165\u4ee3\u7801\uff0c\u65ad\u70b9\u7b49\u3002 - -contextmenu.addTag = \u6dfb\u52a0\u6807\u7b7e - -deobfuscation.comment.tryenable = \u63d0\u793a\uff1a\u5728\u8bbe\u7f6e\u60a8\u53ef\u4ee5\u5c1d\u8bd5\u542f\u7528\u201c\u81ea\u52a8\u53cd\u6df7\u6dc6\u201d -deobfuscation.comment.failed = \u53cd\u6df7\u6dc6\u88ab\u6fc0\u6d3b\uff0c\u4f46\u662f\u53cd\u7f16\u8bd1\u8fd8\u662f\u5931\u8d25\u4e86\u3002\u5982\u679c\u6587\u4ef6\u4e0d\u6df7\u4e71\uff0c\u7981\u7528\u201c\u81ea\u52a8\u53cd\u6df7\u6dc6\u201d\u6548\u679c\u4f1a\u66f4\u597d\u3002 - -#after version 4.0.2 -preview.nextframe = \u4e0b\u4e00\u5e27 -preview.prevframe = \u4e0a\u4e00\u5e27 -preview.gotoframe = \u8f6c\u5230\u5e27... - -preview.gotoframe.dialog.title = \u8f6c\u5230\u5e27 -preview.gotoframe.dialog.message = \u8f93\u5165\u5e27\u53f7 (%min% - %max%) -preview.gotoframe.dialog.frame.error = \u65e0\u6548\u7684\u5e27\u53f7\u3002\u5b83\u5fc5\u987b\u662f\u6570\u5b57 %min% \u548c %max%\u4e4b\u95f4\u3002 - -error.text.invalid.continue = \u65e0\u6548\u6587\u672c: %text% \u5728\u884c %line%\u3002\u4f60\u60f3\u7ee7\u7eed\u5417\uff1f - -#after version 4.0.5 -contextmenu.copyTag = \u590d\u5236\u6807\u7b7e\u5230 -fit = \u9002\u5408 -button.setAdvanceValues = \u8bbe\u7f6e advanc \u503c - -menu.tools.replace = \u6587\u672c\u66ff\u6362 - -message.confirm.close = \u6709\u672a\u4fdd\u5b58\u7684\u66f4\u6539\u3002\u4f60\u771f\u7684\u8981\u5173\u95ed{swfName}\u5417\uff1f -message.confirm.closeAll = \u6709\u672a\u4fdd\u5b58\u7684\u66f4\u6539\u3002\u4f60\u771f\u7684\u8981\u5173\u95ed\u6240\u6709\u7684SWF\u5417\uff1f - -contextmenu.exportJavaSource = \u5bfc\u51fa Java \u6e90\u4ee3\u7801 -contextmenu.exportSwfXml = \u5bfc\u51fa SWF \u4e3a XML -contextmenu.importSwfXml = \u5bfc\u5165 SWF XML - -filter.xml = XML - -#after version 4.1.0 -contextmenu.undo = \u64a4\u6d88 - -text.align.left = \u5de6\u5bf9\u9f50 -text.align.right = \u53f3\u5bf9\u9f50 -text.align.center = \u5c45\u4e2d\u5bf9\u9f50 -text.align.justify = \u4e24\u7aef\u5bf9\u9f50 - -text.undo = \u64a4\u6d88\u66f4\u6539 - -menu.file.import.xml = \u5bfc\u5165 SWF XML -menu.file.export.xml = \u5bfc\u51fa SWF XML - -#after version 4.1.1 -text.align.translatex.decrease = \u51cf\u5c11 TranslateX -text.align.translatex.increase = \u589e\u52a0 TranslateX -selectPreviousTag = \u9009\u62e9\u4e0a\u4e00\u4e2a\u6807\u7b7e -selectNextTag = \u9009\u62e9\u4e0b\u4e00\u4e2a\u6807\u7b7e -button.ignoreAll = \u5ffd\u7565\u5168\u90e8 -menu.file.import.symbolClass = \u5bfc\u5165\u7b26\u53f7-Class -text.toggleCase = \u5207\u6362\u5916\u58f3 - -#after version 5.0.2 -preview.loop = \u5faa\u73af -menu.file.import.script = \u5bfc\u5165\u811a\u672c -contextmenu.copyTagWithDependencies = \u4ee5\u4f9d\u8d56\u5173\u7cfb\u5230\u590d\u5236\u6807\u7b7e -button.replaceWithTag = \u4f7f\u7528\u5176\u5b83\u5b57\u7b26\u66ff\u6362\u6807\u7b7e -button.resolveConstants = \u89e3\u6790\u5e38\u6570 - -#after version 5.1.0 -button.viewConstants = \u67e5\u770b\u5e38\u91cf -work.exported = \u5bfc\u51fa -button.replaceAlphaChannel = \u66ff\u6362 alpha \u901a\u9053... - -tagInfo.header.name = \u540d\u79f0 -tagInfo.header.value = \u503c -tagInfo.tagType = \u6807\u7b7e\u7c7b\u578b -tagInfo.characterId = \u5b57\u7b26 ID -tagInfo.offset = \u504f\u79fb -tagInfo.length = \u957f\u5ea6 -tagInfo.bounds = \u8fb9\u754c -tagInfo.width = \u5bbd\u5ea6 -tagInfo.height = \u9ad8\u5ea6 -tagInfo.neededCharacters = \u9700\u8981\u7684\u5b57\u7b26 - -button.viewhexpcode = \u67e5\u770b\u5341\u516d\u8fdb\u5236\u5e76\u6307\u793a -taginfo.header = \u57fa\u672c\u6807\u7b7e\u4fe1\u606f - -tagInfo.dependentCharacters = \u76f8\u5173\u5b57\u7b26 - -#after version 5.3.0 -header.uncompressed = \u65e0\u538b\u7f29 -header.warning.unsupportedGfxCompression = GFX \u4ec5\u652f\u6301\u975e\u538b\u7f29\u6216\u538b\u7f29\u7684 Zlib \u5185\u5bb9\u3002 -header.warning.minimumZlibVersion = ZLIB \u538b\u7f29\u9700\u8981SWF\u7b2c6\u7248\u6216\u66f4\u9ad8\u7248\u672c\u3002 -header.warning.minimumLzmaVersion = LZMA \u538b\u7f29\u9700\u8981 SWF \u7248\u672c 13 \u6216\u66f4\u9ad8\u7248\u672c\u3002 - -tagInfo.codecName = \u7f16\u89e3\u7801\u5668\u540d\u79f0 -tagInfo.exportFormat = \u5bfc\u51fa\u683c\u5f0f -tagInfo.samplingRate = \u91c7\u6837\u7387 -tagInfo.stereo = \u7acb\u4f53\u58f0 -tagInfo.sampleCount = \u91c7\u6837\u6570\u91cf - -filter.dmg = Mac \u53ef\u6267\u884c\u6587\u4ef6 (*.dmg) -filter.linuxExe = Linux \u53ef\u6267\u884c\u6587\u4ef6 - -import.script.result = %count% \u811a\u672c\u5df2\u5bfc\u5165\u3002 -import.script.as12warning = \u4ec5 1/2 \u7684\u811a\u672c\u53ef\u4ee5\u5bfc\u5165\u3002 - -error.constantPoolTooBig = \u5e38\u91cf\u6c60\u592a\u5927\u3002 \u7d22\u5f15=%index%, \u5927\u5c0f=%size% -error.image.alpha.invalid = \u65e0\u6548\u7684 Alpha \u901a\u9053\u6570\u636e\u3002 - -#after version 6.0.2 -contextmenu.saveUncompressedToFile = \u4fdd\u5b58\u5230\u672a\u538b\u7f29\u6587\u4ef6 -menu.settings.autoOpenLoadedSWFs = \u6253\u5f00\u5df2\u8f7d\u5165 SWF \u6587\u4ef6\u65f6\u64ad\u653e - -#after version 6.1.1 -menu.file.start = \u5f00\u59cb -menu.file.start.run = \u8fd0\u884c -menu.file.start.stop = \u505c\u6b62 -menu.file.start.debug = \u8c03\u8bd5 -menu.debugging = \u8c03\u8bd5\u4e2d -menu.debugging.debug = \u8c03\u8bd5 -menu.debugging.debug.stop = \u505c\u6b62 -menu.debugging.debug.pause = \u6682\u505c -menu.debugging.debug.stepOver = \u5355\u6b65\u6267\u884c -menu.debugging.debug.stepInto = \u5355\u6b65\u6b65\u5165 -menu.debugging.debug.stepOut = \u5355\u6b65\u6b65\u51fa -menu.debugging.debug.continue = \u7ee7\u7eed -menu.debugging.debug.stack = \u5806\u6808... -menu.debugging.debug.watch = \u65b0\u5efa\u67e5\u770b... - -message.playerpath.notset = Flash Player \u653e\u6620\u673a\u6ca1\u6709\u627e\u5230\u3002\u8bf7\u5728\u9ad8\u7ea7\u8bbe\u7f6e/\u8def\u5f84\u914d\u7f6e\u5176\u8def\u5f84\u3002 -message.playerpath.debug.notset = Flash Player \u653e\u6620\u673a\u8c03\u8bd5\u7684\u5185\u5bb9\u6ca1\u6709\u627e\u5230\u3002\u8bf7\u5728\u9ad8\u7ea7\u8bbe\u7f6e/\u8def\u5f84\u914d\u7f6e\u5176\u8def\u5f84\u3002 -message.playerpath.lib.notset = PlayerGlobal (.SWC) \u672a\u627e\u5230\u3002\u8bf7\u5728\u5176\u8def\u5f84\u914d\u7f6e\u9ad8\u7ea7\u8bbe\u7f6e/\u8def\u5f84\u3002 - -debugpanel.header = \u8c03\u8bd5\u4e2d - -variables.header.registers = \u5bc4\u5b58\u5668 -variables.header.locals = \u672c\u673a -variables.header.arguments = \u53c2\u6570 -variables.header.scopeChain = \u4f5c\u7528\u57df\u94fe -variables.column.name = \u540d\u79f0 -variables.column.type = \u7c7b\u578b -variables.column.value = \u503c - -callStack.header = \u8c03\u7528\u5806\u6808 -callStack.header.file = \u6587\u4ef6 -callStack.header.line = \u884c - -stack.header = \u5806\u53e0 -stack.header.item = \u9879\u76ee - -constantpool.header = \u5e38\u91cf\u6c60 -constantpool.header.id = Id -constantpool.header.value = \u503c - -work.running = \u8fd0\u884c\u884c -work.debugging = \u8c03\u8bd5\u4e2d -work.debugging.instrumenting = SWF \u51c6\u5907\u8c03\u8bd5 -work.breakat = \u65ad\u70b9\u5728\u0020 -work.halted = \u8c03\u8bd5\u5f00\u59cb\uff0c\u6267\u884c\u505c\u6b62\u3002\u6dfb\u52a0\u65ad\u70b9\uff0c\u7136\u540e\u70b9\u51fb\u7ee7\u7eed\uff08F5\uff09\u6062\u590d\u8fd0\u884c\u3002 - -debuglog.header = \u65e5\u5fd7 -debuglog.button.clear = \u6e05\u9664 - -#after 7.0.1 -work.debugging.wait = \u7b49\u5f85 Flash \u8c03\u8bd5\u653e\u6620\u673a\u8fde\u63a5 - -error.debug.listen = \u65e0\u6cd5\u76d1\u542c\u7aef\u53e3 %port%\u3002\u6709\u53ef\u80fd\u662f\u53e6\u4e00\u4e2a Flash \u8c03\u8bd5\u5668\u8fd0\u884c\u3002 - -debug.break.reason.unknown = (\u672a\u77e5) -debug.break.reason.breakpoint = (\u65ad\u70b9) -debug.break.reason.watch = (\u89c2\u770b) -debug.break.reason.fault = (\u6545\u969c) -debug.break.reason.stopRequest = (\u505c\u6b62\u8bf7\u6c42) -debug.break.reason.step = (\u6b65\u9aa4) -debug.break.reason.halt = (\u505c\u6b62) -debug.break.reason.scriptLoaded = (\u52a0\u8f7d\u811a\u672c) - -menu.file.start.debugpcode = \u8c03\u8bd5 P-code - -#after 7.1.2 -button.replaceNoFill = \u66ff\u6362 - \u66f4\u65b0\u8303\u56f4... -message.warning.svgImportExperimental = \u5e76\u975e\u6240\u6709\u7684\u529f\u80fd\u652f\u6301 SVG\u3002\u8bf7\u5bfc\u5165\u540e\u68c0\u67e5\u65e5\u5fd7\u3002 - -message.imported.swf = \u8be5 SWF \u6587\u4ef6\u4f7f\u7528\u7684\u90d1\u6e90\u662f\u4ece\u5bfc\u5165 SWF \u6587\u4ef6:\n%url%\n\u4f60\u60f3\u4ece\u8be5URL\u52a0\u8f7d\u5417\uff1f -message.imported.swf.manually = \u65e0\u6cd5\u52a0\u8f7d\u5bfc\u5165\u7684 SWF\n%url%\n\u8be5\u6587\u4ef6\u6216 URL \u4e0d\u5b58\u5728\u3002\n\u4f60\u8981\u9009\u62e9\u672c\u5730\u6587\u4ef6\u5417\uff1f - -message.warning.hexViewNotUpToDate = \u5341\u516d\u8fdb\u5236\u67e5\u770b\u6ca1\u6709\u53ca\u65f6\u66f4\u65b0\u3002\u8bf7\u4fdd\u5b58\u5e76\u91cd\u65b0\u52a0\u8f7d\u66f4\u65b0\u5341\u516d\u8fdb\u5236\u67e5\u770b\u8be5\u6587\u4ef6\u3002 -message.font.replace.updateTexts = \u67d0\u4e9b\u5b57\u7b26\u88ab\u66ff\u6362\u3002\u662f\u5426\u8981\u66f4\u65b0\u73b0\u6709\u7684\u6587\u672c\uff1f - -menu.settings.simplifyExpressions = \u7b80\u5316\u8868\u8fbe\u5f0f - -#after 8.0.1 -menu.recentFiles.empty = \u6700\u8fd1\u7684\u6587\u4ef6\u5217\u8868\u4e3a\u7a7a -message.warning.outOfMemory32BitJre = \u53d1\u751f\u5185\u5b58\u9519\u8bef\u3002\u60a8\u5728 64 \u4f4d\u7cfb\u7edf\u4e0a\u8fd0\u884c 32 \u4f4d\u7684 Java\u3002\u8bf7\u4f7f\u7528 64 \u4f4d\u7684 Java\u3002 - -menu.file.reloadAll = \u91cd\u65b0\u52a0\u8f7d\u6240\u6709 -message.confirm.reloadAll = \u6b64\u64cd\u4f5c\u4f1a\u53d6\u6d88\u6240\u6709\u7684 SWF \u6587\u4ef6\u6240\u6709\u672a\u4fdd\u5b58\u7684\u66f4\u6539\uff0c\u5e76\u518d\u6b21\u91cd\u65b0\u52a0\u8f7d\u6574\u4e2a\u5e94\u7528\u7a0b\u5e8f\u3002\n\u4f60\u60f3\u7ee7\u7eed\u5417\uff1f -export.script.singleFilePallelModeWarning = \u5355\u4e2a\u6587\u4ef6\u7684\u811a\u672c\u8f93\u51fa\u6ca1\u6709\u4f7f\u7528\u542f\u7528\u5e76\u884c\u52a0\u901f\u652f\u6301 - -button.showOriginalBytesInPcodeHex = \u663e\u793a\u539f\u59cb\u5b57\u8282 -button.remove = \u6e05\u9664 -button.showFileOffsetInPcodeHex = \u663e\u793a\u6587\u4ef6\u504f\u79fb - -generic.editor.amf3.title = AMF3 \u7f16\u8f91\u5668 -generic.editor.amf3.help = AMF3 \u503c\u8bed\u6cd5:\n\ - ------------------\n\ - \u6807\u91cf\u7c7b\u578b:\n\ - %scalar_samples%\ - \u5176\u4ed6\u7c7b\u578b:\n\ - %nonscalar_samples%\ - \n\ - \u6ce8\u610f:\n\ - \ * Nonscalar datatypes can be referenced by previously declared "id" attributes with # syntax:\n\ - %reference_sample%\n\ - \ * Keys in Dictionary entries can be any type\n -contextmenu.showInResources = \u5728\u8d44\u6e90\u663e\u793a - +# Copyright (C) 2010-2016 JPEXS +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +menu.file = \u6587\u4ef6 +menu.file.open = \u6253\u5f00... +menu.file.save = \u4fdd\u5b58 +menu.file.saveas = \u53e6\u5b58\u4e3a... +menu.file.export.fla = \u5bfc\u51fa\u5230 FLA +menu.file.export.all = \u5bfc\u51fa\u6240\u6709 +menu.file.export.selection = \u5bfc\u51fa\u6240\u9009 +menu.file.exit = \u9000\u51fa + +menu.tools = \u5de5\u5177 +menu.tools.searchas = \u5728\u6240\u6709AS\u4ee3\u7801\u4e2d\u641c\u7d22... +menu.tools.proxy = \u4ee3\u7406 +menu.tools.deobfuscation = \u53cd\u6df7\u6dc6 +menu.tools.deobfuscation.pcode = P\u4ee3\u7801\u53cd\u6df7\u6dc6... +menu.tools.deobfuscation.globalrename = \u5168\u5c40\u91cd\u547d\u540d\u6807\u8bc6\u7b26 +menu.tools.deobfuscation.renameinvalid = \u91cd\u547d\u540d\u65e0\u6548\u6807\u8bc6\u7b26 +menu.tools.gotoDocumentClass = \u8df3\u8f6c\u5230\u4e3b\u7c7b + +menu.settings = \u8bbe\u7f6e +menu.settings.autodeobfuscation = \u81ea\u52a8\u53cd\u6df7\u6dc6 +menu.settings.internalflashviewer = \u4f7f\u7528\u5185\u90e8Flash\u64ad\u653e\u5668 +menu.settings.parallelspeedup = \u591a\u7ebf\u7a0b\u52a0\u901f +menu.settings.disabledecompilation = \u7981\u7528\u53cd\u7f16\u8bd1 (\u4ec5\u53cd\u6c47\u7f16) +menu.settings.addtocontextmenu = \u6dfb\u52a0FFDec\u5230SWF\u6587\u4ef6\u83dc\u5355 +menu.settings.language = \u66f4\u6539\u8bed\u8a00 +menu.settings.cacheOnDisk = \u4f7f\u7528\u786c\u76d8\u4f5c\u7f13\u5b58 +menu.settings.gotoMainClassOnStartup = \u52a0\u8f7d\u5b8c\u6bd5\u540e\u9ad8\u4eae\u4e3b\u7c7b + +menu.help = \u5e2e\u52a9 +menu.help.checkupdates = \u68c0\u67e5\u66f4\u65b0... +menu.help.helpus = \u5e2e\u52a9\u6211\u4eec! +menu.help.homepage = \u8bbf\u95ee\u4e3b\u9875 +menu.help.about = \u5173\u4e8e... + +contextmenu.remove = \u5220\u9664 + +button.save = \u4fdd\u5b58 +button.edit = \u7f16\u8f91 +button.cancel = \u53d6\u6d88 +button.replace = \u66ff\u6362... + +notavailonthisplatform = \u9884\u89c8\u8be5\u5bf9\u8c61\u662f\u5426\u53ef\u7528\u4e8e\u5f53\u524d\u5e73\u53f0. (\u4ec5Windows) + +swfpreview = SWF \u9884\u89c8 +swfpreview.internal = SWF \u9884\u89c8(\u4f7f\u7528\u5185\u7f6e\u64ad\u653e\u5668) + +parameters = \u53c2\u6570 + +rename.enternew = \u8bf7\u8f93\u5165\u65b0\u540d\u79f0: + +rename.finished.identifier = \u6807\u8bc6\u7b26\u5df2\u88ab\u91cd\u547d\u540d. +rename.finished.multiname = %count% \u4e2a multiname \u5df2\u88ab\u91cd\u547d\u540d. + +node.texts = \u6587\u672c +node.images = \u56fe\u50cf +node.movies = \u89c6\u9891 +node.sounds = \u58f0\u97f3 +node.binaryData = \u4e8c\u8fdb\u5236\u6570\u636e +node.fonts = \u5b57\u4f53 +node.sprites = \u7cbe\u7075 +node.shapes = \u56fe\u5f62 +node.morphshapes = \u53d8\u5f62\u5f62\u72b6 +node.buttons = \u6309\u94ae +node.frames = \u5e27 +node.scripts = \u811a\u672c + +message.warning = \u8b66\u544a +message.confirm.experimental = \u4e0b\u9762\u7684\u64cd\u4f5c\u53ef\u80fd\u4f1a\u635f\u574fSWF\u6587\u4ef6\uff0c\u5e76\u5c06\u5bfc\u81f4\u65e0\u6cd5\u64ad\u653e\u3002\r\n\u60a8\u5fc5\u987b\u6e05\u695a\u5730\u8ba4\u8bc6\u5230\u8fd9\u9879\u98ce\u9669\uff0c\u662f\u5426\u7ee7\u7eed\uff1f +message.confirm.parallel = \u591a\u7ebf\u7a0b\uff0c\u53ef\u4ee5\u52a0\u5feb\u52a0\u8f7d\u53ca\u53cd\u7f16\u8bd1\u901f\u5ea6\uff0c\u4f46\u4f1a\u6d88\u8017\u66f4\u591a\u7684\u5185\u5b58\u3002 +message.confirm.on = \u60a8\u786e\u5b9a\u8981\u5f00\u542f\u5417\uff1f +message.confirm.off = \u60a8\u786e\u5b9a\u8981\u5173\u95ed\u5417\uff1f +message.confirm = \u786e\u8ba4 + +message.confirm.autodeobfuscate = \u81ea\u52a8\u53cd\u6df7\u6dc6\u662f\u4e00\u79cd\u80fd\u53cd\u7f16\u8bd1\u88ab\u6df7\u6dc6\u4ee3\u7801\u7684\u529f\u80fd\u3002\r\n \u53cd\u6df7\u6dc6\u5c06\u5bfc\u81f4\u53cd\u7f16\u8bd1\u7684\u901f\u5ea6\u8f83\u6162\uff0c\u5e76\u53ef\u80fd\u4f1a\u7565\u8fc7\u51fa\u73b0\u7684\u201c\u6b7b\u4ee3\u7801\u201d\u3002\r\n \u5982\u679c\u60a8\u786e\u8ba4\u6587\u4ef6\u4e2d\u7684\u4ee3\u7801\u6ca1\u6709\u88ab\u6df7\u6dc6\uff0c\u5efa\u8bae\u60a8\u5173\u95ed\u8be5\u9009\u9879\u3002 + +message.parallel = \u591a\u7ebf\u7a0b +message.trait.saved = \u5df2\u6210\u529f\u4fdd\u5b58Trait + +message.constant.new.string = \u5728\u5e38\u91cf\u8868\u4e2d\u627e\u4e0d\u5230\u5b57\u7b26\u4e32 "%value%" \uff0c\u9700\u8981\u6dfb\u52a0\u5417\uff1f +message.constant.new.string.title = \u6dfb\u52a0\u5b57\u7b26\u4e32 +message.constant.new.integer = \u5728\u5e38\u91cf\u8868\u4e2d\u627e\u4e0d\u5230\u6574\u6570 "%value%" \uff0c\u9700\u8981\u6dfb\u52a0\u5417\uff1f +message.constant.new.integer.title = \u6dfb\u52a0\u6574\u6570 +message.constant.new.unsignedinteger = \u5728\u5e38\u91cf\u8868\u4e2d\u627e\u4e0d\u5230\u65e0\u7b26\u53f7\u6574\u6570 "%value%" \uff0c\u9700\u8981\u6dfb\u52a0\u5417\uff1f +message.constant.new.unsignedinteger.title = \u6dfb\u52a0\u65e0\u7b26\u53f7\u6574\u6570 +message.constant.new.double = \u5728\u5e38\u91cf\u8868\u4e2d\u627e\u4e0d\u5230\u53cc\u5b57\u8282 "%value%" \uff0c\u9700\u8981\u6dfb\u52a0\u5417\uff1f +message.constant.new.double.title = \u6dfb\u52a0\u53cc\u5b57\u8282 + +work.buffering = \u7f13\u51b2 +work.waitingfordissasembly = \u7b49\u5f85\u53cd\u6c47\u7f16 +work.gettinghilights = \u83b7\u53d6\u9ad8\u4eae +work.disassembling = \u53cd\u6c47\u7f16 +work.exporting = \u5bfc\u51fa\u4e2d +work.searching = \u641c\u7d22\u4e2d +work.renaming = \u91cd\u547d\u540d\u4e2d +work.exporting.fla = \u5bfc\u51fa FLA \u4e2d +work.renaming.identifiers = \u91cd\u547d\u540d\u6807\u8bc6\u7b26\u4e2d +work.deobfuscating = \u53cd\u6df7\u6dc6\u4e2d +work.decompiling = \u53cd\u7f16\u8bd1\u4e2d +work.gettingvariables = \u83b7\u53d6\u53d8\u91cf +work.reading.swf = \u8bfb\u5165 SWF \u4e2d +work.creatingwindow = \u521b\u5efa\u7a97\u4f53 +work.buildingscripttree = \u5efa\u7acb\u811a\u672c\u6811 + +work.deobfuscating.complete = \u53cd\u6df7\u6dc6\u5b8c\u6210 + +message.search.notfound = \u6ca1\u6709\u627e\u5230\u5b57\u7b26\u4e32 "%searchtext%" . +message.search.notfound.title = \u6ca1\u6709\u627e\u5230 + +message.rename.notfound.multiname = \u5728\u5149\u6807\u4e0b\u65b9\u6ca1\u6709\u627e\u5230multiname +message.rename.notfound.identifier = \u5728\u5149\u6807\u4e0b\u65b9\u6ca1\u6709\u627e\u5230\u6807\u8bc6\u7b26 +message.rename.notfound.title = \u6ca1\u6709\u627e\u5230 +message.rename.renamed = \u6807\u8bc6\u7b26\u91cd\u547d\u540d\u6570\uff1a %count% + +filter.images = \u56fe\u7247 (%extensions%) +filter.fla = %version% \u6587\u4ef6 (*.fla) +filter.xfl = %version% \u672a\u538b\u7f29\u6587\u4ef6 (*.xfl) +filter.swf = SWF \u6587\u4ef6 (*.swf) + +error = \u9519\u8bef +error.image.invalid = \u65e0\u6548\u56fe\u7247. + +error.text.invalid = \u65e0\u6548\u6587\u672c: %text% \u5728 %line% \u884c +error.file.save = \u65e0\u6cd5\u4fdd\u5b58\u6587\u4ef6 +error.file.write = \u65e0\u6cd5\u5199\u6587\u4ef6 +error.export = \u5bfc\u51fa\u65f6\u9519\u8bef + +export.select.directory = \u8bf7\u9009\u62e9\u5bfc\u51fa\u76ee\u5f55 +export.finishedin = \u5bfc\u51fa\u5b8c\u6210\uff0c\u8017\u8d39\u65f6\u95f4 %time% + +update.check.title = \u786e\u8ba4\u66f4\u65b0 +update.check.nonewversion = \u65e0\u53ef\u7528\u66f4\u65b0. + +message.helpus = \u8bf7\u8bbf\u95ee\r\n%url%\r\n\u83b7\u5f97\u76f8\u5173\u7ec6\u8282. +message.homepage = \u8bbf\u95ee\u4e3b\u9875\uff1a \r\n%url% + +proxy = \u4ee3\u7406 +proxy.start = \u5f00\u59cb\u4ee3\u7406 +proxy.stop = \u505c\u6b62\u4ee3\u7406 +proxy.show = \u663e\u793a\u4ee3\u7406 +exit = \u9000\u51fa + +panel.disassembled = P\u4ee3\u7801\u8d44\u6e90 +panel.decompiled = AS\u8d44\u6e90 + +search.info = \u641c\u7d22 "%text%" : +search.script = \u811a\u672c + +constants = \u5e38\u91cf +traits = Traits + +pleasewait = \u8bf7\u7a0d\u7b49 + +abc.detail.methodtrait = Method/Getter/Setter Trait +abc.detail.unsupported = - +abc.detail.slotconsttrait = Slot/Const Trait +abc.detail.traitname = \u540d\u79f0: + +abc.detail.body.params.maxstack = \u6700\u5927\u5806\u6808: +abc.detail.body.params.localregcount = \u672c\u5730\u5bc4\u5b58\u5668\u8ba1\u6570: +abc.detail.body.params.minscope = \u6700\u5c0f\u8303\u56f4\u6df1\u5ea6: +abc.detail.body.params.maxscope = \u6700\u5927\u8303\u56f4\u6df1\u5ea6: +abc.detail.body.params.autofill = \u4fdd\u5b58\u65f6\u4ee3\u7801\u81ea\u52a8\u586b\u5145 (\u5168\u5c40\u8bbe\u7f6e) +abc.detail.body.params.autofill.experimental = ...\u5b9e\u9a8c\u7684 + +abc.detail.methodinfo.methodindex = \u65b9\u6cd5\u7d22\u5f15: +abc.detail.methodinfo.parameters = \u53c2\u6570: +abc.detail.methodinfo.returnvalue = \u8fd4\u56de\u503c\u7c7b\u578b: + +error.methodinfo.params = \u65b9\u6cd5\u4fe1\u606f\u7684\u53c2\u6570\u9519\u8bef +error.methodinfo.returnvalue = \u65b9\u6cd5\u4fe1\u606f\u7684\u8fd4\u56de\u503c\u7c7b\u578b\u9519\u8bef + +abc.detail.methodinfo = \u65b9\u6cd5\u4fe1\u606f +abc.detail.body.code = \u65b9\u6cd5\u4e3b\u4f53\u4ee3\u7801 +abc.detail.body.params = \u65b9\u6cd5\u4e3b\u4f53\u53c2\u6570 + +abc.detail.slotconst.typevalue = \u7c7b\u578b\u548c\u503c: + +error.slotconst.typevalue = SlotConst\u7c7b\u578b\u503c\u9519\u8bef + +message.autofill.failed = \u65e0\u6cd5\u81ea\u52a8\u83b7\u5f97\u4e3b\u4f53\u53c2\u6570\u72b6\u6001\u4ee3\u7801\u3002\r\n\u8bf7\u5173\u95ed\u81ea\u52a8\u586b\u5145\u529f\u80fd\u540e\u518d\u8bd5\u4e00\u6b21. +info.selecttrait = \u8bf7\u9009\u62e9\u7c7b\uff0c\u7136\u540e\u70b9\u51fb\u8fdb\u884cActionScript\u6e90\u7684\u7f16\u8f91. + +button.viewgraph = \u6d4f\u89c8\u56fe\u5f62 +button.viewhex = \u6d4f\u89c8\u5341\u516d\u8fdb\u5236 + +action.edit.experimental = (\u5b9e\u9a8c\u7684) + +message.action.saved = \u4fdd\u5b58\u4ee3\u7801\u6210\u529f + +error.action.save = %error% \u5728 %line% \u884c + +message.confirm.remove = \u60a8\u786e\u5b9a\u8981\u5220\u9664 %item% \n \u4ee5\u53ca\u6240\u6709\u4f9d\u8d56\u5b83\u7684\u5bf9\u8c61\u5417\uff1f + +#after version 1.6.5u1: + +button.ok = \u786e\u5b9a +button.cancel = \u53d6\u6d88 + +font.name = \u5b57\u4f53\u540d\u79f0: +font.isbold = \u52a0\u7c97: +font.isitalic = \u659c\u4f53: +font.ascent = \u4e0a\u6807: +font.descent = \u4e0b\u6807: +font.leading = Leading: +font.characters = \u5b57\u7b26\u96c6: +font.characters.add = \u6dfb\u52a0\u5b57\u7b26\u96c6: +value.unknown = ? + +yes = \u662f +no = \u5426 + +errors.present = \u5728\u65e5\u5fd7\u4e2d\u8bb0\u5f55\u4e86\u9519\u8bef\uff0c\u70b9\u51fb\u67e5\u770b\u3002 +errors.none = \u5728\u65e5\u5fd7\u4e2d\u6ca1\u6709\u53d1\u73b0\u9519\u8bef\u3002 + +#after version 1.6.6: + +dialog.message.title = \u6d88\u606f +dialog.select.title = \u9009\u62e9\u4e00\u4e2a\u9009\u9879 + +button.yes = \u662f +button.no = \u5426 + +FileChooser.openButtonText = \u6253\u5f00 +FileChooser.openButtonToolTipText = \u6253\u5f00 +FileChooser.lookInLabelText = \u6d4f\u89c8: +FileChooser.acceptAllFileFilterText = \u6240\u6709\u6587\u4ef6 +FileChooser.filesOfTypeLabelText = \u6587\u4ef6\u7c7b\u578b: +FileChooser.fileNameLabelText = \u6587\u4ef6\u540d: +FileChooser.listViewButtonToolTipText = \u5217\u8868 +FileChooser.listViewButtonAccessibleName = \u5217\u8868 +FileChooser.detailsViewButtonToolTipText = \u8be6\u7ec6\u4fe1\u606f +FileChooser.detailsViewButtonAccessibleName = \u8be6\u7ec6\u4fe1\u606f +FileChooser.upFolderToolTipText = \u4e0a\u7ea7\u76ee\u5f55 +FileChooser.upFolderAccessibleName = \u4e0a\u7ea7\u76ee\u5f55 +FileChooser.homeFolderToolTipText = \u4e3b\u76ee\u5f55 +FileChooser.homeFolderAccessibleName = \u4e3b\u76ee\u5f55 +FileChooser.fileNameHeaderText = \u540d\u79f0 +FileChooser.fileSizeHeaderText = \u5927\u5c0f +FileChooser.fileTypeHeaderText = \u7c7b\u578b +FileChooser.fileDateHeaderText = \u65e5\u671f +FileChooser.fileAttrHeaderText = \u5c5e\u6027 +FileChooser.openDialogTitleText = \u6253\u5f00 +FileChooser.directoryDescriptionText = \u76ee\u5f55 +FileChooser.directoryOpenButtonText = \u6253\u5f00 +FileChooser.directoryOpenButtonToolTipText = \u6253\u5f00\u9009\u5b9a\u7684\u76ee\u5f55 +FileChooser.fileDescriptionText = \u901a\u7528\u6587\u4ef6 +FileChooser.helpButtonText = \u5e2e\u52a9 +FileChooser.helpButtonToolTipText = \u6587\u4ef6\u9009\u62e9\u5668\u5e2e\u52a9 +FileChooser.newFolderAccessibleName = \u65b0\u5efa\u6587\u4ef6\u5939 +FileChooser.newFolderErrorText = \u5efa\u7acb\u65b0\u6587\u4ef6\u5939\u65f6\u51fa\u9519 +FileChooser.newFolderToolTipText = \u65b0\u5efa\u6587\u4ef6\u5939 +FileChooser.other.newFolder = \u65b0\u6587\u4ef6\u5939 +FileChooser.other.newFolder.subsequent = \u65b0\u6587\u4ef6\u5939.{0} +FileChooser.win32.newFolder = \u65b0\u6587\u4ef6\u5939 +FileChooser.win32.newFolder.subsequent = \u65b0\u6587\u4ef6\u5939 ({0}) +FileChooser.saveButtonText = \u4fdd\u5b58 +FileChooser.saveButtonToolTipText = \u4fdd\u5b58\u9009\u5b9a\u6587\u4ef6 +FileChooser.saveDialogTitleText = \u4fdd\u5b58 +FileChooser.saveInLabelText = \u4fdd\u5b58\u5230: +FileChooser.updateButtonText = \u5237\u65b0 +FileChooser.updateButtonToolTipText = \u5237\u65b0\u76ee\u5f55\u5217\u8868 + +#after version 1.6.6u2: + +FileChooser.detailsViewActionLabel.textAndMnemonic = \u8be6\u7ec6\u4fe1\u606f +FileChooser.detailsViewButtonToolTip.textAndMnemonic = \u8be6\u7ec6\u4fe1\u606f +FileChooser.fileAttrHeader.textAndMnemonic = \u5c5e\u6027 +FileChooser.fileDateHeader.textAndMnemonic = Modified +FileChooser.fileNameHeader.textAndMnemonic = \u540d\u79f0 +FileChooser.fileNameLabel.textAndMnemonic = \u6587\u4ef6\u540d: +FileChooser.fileSizeHeader.textAndMnemonic = \u5927\u5c0f +FileChooser.fileTypeHeader.textAndMnemonic = \u7c7b\u578b +FileChooser.filesOfTypeLabel.textAndMnemonic = \u6587\u4ef6\u7c7b\u578b: +FileChooser.folderNameLabel.textAndMnemonic = \u76ee\u5f55\u540d: +FileChooser.homeFolderToolTip.textAndMnemonic = \u4e3b\u76ee\u5f55 +FileChooser.listViewActionLabel.textAndMnemonic = \u5217\u8868 +FileChooser.listViewButtonToolTip.textAndMnemonic = \u5217\u8868 +FileChooser.lookInLabel.textAndMnemonic = \u6d4f\u89c8: +FileChooser.newFolderActionLabel.textAndMnemonic = \u65b0\u6587\u4ef6\u5939 +FileChooser.newFolderToolTip.textAndMnemonic = \u65b0\u5efa\u6587\u4ef6\u5939 +FileChooser.refreshActionLabel.textAndMnemonic = \u5237\u65b0 +FileChooser.saveInLabel.textAndMnemonic = \u4fdd\u5b58\u5230: +FileChooser.upFolderToolTip.textAndMnemonic = \u4e0a\u7ea7\u76ee\u5f55 +FileChooser.viewMenuButtonAccessibleName = \u6d4f\u89c8\u83dc\u5355 +FileChooser.viewMenuButtonToolTipText = \u6d4f\u89c8\u83dc\u5355 +FileChooser.viewMenuLabel.textAndMnemonic = \u6d4f\u89c8 +FileChooser.newFolderActionLabelText = \u65b0\u6587\u4ef6\u5939 +FileChooser.listViewActionLabelText = \u5217\u8868 +FileChooser.detailsViewActionLabelText = \u8be6\u7ec6\u4fe1\u606f +FileChooser.refreshActionLabelText = \u5237\u65b0 +FileChooser.sortMenuLabelText = \u6392\u5217\u56fe\u6807 +FileChooser.viewMenuLabelText = \u6d4f\u89c8 +FileChooser.fileSizeKiloBytes = {0} KB +FileChooser.fileSizeMegaBytes = {0} MB +FileChooser.fileSizeGigaBytes = {0} GB +FileChooser.folderNameLabelText = \u76ee\u5f55\u540d: + +error.occured = \u53d1\u751f\u9519\u8bef : %error% +button.abort = \u7ec8\u6b62 +button.retry = \u91cd\u8bd5 +button.ignore = \u5ffd\u7565 + +font.source = \u6e90\u5b57\u4f53: + +#after version 1.6.7: + +menu.export = \u5bfc\u51fa +menu.general = \u901a\u7528 +menu.language = \u8bed\u8a00 + +startup.welcometo = \u6b22\u8fce\u4f7f\u7528 +startup.selectopen = \u4f7f\u7528\u4e0a\u65b9\u9762\u677f\u7684\u6253\u5f00\u56fe\u6807\u6216\u8005\u62d6\u52a8SWF\u6587\u4ef6\u5230\u5f53\u524d\u7a97\u53e3\u4ee5\u5f00\u59cb\u3002 + +error.font.nocharacter = \u9009\u62e9\u7684\u6e90\u5b57\u4f53\u4e0d\u5305\u542b\u5b57\u7b26 "%char%". + +warning.initializers = \u9759\u6001\u5b57\u6bb5\u548c\u5e38\u91cf\u901a\u5e38\u5728\u521d\u59cb\u5316\u65f6\u88ab\u521d\u59cb\u5316\uff0c\n\u5728\u6b64\u7f16\u8f91\u901a\u5e38\u662f\u4e0d\u591f\u7684\uff01 + +#after version 1.7.0u1: + +menu.tools.searchMemory = \u641c\u7d22\u5185\u5b58\u4e2d\u7684SWF +menu.file.reload = \u91cd\u8f7d +message.confirm.reload = \u8be5\u52a8\u4f5c\u5c06\u4f1a\u4e22\u5931\u6240\u6709\u672a\u4fdd\u5b58\u7684\u6539\u52a8\uff0c\u5e76\u91cd\u65b0\u52a0\u8f7d\u5f53\u524dSWF\u6587\u4ef6\u3002\n\u662f\u5426\u7ee7\u7eed\uff1f + +dialog.selectbkcolor.title = \u8bf7\u9009\u62e9SWF\u663e\u793a\u7684\u80cc\u666f\u8272 +button.selectbkcolor.hint = \u9009\u62e9\u80cc\u666f\u8272 + +ColorChooser.okText = \u786e\u5b9a +ColorChooser.cancelText = \u53d6\u6d88 +ColorChooser.resetText = \u91cd\u7f6e +ColorChooser.previewText = \u9884\u89c8 +ColorChooser.swatchesNameText = \u8c03\u8272\u677f +ColorChooser.swatchesRecentText = \u6700\u8fd1: +ColorChooser.sampleText = \u793a\u4f8b\u6587\u5b57 \u793a\u4f8b\u6587\u672c + +#after version 1.7.1: + +preview.play = \u64ad\u653e +preview.pause = \u6682\u505c +preview.stop = \u505c\u6b62 + +message.confirm.removemultiple = \u60a8\u786e\u5b9a\u8981\u79fb\u9664 %count% \u4e2a\u9879\u76ee\uff0c\n\u4ee5\u53ca\u5176\u6240\u6709\u7684\u4f9d\u8d56\u5bf9\u8c61\u5417\uff1f + +menu.tools.searchCache = \u641c\u7d22\u6d4f\u89c8\u5668\u7f13\u5b58 + +#after version 1.7.2u2 + +error.trait.exists = Trait \u6240\u7528\u7684\u540d\u79f0 \u201c%name%\u201d\u5df2\u5b58\u5728\u3002 +button.addtrait = \u6dfb\u52a0 Trait +button.font.embed = \u5d4c\u5165... +button.yes.all = \u5168\u662f +button.no.all = \u5168\u5426 +message.font.add.exists = \u5b57\u7b26 %char% \u5df2\u5b58\u5728\u3002\n\u60a8\u662f\u5426\u8981\u66ff\u6362\uff1f + +filter.gfx = ScaleForm GFx \u6587\u4ef6 (*.gfx) +filter.supported = \u6240\u6709\u652f\u6301\u6587\u4ef6\u7c7b\u578b +work.canceled = \u5df2\u53d6\u6d88 +work.restoringControlFlow = \u6062\u590d\u63a7\u5236\u5668\u6d41\u7a0b +menu.advancedsettings.advancedsettings = \u9ad8\u7ea7\u8bbe\u7f6e +menu.recentFiles = \u6700\u8fd1\u6587\u4ef6 + +#after version 1.7.4 +work.restoringControlFlow.complete = \u63a7\u5236\u5668\u6d41\u7a0b\u5df2\u6062\u590d +message.confirm.recentFileNotFound = \u627e\u4e0d\u5230\u6587\u4ef6\u3002\u662f\u5426\u4ece\u6700\u8fd1\u6587\u4ef6\u5217\u8868\u79fb\u9664\uff1f +contextmenu.closeSwf = \u5173\u95ed SWF +menu.settings.autoRenameIdentifiers = \u81ea\u52a8\u91cd\u547d\u540d\u6807\u8bc6 +menu.file.saveasexe = \u53e6\u5b58\u4e3aexe... +filter.exe = \u53ef\u6267\u884c\u6587\u4ef6(*.exe) + +#after version 1.8.0 +font.updateTexts = \u66f4\u65b0\u6587\u672c + +#after version 1.8.0u1 +menu.file.close = \u5173\u95ed +menu.file.closeAll = \u5168\u90e8\u5173\u95ed +menu.tools.otherTools = \u5176\u4ed6 +menu.tools.otherTools.clearRecentFiles = \u6e05\u9664\u6700\u8fd1\u6587\u4ef6 +fontName.name = \u5b57\u4f53\u663e\u793a\u540d\u79f0: +fontName.copyright = \u5b57\u4f53\u7248\u6743: +button.preview = \u9884\u89c8 +button.reset = \u91cd\u7f6e +errors.info = \u6709\u4fe1\u606f\u65e5\u5fd7\u3002\u70b9\u51fb\u67e5\u770b\u3002 +errors.warning = \u6709\u8b66\u544a\u65e5\u5fd7\u3002\u70b9\u51fb\u67e5\u770b\u3002 + +decompilationError = \u53cd\u7f16\u8bd1\u9519\u8bef + +disassemblingProgress.toString = \u5230\u5b57\u7b26\u4e32 +disassemblingProgress.reading = \u8bfb\u53d6\u4e2d +disassemblingProgress.deobfuscating = \u6df7\u6dc6 + +contextmenu.moveTag = \u79fb\u52a8\u6807\u7b7e\u5230 + +filter.swc = SWC\u7ec4\u4ef6\u6587\u4ef6 (*.swc) +filter.zip = ZIP\u538b\u7f29\u6587\u4ef6 (*.zip) +filter.binary = \u4e8c\u8fdb\u5236\u67e5\u627e - \u6240\u6709\u6587\u4ef6 (*.*) + +open.error = \u9519\u8bef +open.error.fileNotFound = \u672a\u627e\u5230\u6587\u4ef6 +open.error.cannotOpen = \u65e0\u6cd5\u6253\u5f00\u6587\u4ef6 + +node.others = \u5176\u4ed6 + +#after version 1.8.1 +menu.tools.search = \u6587\u672c\u67e5\u627e + +#after version 1.8.1u1 +menu.tools.timeline = \u65f6\u95f4\u8f74 + +dialog.selectcolor.title = \u9009\u62e9\u989c\u8272 +button.selectcolor.hint = \u70b9\u51fb\u9009\u62e9\u989c\u8272 + +#default item name, will be used in following sentences +generictag.array.item = \u9879\u76ee +generictag.array.insertbeginning = \u5728\u4e00\u5f00\u59cb\u63d2\u5165 %item% +generictag.array.insertbefore = \u63d2\u5165 %item% \u4e4b\u524d +generictag.array.remove = \u79fb\u9664 %item% +generictag.array.insertafter = \u63d2\u5165 %item% \u4e4b\u540e +generictag.array.insertend = \u5728\u7ed3\u675f\u63d2\u5165 %item% + +#after version 2.0.0 +contextmenu.expandAll = \u5168\u90e8\u5c55\u5f00 + +filter.sounds = \u652f\u6301\u7684\u58f0\u97f3\u683c\u5f0f (*.wav, *.mp3) +filter.sounds.wav = Wave\u6587\u4ef6\u683c\u5f0f (*.wav) +filter.sounds.mp3 = MP3\u538b\u7f29\u683c\u5f0f (*.mp3) + +error.sound.invalid = \u65e0\u6548\u6587\u4ef6\u3002 + +button.prev = \u4e0a\u4e00\u9875 +button.next = \u4e0b\u4e00\u9875 + +#after version 2.1.0 +message.action.playerglobal.title = \u9700\u8981PlayerGlobal\u652f\u6301\u5e93 +message.action.playerglobal.needed = \u82e5\u8981\u76f4\u63a5\u7f16\u8f91AS3\u811a\u672c, \u9700\u8981\u4eceAdobe\u4e3b\u9875\u4e0b\u8f7d\u4e00\u4e2a"PlayerGlobal.swc"\u7684\u652f\u6301\u5e93\u3002\r\n%adobehomepage%\r\n\u70b9\u51fb\u201c\u786e\u5b9a\u201d\u8f6c\u5230\u4e0b\u8f7d\u9875\u9762\u3002 +message.action.playerglobal.place = \u4e0b\u8f7d\u652f\u6301\u5e93PlayerGlobal(.swc),\u5e76\u653e\u5165\u8be5\u6587\u4ef6\u5939\u3002\r\n%libpath%\r\n \u70b9\u51fb\u201c\u786e\u5b9a\u201d\u7ee7\u7eed\u3002 + +message.confirm.experimental.function = \u6b64\u529f\u80fd\u4e3a\u5b9e\u9a8c\u6027\uff01\u8fd9\u610f\u5473\u7740\u7ed3\u679c\u5e76\u4e0d\u53ef\u9760\u5e76\u4e14\u4fdd\u5b58\u4e4b\u540e\u65e0\u6cd5\u6b63\u5e38\u8fd0\u884c\u3002 +message.confirm.donotshowagain = \u4e0d\u518d\u663e\u793a + +menu.import = \u5bfc\u5165 +menu.file.import.text = \u5bfc\u5165\u6587\u672c +import.select.directory = \u9009\u62e9\u5bfc\u5165\u76ee\u5f55 +error.text.import = \u5bfc\u5165\u6587\u672c\u9519\u8bef\u3002\u7ee7\u7eed\uff1f + +#after version 2.1.1 +contextmenu.removeWithDependencies = \u79fb\u9664\u4f9d\u8d56 + +abc.action.find-usages = \u67e5\u627e\u5f15\u7528 +abc.action.find-declaration = \u67e5\u627e\u58f0\u660e + +contextmenu.rawEdit = RAW\u7f16\u8f91 +contextmenu.jumpToCharacter = \u8f6c\u5230\u5b57\u7b26 + +menu.settings.dumpView = \u67e5\u770b\u8f6c\u50a8 + +menu.view = \u67e5\u770b +menu.file.view.resources = \u8d44\u6e90 +menu.file.view.hex = \u4e8c\u8fdb\u5236 + +node.header = \u6587\u4ef6\u5934 + +header.signature = \u6587\u4ef6\u6807\u8bc6: +header.compression = \u538b\u7f29\u6a21\u5f0f: +header.compression.lzma = LZMA +header.compression.zlib = ZLIB +header.compression.none = \u65e0\u538b\u7f29 +header.version = SWF\u7248\u672c: +header.gfx = GFX: +header.filesize = \u6587\u4ef6\u5927\u5c0f +header.framerate = \u5e27\u7387: +header.framecount = \u5e27\u6570: +header.displayrect = \u663e\u793a\u533a\u57df: +header.displayrect.value.twips = %xmin%,%ymin% => %xmax%,%ymax% twips +header.displayrect.value.pixels = %xmin%,%ymin% => %xmax%,%ymax% pixels + +#after version 2.1.2 +contextmenu.saveToFile = \u53e6\u5b58\u4e3a\u6587\u4ef6 +contextmenu.parseActions = \u89e3\u6790\u52a8\u4f5c +contextmenu.parseABC = \u89e3\u6790ABC +contextmenu.parseInstructions = \u89e3\u6790AVM2\u6307\u4ee4 + +#after version 2.1.3 +menu.deobfuscation = \u53cd\u6df7\u6dc6 +menu.file.deobfuscation.old = \u65e7\u6837\u5f0f +menu.file.deobfuscation.new = \u65b0\u6837\u5f0f + +#after version 2.1.4 +contextmenu.openswfinside = \u6253\u5f00 SWF \u5185\u90e8 +binarydata.swfInside = \u5b83\u770b\u8d77\u6765\u50cf\u6709\u8fd9\u4e2a\u4e8c\u8fdb\u5236\u6570\u636e\u6807\u7b7e\u5185\u7684 SWF\u3002\u70b9\u51fb\u6b64\u5904\u5c06\u5176\u52a0\u8f7d\u4e3a\u5b50\u6811\u3002 + +#after version 3.0.0 +button.zoomin.hint = \u653e\u5927 +button.zoomout.hint = \u7f29\u5c0f +button.zoomfit.hint = \u7f29\u653e\u5230\u9002\u5408 +button.zoomnone.hint = \u7f29\u653e\u5230 1:1 +button.snapshot.hint = \u6355\u83b7\u5feb\u7167\u5230\u526a\u8d34\u677f + +editorTruncateWarning = \u5728\u8c03\u8bd5\u6a21\u5f0f\u4e0b\u6587\u672c\u88ab\u622a\u65ad\u5728 %chars% \u4f4d\u7f6e\u3002 + +#Font name which is presented in the SWF Font tag +font.name.intag = \u5728\u6807\u7b7e\u5b57\u4f53\u540d\u79f0: + +menu.debugger = \u8c03\u8bd5\u5668 +menu.debugger.switch = \u8c03\u8bd5\u5668 +menu.debugger.replacetrace = \u66ff\u6362\u8ddf\u8e2a\u8c03\u7528 +menu.debugger.showlog = \u663e\u793a\u65e5\u5fd7 + +message.debugger = \u8be5 SWF \u8c03\u8bd5\u5668\u53ea\u80fd\u7528\u4e8e\u6253\u5370\u8bb0\u5f55\u6d88\u606f\u7684\u7a97\u53e3\uff0c\u6d4f\u89c8\u5668\u63a7\u5236\u53f0\u6216\u8b66\u62a5\u3002\r\n\u5b83\u4e0d\u662f\u8bbe\u8ba1\u7528\u4e8e\u529f\u80fd\uff0c\u5982\u6b65\u5165\u4ee3\u7801\uff0c\u65ad\u70b9\u7b49\u3002 + +contextmenu.addTag = \u6dfb\u52a0\u6807\u7b7e + +deobfuscation.comment.tryenable = \u63d0\u793a\uff1a\u5728\u8bbe\u7f6e\u60a8\u53ef\u4ee5\u5c1d\u8bd5\u542f\u7528\u201c\u81ea\u52a8\u53cd\u6df7\u6dc6\u201d +deobfuscation.comment.failed = \u53cd\u6df7\u6dc6\u88ab\u6fc0\u6d3b\uff0c\u4f46\u662f\u53cd\u7f16\u8bd1\u8fd8\u662f\u5931\u8d25\u4e86\u3002\u5982\u679c\u6587\u4ef6\u4e0d\u6df7\u4e71\uff0c\u7981\u7528\u201c\u81ea\u52a8\u53cd\u6df7\u6dc6\u201d\u6548\u679c\u4f1a\u66f4\u597d\u3002 + +#after version 4.0.2 +preview.nextframe = \u4e0b\u4e00\u5e27 +preview.prevframe = \u4e0a\u4e00\u5e27 +preview.gotoframe = \u8f6c\u5230\u5e27... + +preview.gotoframe.dialog.title = \u8f6c\u5230\u5e27 +preview.gotoframe.dialog.message = \u8f93\u5165\u5e27\u53f7 (%min% - %max%) +preview.gotoframe.dialog.frame.error = \u65e0\u6548\u7684\u5e27\u53f7\u3002\u5b83\u5fc5\u987b\u662f\u6570\u5b57 %min% \u548c %max%\u4e4b\u95f4\u3002 + +error.text.invalid.continue = \u65e0\u6548\u6587\u672c: %text% \u5728\u884c %line%\u3002\u4f60\u60f3\u7ee7\u7eed\u5417\uff1f + +#after version 4.0.5 +contextmenu.copyTag = \u590d\u5236\u6807\u7b7e\u5230 +fit = \u9002\u5408 +button.setAdvanceValues = \u8bbe\u7f6e advanc \u503c + +menu.tools.replace = \u6587\u672c\u66ff\u6362 + +message.confirm.close = \u6709\u672a\u4fdd\u5b58\u7684\u66f4\u6539\u3002\u4f60\u771f\u7684\u8981\u5173\u95ed{swfName}\u5417\uff1f +message.confirm.closeAll = \u6709\u672a\u4fdd\u5b58\u7684\u66f4\u6539\u3002\u4f60\u771f\u7684\u8981\u5173\u95ed\u6240\u6709\u7684SWF\u5417\uff1f + +contextmenu.exportJavaSource = \u5bfc\u51fa Java \u6e90\u4ee3\u7801 +contextmenu.exportSwfXml = \u5bfc\u51fa SWF \u4e3a XML +contextmenu.importSwfXml = \u5bfc\u5165 SWF XML + +filter.xml = XML + +#after version 4.1.0 +contextmenu.undo = \u64a4\u6d88 + +text.align.left = \u5de6\u5bf9\u9f50 +text.align.right = \u53f3\u5bf9\u9f50 +text.align.center = \u5c45\u4e2d\u5bf9\u9f50 +text.align.justify = \u4e24\u7aef\u5bf9\u9f50 + +text.undo = \u64a4\u6d88\u66f4\u6539 + +menu.file.import.xml = \u5bfc\u5165 SWF XML +menu.file.export.xml = \u5bfc\u51fa SWF XML + +#after version 4.1.1 +text.align.translatex.decrease = \u51cf\u5c11 TranslateX +text.align.translatex.increase = \u589e\u52a0 TranslateX +selectPreviousTag = \u9009\u62e9\u4e0a\u4e00\u4e2a\u6807\u7b7e +selectNextTag = \u9009\u62e9\u4e0b\u4e00\u4e2a\u6807\u7b7e +button.ignoreAll = \u5ffd\u7565\u5168\u90e8 +menu.file.import.symbolClass = \u5bfc\u5165\u7b26\u53f7-Class +text.toggleCase = \u5207\u6362\u5916\u58f3 + +#after version 5.0.2 +preview.loop = \u5faa\u73af +menu.file.import.script = \u5bfc\u5165\u811a\u672c +contextmenu.copyTagWithDependencies = \u4ee5\u4f9d\u8d56\u5173\u7cfb\u5230\u590d\u5236\u6807\u7b7e +button.replaceWithTag = \u4f7f\u7528\u5176\u5b83\u5b57\u7b26\u66ff\u6362\u6807\u7b7e +button.resolveConstants = \u89e3\u6790\u5e38\u6570 + +#after version 5.1.0 +button.viewConstants = \u67e5\u770b\u5e38\u91cf +work.exported = \u5bfc\u51fa +button.replaceAlphaChannel = \u66ff\u6362 alpha \u901a\u9053... + +tagInfo.header.name = \u540d\u79f0 +tagInfo.header.value = \u503c +tagInfo.tagType = \u6807\u7b7e\u7c7b\u578b +tagInfo.characterId = \u5b57\u7b26 ID +tagInfo.offset = \u504f\u79fb +tagInfo.length = \u957f\u5ea6 +tagInfo.bounds = \u8fb9\u754c +tagInfo.width = \u5bbd\u5ea6 +tagInfo.height = \u9ad8\u5ea6 +tagInfo.neededCharacters = \u9700\u8981\u7684\u5b57\u7b26 + +button.viewhexpcode = \u67e5\u770b\u5341\u516d\u8fdb\u5236\u5e76\u6307\u793a +taginfo.header = \u57fa\u672c\u6807\u7b7e\u4fe1\u606f + +tagInfo.dependentCharacters = \u76f8\u5173\u5b57\u7b26 + +#after version 5.3.0 +header.uncompressed = \u65e0\u538b\u7f29 +header.warning.unsupportedGfxCompression = GFX \u4ec5\u652f\u6301\u975e\u538b\u7f29\u6216\u538b\u7f29\u7684 Zlib \u5185\u5bb9\u3002 +header.warning.minimumZlibVersion = ZLIB \u538b\u7f29\u9700\u8981SWF\u7b2c6\u7248\u6216\u66f4\u9ad8\u7248\u672c\u3002 +header.warning.minimumLzmaVersion = LZMA \u538b\u7f29\u9700\u8981 SWF \u7248\u672c 13 \u6216\u66f4\u9ad8\u7248\u672c\u3002 + +tagInfo.codecName = \u7f16\u89e3\u7801\u5668\u540d\u79f0 +tagInfo.exportFormat = \u5bfc\u51fa\u683c\u5f0f +tagInfo.samplingRate = \u91c7\u6837\u7387 +tagInfo.stereo = \u7acb\u4f53\u58f0 +tagInfo.sampleCount = \u91c7\u6837\u6570\u91cf + +filter.dmg = Mac \u53ef\u6267\u884c\u6587\u4ef6 (*.dmg) +filter.linuxExe = Linux \u53ef\u6267\u884c\u6587\u4ef6 + +import.script.result = %count% \u811a\u672c\u5df2\u5bfc\u5165\u3002 +import.script.as12warning = \u4ec5 1/2 \u7684\u811a\u672c\u53ef\u4ee5\u5bfc\u5165\u3002 + +error.constantPoolTooBig = \u5e38\u91cf\u6c60\u592a\u5927\u3002 \u7d22\u5f15=%index%, \u5927\u5c0f=%size% +error.image.alpha.invalid = \u65e0\u6548\u7684 Alpha \u901a\u9053\u6570\u636e\u3002 + +#after version 6.0.2 +contextmenu.saveUncompressedToFile = \u4fdd\u5b58\u5230\u672a\u538b\u7f29\u6587\u4ef6 +menu.settings.autoOpenLoadedSWFs = \u6253\u5f00\u5df2\u8f7d\u5165 SWF \u6587\u4ef6\u65f6\u64ad\u653e + +#after version 6.1.1 +menu.file.start = \u5f00\u59cb +menu.file.start.run = \u8fd0\u884c +menu.file.start.stop = \u505c\u6b62 +menu.file.start.debug = \u8c03\u8bd5 +menu.debugging = \u8c03\u8bd5\u4e2d +menu.debugging.debug = \u8c03\u8bd5 +menu.debugging.debug.stop = \u505c\u6b62 +menu.debugging.debug.pause = \u6682\u505c +menu.debugging.debug.stepOver = \u5355\u6b65\u6267\u884c +menu.debugging.debug.stepInto = \u5355\u6b65\u6b65\u5165 +menu.debugging.debug.stepOut = \u5355\u6b65\u6b65\u51fa +menu.debugging.debug.continue = \u7ee7\u7eed +menu.debugging.debug.stack = \u5806\u6808... +menu.debugging.debug.watch = \u65b0\u5efa\u67e5\u770b... + +message.playerpath.notset = Flash Player \u653e\u6620\u673a\u6ca1\u6709\u627e\u5230\u3002\u8bf7\u5728\u9ad8\u7ea7\u8bbe\u7f6e/\u8def\u5f84\u914d\u7f6e\u5176\u8def\u5f84\u3002 +message.playerpath.debug.notset = Flash Player \u653e\u6620\u673a\u8c03\u8bd5\u7684\u5185\u5bb9\u6ca1\u6709\u627e\u5230\u3002\u8bf7\u5728\u9ad8\u7ea7\u8bbe\u7f6e/\u8def\u5f84\u914d\u7f6e\u5176\u8def\u5f84\u3002 +message.playerpath.lib.notset = PlayerGlobal (.SWC) \u672a\u627e\u5230\u3002\u8bf7\u5728\u5176\u8def\u5f84\u914d\u7f6e\u9ad8\u7ea7\u8bbe\u7f6e/\u8def\u5f84\u3002 + +debugpanel.header = \u8c03\u8bd5\u4e2d + +variables.header.registers = \u5bc4\u5b58\u5668 +variables.header.locals = \u672c\u673a +variables.header.arguments = \u53c2\u6570 +variables.header.scopeChain = \u4f5c\u7528\u57df\u94fe +variables.column.name = \u540d\u79f0 +variables.column.type = \u7c7b\u578b +variables.column.value = \u503c + +callStack.header = \u8c03\u7528\u5806\u6808 +callStack.header.file = \u6587\u4ef6 +callStack.header.line = \u884c + +stack.header = \u5806\u53e0 +stack.header.item = \u9879\u76ee + +constantpool.header = \u5e38\u91cf\u6c60 +constantpool.header.id = Id +constantpool.header.value = \u503c + +work.running = \u8fd0\u884c\u884c +work.debugging = \u8c03\u8bd5\u4e2d +work.debugging.instrumenting = SWF \u51c6\u5907\u8c03\u8bd5 +work.breakat = \u65ad\u70b9\u5728\u0020 +work.halted = \u8c03\u8bd5\u5f00\u59cb\uff0c\u6267\u884c\u505c\u6b62\u3002\u6dfb\u52a0\u65ad\u70b9\uff0c\u7136\u540e\u70b9\u51fb\u7ee7\u7eed\uff08F5\uff09\u6062\u590d\u8fd0\u884c\u3002 + +debuglog.header = \u65e5\u5fd7 +debuglog.button.clear = \u6e05\u9664 + +#after 7.0.1 +work.debugging.wait = \u7b49\u5f85 Flash \u8c03\u8bd5\u653e\u6620\u673a\u8fde\u63a5 + +error.debug.listen = \u65e0\u6cd5\u76d1\u542c\u7aef\u53e3 %port%\u3002\u6709\u53ef\u80fd\u662f\u53e6\u4e00\u4e2a Flash \u8c03\u8bd5\u5668\u8fd0\u884c\u3002 + +debug.break.reason.unknown = (\u672a\u77e5) +debug.break.reason.breakpoint = (\u65ad\u70b9) +debug.break.reason.watch = (\u89c2\u770b) +debug.break.reason.fault = (\u6545\u969c) +debug.break.reason.stopRequest = (\u505c\u6b62\u8bf7\u6c42) +debug.break.reason.step = (\u6b65\u9aa4) +debug.break.reason.halt = (\u505c\u6b62) +debug.break.reason.scriptLoaded = (\u52a0\u8f7d\u811a\u672c) + +menu.file.start.debugpcode = \u8c03\u8bd5 P-code + +#after 7.1.2 +button.replaceNoFill = \u66ff\u6362 - \u66f4\u65b0\u8303\u56f4... +message.warning.svgImportExperimental = \u5e76\u975e\u6240\u6709\u7684\u529f\u80fd\u652f\u6301 SVG\u3002\u8bf7\u5bfc\u5165\u540e\u68c0\u67e5\u65e5\u5fd7\u3002 + +message.imported.swf = \u8be5 SWF \u6587\u4ef6\u4f7f\u7528\u7684\u90d1\u6e90\u662f\u4ece\u5bfc\u5165 SWF \u6587\u4ef6:\n%url%\n\u4f60\u60f3\u4ece\u8be5URL\u52a0\u8f7d\u5417\uff1f +message.imported.swf.manually = \u65e0\u6cd5\u52a0\u8f7d\u5bfc\u5165\u7684 SWF\n%url%\n\u8be5\u6587\u4ef6\u6216 URL \u4e0d\u5b58\u5728\u3002\n\u4f60\u8981\u9009\u62e9\u672c\u5730\u6587\u4ef6\u5417\uff1f + +message.warning.hexViewNotUpToDate = \u5341\u516d\u8fdb\u5236\u67e5\u770b\u6ca1\u6709\u53ca\u65f6\u66f4\u65b0\u3002\u8bf7\u4fdd\u5b58\u5e76\u91cd\u65b0\u52a0\u8f7d\u66f4\u65b0\u5341\u516d\u8fdb\u5236\u67e5\u770b\u8be5\u6587\u4ef6\u3002 +message.font.replace.updateTexts = \u67d0\u4e9b\u5b57\u7b26\u88ab\u66ff\u6362\u3002\u662f\u5426\u8981\u66f4\u65b0\u73b0\u6709\u7684\u6587\u672c\uff1f + +menu.settings.simplifyExpressions = \u7b80\u5316\u8868\u8fbe\u5f0f + +#after 8.0.1 +menu.recentFiles.empty = \u6700\u8fd1\u7684\u6587\u4ef6\u5217\u8868\u4e3a\u7a7a +message.warning.outOfMemory32BitJre = \u53d1\u751f\u5185\u5b58\u9519\u8bef\u3002\u60a8\u5728 64 \u4f4d\u7cfb\u7edf\u4e0a\u8fd0\u884c 32 \u4f4d\u7684 Java\u3002\u8bf7\u4f7f\u7528 64 \u4f4d\u7684 Java\u3002 + +menu.file.reloadAll = \u91cd\u65b0\u52a0\u8f7d\u6240\u6709 +message.confirm.reloadAll = \u6b64\u64cd\u4f5c\u4f1a\u53d6\u6d88\u6240\u6709\u7684 SWF \u6587\u4ef6\u6240\u6709\u672a\u4fdd\u5b58\u7684\u66f4\u6539\uff0c\u5e76\u518d\u6b21\u91cd\u65b0\u52a0\u8f7d\u6574\u4e2a\u5e94\u7528\u7a0b\u5e8f\u3002\n\u4f60\u60f3\u7ee7\u7eed\u5417\uff1f +export.script.singleFilePallelModeWarning = \u5355\u4e2a\u6587\u4ef6\u7684\u811a\u672c\u8f93\u51fa\u6ca1\u6709\u4f7f\u7528\u542f\u7528\u5e76\u884c\u52a0\u901f\u652f\u6301 + +button.showOriginalBytesInPcodeHex = \u663e\u793a\u539f\u59cb\u5b57\u8282 +button.remove = \u6e05\u9664 +button.showFileOffsetInPcodeHex = \u663e\u793a\u6587\u4ef6\u504f\u79fb + +generic.editor.amf3.title = AMF3 \u7f16\u8f91\u5668 +generic.editor.amf3.help = AMF3 \u503c\u8bed\u6cd5:\n\ + ------------------\n\ + \u6807\u91cf\u7c7b\u578b:\n\ + %scalar_samples%\ + \u5176\u4ed6\u7c7b\u578b:\n\ + %nonscalar_samples%\ + \n\ + \u6ce8\u610f:\n\ + \ * Nonscalar datatypes can be referenced by previously declared "id" attributes with # syntax:\n\ + %reference_sample%\n\ + \ * Keys in Dictionary entries can be any type\n +contextmenu.showInResources = \u5728\u8d44\u6e90\u663e\u793a + diff --git a/src/com/jpexs/decompiler/flash/gui/player/FlashPlayerPanel.java b/src/com/jpexs/decompiler/flash/gui/player/FlashPlayerPanel.java index 1db811dfd..8de3c6ba2 100644 --- a/src/com/jpexs/decompiler/flash/gui/player/FlashPlayerPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/player/FlashPlayerPanel.java @@ -1,438 +1,438 @@ -/* - * Copyright (C) 2010-2016 JPEXS - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.jpexs.decompiler.flash.gui.player; - -import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.decompiler.flash.gui.FlashUnsupportedException; -import com.jpexs.decompiler.flash.gui.Main; -import com.jpexs.helpers.CancellableWorker; -import com.jpexs.javactivex.ActiveX; -import com.jpexs.javactivex.ActiveXEvent; -import com.jpexs.javactivex.ActiveXException; -import com.jpexs.javactivex.example.controls.flash.ShockwaveFlash; -import com.sun.jna.Platform; -import java.awt.AWTException; -import java.awt.Color; -import java.awt.Component; -import java.awt.Panel; -import java.awt.Point; -import java.awt.Rectangle; -import java.awt.Robot; -import java.awt.image.BufferedImage; -import java.io.Closeable; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Timer; -import java.util.TimerTask; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * - * @author JPEXS - */ -public final class FlashPlayerPanel extends Panel implements Closeable, MediaDisplay { - - private static final Logger logger = Logger.getLogger(FlashPlayerPanel.class.getName()); - - private final int setMovieDelay = Configuration.setMovieDelay.get(); - - private final List listeners = new ArrayList<>(); - - private final ShockwaveFlash flash; - - private final Timer timer; - - private boolean stopped = true; - - private boolean closed = false; - - private float frameRate; - - @Override - public boolean loopAvailable() { - return false; - } - - @Override - public boolean screenAvailable() { - return true; - } - - @Override - public boolean zoomAvailable() { - return true; - } - - @Override - public double getZoomToFit() { - //TODO - return 1; - } - - @Override - public Zoom getZoom() { - return null; - } - - private double zoom = 1.0; - - @Override - public synchronized void zoom(Zoom zoom) { - double zoomDouble = zoom.fit ? getZoomToFit() : zoom.value; - int zoomint = (int) Math.round(100 / (zoomDouble / this.zoom)); - if (zoomint == 0) { - zoomint = 1; - } - if (zoomint > 32767) { - zoomint = 32767; - } - if (zoomint == 100) { - zoomint = 0; - } - - flash.Zoom(0); // hack, but this call is needed otherwise unzoom will fail for larger zoom values - flash.Zoom(zoomint); - } - - public synchronized String getVariable(String name) throws IOException { - return flash.GetVariable(name); - } - - public synchronized void setVariable(String name, String value) throws IOException { - flash.SetVariable(name, value); - } - - public synchronized String call(String callString) throws IOException { - - return flash.CallFunction(callString); - } - - @Override - public synchronized int getCurrentFrame() { - if (flash == null) { - return 0; - } - try { - return flash.getFrameNum(); - } catch (ActiveXException | NullPointerException ex) { // Can be "Data not available yet exception" - } - return 0; - } - - @Override - public synchronized int getTotalFrames() { - if (flash == null) { - return 0; - } - try { - if (flash.getReadyState() == 4) { - return flash.getTotalFrames(); - } - } catch (ActiveXException | NullPointerException ex) { // Can be "Data not available yet exception" - } - return 0; - } - - @Override - public synchronized void setBackground(Color color) { - try { - flash.setBackgroundColor((color.getRed() << 16) + (color.getGreen() << 8) + color.getBlue()); - } catch (ActiveXException | NullPointerException ex) { // Can be "Data not available yet exception" - } - } - - public FlashPlayerPanel(Component frame) { - if (!Platform.isWindows()) { - throw new FlashUnsupportedException(); - } - - try { - Callable callable = new Callable() { - @Override - public ShockwaveFlash call() throws InterruptedException { - return ActiveX.createObject(ShockwaveFlash.class, FlashPlayerPanel.this); - } - }; - - // hack: Kernel32.INSTANCE.ConnectNamedPipe never completes in ActiveXControl static constructor - flash = CancellableWorker.call(callable, 5, TimeUnit.SECONDS); - } catch (ActiveXException | TimeoutException | InterruptedException | ExecutionException ex) { - logger.log(Level.WARNING, "Cannot initialize flash panel", ex); - throw new FlashUnsupportedException(); - } - - flash.setAllowScriptAccess("always"); - try { - flash.setAllowNetworking("all"); - } catch (ActiveXException ex) { - // ignore - } - - flash.addOnReadyStateChangeListener((ActiveXEvent axe) -> { - fireMediaDisplayStateChanged(); - }); - - flash.addFlashCallListener((ActiveXEvent axe) -> { - String req = (String) axe.args.get("request"); - Matcher m = Pattern.compile("(.*)").matcher(req); - if (m.matches()) { - String funname = m.group(1); - String msg = m.group(2); - if (funname.equals("alert") || funname.equals("console.log")) { - if (Main.debugDialog != null) { - Main.debugDialog.log(funname + ":" + msg); - } - } - } - }); - - timer = new Timer(); - timer.schedule(new TimerTask() { - private boolean isPlaying = false; - - private int currentFrame = 0; - - @Override - public void run() { - if (closed) { - return; - } - try { - ShockwaveFlash flash1 = flash; - - boolean changed = false; - - if (flash1.getReadyState() >= 3) { - boolean isPlaying = flash1.IsPlaying(); - if (this.isPlaying != isPlaying) { - this.isPlaying = isPlaying; - } - - int currentFrame = flash1.CurrentFrame(); - if (this.currentFrame != currentFrame) { - this.currentFrame = currentFrame; - changed = true; - } - } else { - this.isPlaying = false; - } - - if (changed) { - fireMediaDisplayStateChanged(); - } - } catch (Exception ex) { - // ignore - cancel(); - } - } - }, 100, 100); - } - - public synchronized void stopSWF() { - displaySWF("-", null, 1); - stopped = true; - fireMediaDisplayStateChanged(); - } - - public synchronized boolean isStopped() { - return stopped; - } - - @Override - public BufferedImage printScreen() { - Point screenloc = getLocationOnScreen(); - try { - return new Robot().createScreenCapture(new Rectangle(screenloc.x, screenloc.y, getWidth(), getHeight())); - } catch (AWTException ex) { - return null; - } - } - - private String movieToPlay = null; - - private Thread playQueue; - - private final Object queueLock = new Object(); - - public synchronized void displaySWF(final String flashName, final Color bgColor, final float frameRate) { - - // Minimum of 1000 ms (setMovieDelay) delay before calling flash.setMovie to avoid illegalAccess errors - if (playQueue == null) { - playQueue = new Thread() { - long lastTime; - - @Override - public void run() { - while (true) { - boolean empty; - synchronized (queueLock) { - empty = movieToPlay == null; - if (empty) { - try { - queueLock.wait(); - } catch (InterruptedException ex) { - break; - } - } - } - if (!empty) { - flash.setMovie(movieToPlay); - synchronized (queueLock) { - movieToPlay = null; - } - try { - Thread.sleep(setMovieDelay); - } catch (InterruptedException ex) { - break; - } - } - } - } - }; - playQueue.start(); - } - zoom = 1.0; - this.frameRate = frameRate; - if (bgColor != null) { - setBackground(bgColor); - } - synchronized (queueLock) { - movieToPlay = flashName; - queueLock.notify(); - } - - //play - stopped = false; - fireMediaDisplayStateChanged(); - } - - @Override - public synchronized void close() throws IOException { - timer.cancel(); - closed = true; - } - - @Override - public void pause() { - try { - if (flash.getReadyState() >= 3) { - flash.Stop(); - } - } catch (ActiveXException | NullPointerException ex) { // Can be "Data not available yet exception" - } - } - - @Override - public void stop() { - try { - if (flash.getReadyState() >= 3) { - flash.Stop(); - flash.Rewind(); - } - } catch (ActiveXException | NullPointerException ex) { // Can be "Data not available yet exception" - } - } - - @Override - public void rewind() { - try { - if (flash.getReadyState() >= 3) { - flash.Rewind(); - } - } catch (ActiveXException | NullPointerException ex) { // Can be "Data not available yet exception" - } - } - - @Override - public void play() { - try { - if (flash.getReadyState() >= 3) { - flash.Play(); - } - } catch (ActiveXException | NullPointerException ex) { // Can be "Data not available yet exception" - } - } - - @Override - public boolean isPlaying() { - try { - if (flash.getReadyState() >= 3) { - return flash.IsPlaying(); - } else { - return false; - } - } catch (ActiveXException | NullPointerException ex) { // Can be "Data not available yet exception" - return false; - } - } - - @Override - public void setLoop(boolean loop - ) { - } - - @Override - public void gotoFrame(int frame - ) { - if (frame < 0) { - return; - } - if (frame >= getTotalFrames()) { - return; - } - try { - if (flash.getReadyState() >= 3) { - flash.GotoFrame(frame); - } - } catch (ActiveXException | NullPointerException ex) { // Can be "Data not available yet exception" - } - } - - @Override - public float getFrameRate() { - return frameRate; - } - - @Override - public boolean isLoaded() { - return !isStopped(); - } - - public void fireMediaDisplayStateChanged() { - for (MediaDisplayListener l : listeners) { - l.mediaDisplayStateChanged(this); - } - } - - @Override - public void addEventListener(MediaDisplayListener listener) { - listeners.add(listener); - } - - @Override - public void removeEventListener(MediaDisplayListener listener) { - listeners.remove(listener); - } -} +/* + * Copyright (C) 2010-2016 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.jpexs.decompiler.flash.gui.player; + +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.gui.FlashUnsupportedException; +import com.jpexs.decompiler.flash.gui.Main; +import com.jpexs.helpers.CancellableWorker; +import com.jpexs.javactivex.ActiveX; +import com.jpexs.javactivex.ActiveXEvent; +import com.jpexs.javactivex.ActiveXException; +import com.jpexs.javactivex.example.controls.flash.ShockwaveFlash; +import com.sun.jna.Platform; +import java.awt.AWTException; +import java.awt.Color; +import java.awt.Component; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.image.BufferedImage; +import java.io.Closeable; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * + * @author JPEXS + */ +public final class FlashPlayerPanel extends Panel implements Closeable, MediaDisplay { + + private static final Logger logger = Logger.getLogger(FlashPlayerPanel.class.getName()); + + private final int setMovieDelay = Configuration.setMovieDelay.get(); + + private final List listeners = new ArrayList<>(); + + private final ShockwaveFlash flash; + + private final Timer timer; + + private boolean stopped = true; + + private boolean closed = false; + + private float frameRate; + + @Override + public boolean loopAvailable() { + return false; + } + + @Override + public boolean screenAvailable() { + return true; + } + + @Override + public boolean zoomAvailable() { + return true; + } + + @Override + public double getZoomToFit() { + //TODO + return 1; + } + + @Override + public Zoom getZoom() { + return null; + } + + private double zoom = 1.0; + + @Override + public synchronized void zoom(Zoom zoom) { + double zoomDouble = zoom.fit ? getZoomToFit() : zoom.value; + int zoomint = (int) Math.round(100 / (zoomDouble / this.zoom)); + if (zoomint == 0) { + zoomint = 1; + } + if (zoomint > 32767) { + zoomint = 32767; + } + if (zoomint == 100) { + zoomint = 0; + } + + flash.Zoom(0); // hack, but this call is needed otherwise unzoom will fail for larger zoom values + flash.Zoom(zoomint); + } + + public synchronized String getVariable(String name) throws IOException { + return flash.GetVariable(name); + } + + public synchronized void setVariable(String name, String value) throws IOException { + flash.SetVariable(name, value); + } + + public synchronized String call(String callString) throws IOException { + + return flash.CallFunction(callString); + } + + @Override + public synchronized int getCurrentFrame() { + if (flash == null) { + return 0; + } + try { + return flash.getFrameNum(); + } catch (ActiveXException | NullPointerException ex) { // Can be "Data not available yet exception" + } + return 0; + } + + @Override + public synchronized int getTotalFrames() { + if (flash == null) { + return 0; + } + try { + if (flash.getReadyState() == 4) { + return flash.getTotalFrames(); + } + } catch (ActiveXException | NullPointerException ex) { // Can be "Data not available yet exception" + } + return 0; + } + + @Override + public synchronized void setBackground(Color color) { + try { + flash.setBackgroundColor((color.getRed() << 16) + (color.getGreen() << 8) + color.getBlue()); + } catch (ActiveXException | NullPointerException ex) { // Can be "Data not available yet exception" + } + } + + public FlashPlayerPanel(Component frame) { + if (!Platform.isWindows()) { + throw new FlashUnsupportedException(); + } + + try { + Callable callable = new Callable() { + @Override + public ShockwaveFlash call() throws InterruptedException { + return ActiveX.createObject(ShockwaveFlash.class, FlashPlayerPanel.this); + } + }; + + // hack: Kernel32.INSTANCE.ConnectNamedPipe never completes in ActiveXControl static constructor + flash = CancellableWorker.call(callable, 5, TimeUnit.SECONDS); + } catch (ActiveXException | TimeoutException | InterruptedException | ExecutionException ex) { + logger.log(Level.WARNING, "Cannot initialize flash panel", ex); + throw new FlashUnsupportedException(); + } + + flash.setAllowScriptAccess("always"); + try { + flash.setAllowNetworking("all"); + } catch (ActiveXException ex) { + // ignore + } + + flash.addOnReadyStateChangeListener((ActiveXEvent axe) -> { + fireMediaDisplayStateChanged(); + }); + + flash.addFlashCallListener((ActiveXEvent axe) -> { + String req = (String) axe.args.get("request"); + Matcher m = Pattern.compile("(.*)").matcher(req); + if (m.matches()) { + String funname = m.group(1); + String msg = m.group(2); + if (funname.equals("alert") || funname.equals("console.log")) { + if (Main.debugDialog != null) { + Main.debugDialog.log(funname + ":" + msg); + } + } + } + }); + + timer = new Timer(); + timer.schedule(new TimerTask() { + private boolean isPlaying = false; + + private int currentFrame = 0; + + @Override + public void run() { + if (closed) { + return; + } + try { + ShockwaveFlash flash1 = flash; + + boolean changed = false; + + if (flash1.getReadyState() >= 3) { + boolean isPlaying = flash1.IsPlaying(); + if (this.isPlaying != isPlaying) { + this.isPlaying = isPlaying; + } + + int currentFrame = flash1.CurrentFrame(); + if (this.currentFrame != currentFrame) { + this.currentFrame = currentFrame; + changed = true; + } + } else { + this.isPlaying = false; + } + + if (changed) { + fireMediaDisplayStateChanged(); + } + } catch (Exception ex) { + // ignore + cancel(); + } + } + }, 100, 100); + } + + public synchronized void stopSWF() { + displaySWF("-", null, 1); + stopped = true; + fireMediaDisplayStateChanged(); + } + + public synchronized boolean isStopped() { + return stopped; + } + + @Override + public BufferedImage printScreen() { + Point screenloc = getLocationOnScreen(); + try { + return new Robot().createScreenCapture(new Rectangle(screenloc.x, screenloc.y, getWidth(), getHeight())); + } catch (AWTException ex) { + return null; + } + } + + private String movieToPlay = null; + + private Thread playQueue; + + private final Object queueLock = new Object(); + + public synchronized void displaySWF(final String flashName, final Color bgColor, final float frameRate) { + + // Minimum of 1000 ms (setMovieDelay) delay before calling flash.setMovie to avoid illegalAccess errors + if (playQueue == null) { + playQueue = new Thread() { + long lastTime; + + @Override + public void run() { + while (true) { + boolean empty; + synchronized (queueLock) { + empty = movieToPlay == null; + if (empty) { + try { + queueLock.wait(); + } catch (InterruptedException ex) { + break; + } + } + } + if (!empty) { + flash.setMovie(movieToPlay); + synchronized (queueLock) { + movieToPlay = null; + } + try { + Thread.sleep(setMovieDelay); + } catch (InterruptedException ex) { + break; + } + } + } + } + }; + playQueue.start(); + } + zoom = 1.0; + this.frameRate = frameRate; + if (bgColor != null) { + setBackground(bgColor); + } + synchronized (queueLock) { + movieToPlay = flashName; + queueLock.notify(); + } + + //play + stopped = false; + fireMediaDisplayStateChanged(); + } + + @Override + public synchronized void close() throws IOException { + timer.cancel(); + closed = true; + } + + @Override + public void pause() { + try { + if (flash.getReadyState() >= 3) { + flash.Stop(); + } + } catch (ActiveXException | NullPointerException ex) { // Can be "Data not available yet exception" + } + } + + @Override + public void stop() { + try { + if (flash.getReadyState() >= 3) { + flash.Stop(); + flash.Rewind(); + } + } catch (ActiveXException | NullPointerException ex) { // Can be "Data not available yet exception" + } + } + + @Override + public void rewind() { + try { + if (flash.getReadyState() >= 3) { + flash.Rewind(); + } + } catch (ActiveXException | NullPointerException ex) { // Can be "Data not available yet exception" + } + } + + @Override + public void play() { + try { + if (flash.getReadyState() >= 3) { + flash.Play(); + } + } catch (ActiveXException | NullPointerException ex) { // Can be "Data not available yet exception" + } + } + + @Override + public boolean isPlaying() { + try { + if (flash.getReadyState() >= 3) { + return flash.IsPlaying(); + } else { + return false; + } + } catch (ActiveXException | NullPointerException ex) { // Can be "Data not available yet exception" + return false; + } + } + + @Override + public void setLoop(boolean loop + ) { + } + + @Override + public void gotoFrame(int frame + ) { + if (frame < 0) { + return; + } + if (frame >= getTotalFrames()) { + return; + } + try { + if (flash.getReadyState() >= 3) { + flash.GotoFrame(frame); + } + } catch (ActiveXException | NullPointerException ex) { // Can be "Data not available yet exception" + } + } + + @Override + public float getFrameRate() { + return frameRate; + } + + @Override + public boolean isLoaded() { + return !isStopped(); + } + + public void fireMediaDisplayStateChanged() { + for (MediaDisplayListener l : listeners) { + l.mediaDisplayStateChanged(this); + } + } + + @Override + public void addEventListener(MediaDisplayListener listener) { + listeners.add(listener); + } + + @Override + public void removeEventListener(MediaDisplayListener listener) { + listeners.remove(listener); + } +}