From dc79350a9764e6d06de8faebbe075ba525b46aff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Tue, 22 Nov 2016 13:38:45 +0100 Subject: [PATCH] Saving files before refreshing line endings --- CHANGELOG.md | 4528 +++++----- .../flash/locales/docs/pcode/AS3.properties | 2922 +++---- .../decompiler/flash/gui/ImagePanel.java | 2874 +++---- src/com/jpexs/decompiler/flash/gui/Main.java | 4754 +++++------ .../jpexs/decompiler/flash/gui/MainPanel.java | 7362 ++++++++--------- 5 files changed, 11220 insertions(+), 11220 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c0d672ea0..6df593067 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,2265 +1,2265 @@ -# Change Log -All notable changes to this project will be documented in this file. - -## [Unreleased] -### Added -- 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. -- Display warning when library version and GUI version mismatch -- Changelog file - -### 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 - -## [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 update 1] - 2013-01-19 -## [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.0u1...version1.3.0 -[1.2.0 update 1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.2.0...version1.2.0u1 -[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 -[#1162]: https://www.free-decompiler.com/flash/issues/1162 -[#1156]: https://www.free-decompiler.com/flash/issues/1156 -[#1171]: https://www.free-decompiler.com/flash/issues/1171 -[#1199]: https://www.free-decompiler.com/flash/issues/1199 -[#1170]: https://www.free-decompiler.com/flash/issues/1170 -[#1241]: https://www.free-decompiler.com/flash/issues/1241 -[#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 -[#1145]: https://www.free-decompiler.com/flash/issues/1145 -[#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 -[#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 -[#418]: https://www.free-decompiler.com/flash/issues/418 -[#1062]: https://www.free-decompiler.com/flash/issues/1062 -[#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 -[#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 -[#949]: https://www.free-decompiler.com/flash/issues/949 -[#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 -[#772]: https://www.free-decompiler.com/flash/issues/772 -[#762]: https://www.free-decompiler.com/flash/issues/762 -[#841]: https://www.free-decompiler.com/flash/issues/841 -[#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 -[#350]: https://www.free-decompiler.com/flash/issues/350 -[#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 -[#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 -[#720]: https://www.free-decompiler.com/flash/issues/720 -[#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 -[#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 -[#337]: https://www.free-decompiler.com/flash/issues/337 -[#584]: https://www.free-decompiler.com/flash/issues/584 -[#428]: https://www.free-decompiler.com/flash/issues/428 -[#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 -[#369]: https://www.free-decompiler.com/flash/issues/369 -[#371]: https://www.free-decompiler.com/flash/issues/371 -[#390]: https://www.free-decompiler.com/flash/issues/390 -[#426]: https://www.free-decompiler.com/flash/issues/426 -[#453]: https://www.free-decompiler.com/flash/issues/453 -[#457]: https://www.free-decompiler.com/flash/issues/457 -[#458]: https://www.free-decompiler.com/flash/issues/458 -[#459]: https://www.free-decompiler.com/flash/issues/459 -[#460]: https://www.free-decompiler.com/flash/issues/460 -[#461]: https://www.free-decompiler.com/flash/issues/461 -[#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 -[#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 -[#301]: https://www.free-decompiler.com/flash/issues/301 -[#334]: https://www.free-decompiler.com/flash/issues/334 -[#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 -[#258]: https://www.free-decompiler.com/flash/issues/258 -[#261]: https://www.free-decompiler.com/flash/issues/261 -[#267]: https://www.free-decompiler.com/flash/issues/267 -[#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 -[#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 -[#207]: https://www.free-decompiler.com/flash/issues/207 -[#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 -[#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 -[#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 -[#176]: https://www.free-decompiler.com/flash/issues/176 -[#177]: https://www.free-decompiler.com/flash/issues/177 -[#180]: https://www.free-decompiler.com/flash/issues/180 -[#202]: https://www.free-decompiler.com/flash/issues/202 -[#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 -[#142]: https://www.free-decompiler.com/flash/issues/142 -[#146]: https://www.free-decompiler.com/flash/issues/146 -[#155]: https://www.free-decompiler.com/flash/issues/155 -[#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 +- 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. +- Display warning when library version and GUI version mismatch +- Changelog file + +### 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 + +## [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 update 1] - 2013-01-19 +## [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.0u1...version1.3.0 +[1.2.0 update 1]: https://github.com/jindrapetrik/jpexs-decompiler/compare/version1.2.0...version1.2.0u1 +[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 +[#1162]: https://www.free-decompiler.com/flash/issues/1162 +[#1156]: https://www.free-decompiler.com/flash/issues/1156 +[#1171]: https://www.free-decompiler.com/flash/issues/1171 +[#1199]: https://www.free-decompiler.com/flash/issues/1199 +[#1170]: https://www.free-decompiler.com/flash/issues/1170 +[#1241]: https://www.free-decompiler.com/flash/issues/1241 +[#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 +[#1145]: https://www.free-decompiler.com/flash/issues/1145 +[#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 +[#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 +[#418]: https://www.free-decompiler.com/flash/issues/418 +[#1062]: https://www.free-decompiler.com/flash/issues/1062 +[#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 +[#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 +[#949]: https://www.free-decompiler.com/flash/issues/949 +[#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 +[#772]: https://www.free-decompiler.com/flash/issues/772 +[#762]: https://www.free-decompiler.com/flash/issues/762 +[#841]: https://www.free-decompiler.com/flash/issues/841 +[#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 +[#350]: https://www.free-decompiler.com/flash/issues/350 +[#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 +[#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 +[#720]: https://www.free-decompiler.com/flash/issues/720 +[#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 +[#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 +[#337]: https://www.free-decompiler.com/flash/issues/337 +[#584]: https://www.free-decompiler.com/flash/issues/584 +[#428]: https://www.free-decompiler.com/flash/issues/428 +[#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 +[#369]: https://www.free-decompiler.com/flash/issues/369 +[#371]: https://www.free-decompiler.com/flash/issues/371 +[#390]: https://www.free-decompiler.com/flash/issues/390 +[#426]: https://www.free-decompiler.com/flash/issues/426 +[#453]: https://www.free-decompiler.com/flash/issues/453 +[#457]: https://www.free-decompiler.com/flash/issues/457 +[#458]: https://www.free-decompiler.com/flash/issues/458 +[#459]: https://www.free-decompiler.com/flash/issues/459 +[#460]: https://www.free-decompiler.com/flash/issues/460 +[#461]: https://www.free-decompiler.com/flash/issues/461 +[#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 +[#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 +[#301]: https://www.free-decompiler.com/flash/issues/301 +[#334]: https://www.free-decompiler.com/flash/issues/334 +[#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 +[#258]: https://www.free-decompiler.com/flash/issues/258 +[#261]: https://www.free-decompiler.com/flash/issues/261 +[#267]: https://www.free-decompiler.com/flash/issues/267 +[#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 +[#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 +[#207]: https://www.free-decompiler.com/flash/issues/207 +[#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 +[#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 +[#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 +[#176]: https://www.free-decompiler.com/flash/issues/176 +[#177]: https://www.free-decompiler.com/flash/issues/177 +[#180]: https://www.free-decompiler.com/flash/issues/180 +[#202]: https://www.free-decompiler.com/flash/issues/202 +[#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 +[#142]: https://www.free-decompiler.com/flash/issues/142 +[#146]: https://www.free-decompiler.com/flash/issues/146 +[#155]: https://www.free-decompiler.com/flash/issues/155 +[#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/locales/docs/pcode/AS3.properties b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/locales/docs/pcode/AS3.properties index 353ed284a..8ff27e646 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/locales/docs/pcode/AS3.properties +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/locales/docs/pcode/AS3.properties @@ -1,1462 +1,1462 @@ -# 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. - -#String for whole list generation -ui.list.heading = AVM2 Instruction list -ui.list.pageTitle = AVM2 Instruction list -ui.list.documentTitle = AVM2 Instruction list -ui.list.pageDescription = List of all known ActionScript 3 - AVM2 instructions with their operands and stack values - -#various strings in UI: -ui.unknown = ??? -ui.stack = Stack:\u0020 -ui.stack.before = ...,\u0020 -ui.stack.before.empty = ... -ui.stack.to = \u0020\u279e\u0020 -ui.flags = Flags:\u0020 -ui.description = Description:\u0020 -ui.filter.hide = Hide:\u0020 -ui.filter.byname = Find by name:\u0020 -ui.filter.order = Order by:\u0020 -ui.filter.order.code = code -ui.filter.order.name = name - - -#----------------------- Flags of the instructions -instructionFlag.undocumented = Undocumented -instructionFlag.unknownStack = Unknown stack -instructionFlag.es4NumericsMinor = ES4 numerics (ABC minor 17) -instructionFlag.floatMajor = Float values (ABC major 47) -instructionFlag.unknownOperands = Unknown operands -instructionFlag.noFlashPlayer = Not in standard Flash Player -instructionFlag.deprecated = Deprecated -instructionFlag.domainMemory = Domain memory operation - -#----------------------- Operand types -operandType.multinameIndex = Multiname index -operandType.multinameIndex.description = Index into multiname constant pool -operandType.multinameIndex.name = multinameIndex -operandType.multinameIndex.uiName = multiname - -operandType.argCount = Number of arguments -operandType.argCount.description = Number of following arguments -operandType.argCount.name = argCount -operandType.argCount.uiName = uint - - -operandType.methodIndex = Method index -operandType.methodIndex.description = Index of method in the ABC -operandType.methodIndex.name = methodIndex -operandType.methodIndex.uiName = methodIndex - -operandType.stringIndex = String index -operandType.stringIndex.description = Index into string values constant pool -operandType.stringIndex.name = stringIndex -operandType.stringIndex.uiName = string - - -operandType.debugType = Debug type -operandType.debugType.description = Type of debug information. Currently only value of 1 is used. -operandType.debugType.name = debugType -operandType.debugType.uiName = debugType - - -operandType.registerIndex = Register index -operandType.registerIndex.description = Index of a local register (0-255) -operandType.registerIndex.name = registerIndex -operandType.registerIndex.uiName = uint - -operandType.linenum = Line number -operandType.linenum.description = Line number of file -operandType.linenum.name = linenum -operandType.linenum.uiName = linenum - - -#similar as registerIndex, but U30 instead of U8 -operandType.localRegIndex = Register index -operandType.localRegIndex.description = Index of a local register -operandType.localRegIndex.name = localRegIndex -operandType.localRegIndex.uiName = uint - - -operandType.slotIndex = Slot index -operandType.slotIndex.description = Index of the slot on an object -operandType.slotIndex.name = slotIndex -operandType.slotIndex.uiName = slotIndex - -operandType.scopeIndex = Scope stack index -operandType.scopeIndex.description = Index in the scope stack -operandType.scopeIndex.name = scopeIndex -operandType.scopeIndex.uiName = scopeIndex - -operandType.offset = Offset -operandType.offset.description = Offset to other location -operandType.offset.name = offset -operandType.offset.uiName = labelName - -operandType.exceptionIndex = Exception index -operandType.exceptionIndex.description = Index of exception in current method info -operandType.exceptionIndex.name = exceptionIndex -operandType.exceptionIndex.uiName = exceptionIndex - - -operandType.classIndex = Class index -operandType.classIndex.description = Index of class in ABC -operandType.classIndex.name = classIndex -operandType.classIndex.uiName = classIndex - -operandType.intIndex = Int index -operandType.intIndex.description = Index into integer values constant pool -operandType.intIndex.name = intIndex -operandType.intIndex.uiName = int - -operandType.uintIndex = UInt index -operandType.uintIndex.description = Index into unsigned integer values constant pool -operandType.uintIndex.name = uintIndex -operandType.uintIndex.uiName = uint - - -operandType.doubleIndex = Double index -operandType.doubleIndex.description = Index into double precision floating point values constant pool -operandType.doubleIndex.name = doubleIndex -operandType.doubleIndex.uiName = double - -operandType.decimalIndex = Decimal index -operandType.decimalIndex.description = Index into decimal values (128bit floating point) constant pool -operandType.decimalIndex.name = decimalIndex -operandType.decimalIndex.uiName = decimal - -operandType.caseBaseoffset = Base offset -operandType.caseBaseoffset.description = Base offset of lookupswitch triggered when no value matches -operandType.caseBaseoffset.name = offset -operandType.caseBaseoffset.uiName = labelName - -operandType.numberContext = Number context (ES4) -operandType.numberContext.description = Context of calculations when using EcmaScript 4 numerics (ABC minorVersion 17).\nBits 0-2 type,3-5 rounding type, 6-12 precision.\nType: 0=number,1=decimal,2=double,3=int,4=uint\nRounding: 0=ceiling,1=up,2=half_up,3=half_even,4=half_down,5=down,6=floor\nPrecision:0-34 -operandType.numberContext.name = numberContext -operandType.numberContext.uiName = uint - -operandType.dispatchId = Dispatch id -operandType.dispatchId.description = Id of the method dispatch -operandType.dispatchId.name = dispatchId -operandType.dispatchId.uiName = uint - -operandType.floatIndex = Float index -operandType.floatIndex.description = Index into float values constant pool -operandType.floatIndex.name = floatIndex -operandType.floatIndex.uiName = float - -operandType.float4Index = Float4 index -operandType.float4Index.description = Index into float4 values constant pool -operandType.float4Index.name = float4Index -operandType.float4Index.uiName = float4 - -operandType.namespaceIndex = Namespace index -operandType.namespaceIndex = Index into namespace constant pool -operandType.namespaceIndex.name = namespaceIndex -operandType.namespaceIndex.uiName = namespace - - -#----------------------- Instructions - -instruction.bkpt.shortDescription = Breakpoint -instruction.bkpt.description = Breakpoint when debugging -instruction.bkpt.stackBefore = -instruction.bkpt.stackAfter = -instruction.bkpt.operands = - -instruction.nop.shortDescription = No operation -instruction.nop.description = Does nothing -instruction.nop.stackBefore = -instruction.nop.stackAfter = -instruction.nop.operands = - -instruction.throw.shortDescription = Throw exception -instruction.throw.description = Pops value off the stack and throws it -instruction.throw.stackBefore = value -instruction.throw.stackAfter = -instruction.throw.operands = - -instruction.getsuper.shortDescription = Get parent class property -instruction.getsuper.description = -instruction.getsuper.stackBefore = obj, [ns], [name] -instruction.getsuper.stackAfter = value -instruction.getsuper.operands = parentClassMultiname - -instruction.setsuper.shortDescription = Set parent class property -instruction.setsuper.description = -instruction.setsuper.stackBefore = obj, [ns], [name], value -instruction.setsuper.stackAfter = -instruction.setsuper.operands = parentClassMultiname - -instruction.dxns.shortDescription = Set default XML namespace -instruction.dxns.description = -instruction.dxns.stackBefore = -instruction.dxns.stackAfter = -instruction.dxns.operands = uriString - -instruction.dxnslate.shortDescription = Set default XML namespace at runtime -instruction.dxnslate.description = -instruction.dxnslate.stackBefore = uriValue -instruction.dxnslate.stackAfter = -instruction.dxnslate.operands = - -instruction.kill.shortDescription = Kill local register -instruction.kill.description = -instruction.kill.stackBefore = -instruction.kill.stackAfter = -instruction.kill.operands = killedRegister - -instruction.label.shortDescription = Target of a branch -instruction.label.description = Just a mark that this is target of following branch -instruction.label.stackBefore = -instruction.label.stackAfter = -instruction.label.operands = - -instruction.lf32x4.shortDescription = Load 32bit float4 -instruction.lf32x4.description = -instruction.lf32x4.stackBefore = address -instruction.lf32x4.stackAfter = float4Value -instruction.lf32x4.operands = - -instruction.sf32x4.shortDescription = Store 32bit float4 -instruction.sf32x4.description = -instruction.sf32x4.stackBefore = float4Value, address -instruction.sf32x4.stackAfter = -instruction.sf32x4.operands = - -instruction.ifnlt.shortDescription = Branch if not lower than -instruction.ifnlt.description = -instruction.ifnlt.stackBefore = value1, value2 -instruction.ifnlt.stackAfter = -instruction.ifnlt.operands = branchTarget - -instruction.ifnle.shortDescription = Branch if not lower or equal -instruction.ifnle.description = -instruction.ifnle.stackBefore = value1, value2 -instruction.ifnle.stackAfter = -instruction.ifnle.operands = branchTarget - -instruction.ifngt.shortDescription = Branch if not greater than -instruction.ifngt.description = -instruction.ifngt.stackBefore = value1, value2 -instruction.ifngt.stackAfter = -instruction.ifngt.operands = branchTarget - -instruction.ifnge.shortDescription = Branch if not greater ot equal -instruction.ifnge.description = -instruction.ifnge.stackBefore = value1, value2 -instruction.ifnge.stackAfter = -instruction.ifnge.operands = branchTarget - -instruction.jump.shortDescription = Jump to location -instruction.jump.description = -instruction.jump.stackBefore = -instruction.jump.stackAfter = -instruction.jump.operands = location - -instruction.iftrue.shortDescription = Branch if true -instruction.iftrue.description = -instruction.iftrue.stackBefore = value -instruction.iftrue.stackAfter = -instruction.iftrue.operands = branchTarget - -instruction.iffalse.shortDescription = Branch if false -instruction.iffalse.description = -instruction.iffalse.stackBefore = value -instruction.iffalse.stackAfter = -instruction.iffalse.operands = branchTarget - -instruction.ifeq.shortDescription = Branch if equal -instruction.ifeq.description = -instruction.ifeq.stackBefore = value1, value2 -instruction.ifeq.stackAfter = -instruction.ifeq.operands = branchTarget - -instruction.ifne.shortDescription = Branch if not equal -instruction.ifne.description = -instruction.ifne.stackBefore = value1, value2 -instruction.ifne.stackAfter = -instruction.ifne.operands = branchTarget - -instruction.iflt.shortDescription = Branch if lower than -instruction.iflt.description = -instruction.iflt.stackBefore = value1, value2 -instruction.iflt.stackAfter = -instruction.iflt.operands = branchTarget - -instruction.ifle.shortDescription = Branch if lower or equal -instruction.ifle.description = -instruction.ifle.stackBefore = value1, value2 -instruction.ifle.stackAfter = -instruction.ifle.operands = branchTarget - -instruction.ifgt.shortDescription = Branch if greater than -instruction.ifgt.description = -instruction.ifgt.stackBefore = value1, value2 -instruction.ifgt.stackAfter = -instruction.ifgt.operands = branchTarget - -instruction.ifge.shortDescription = Branch if greater or equal -instruction.ifge.description = -instruction.ifge.stackBefore = value1, value2 -instruction.ifge.stackAfter = -instruction.ifge.operands = branchTarget - -instruction.ifstricteq.shortDescription = Branch if strict equal -instruction.ifstricteq.description = -instruction.ifstricteq.stackBefore = value1, value2 -instruction.ifstricteq.stackAfter = -instruction.ifstricteq.operands = branchTarget - -instruction.ifstrictne.shortDescription = Branch if not strict equal -instruction.ifstrictne.description = -instruction.ifstrictne.stackBefore = value1, value2 -instruction.ifstrictne.stackAfter = -instruction.ifstrictne.operands = branchTarget - -instruction.lookupswitch.shortDescription = Branch based on index -instruction.lookupswitch.description = -instruction.lookupswitch.stackBefore = index -instruction.lookupswitch.stackAfter = -instruction.lookupswitch.operands = defaultTarget, caseCount, case0Target, case1Target, ... - -instruction.pushwith.shortDescription = Push with onto scope stack -instruction.pushwith.description = -instruction.pushwith.stackBefore = withScope -instruction.pushwith.stackAfter = -instruction.pushwith.operands = - -instruction.popscope.shortDescription = Pop from scope stack and discard value -instruction.popscope.description = -instruction.popscope.stackBefore = -instruction.popscope.stackAfter = -instruction.popscope.operands = - -instruction.nextname.shortDescription = Get name of next property -instruction.nextname.description = -instruction.nextname.stackBefore = obj, index -instruction.nextname.stackAfter = name -instruction.nextname.operands = - -instruction.hasnext.shortDescription = Check if the object has more properties -instruction.hasnext.description = -instruction.hasnext.stackBefore = obj, currentIndex -instruction.hasnext.stackAfter = nextIndex -instruction.hasnext.operands = - -instruction.pushnull.shortDescription = Push null value on stack -instruction.pushnull.description = -instruction.pushnull.stackBefore = -instruction.pushnull.stackAfter = null -instruction.pushnull.operands = - -instruction.pushundefined.shortDescription = Push undefined value on stack -instruction.pushundefined.description = -instruction.pushundefined.stackBefore = -instruction.pushundefined.stackAfter = undefined -instruction.pushundefined.operands = - -instruction.pushfloat.shortDescription = Push float value on stack -instruction.pushfloat.description = -instruction.pushfloat.stackBefore = -instruction.pushfloat.stackAfter = floatValue -instruction.pushfloat.operands = float - -instruction.nextvalue.shortDescription = Get value of next property -instruction.nextvalue.description = -instruction.nextvalue.stackBefore = obj, index -instruction.nextvalue.stackAfter = value -instruction.nextvalue.operands = - -instruction.pushbyte.shortDescription = Push byte value on stack -instruction.pushbyte.description = -instruction.pushbyte.stackBefore = -instruction.pushbyte.stackAfter = byteValue -instruction.pushbyte.operands = value - -instruction.pushshort.shortDescription = Push short value on stack -instruction.pushshort.description = -instruction.pushshort.stackBefore = -instruction.pushshort.stackAfter = shortValue -instruction.pushshort.operands = value - -instruction.pushtrue.shortDescription = Push true on stack -instruction.pushtrue.description = -instruction.pushtrue.stackBefore = -instruction.pushtrue.stackAfter = true -instruction.pushtrue.operands = - -instruction.pushfalse.shortDescription = Push false on stack -instruction.pushfalse.description = -instruction.pushfalse.stackBefore = -instruction.pushfalse.stackAfter = false -instruction.pushfalse.operands = - -instruction.pushnan.shortDescription = Push NaN value on stack -instruction.pushnan.description = -instruction.pushnan.stackBefore = -instruction.pushnan.stackAfter = NaN -instruction.pushnan.operands = - -instruction.pop.shortDescription = Pop top value from stack -instruction.pop.description = -instruction.pop.stackBefore = value -instruction.pop.stackAfter = -instruction.pop.operands = - -instruction.dup.shortDescription = Duplicate value on stack -instruction.dup.description = -instruction.dup.stackBefore = value -instruction.dup.stackAfter = value, value -instruction.dup.operands = - -instruction.swap.shortDescription = Swap two values on top of the stack -instruction.swap.description = -instruction.swap.stackBefore = value1, value2 -instruction.swap.stackAfter = value2, value1 -instruction.swap.operands = - -instruction.pushstring.shortDescription = Push string value on the stack -instruction.pushstring.description = -instruction.pushstring.stackBefore = -instruction.pushstring.stackAfter = stringValue -instruction.pushstring.operands = value - -instruction.pushint.shortDescription = Push integer value on the stack -instruction.pushint.description = -instruction.pushint.stackBefore = -instruction.pushint.stackAfter = intValue -instruction.pushint.operands = value - -instruction.pushuint.shortDescription = Push unsigned integer value on the stack -instruction.pushuint.description = -instruction.pushuint.stackBefore = -instruction.pushuint.stackAfter = uintValue -instruction.pushuint.operands = value - -instruction.pushdouble.shortDescription = Push double precision value on the stack -instruction.pushdouble.description = -instruction.pushdouble.stackBefore = -instruction.pushdouble.stackAfter = doubleValue -instruction.pushdouble.operands = value - -instruction.pushscope.shortDescription = Push object on the scope stack -instruction.pushscope.description = -instruction.pushscope.stackBefore = obj -instruction.pushscope.stackAfter = -instruction.pushscope.operands = - -instruction.pushnamespace.shortDescription = Push namespace on the stack -instruction.pushnamespace.description = -instruction.pushnamespace.stackBefore = -instruction.pushnamespace.stackAfter = namespace -instruction.pushnamespace.operands = value - -instruction.hasnext2.shortDescription = Check if the object has more properties (register based) -instruction.hasnext2.description = -instruction.hasnext2.stackBefore = -instruction.hasnext2.stackAfter = boolValue -instruction.hasnext2.operands = objectReg, indexReg - -instruction.pushdecimal.shortDescription = Push decimal value on the stack -instruction.pushdecimal.description = -instruction.pushdecimal.stackBefore = -instruction.pushdecimal.stackAfter = decimalValue -instruction.pushdecimal.operands = value - -#Undocumented: -instruction.pushdnan.shortDescription = Push decimal NaN value on the stack -instruction.pushdnan.description = -#instruction.pushdnan.stackBefore = -#instruction.pushdnan.stackAfter = -instruction.pushdnan.operands = - -instruction.li8.shortDescription = Load 8bit integer value -instruction.li8.description = -instruction.li8.stackBefore = address -instruction.li8.stackAfter = int8Value -instruction.li8.operands = - -instruction.li16.shortDescription = Load 16bit integer value -instruction.li16.description = -instruction.li16.stackBefore = address -instruction.li16.stackAfter = int16Value -instruction.li16.operands = - -instruction.li32.shortDescription = Load 32bit integer value -instruction.li32.description = -instruction.li32.stackBefore = address -instruction.li32.stackAfter = int32Value -instruction.li32.operands = - -instruction.lf32.shortDescription = Load 32bit float value -instruction.lf32.description = -instruction.lf32.stackBefore = address -instruction.lf32.stackAfter = float32Value -instruction.lf32.operands = - -instruction.lf64.shortDescription = Load 64bit float value -instruction.lf64.description = -instruction.lf64.stackBefore = address -instruction.lf64.stackAfter = float64Value -instruction.lf64.operands = - -instruction.si8.shortDescription = Store 8bit integer value -instruction.si8.description = -instruction.si8.stackBefore = value, address -instruction.si8.stackAfter = -instruction.si8.operands = - -instruction.si16.shortDescription = Store 16bit integer value -instruction.si16.description = -instruction.si16.stackBefore = value, address -instruction.si16.stackAfter = -instruction.si16.operands = - -instruction.si32.shortDescription = Store 32bit integer value -instruction.si32.description = -instruction.si32.stackBefore = value, address -instruction.si32.stackAfter = -instruction.si32.operands = - -instruction.sf32.shortDescription = Store 32bit float value -instruction.sf32.description = -instruction.sf32.stackBefore = value, address -instruction.sf32.stackAfter = -instruction.sf32.operands = - -instruction.sf64.shortDescription = Store 64bit float value -instruction.sf64.description = -instruction.sf64.stackBefore = value, address -instruction.sf64.stackAfter = -instruction.sf64.operands = - -instruction.newfunction.shortDescription = Create new Function object -instruction.newfunction.description = -instruction.newfunction.stackBefore = -instruction.newfunction.stackAfter = function -instruction.newfunction.operands = method - -instruction.call.shortDescription = Call function on the stack -instruction.call.description = -instruction.call.stackBefore = function, this, arg1, ..., argN -instruction.call.stackAfter = value -instruction.call.operands = argCount - -instruction.construct.shortDescription = Call constructor function on the stack -instruction.construct.description = -instruction.construct.stackBefore = function, arg1, ..., argN -instruction.construct.stackAfter = value -instruction.construct.operands = argCount - -instruction.callmethod.shortDescription = Call method of object by dispatch id -instruction.callmethod.description = -instruction.callmethod.stackBefore = this, arg1, ..., argN -instruction.callmethod.stackAfter = value -instruction.callmethod.operands = method, argCount - -instruction.callstatic.shortDescription = Call method by method id in ABC file -instruction.callstatic.description = -instruction.callstatic.stackBefore = this, arg1, ..., argN -instruction.callstatic.stackAfter = value -instruction.callstatic.operands = method, argCount - -instruction.callsuper.shortDescription = Call method on parent class -instruction.callsuper.description = -instruction.callsuper.stackBefore = obj, [ns], [name], arg1, ..., argN -instruction.callsuper.stackAfter = value -instruction.callsuper.operands = methodName, argCount - -instruction.callproperty.shortDescription = Call property -instruction.callproperty.description = -instruction.callproperty.stackBefore = obj, [ns], [name], arg1, ..., argN -instruction.callproperty.stackAfter = value -instruction.callproperty.operands = property, argCount - -instruction.returnvoid.shortDescription = Return from a method -instruction.returnvoid.description = -instruction.returnvoid.stackBefore = -instruction.returnvoid.stackAfter = -instruction.returnvoid.operands = - -instruction.returnvalue.shortDescription = Return value from a method -instruction.returnvalue.description = -instruction.returnvalue.stackBefore = value -instruction.returnvalue.stackAfter = -instruction.returnvalue.operands = - -instruction.constructsuper.shortDescription = Call parent constructor of an object -instruction.constructsuper.description = -instruction.constructsuper.stackBefore = obj, arg1, ..., argN -instruction.constructsuper.stackAfter = -instruction.constructsuper.operands = argCount - -instruction.constructprop.shortDescription = Construct a property of an object -instruction.constructprop.description = -instruction.constructprop.stackBefore = obj, [ns], [name], arg1, ..., argN -instruction.constructprop.stackAfter = value -instruction.constructprop.operands = property, argCount - -#Undocumented: -instruction.callsuperid.shortDescription = Call super id -instruction.callsuperid.description = -#instruction.callsuperid.stackBefore = -#instruction.callsuperid.stackAfter = -#instruction.callsuperid.operands = - -instruction.callproplex.shortDescription = Call property with null as this -instruction.callproplex.description = -instruction.callproplex.stackBefore = obj, [ns], [name], arg1, ..., argN -instruction.callproplex.stackAfter = value -instruction.callproplex.operands = property, argCount - -#Undocumented: -instruction.callinterface.shortDescription = Call interface -instruction.callinterface.description = -#instruction.callinterface.stackBefore = -#instruction.callinterface.stackAfter = -instruction.callinterface.operands = interface, argCount - - -instruction.callsupervoid.shortDescription = Call method on parent class, discard return value -instruction.callsupervoid.description = -instruction.callsupervoid.stackBefore = obj, [ns], [name], arg1, ..., argN -instruction.callsupervoid.stackAfter = -instruction.callsupervoid.operands = methodName, argCount - - -instruction.callpropvoid.shortDescription = Call property, discard return value -instruction.callpropvoid.description = -instruction.callpropvoid.stackBefore = obj, [ns], [name], arg1, ..., argN -instruction.callpropvoid.stackAfter = -instruction.callpropvoid.operands = property, argCount - -instruction.sxi1.shortDescription = Sign extend 1bit value to 32bits -instruction.sxi1.description = -instruction.sxi1.stackBefore = value -instruction.sxi1.stackAfter = valueExtended -instruction.sxi1.operands = - -instruction.sxi8.shortDescription = Sign extend 8bit value to 32bits -instruction.sxi8.description = -instruction.sxi8.stackBefore = value -instruction.sxi8.stackAfter = valueExtended -instruction.sxi8.operands = - -instruction.sxi16.shortDescription = Sign extend 16bit value to 32bits -instruction.sxi16.description = -instruction.sxi16.stackBefore = value -instruction.sxi16.stackAfter = valueExtended -instruction.sxi16.operands = - -instruction.applytype.shortDescription = Apply type parameters -instruction.applytype.description = Apply parameter types to base type. For example when Vector is resolved at runtime. String is parameter, Vector is baseclass. -instruction.applytype.stackBefore = baseType, typeParam1, ..., typeParamN -instruction.applytype.stackAfter = baseType -instruction.applytype.operands = typeParamCount - -instruction.pushfloat4.shortDescription = Push float4 value on the stack -instruction.pushfloat4.description = -instruction.pushfloat4.stackBefore = -instruction.pushfloat4.stackAfter = float4Value -instruction.pushfloat4.operands = float4 - -instruction.newobject.shortDescription = Creates new object -instruction.newobject.description = -instruction.newobject.stackBefore = name1, value1, name2, value2, ..., nameN, valueN -instruction.newobject.stackAfter = newObject -instruction.newobject.operands = propertyCount - -instruction.newarray.shortDescription = Creates new array -instruction.newarray.description = -instruction.newarray.stackBefore = value1, value2, ..., valueN -instruction.newarray.stackAfter = newArray -instruction.newarray.operands = valueCount - -instruction.newactivation.shortDescription = Creates new activation object -instruction.newactivation.description = -instruction.newactivation.stackBefore = -instruction.newactivation.stackAfter = newActivation -instruction.newactivation.operands = - -instruction.newclass.shortDescription = Creates new class -instruction.newclass.description = -instruction.newclass.stackBefore = baseType -instruction.newclass.stackAfter = newClass -instruction.newclass.operands = class - -instruction.getdescendants.shortDescription = Get descendants -instruction.getdescendants.description = -instruction.getdescendants.stackBefore = obj, [ns], [name] -instruction.getdescendants.stackAfter = value -instruction.getdescendants.operands = operand1 - -instruction.newcatch.shortDescription = Create new catch scope -instruction.newcatch.description = -instruction.newcatch.stackBefore = -instruction.newcatch.stackAfter = catchScope -instruction.newcatch.operands = exception - -#Undocumented: -instruction.deldescendants.shortDescription = Delete descendants -instruction.deldescendants.description = -#instruction.deldescendants.stackBefore = -#instruction.deldescendants.stackAfter = -instruction.deldescendants.operands = - -#Undocumented: -instruction.findpropglobal.shortDescription = Search property in global scope -instruction.findpropglobal.description = -instruction.findpropglobal.stackBefore = [ns], [name] -instruction.findpropglobal.stackAfter = obj -instruction.findpropglobal.operands = property - -instruction.findpropstrict.shortDescription = Search property in scope stack, error when not found -instruction.findpropstrict.description = -instruction.findpropstrict.stackBefore = [ns], [name] -instruction.findpropstrict.stackAfter = obj -instruction.findpropstrict.operands = property - -instruction.findproperty.shortDescription = Search property in scope stack, top object when not found -instruction.findproperty.description = -instruction.findproperty.stackBefore = [ns], [name] -instruction.findproperty.stackAfter = obj -instruction.findproperty.operands = property - -#Undocumented: -instruction.finddef.shortDescription = Search script level definition -instruction.finddef.description = -instruction.finddef.stackBefore = [ns], [name] -instruction.finddef.stackAfter = obj -instruction.finddef.operands = property - -instruction.getlex.shortDescription = Find and get property -instruction.getlex.description = -instruction.getlex.stackBefore = -instruction.getlex.stackAfter = obj -instruction.getlex.operands = property - -instruction.setproperty.shortDescription = Set property -instruction.setproperty.description = -instruction.setproperty.stackBefore = obj, [ns], [name], value -instruction.setproperty.stackAfter = -instruction.setproperty.operands = property - -instruction.getlocal.shortDescription = Get local register value -instruction.getlocal.description = -instruction.getlocal.stackBefore = -instruction.getlocal.stackAfter = value -instruction.getlocal.operands = localRegIndex - -instruction.setlocal.shortDescription = Set local register value -instruction.setlocal.description = -instruction.setlocal.stackBefore = value -instruction.setlocal.stackAfter = -instruction.setlocal.operands = localRegIndex - -instruction.getglobalscope.shortDescription = Get global scope -instruction.getglobalscope.description = -instruction.getglobalscope.stackBefore = -instruction.getglobalscope.stackAfter = obj -instruction.getglobalscope.operands = - -instruction.getscopeobject.shortDescription = Get scope object -instruction.getscopeobject.description = -instruction.getscopeobject.stackBefore = -instruction.getscopeobject.stackAfter = obj -instruction.getscopeobject.operands = scopeIndex - -instruction.getproperty.shortDescription = Get property -instruction.getproperty.description = -instruction.getproperty.stackBefore = obj, [ns], [name] -instruction.getproperty.stackAfter = value -instruction.getproperty.operands = property - -instruction.getouterscope.shortDescription = Get scope object on all levels -instruction.getouterscope.description = -instruction.getouterscope.stackBefore = -instruction.getouterscope.stackAfter = obj -instruction.getouterscope.operands = allLevelScopeIndex - -instruction.initproperty.shortDescription = Initialize property -instruction.initproperty.description = -instruction.initproperty.stackBefore = obj, [ns], [name], value -instruction.initproperty.stackAfter = -instruction.initproperty.operands = property - -#Undocumented: -instruction.setpropertylate.shortDescription = Set property (stack based) -instruction.setpropertylate.description = -#instruction.setpropertylate.stackBefore = -#instruction.setpropertylate.stackAfter = -#instruction.setpropertylate.operands = - -instruction.deleteproperty.shortDescription = Delete property -instruction.deleteproperty.description = -instruction.deleteproperty.stackBefore = obj, [ns], [name] -instruction.deleteproperty.stackAfter = boolResult -instruction.deleteproperty.operands = property - -#Undocumented: -instruction.deletepropertylate.shortDescription = Delete property (stack based) -instruction.deletepropertylate.description = -#instruction.deletepropertylate.stackBefore = -#instruction.deletepropertylate.stackAfter = -instruction.deletepropertylate.operands = - -instruction.getslot.shortDescription = Get value of a slot -instruction.getslot.description = -instruction.getslot.stackBefore = obj -instruction.getslot.stackAfter = value -instruction.getslot.operands = slotIndex - -instruction.setslot.shortDescription = Set value of a slot -instruction.setslot.description = -instruction.setslot.stackBefore = obj, value -instruction.setslot.stackAfter = -instruction.setslot.operands = slotIndex - -instruction.getglobalslot.shortDescription = Get value of slot on global scope -instruction.getglobalslot.description = -instruction.getglobalslot.stackBefore = -instruction.getglobalslot.stackAfter = value -instruction.getglobalslot.operands = slotIndex - -instruction.setglobalslot.shortDescription = Set value of slot on global scope -instruction.setglobalslot.description = -instruction.setglobalslot.stackBefore = value -instruction.setglobalslot.stackAfter = -instruction.setglobalslot.operands = slotIndex - -instruction.convert_s.shortDescription = Convert value to string -instruction.convert_s.description = -instruction.convert_s.stackBefore = value -instruction.convert_s.stackAfter = stringValue -instruction.convert_s.operands = - -instruction.esc_xelem.shortDescription = Escape XML element -instruction.esc_xelem.description = -instruction.esc_xelem.stackBefore = value -instruction.esc_xelem.stackAfter = stringValue -instruction.esc_xelem.operands = - -instruction.esc_xattr.shortDescription = Escape XML attribute -instruction.esc_xattr.description = -instruction.esc_xattr.stackBefore = value -instruction.esc_xattr.stackAfter = stringValue -instruction.esc_xattr.operands = - -instruction.convert_i.shortDescription = Convert value to integer -instruction.convert_i.description = -instruction.convert_i.stackBefore = value -instruction.convert_i.stackAfter = intValue -instruction.convert_i.operands = - -instruction.convert_u.shortDescription = Convert value to unsigned integer -instruction.convert_u.description = -instruction.convert_u.stackBefore = value -instruction.convert_u.stackAfter = uintValue -instruction.convert_u.operands = - -instruction.convert_d.shortDescription = Convert value to double -instruction.convert_d.description = -instruction.convert_d.stackBefore = value -instruction.convert_d.stackAfter = doubleValue -instruction.convert_d.operands = - -instruction.convert_b.shortDescription = Convert value to boolean -instruction.convert_b.description = -instruction.convert_b.stackBefore = value -instruction.convert_b.stackAfter = booleanValue -instruction.convert_b.operands = - -instruction.convert_o.shortDescription = Convert value to Object -instruction.convert_o.description = -instruction.convert_o.stackBefore = value -instruction.convert_o.stackAfter = value -instruction.convert_o.operands = - -instruction.checkfilter.shortDescription = Check that object can have filter operation applied -instruction.checkfilter.description = -instruction.checkfilter.stackBefore = value -instruction.checkfilter.stackAfter = value -instruction.checkfilter.operands = - -instruction.convert_m.shortDescription = Convert value to decimal -instruction.convert_m.description = -instruction.convert_m.stackBefore = value -instruction.convert_m.stackAfter = decimalValue -instruction.convert_m.operands = - -instruction.convert_m_p.shortDescription = Convert value to decimal with number context -instruction.convert_m_p.description = -instruction.convert_m_p.stackBefore = value -instruction.convert_m_p.stackAfter = decimalValue -instruction.convert_m_p.operands = numberContext - -instruction.convert_f.shortDescription = Convert value to float -instruction.convert_f.description = -instruction.convert_f.stackBefore = value -instruction.convert_f.stackAfter = floatValue -instruction.convert_f.operands = - -instruction.convert_f4.shortDescription = Convert value to float4 -instruction.convert_f4.description = -instruction.convert_f4.stackBefore = value -instruction.convert_f4.stackAfter = float4Value -instruction.convert_f4.operands = - -instruction.coerce.shortDescription = Coerce value to specified type -instruction.coerce.description = -instruction.coerce.stackBefore = value -instruction.coerce.stackAfter = coercedValue -instruction.coerce.operands = type - -instruction.coerce_b.shortDescription = Coerce value to boolean -instruction.coerce_b.description = -instruction.coerce_b.stackBefore = value -instruction.coerce_b.stackAfter = booleanValue -instruction.coerce_b.operands = -instruction.coerce_b.deprecated = Use convert_b instead - -instruction.coerce_a.shortDescription = Coerce value to any type -instruction.coerce_a.description = -instruction.coerce_a.stackBefore = value -instruction.coerce_a.stackAfter = value -instruction.coerce_a.operands = - -instruction.coerce_i.shortDescription = Coerce value to integer -instruction.coerce_i.description = -instruction.coerce_i.stackBefore = value -instruction.coerce_i.stackAfter = intValue -instruction.coerce_i.operands = -instruction.coerce_i.deprecated = Use convert_i instead - -instruction.coerce_d.shortDescription = Coerce value to double -instruction.coerce_d.description = -instruction.coerce_d.stackBefore = value -instruction.coerce_d.stackAfter = doubleValue -instruction.coerce_d.operands = -instruction.coerce_d.deprecated = Use convert_d instead - -instruction.coerce_s.shortDescription = Coerce value to string -instruction.coerce_s.description = -instruction.coerce_s.stackBefore = value -instruction.coerce_s.stackAfter = stringValue -instruction.coerce_s.operands = - -instruction.astype.shortDescription = Return same value or null if not specified type -instruction.astype.description = -instruction.astype.stackBefore = value -instruction.astype.stackAfter = value -instruction.astype.operands = type - -instruction.astypelate.shortDescription = Return same value or null if not specified type (stack based) -instruction.astypelate.description = -instruction.astypelate.stackBefore = value, type -instruction.astypelate.stackAfter = value -instruction.astypelate.operands = - -instruction.coerce_u.shortDescription = Coerce value to unsigned integer -instruction.coerce_u.description = -instruction.coerce_u.stackBefore = value -instruction.coerce_u.stackAfter = uintValue -instruction.coerce_u.operands = - -instruction.coerce_o.shortDescription = Coerce value to Object -instruction.coerce_o.description = -instruction.coerce_o.stackBefore = value -instruction.coerce_o.stackAfter = value -instruction.coerce_o.operands = - -instruction.negate_p.shortDescription = Negate value using number context -instruction.negate_p.description = -instruction.negate_p.stackBefore = value -instruction.negate_p.stackAfter = -value -instruction.negate_p.operands = operand1 - -instruction.negate.shortDescription = Negate value -instruction.negate.description = -instruction.negate.stackBefore = value -instruction.negate.stackAfter = -value -instruction.negate.operands = - -instruction.increment.shortDescription = Increment value -instruction.increment.description = -instruction.increment.stackBefore = value -instruction.increment.stackAfter = incrementedValue -instruction.increment.operands = - -instruction.inclocal.shortDescription = Increment local register -instruction.inclocal.description = -instruction.inclocal.stackBefore = -instruction.inclocal.stackAfter = -instruction.inclocal.operands = localRegister - -instruction.decrement.shortDescription = Decrement value -instruction.decrement.description = -instruction.decrement.stackBefore = value -instruction.decrement.stackAfter = decrementedValue -instruction.decrement.operands = - -instruction.declocal.shortDescription = Decrement local register -instruction.declocal.description = -instruction.declocal.stackBefore = -instruction.declocal.stackAfter = -instruction.declocal.operands = localRegister - -instruction.typeof.shortDescription = Get name of value type -instruction.typeof.description = -instruction.typeof.stackBefore = value -instruction.typeof.stackAfter = typeName -instruction.typeof.operands = - -instruction.not.shortDescription = Boolean negate -instruction.not.description = -instruction.not.stackBefore = value -instruction.not.stackAfter = !value -instruction.not.operands = - -instruction.bitnot.shortDescription = Bitwise negate -instruction.bitnot.description = -instruction.bitnot.stackBefore = value -instruction.bitnot.stackAfter = ~value -instruction.bitnot.operands = - -#Undocumented: -instruction.concat.shortDescription = Concat -instruction.concat.description = -#instruction.concat.stackBefore = -#instruction.concat.stackAfter = -#instruction.concat.operands = - -#Undocumented: -instruction.add_d.shortDescription = Add_d -instruction.add_d.description = -#instruction.add_d.stackBefore = -#instruction.add_d.stackAfter = -#instruction.add_d.operands = - -instruction.increment_p.shortDescription = Increment value using number context -instruction.increment_p.description = -instruction.increment_p.stackBefore = value -instruction.increment_p.stackAfter = incrementedValue -instruction.increment_p.operands = numberContext - -instruction.inclocal_p.shortDescription = Increment local register using number context -instruction.inclocal_p.description = -instruction.inclocal_p.stackBefore = -instruction.inclocal_p.stackAfter = -instruction.inclocal_p.operands = numberContext, localRegister - -instruction.decrement_p.shortDescription = Decrement value using number context -instruction.decrement_p.description = -instruction.decrement_p.stackBefore = value -instruction.decrement_p.stackAfter = decrementedValue -instruction.decrement_p.operands = numberContext - -instruction.declocal_p.shortDescription = Decrement local register using number context -instruction.declocal_p.description = -instruction.declocal_p.stackBefore = -instruction.declocal_p.stackAfter = -instruction.declocal_p.operands = numberContext, localRegister - -instruction.add.shortDescription = Add two values -instruction.add.description = -instruction.add.stackBefore = value1, value2 -instruction.add.stackAfter = value3 -instruction.add.operands = - -instruction.subtract.shortDescription = Subtract two values -instruction.subtract.description = -instruction.subtract.stackBefore = value1, value2 -instruction.subtract.stackAfter = value3 -instruction.subtract.operands = - -instruction.multiply.shortDescription = Multiply two values -instruction.multiply.description = -instruction.multiply.stackBefore = value1, value2 -instruction.multiply.stackAfter = value3 -instruction.multiply.operands = - -instruction.divide.shortDescription = Divide two values -instruction.divide.description = -instruction.divide.stackBefore = value1, value2 -instruction.divide.stackAfter = value3 -instruction.divide.operands = - -instruction.modulo.shortDescription = Modulo divide two values -instruction.modulo.description = -instruction.modulo.stackBefore = value1, value2 -instruction.modulo.stackAfter = value3 -instruction.modulo.operands = - -instruction.lshift.shortDescription = Bitwise left shift -instruction.lshift.description = -instruction.lshift.stackBefore = value1, value2 -instruction.lshift.stackAfter = value3 -instruction.lshift.operands = - -instruction.rshift.shortDescription = Bitwise right shift -instruction.rshift.description = -instruction.rshift.stackBefore = value1, value2 -instruction.rshift.stackAfter = value3 -instruction.rshift.operands = - -instruction.urshift.shortDescription = Unsigned bitwise right shift -instruction.urshift.description = -instruction.urshift.stackBefore = value1, value2 -instruction.urshift.stackAfter = value3 -instruction.urshift.operands = - -instruction.bitand.shortDescription = Bitwise and -instruction.bitand.description = -instruction.bitand.stackBefore = value1, value2 -instruction.bitand.stackAfter = value3 -instruction.bitand.operands = - -instruction.bitor.shortDescription = Bitwise or -instruction.bitor.description = -instruction.bitor.stackBefore = value1, value2 -instruction.bitor.stackAfter = value3 -instruction.bitor.operands = - -instruction.bitxor.shortDescription = Bitwise xor -instruction.bitxor.description = -instruction.bitxor.stackBefore = value1, value2 -instruction.bitxor.stackAfter = value3 -instruction.bitxor.operands = - -instruction.equals.shortDescription = Compare two values -instruction.equals.description = -instruction.equals.stackBefore = value1, value2 -instruction.equals.stackAfter = booleanResult -instruction.equals.operands = - -instruction.strictequals.shortDescription = Strict compare two values -instruction.strictequals.description = -instruction.strictequals.stackBefore = value1, value2 -instruction.strictequals.stackAfter = booleanResult -instruction.strictequals.operands = - -instruction.lessthan.shortDescription = Check that value is less than other value -instruction.lessthan.description = -instruction.lessthan.stackBefore = value1, value2 -instruction.lessthan.stackAfter = booleanResult -instruction.lessthan.operands = - -instruction.lessequals.shortDescription = Check that value is less or equal than other value -instruction.lessequals.description = -instruction.lessequals.stackBefore = value1, value2 -instruction.lessequals.stackAfter = booleanResult -instruction.lessequals.operands = booleanResult - -instruction.greaterthan.shortDescription = Check that value is greater or equal than other value -instruction.greaterthan.description = -instruction.greaterthan.stackBefore = value1, value2 -instruction.greaterthan.stackAfter = booleanResult -instruction.greaterthan.operands = - -instruction.greaterequals.shortDescription = Check that value is greater or equal than other value -instruction.greaterequals.description = -instruction.greaterequals.stackBefore = value1, value2 -instruction.greaterequals.stackAfter = booleanResult -instruction.greaterequals.operands = - -instruction.instanceof.shortDescription = Check that type exists in object prototype chain -instruction.instanceof.description = -instruction.instanceof.stackBefore = value, type -instruction.instanceof.stackAfter = booleanResult -instruction.instanceof.operands = - -instruction.istype.shortDescription = Check that object is of specified type -instruction.istype.description = -instruction.istype.stackBefore = value -instruction.istype.stackAfter = booleanResult -instruction.istype.operands = type - -instruction.istypelate.shortDescription = Check that object is of specified type (stack based) -instruction.istypelate.description = -instruction.istypelate.stackBefore = value, type -instruction.istypelate.stackAfter = booleanResult -instruction.istypelate.operands = - -instruction.in.shortDescription = Check that object has named property -instruction.in.description = -instruction.in.stackBefore = name, obj -instruction.in.stackAfter = booleanResult -instruction.in.operands = - -instruction.add_p.shortDescription = Add two values using number context -instruction.add_p.description = -instruction.add_p.stackBefore = value1, value2 -instruction.add_p.stackAfter = value3 -instruction.add_p.operands = numberContext - -instruction.subtract_p.shortDescription = Subtract two values using number context -instruction.subtract_p.description = -instruction.subtract_p.stackBefore = value1, value2 -instruction.subtract_p.stackAfter = value3 -instruction.subtract_p.operands = numberContext - -instruction.multiply_p.shortDescription = Multiply two values using number context -instruction.multiply_p.description = -instruction.multiply_p.stackBefore = value1, value2 -instruction.multiply_p.stackAfter = value3 -instruction.multiply_p.operands = numberContext - -instruction.divide_p.shortDescription = Divide two values using number context -instruction.divide_p.description = -instruction.divide_p.stackBefore = value1, value2 -instruction.divide_p.stackAfter = value3 -instruction.divide_p.operands = numberContext - -instruction.modulo_p.shortDescription = Modulo divide two values using number context -instruction.modulo_p.description = -instruction.modulo_p.stackBefore = value1, value2 -instruction.modulo_p.stackAfter = value3 -instruction.modulo_p.operands = numberContext - -instruction.increment_i.shortDescription = Increment integer value -instruction.increment_i.description = -instruction.increment_i.stackBefore = value -instruction.increment_i.stackAfter = incrementedValue -instruction.increment_i.operands = - -instruction.decrement_i.shortDescription = Decrement integer value -instruction.decrement_i.description = -instruction.decrement_i.stackBefore = value -instruction.decrement_i.stackAfter = decrementedValue -instruction.decrement_i.operands = - -instruction.inclocal_i.shortDescription = Increment local register integer value -instruction.inclocal_i.description = -instruction.inclocal_i.stackBefore = -instruction.inclocal_i.stackAfter = -instruction.inclocal_i.operands = localRegister - -instruction.declocal_i.shortDescription = Decrement local register integer value -instruction.declocal_i.description = -instruction.declocal_i.stackBefore = -instruction.declocal_i.stackAfter = -instruction.declocal_i.operands = localRegister - -instruction.negate_i.shortDescription = Negate integer value -instruction.negate_i.description = -instruction.negate_i.stackBefore = value -instruction.negate_i.stackAfter = -value -instruction.negate_i.operands = - -instruction.add_i.shortDescription = Add two integer values -instruction.add_i.description = -instruction.add_i.stackBefore = value1, value2 -instruction.add_i.stackAfter = value3 -instruction.add_i.operands = - -instruction.subtract_i.shortDescription = Subtract two integer values -instruction.subtract_i.description = -instruction.subtract_i.stackBefore = value1, value2 -instruction.subtract_i.stackAfter = value3 -instruction.subtract_i.operands = - -instruction.multiply_i.shortDescription = Multiply two integer values -instruction.multiply_i.description = -instruction.multiply_i.stackBefore = value1, value2 -instruction.multiply_i.stackAfter = value3 -instruction.multiply_i.operands = - -instruction.getlocal_0.shortDescription = Get local register 0 -instruction.getlocal_0.description = -instruction.getlocal_0.stackBefore = -instruction.getlocal_0.stackAfter = value -instruction.getlocal_0.operands = - -instruction.getlocal_1.shortDescription = Get local register 1 -instruction.getlocal_1.description = -instruction.getlocal_1.stackBefore = -instruction.getlocal_1.stackAfter = value -instruction.getlocal_1.operands = - -instruction.getlocal_2.shortDescription = Get local register 2 -instruction.getlocal_2.description = -instruction.getlocal_2.stackBefore = -instruction.getlocal_2.stackAfter = value -instruction.getlocal_2.operands = - -instruction.getlocal_3.shortDescription = Get local register 3 -instruction.getlocal_3.description = -instruction.getlocal_3.stackBefore = -instruction.getlocal_3.stackAfter = value -instruction.getlocal_3.operands = - -instruction.setlocal_0.shortDescription = Set local register 0 -instruction.setlocal_0.description = -instruction.setlocal_0.stackBefore = value -instruction.setlocal_0.stackAfter = -instruction.setlocal_0.operands = - -instruction.setlocal_1.shortDescription = Set local register 1 -instruction.setlocal_1.description = -instruction.setlocal_1.stackBefore = value -instruction.setlocal_1.stackAfter = -instruction.setlocal_1.operands = - -instruction.setlocal_2.shortDescription = Set local register 2 -instruction.setlocal_2.description = -instruction.setlocal_2.stackBefore = value -instruction.setlocal_2.stackAfter = -instruction.setlocal_2.operands = - -instruction.setlocal_3.shortDescription = Set local register 3 -instruction.setlocal_3.description = -instruction.setlocal_3.stackBefore = value -instruction.setlocal_3.stackAfter = -instruction.setlocal_3.operands = - -#Undocumented: -instruction.invalid.shortDescription = Invalid -instruction.invalid.description = -#instruction.invalid.stackBefore = -#instruction.invalid.stackAfter = -#instruction.invalid.operands = - -#Undocumented: -instruction.abs_jump.shortDescription = Absolute jump -instruction.abs_jump.description = -#instruction.abs_jump.stackBefore = -#instruction.abs_jump.stackAfter = -#instruction.abs_jump.operands = - -instruction.debug.shortDescription = Debugging info -instruction.debug.description = -instruction.debug.stackBefore = -instruction.debug.stackAfter = -instruction.debug.operands = debugType, regName, localRegister, extra - -instruction.debugline.shortDescription = Debugging line number info -instruction.debugline.description = -instruction.debugline.stackBefore = -instruction.debugline.stackAfter = -instruction.debugline.operands = lineNumber - -instruction.debugfile.shortDescription = Debugging file info -instruction.debugfile.description = -instruction.debugfile.stackBefore = -instruction.debugfile.stackAfter = -instruction.debugfile.operands = fileName - -instruction.bkptline.shortDescription = Breakpoint on line -instruction.bkptline.description = -instruction.bkptline.stackBefore = -instruction.bkptline.stackAfter = -instruction.bkptline.operands = lineNumber - -#Undocumented: -instruction.timestamp.shortDescription = Timestamp -instruction.timestamp.description = -instruction.timestamp.stackBefore = -instruction.timestamp.stackAfter = -instruction.timestamp.operands = - -#Undocumented: -instruction.verifypass.shortDescription = Verify pass -instruction.verifypass.description = -#instruction.verifypass.stackBefore = -#instruction.verifypass.stackAfter = -#instruction.verifypass.operands = - -#Undocumented: -instruction.alloc.shortDescription = Alloc -instruction.alloc.description = -#instruction.alloc.stackBefore = -#instruction.alloc.stackAfter = -#instruction.alloc.operands = - -#Undocumented: -instruction.mark.shortDescription = Mark -instruction.mark.description = -#instruction.mark.stackBefore = -#instruction.mark.stackAfter = -#instruction.mark.operands = - -#Undocumented: -instruction.wb.shortDescription = Wb -instruction.wb.description = -#instruction.wb.stackBefore = -#instruction.wb.stackAfter = -#instruction.wb.operands = - -#Undocumented: -instruction.prologue.shortDescription = Prologue -instruction.prologue.description = -#instruction.prologue.stackBefore = -#instruction.prologue.stackAfter = -#instruction.prologue.operands = - -#Undocumented: -instruction.sendenter.shortDescription = Send enter -instruction.sendenter.description = -#instruction.sendenter.stackBefore = -#instruction.sendenter.stackAfter = -#instruction.sendenter.operands = - -#Undocumented: -instruction.doubletoatom.shortDescription = Double to atom -instruction.doubletoatom.description = -#instruction.doubletoatom.stackBefore = -#instruction.doubletoatom.stackAfter = -#instruction.doubletoatom.operands = - -#Undocumented: -instruction.sweep.shortDescription = Sweep -instruction.sweep.description = -#instruction.sweep.stackBefore = -#instruction.sweep.stackAfter = -#instruction.sweep.operands = - -#Undocumented: -instruction.codegenop.shortDescription = CodeGenOp -instruction.codegenop.description = -#instruction.codegenop.stackBefore = -#instruction.codegenop.stackAfter = -#instruction.codegenop.operands = - -#Undocumented: -instruction.verifyop.shortDescription = VerifyOp -instruction.verifyop.description = -#instruction.verifyop.stackBefore = -#instruction.verifyop.stackAfter = -#instruction.verifyop.operands = - -#Undocumented: -instruction.decode.shortDescription = Decode -instruction.decode.description = -#instruction.decode.stackBefore = -#instruction.decode.stackAfter = -#instruction.decode.operands = - - -instruction.unplus.shortDescription = Unary plus - coerce to numeric -instruction.unplus.description = -instruction.unplus.stackBefore = value -instruction.unplus.stackAfter = value -instruction.unplus.operands = - -instruction.pushconstant.shortDescription = Push constant value on stack -instruction.pushconstant.description = -#instruction.pushconstant.stackBefore = -#instruction.pushconstant.stackAfter = +# 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. + +#String for whole list generation +ui.list.heading = AVM2 Instruction list +ui.list.pageTitle = AVM2 Instruction list +ui.list.documentTitle = AVM2 Instruction list +ui.list.pageDescription = List of all known ActionScript 3 - AVM2 instructions with their operands and stack values + +#various strings in UI: +ui.unknown = ??? +ui.stack = Stack:\u0020 +ui.stack.before = ...,\u0020 +ui.stack.before.empty = ... +ui.stack.to = \u0020\u279e\u0020 +ui.flags = Flags:\u0020 +ui.description = Description:\u0020 +ui.filter.hide = Hide:\u0020 +ui.filter.byname = Find by name:\u0020 +ui.filter.order = Order by:\u0020 +ui.filter.order.code = code +ui.filter.order.name = name + + +#----------------------- Flags of the instructions +instructionFlag.undocumented = Undocumented +instructionFlag.unknownStack = Unknown stack +instructionFlag.es4NumericsMinor = ES4 numerics (ABC minor 17) +instructionFlag.floatMajor = Float values (ABC major 47) +instructionFlag.unknownOperands = Unknown operands +instructionFlag.noFlashPlayer = Not in standard Flash Player +instructionFlag.deprecated = Deprecated +instructionFlag.domainMemory = Domain memory operation + +#----------------------- Operand types +operandType.multinameIndex = Multiname index +operandType.multinameIndex.description = Index into multiname constant pool +operandType.multinameIndex.name = multinameIndex +operandType.multinameIndex.uiName = multiname + +operandType.argCount = Number of arguments +operandType.argCount.description = Number of following arguments +operandType.argCount.name = argCount +operandType.argCount.uiName = uint + + +operandType.methodIndex = Method index +operandType.methodIndex.description = Index of method in the ABC +operandType.methodIndex.name = methodIndex +operandType.methodIndex.uiName = methodIndex + +operandType.stringIndex = String index +operandType.stringIndex.description = Index into string values constant pool +operandType.stringIndex.name = stringIndex +operandType.stringIndex.uiName = string + + +operandType.debugType = Debug type +operandType.debugType.description = Type of debug information. Currently only value of 1 is used. +operandType.debugType.name = debugType +operandType.debugType.uiName = debugType + + +operandType.registerIndex = Register index +operandType.registerIndex.description = Index of a local register (0-255) +operandType.registerIndex.name = registerIndex +operandType.registerIndex.uiName = uint + +operandType.linenum = Line number +operandType.linenum.description = Line number of file +operandType.linenum.name = linenum +operandType.linenum.uiName = linenum + + +#similar as registerIndex, but U30 instead of U8 +operandType.localRegIndex = Register index +operandType.localRegIndex.description = Index of a local register +operandType.localRegIndex.name = localRegIndex +operandType.localRegIndex.uiName = uint + + +operandType.slotIndex = Slot index +operandType.slotIndex.description = Index of the slot on an object +operandType.slotIndex.name = slotIndex +operandType.slotIndex.uiName = slotIndex + +operandType.scopeIndex = Scope stack index +operandType.scopeIndex.description = Index in the scope stack +operandType.scopeIndex.name = scopeIndex +operandType.scopeIndex.uiName = scopeIndex + +operandType.offset = Offset +operandType.offset.description = Offset to other location +operandType.offset.name = offset +operandType.offset.uiName = labelName + +operandType.exceptionIndex = Exception index +operandType.exceptionIndex.description = Index of exception in current method info +operandType.exceptionIndex.name = exceptionIndex +operandType.exceptionIndex.uiName = exceptionIndex + + +operandType.classIndex = Class index +operandType.classIndex.description = Index of class in ABC +operandType.classIndex.name = classIndex +operandType.classIndex.uiName = classIndex + +operandType.intIndex = Int index +operandType.intIndex.description = Index into integer values constant pool +operandType.intIndex.name = intIndex +operandType.intIndex.uiName = int + +operandType.uintIndex = UInt index +operandType.uintIndex.description = Index into unsigned integer values constant pool +operandType.uintIndex.name = uintIndex +operandType.uintIndex.uiName = uint + + +operandType.doubleIndex = Double index +operandType.doubleIndex.description = Index into double precision floating point values constant pool +operandType.doubleIndex.name = doubleIndex +operandType.doubleIndex.uiName = double + +operandType.decimalIndex = Decimal index +operandType.decimalIndex.description = Index into decimal values (128bit floating point) constant pool +operandType.decimalIndex.name = decimalIndex +operandType.decimalIndex.uiName = decimal + +operandType.caseBaseoffset = Base offset +operandType.caseBaseoffset.description = Base offset of lookupswitch triggered when no value matches +operandType.caseBaseoffset.name = offset +operandType.caseBaseoffset.uiName = labelName + +operandType.numberContext = Number context (ES4) +operandType.numberContext.description = Context of calculations when using EcmaScript 4 numerics (ABC minorVersion 17).\nBits 0-2 type,3-5 rounding type, 6-12 precision.\nType: 0=number,1=decimal,2=double,3=int,4=uint\nRounding: 0=ceiling,1=up,2=half_up,3=half_even,4=half_down,5=down,6=floor\nPrecision:0-34 +operandType.numberContext.name = numberContext +operandType.numberContext.uiName = uint + +operandType.dispatchId = Dispatch id +operandType.dispatchId.description = Id of the method dispatch +operandType.dispatchId.name = dispatchId +operandType.dispatchId.uiName = uint + +operandType.floatIndex = Float index +operandType.floatIndex.description = Index into float values constant pool +operandType.floatIndex.name = floatIndex +operandType.floatIndex.uiName = float + +operandType.float4Index = Float4 index +operandType.float4Index.description = Index into float4 values constant pool +operandType.float4Index.name = float4Index +operandType.float4Index.uiName = float4 + +operandType.namespaceIndex = Namespace index +operandType.namespaceIndex = Index into namespace constant pool +operandType.namespaceIndex.name = namespaceIndex +operandType.namespaceIndex.uiName = namespace + + +#----------------------- Instructions + +instruction.bkpt.shortDescription = Breakpoint +instruction.bkpt.description = Breakpoint when debugging +instruction.bkpt.stackBefore = +instruction.bkpt.stackAfter = +instruction.bkpt.operands = + +instruction.nop.shortDescription = No operation +instruction.nop.description = Does nothing +instruction.nop.stackBefore = +instruction.nop.stackAfter = +instruction.nop.operands = + +instruction.throw.shortDescription = Throw exception +instruction.throw.description = Pops value off the stack and throws it +instruction.throw.stackBefore = value +instruction.throw.stackAfter = +instruction.throw.operands = + +instruction.getsuper.shortDescription = Get parent class property +instruction.getsuper.description = +instruction.getsuper.stackBefore = obj, [ns], [name] +instruction.getsuper.stackAfter = value +instruction.getsuper.operands = parentClassMultiname + +instruction.setsuper.shortDescription = Set parent class property +instruction.setsuper.description = +instruction.setsuper.stackBefore = obj, [ns], [name], value +instruction.setsuper.stackAfter = +instruction.setsuper.operands = parentClassMultiname + +instruction.dxns.shortDescription = Set default XML namespace +instruction.dxns.description = +instruction.dxns.stackBefore = +instruction.dxns.stackAfter = +instruction.dxns.operands = uriString + +instruction.dxnslate.shortDescription = Set default XML namespace at runtime +instruction.dxnslate.description = +instruction.dxnslate.stackBefore = uriValue +instruction.dxnslate.stackAfter = +instruction.dxnslate.operands = + +instruction.kill.shortDescription = Kill local register +instruction.kill.description = +instruction.kill.stackBefore = +instruction.kill.stackAfter = +instruction.kill.operands = killedRegister + +instruction.label.shortDescription = Target of a branch +instruction.label.description = Just a mark that this is target of following branch +instruction.label.stackBefore = +instruction.label.stackAfter = +instruction.label.operands = + +instruction.lf32x4.shortDescription = Load 32bit float4 +instruction.lf32x4.description = +instruction.lf32x4.stackBefore = address +instruction.lf32x4.stackAfter = float4Value +instruction.lf32x4.operands = + +instruction.sf32x4.shortDescription = Store 32bit float4 +instruction.sf32x4.description = +instruction.sf32x4.stackBefore = float4Value, address +instruction.sf32x4.stackAfter = +instruction.sf32x4.operands = + +instruction.ifnlt.shortDescription = Branch if not lower than +instruction.ifnlt.description = +instruction.ifnlt.stackBefore = value1, value2 +instruction.ifnlt.stackAfter = +instruction.ifnlt.operands = branchTarget + +instruction.ifnle.shortDescription = Branch if not lower or equal +instruction.ifnle.description = +instruction.ifnle.stackBefore = value1, value2 +instruction.ifnle.stackAfter = +instruction.ifnle.operands = branchTarget + +instruction.ifngt.shortDescription = Branch if not greater than +instruction.ifngt.description = +instruction.ifngt.stackBefore = value1, value2 +instruction.ifngt.stackAfter = +instruction.ifngt.operands = branchTarget + +instruction.ifnge.shortDescription = Branch if not greater ot equal +instruction.ifnge.description = +instruction.ifnge.stackBefore = value1, value2 +instruction.ifnge.stackAfter = +instruction.ifnge.operands = branchTarget + +instruction.jump.shortDescription = Jump to location +instruction.jump.description = +instruction.jump.stackBefore = +instruction.jump.stackAfter = +instruction.jump.operands = location + +instruction.iftrue.shortDescription = Branch if true +instruction.iftrue.description = +instruction.iftrue.stackBefore = value +instruction.iftrue.stackAfter = +instruction.iftrue.operands = branchTarget + +instruction.iffalse.shortDescription = Branch if false +instruction.iffalse.description = +instruction.iffalse.stackBefore = value +instruction.iffalse.stackAfter = +instruction.iffalse.operands = branchTarget + +instruction.ifeq.shortDescription = Branch if equal +instruction.ifeq.description = +instruction.ifeq.stackBefore = value1, value2 +instruction.ifeq.stackAfter = +instruction.ifeq.operands = branchTarget + +instruction.ifne.shortDescription = Branch if not equal +instruction.ifne.description = +instruction.ifne.stackBefore = value1, value2 +instruction.ifne.stackAfter = +instruction.ifne.operands = branchTarget + +instruction.iflt.shortDescription = Branch if lower than +instruction.iflt.description = +instruction.iflt.stackBefore = value1, value2 +instruction.iflt.stackAfter = +instruction.iflt.operands = branchTarget + +instruction.ifle.shortDescription = Branch if lower or equal +instruction.ifle.description = +instruction.ifle.stackBefore = value1, value2 +instruction.ifle.stackAfter = +instruction.ifle.operands = branchTarget + +instruction.ifgt.shortDescription = Branch if greater than +instruction.ifgt.description = +instruction.ifgt.stackBefore = value1, value2 +instruction.ifgt.stackAfter = +instruction.ifgt.operands = branchTarget + +instruction.ifge.shortDescription = Branch if greater or equal +instruction.ifge.description = +instruction.ifge.stackBefore = value1, value2 +instruction.ifge.stackAfter = +instruction.ifge.operands = branchTarget + +instruction.ifstricteq.shortDescription = Branch if strict equal +instruction.ifstricteq.description = +instruction.ifstricteq.stackBefore = value1, value2 +instruction.ifstricteq.stackAfter = +instruction.ifstricteq.operands = branchTarget + +instruction.ifstrictne.shortDescription = Branch if not strict equal +instruction.ifstrictne.description = +instruction.ifstrictne.stackBefore = value1, value2 +instruction.ifstrictne.stackAfter = +instruction.ifstrictne.operands = branchTarget + +instruction.lookupswitch.shortDescription = Branch based on index +instruction.lookupswitch.description = +instruction.lookupswitch.stackBefore = index +instruction.lookupswitch.stackAfter = +instruction.lookupswitch.operands = defaultTarget, caseCount, case0Target, case1Target, ... + +instruction.pushwith.shortDescription = Push with onto scope stack +instruction.pushwith.description = +instruction.pushwith.stackBefore = withScope +instruction.pushwith.stackAfter = +instruction.pushwith.operands = + +instruction.popscope.shortDescription = Pop from scope stack and discard value +instruction.popscope.description = +instruction.popscope.stackBefore = +instruction.popscope.stackAfter = +instruction.popscope.operands = + +instruction.nextname.shortDescription = Get name of next property +instruction.nextname.description = +instruction.nextname.stackBefore = obj, index +instruction.nextname.stackAfter = name +instruction.nextname.operands = + +instruction.hasnext.shortDescription = Check if the object has more properties +instruction.hasnext.description = +instruction.hasnext.stackBefore = obj, currentIndex +instruction.hasnext.stackAfter = nextIndex +instruction.hasnext.operands = + +instruction.pushnull.shortDescription = Push null value on stack +instruction.pushnull.description = +instruction.pushnull.stackBefore = +instruction.pushnull.stackAfter = null +instruction.pushnull.operands = + +instruction.pushundefined.shortDescription = Push undefined value on stack +instruction.pushundefined.description = +instruction.pushundefined.stackBefore = +instruction.pushundefined.stackAfter = undefined +instruction.pushundefined.operands = + +instruction.pushfloat.shortDescription = Push float value on stack +instruction.pushfloat.description = +instruction.pushfloat.stackBefore = +instruction.pushfloat.stackAfter = floatValue +instruction.pushfloat.operands = float + +instruction.nextvalue.shortDescription = Get value of next property +instruction.nextvalue.description = +instruction.nextvalue.stackBefore = obj, index +instruction.nextvalue.stackAfter = value +instruction.nextvalue.operands = + +instruction.pushbyte.shortDescription = Push byte value on stack +instruction.pushbyte.description = +instruction.pushbyte.stackBefore = +instruction.pushbyte.stackAfter = byteValue +instruction.pushbyte.operands = value + +instruction.pushshort.shortDescription = Push short value on stack +instruction.pushshort.description = +instruction.pushshort.stackBefore = +instruction.pushshort.stackAfter = shortValue +instruction.pushshort.operands = value + +instruction.pushtrue.shortDescription = Push true on stack +instruction.pushtrue.description = +instruction.pushtrue.stackBefore = +instruction.pushtrue.stackAfter = true +instruction.pushtrue.operands = + +instruction.pushfalse.shortDescription = Push false on stack +instruction.pushfalse.description = +instruction.pushfalse.stackBefore = +instruction.pushfalse.stackAfter = false +instruction.pushfalse.operands = + +instruction.pushnan.shortDescription = Push NaN value on stack +instruction.pushnan.description = +instruction.pushnan.stackBefore = +instruction.pushnan.stackAfter = NaN +instruction.pushnan.operands = + +instruction.pop.shortDescription = Pop top value from stack +instruction.pop.description = +instruction.pop.stackBefore = value +instruction.pop.stackAfter = +instruction.pop.operands = + +instruction.dup.shortDescription = Duplicate value on stack +instruction.dup.description = +instruction.dup.stackBefore = value +instruction.dup.stackAfter = value, value +instruction.dup.operands = + +instruction.swap.shortDescription = Swap two values on top of the stack +instruction.swap.description = +instruction.swap.stackBefore = value1, value2 +instruction.swap.stackAfter = value2, value1 +instruction.swap.operands = + +instruction.pushstring.shortDescription = Push string value on the stack +instruction.pushstring.description = +instruction.pushstring.stackBefore = +instruction.pushstring.stackAfter = stringValue +instruction.pushstring.operands = value + +instruction.pushint.shortDescription = Push integer value on the stack +instruction.pushint.description = +instruction.pushint.stackBefore = +instruction.pushint.stackAfter = intValue +instruction.pushint.operands = value + +instruction.pushuint.shortDescription = Push unsigned integer value on the stack +instruction.pushuint.description = +instruction.pushuint.stackBefore = +instruction.pushuint.stackAfter = uintValue +instruction.pushuint.operands = value + +instruction.pushdouble.shortDescription = Push double precision value on the stack +instruction.pushdouble.description = +instruction.pushdouble.stackBefore = +instruction.pushdouble.stackAfter = doubleValue +instruction.pushdouble.operands = value + +instruction.pushscope.shortDescription = Push object on the scope stack +instruction.pushscope.description = +instruction.pushscope.stackBefore = obj +instruction.pushscope.stackAfter = +instruction.pushscope.operands = + +instruction.pushnamespace.shortDescription = Push namespace on the stack +instruction.pushnamespace.description = +instruction.pushnamespace.stackBefore = +instruction.pushnamespace.stackAfter = namespace +instruction.pushnamespace.operands = value + +instruction.hasnext2.shortDescription = Check if the object has more properties (register based) +instruction.hasnext2.description = +instruction.hasnext2.stackBefore = +instruction.hasnext2.stackAfter = boolValue +instruction.hasnext2.operands = objectReg, indexReg + +instruction.pushdecimal.shortDescription = Push decimal value on the stack +instruction.pushdecimal.description = +instruction.pushdecimal.stackBefore = +instruction.pushdecimal.stackAfter = decimalValue +instruction.pushdecimal.operands = value + +#Undocumented: +instruction.pushdnan.shortDescription = Push decimal NaN value on the stack +instruction.pushdnan.description = +#instruction.pushdnan.stackBefore = +#instruction.pushdnan.stackAfter = +instruction.pushdnan.operands = + +instruction.li8.shortDescription = Load 8bit integer value +instruction.li8.description = +instruction.li8.stackBefore = address +instruction.li8.stackAfter = int8Value +instruction.li8.operands = + +instruction.li16.shortDescription = Load 16bit integer value +instruction.li16.description = +instruction.li16.stackBefore = address +instruction.li16.stackAfter = int16Value +instruction.li16.operands = + +instruction.li32.shortDescription = Load 32bit integer value +instruction.li32.description = +instruction.li32.stackBefore = address +instruction.li32.stackAfter = int32Value +instruction.li32.operands = + +instruction.lf32.shortDescription = Load 32bit float value +instruction.lf32.description = +instruction.lf32.stackBefore = address +instruction.lf32.stackAfter = float32Value +instruction.lf32.operands = + +instruction.lf64.shortDescription = Load 64bit float value +instruction.lf64.description = +instruction.lf64.stackBefore = address +instruction.lf64.stackAfter = float64Value +instruction.lf64.operands = + +instruction.si8.shortDescription = Store 8bit integer value +instruction.si8.description = +instruction.si8.stackBefore = value, address +instruction.si8.stackAfter = +instruction.si8.operands = + +instruction.si16.shortDescription = Store 16bit integer value +instruction.si16.description = +instruction.si16.stackBefore = value, address +instruction.si16.stackAfter = +instruction.si16.operands = + +instruction.si32.shortDescription = Store 32bit integer value +instruction.si32.description = +instruction.si32.stackBefore = value, address +instruction.si32.stackAfter = +instruction.si32.operands = + +instruction.sf32.shortDescription = Store 32bit float value +instruction.sf32.description = +instruction.sf32.stackBefore = value, address +instruction.sf32.stackAfter = +instruction.sf32.operands = + +instruction.sf64.shortDescription = Store 64bit float value +instruction.sf64.description = +instruction.sf64.stackBefore = value, address +instruction.sf64.stackAfter = +instruction.sf64.operands = + +instruction.newfunction.shortDescription = Create new Function object +instruction.newfunction.description = +instruction.newfunction.stackBefore = +instruction.newfunction.stackAfter = function +instruction.newfunction.operands = method + +instruction.call.shortDescription = Call function on the stack +instruction.call.description = +instruction.call.stackBefore = function, this, arg1, ..., argN +instruction.call.stackAfter = value +instruction.call.operands = argCount + +instruction.construct.shortDescription = Call constructor function on the stack +instruction.construct.description = +instruction.construct.stackBefore = function, arg1, ..., argN +instruction.construct.stackAfter = value +instruction.construct.operands = argCount + +instruction.callmethod.shortDescription = Call method of object by dispatch id +instruction.callmethod.description = +instruction.callmethod.stackBefore = this, arg1, ..., argN +instruction.callmethod.stackAfter = value +instruction.callmethod.operands = method, argCount + +instruction.callstatic.shortDescription = Call method by method id in ABC file +instruction.callstatic.description = +instruction.callstatic.stackBefore = this, arg1, ..., argN +instruction.callstatic.stackAfter = value +instruction.callstatic.operands = method, argCount + +instruction.callsuper.shortDescription = Call method on parent class +instruction.callsuper.description = +instruction.callsuper.stackBefore = obj, [ns], [name], arg1, ..., argN +instruction.callsuper.stackAfter = value +instruction.callsuper.operands = methodName, argCount + +instruction.callproperty.shortDescription = Call property +instruction.callproperty.description = +instruction.callproperty.stackBefore = obj, [ns], [name], arg1, ..., argN +instruction.callproperty.stackAfter = value +instruction.callproperty.operands = property, argCount + +instruction.returnvoid.shortDescription = Return from a method +instruction.returnvoid.description = +instruction.returnvoid.stackBefore = +instruction.returnvoid.stackAfter = +instruction.returnvoid.operands = + +instruction.returnvalue.shortDescription = Return value from a method +instruction.returnvalue.description = +instruction.returnvalue.stackBefore = value +instruction.returnvalue.stackAfter = +instruction.returnvalue.operands = + +instruction.constructsuper.shortDescription = Call parent constructor of an object +instruction.constructsuper.description = +instruction.constructsuper.stackBefore = obj, arg1, ..., argN +instruction.constructsuper.stackAfter = +instruction.constructsuper.operands = argCount + +instruction.constructprop.shortDescription = Construct a property of an object +instruction.constructprop.description = +instruction.constructprop.stackBefore = obj, [ns], [name], arg1, ..., argN +instruction.constructprop.stackAfter = value +instruction.constructprop.operands = property, argCount + +#Undocumented: +instruction.callsuperid.shortDescription = Call super id +instruction.callsuperid.description = +#instruction.callsuperid.stackBefore = +#instruction.callsuperid.stackAfter = +#instruction.callsuperid.operands = + +instruction.callproplex.shortDescription = Call property with null as this +instruction.callproplex.description = +instruction.callproplex.stackBefore = obj, [ns], [name], arg1, ..., argN +instruction.callproplex.stackAfter = value +instruction.callproplex.operands = property, argCount + +#Undocumented: +instruction.callinterface.shortDescription = Call interface +instruction.callinterface.description = +#instruction.callinterface.stackBefore = +#instruction.callinterface.stackAfter = +instruction.callinterface.operands = interface, argCount + + +instruction.callsupervoid.shortDescription = Call method on parent class, discard return value +instruction.callsupervoid.description = +instruction.callsupervoid.stackBefore = obj, [ns], [name], arg1, ..., argN +instruction.callsupervoid.stackAfter = +instruction.callsupervoid.operands = methodName, argCount + + +instruction.callpropvoid.shortDescription = Call property, discard return value +instruction.callpropvoid.description = +instruction.callpropvoid.stackBefore = obj, [ns], [name], arg1, ..., argN +instruction.callpropvoid.stackAfter = +instruction.callpropvoid.operands = property, argCount + +instruction.sxi1.shortDescription = Sign extend 1bit value to 32bits +instruction.sxi1.description = +instruction.sxi1.stackBefore = value +instruction.sxi1.stackAfter = valueExtended +instruction.sxi1.operands = + +instruction.sxi8.shortDescription = Sign extend 8bit value to 32bits +instruction.sxi8.description = +instruction.sxi8.stackBefore = value +instruction.sxi8.stackAfter = valueExtended +instruction.sxi8.operands = + +instruction.sxi16.shortDescription = Sign extend 16bit value to 32bits +instruction.sxi16.description = +instruction.sxi16.stackBefore = value +instruction.sxi16.stackAfter = valueExtended +instruction.sxi16.operands = + +instruction.applytype.shortDescription = Apply type parameters +instruction.applytype.description = Apply parameter types to base type. For example when Vector is resolved at runtime. String is parameter, Vector is baseclass. +instruction.applytype.stackBefore = baseType, typeParam1, ..., typeParamN +instruction.applytype.stackAfter = baseType +instruction.applytype.operands = typeParamCount + +instruction.pushfloat4.shortDescription = Push float4 value on the stack +instruction.pushfloat4.description = +instruction.pushfloat4.stackBefore = +instruction.pushfloat4.stackAfter = float4Value +instruction.pushfloat4.operands = float4 + +instruction.newobject.shortDescription = Creates new object +instruction.newobject.description = +instruction.newobject.stackBefore = name1, value1, name2, value2, ..., nameN, valueN +instruction.newobject.stackAfter = newObject +instruction.newobject.operands = propertyCount + +instruction.newarray.shortDescription = Creates new array +instruction.newarray.description = +instruction.newarray.stackBefore = value1, value2, ..., valueN +instruction.newarray.stackAfter = newArray +instruction.newarray.operands = valueCount + +instruction.newactivation.shortDescription = Creates new activation object +instruction.newactivation.description = +instruction.newactivation.stackBefore = +instruction.newactivation.stackAfter = newActivation +instruction.newactivation.operands = + +instruction.newclass.shortDescription = Creates new class +instruction.newclass.description = +instruction.newclass.stackBefore = baseType +instruction.newclass.stackAfter = newClass +instruction.newclass.operands = class + +instruction.getdescendants.shortDescription = Get descendants +instruction.getdescendants.description = +instruction.getdescendants.stackBefore = obj, [ns], [name] +instruction.getdescendants.stackAfter = value +instruction.getdescendants.operands = operand1 + +instruction.newcatch.shortDescription = Create new catch scope +instruction.newcatch.description = +instruction.newcatch.stackBefore = +instruction.newcatch.stackAfter = catchScope +instruction.newcatch.operands = exception + +#Undocumented: +instruction.deldescendants.shortDescription = Delete descendants +instruction.deldescendants.description = +#instruction.deldescendants.stackBefore = +#instruction.deldescendants.stackAfter = +instruction.deldescendants.operands = + +#Undocumented: +instruction.findpropglobal.shortDescription = Search property in global scope +instruction.findpropglobal.description = +instruction.findpropglobal.stackBefore = [ns], [name] +instruction.findpropglobal.stackAfter = obj +instruction.findpropglobal.operands = property + +instruction.findpropstrict.shortDescription = Search property in scope stack, error when not found +instruction.findpropstrict.description = +instruction.findpropstrict.stackBefore = [ns], [name] +instruction.findpropstrict.stackAfter = obj +instruction.findpropstrict.operands = property + +instruction.findproperty.shortDescription = Search property in scope stack, top object when not found +instruction.findproperty.description = +instruction.findproperty.stackBefore = [ns], [name] +instruction.findproperty.stackAfter = obj +instruction.findproperty.operands = property + +#Undocumented: +instruction.finddef.shortDescription = Search script level definition +instruction.finddef.description = +instruction.finddef.stackBefore = [ns], [name] +instruction.finddef.stackAfter = obj +instruction.finddef.operands = property + +instruction.getlex.shortDescription = Find and get property +instruction.getlex.description = +instruction.getlex.stackBefore = +instruction.getlex.stackAfter = obj +instruction.getlex.operands = property + +instruction.setproperty.shortDescription = Set property +instruction.setproperty.description = +instruction.setproperty.stackBefore = obj, [ns], [name], value +instruction.setproperty.stackAfter = +instruction.setproperty.operands = property + +instruction.getlocal.shortDescription = Get local register value +instruction.getlocal.description = +instruction.getlocal.stackBefore = +instruction.getlocal.stackAfter = value +instruction.getlocal.operands = localRegIndex + +instruction.setlocal.shortDescription = Set local register value +instruction.setlocal.description = +instruction.setlocal.stackBefore = value +instruction.setlocal.stackAfter = +instruction.setlocal.operands = localRegIndex + +instruction.getglobalscope.shortDescription = Get global scope +instruction.getglobalscope.description = +instruction.getglobalscope.stackBefore = +instruction.getglobalscope.stackAfter = obj +instruction.getglobalscope.operands = + +instruction.getscopeobject.shortDescription = Get scope object +instruction.getscopeobject.description = +instruction.getscopeobject.stackBefore = +instruction.getscopeobject.stackAfter = obj +instruction.getscopeobject.operands = scopeIndex + +instruction.getproperty.shortDescription = Get property +instruction.getproperty.description = +instruction.getproperty.stackBefore = obj, [ns], [name] +instruction.getproperty.stackAfter = value +instruction.getproperty.operands = property + +instruction.getouterscope.shortDescription = Get scope object on all levels +instruction.getouterscope.description = +instruction.getouterscope.stackBefore = +instruction.getouterscope.stackAfter = obj +instruction.getouterscope.operands = allLevelScopeIndex + +instruction.initproperty.shortDescription = Initialize property +instruction.initproperty.description = +instruction.initproperty.stackBefore = obj, [ns], [name], value +instruction.initproperty.stackAfter = +instruction.initproperty.operands = property + +#Undocumented: +instruction.setpropertylate.shortDescription = Set property (stack based) +instruction.setpropertylate.description = +#instruction.setpropertylate.stackBefore = +#instruction.setpropertylate.stackAfter = +#instruction.setpropertylate.operands = + +instruction.deleteproperty.shortDescription = Delete property +instruction.deleteproperty.description = +instruction.deleteproperty.stackBefore = obj, [ns], [name] +instruction.deleteproperty.stackAfter = boolResult +instruction.deleteproperty.operands = property + +#Undocumented: +instruction.deletepropertylate.shortDescription = Delete property (stack based) +instruction.deletepropertylate.description = +#instruction.deletepropertylate.stackBefore = +#instruction.deletepropertylate.stackAfter = +instruction.deletepropertylate.operands = + +instruction.getslot.shortDescription = Get value of a slot +instruction.getslot.description = +instruction.getslot.stackBefore = obj +instruction.getslot.stackAfter = value +instruction.getslot.operands = slotIndex + +instruction.setslot.shortDescription = Set value of a slot +instruction.setslot.description = +instruction.setslot.stackBefore = obj, value +instruction.setslot.stackAfter = +instruction.setslot.operands = slotIndex + +instruction.getglobalslot.shortDescription = Get value of slot on global scope +instruction.getglobalslot.description = +instruction.getglobalslot.stackBefore = +instruction.getglobalslot.stackAfter = value +instruction.getglobalslot.operands = slotIndex + +instruction.setglobalslot.shortDescription = Set value of slot on global scope +instruction.setglobalslot.description = +instruction.setglobalslot.stackBefore = value +instruction.setglobalslot.stackAfter = +instruction.setglobalslot.operands = slotIndex + +instruction.convert_s.shortDescription = Convert value to string +instruction.convert_s.description = +instruction.convert_s.stackBefore = value +instruction.convert_s.stackAfter = stringValue +instruction.convert_s.operands = + +instruction.esc_xelem.shortDescription = Escape XML element +instruction.esc_xelem.description = +instruction.esc_xelem.stackBefore = value +instruction.esc_xelem.stackAfter = stringValue +instruction.esc_xelem.operands = + +instruction.esc_xattr.shortDescription = Escape XML attribute +instruction.esc_xattr.description = +instruction.esc_xattr.stackBefore = value +instruction.esc_xattr.stackAfter = stringValue +instruction.esc_xattr.operands = + +instruction.convert_i.shortDescription = Convert value to integer +instruction.convert_i.description = +instruction.convert_i.stackBefore = value +instruction.convert_i.stackAfter = intValue +instruction.convert_i.operands = + +instruction.convert_u.shortDescription = Convert value to unsigned integer +instruction.convert_u.description = +instruction.convert_u.stackBefore = value +instruction.convert_u.stackAfter = uintValue +instruction.convert_u.operands = + +instruction.convert_d.shortDescription = Convert value to double +instruction.convert_d.description = +instruction.convert_d.stackBefore = value +instruction.convert_d.stackAfter = doubleValue +instruction.convert_d.operands = + +instruction.convert_b.shortDescription = Convert value to boolean +instruction.convert_b.description = +instruction.convert_b.stackBefore = value +instruction.convert_b.stackAfter = booleanValue +instruction.convert_b.operands = + +instruction.convert_o.shortDescription = Convert value to Object +instruction.convert_o.description = +instruction.convert_o.stackBefore = value +instruction.convert_o.stackAfter = value +instruction.convert_o.operands = + +instruction.checkfilter.shortDescription = Check that object can have filter operation applied +instruction.checkfilter.description = +instruction.checkfilter.stackBefore = value +instruction.checkfilter.stackAfter = value +instruction.checkfilter.operands = + +instruction.convert_m.shortDescription = Convert value to decimal +instruction.convert_m.description = +instruction.convert_m.stackBefore = value +instruction.convert_m.stackAfter = decimalValue +instruction.convert_m.operands = + +instruction.convert_m_p.shortDescription = Convert value to decimal with number context +instruction.convert_m_p.description = +instruction.convert_m_p.stackBefore = value +instruction.convert_m_p.stackAfter = decimalValue +instruction.convert_m_p.operands = numberContext + +instruction.convert_f.shortDescription = Convert value to float +instruction.convert_f.description = +instruction.convert_f.stackBefore = value +instruction.convert_f.stackAfter = floatValue +instruction.convert_f.operands = + +instruction.convert_f4.shortDescription = Convert value to float4 +instruction.convert_f4.description = +instruction.convert_f4.stackBefore = value +instruction.convert_f4.stackAfter = float4Value +instruction.convert_f4.operands = + +instruction.coerce.shortDescription = Coerce value to specified type +instruction.coerce.description = +instruction.coerce.stackBefore = value +instruction.coerce.stackAfter = coercedValue +instruction.coerce.operands = type + +instruction.coerce_b.shortDescription = Coerce value to boolean +instruction.coerce_b.description = +instruction.coerce_b.stackBefore = value +instruction.coerce_b.stackAfter = booleanValue +instruction.coerce_b.operands = +instruction.coerce_b.deprecated = Use convert_b instead + +instruction.coerce_a.shortDescription = Coerce value to any type +instruction.coerce_a.description = +instruction.coerce_a.stackBefore = value +instruction.coerce_a.stackAfter = value +instruction.coerce_a.operands = + +instruction.coerce_i.shortDescription = Coerce value to integer +instruction.coerce_i.description = +instruction.coerce_i.stackBefore = value +instruction.coerce_i.stackAfter = intValue +instruction.coerce_i.operands = +instruction.coerce_i.deprecated = Use convert_i instead + +instruction.coerce_d.shortDescription = Coerce value to double +instruction.coerce_d.description = +instruction.coerce_d.stackBefore = value +instruction.coerce_d.stackAfter = doubleValue +instruction.coerce_d.operands = +instruction.coerce_d.deprecated = Use convert_d instead + +instruction.coerce_s.shortDescription = Coerce value to string +instruction.coerce_s.description = +instruction.coerce_s.stackBefore = value +instruction.coerce_s.stackAfter = stringValue +instruction.coerce_s.operands = + +instruction.astype.shortDescription = Return same value or null if not specified type +instruction.astype.description = +instruction.astype.stackBefore = value +instruction.astype.stackAfter = value +instruction.astype.operands = type + +instruction.astypelate.shortDescription = Return same value or null if not specified type (stack based) +instruction.astypelate.description = +instruction.astypelate.stackBefore = value, type +instruction.astypelate.stackAfter = value +instruction.astypelate.operands = + +instruction.coerce_u.shortDescription = Coerce value to unsigned integer +instruction.coerce_u.description = +instruction.coerce_u.stackBefore = value +instruction.coerce_u.stackAfter = uintValue +instruction.coerce_u.operands = + +instruction.coerce_o.shortDescription = Coerce value to Object +instruction.coerce_o.description = +instruction.coerce_o.stackBefore = value +instruction.coerce_o.stackAfter = value +instruction.coerce_o.operands = + +instruction.negate_p.shortDescription = Negate value using number context +instruction.negate_p.description = +instruction.negate_p.stackBefore = value +instruction.negate_p.stackAfter = -value +instruction.negate_p.operands = operand1 + +instruction.negate.shortDescription = Negate value +instruction.negate.description = +instruction.negate.stackBefore = value +instruction.negate.stackAfter = -value +instruction.negate.operands = + +instruction.increment.shortDescription = Increment value +instruction.increment.description = +instruction.increment.stackBefore = value +instruction.increment.stackAfter = incrementedValue +instruction.increment.operands = + +instruction.inclocal.shortDescription = Increment local register +instruction.inclocal.description = +instruction.inclocal.stackBefore = +instruction.inclocal.stackAfter = +instruction.inclocal.operands = localRegister + +instruction.decrement.shortDescription = Decrement value +instruction.decrement.description = +instruction.decrement.stackBefore = value +instruction.decrement.stackAfter = decrementedValue +instruction.decrement.operands = + +instruction.declocal.shortDescription = Decrement local register +instruction.declocal.description = +instruction.declocal.stackBefore = +instruction.declocal.stackAfter = +instruction.declocal.operands = localRegister + +instruction.typeof.shortDescription = Get name of value type +instruction.typeof.description = +instruction.typeof.stackBefore = value +instruction.typeof.stackAfter = typeName +instruction.typeof.operands = + +instruction.not.shortDescription = Boolean negate +instruction.not.description = +instruction.not.stackBefore = value +instruction.not.stackAfter = !value +instruction.not.operands = + +instruction.bitnot.shortDescription = Bitwise negate +instruction.bitnot.description = +instruction.bitnot.stackBefore = value +instruction.bitnot.stackAfter = ~value +instruction.bitnot.operands = + +#Undocumented: +instruction.concat.shortDescription = Concat +instruction.concat.description = +#instruction.concat.stackBefore = +#instruction.concat.stackAfter = +#instruction.concat.operands = + +#Undocumented: +instruction.add_d.shortDescription = Add_d +instruction.add_d.description = +#instruction.add_d.stackBefore = +#instruction.add_d.stackAfter = +#instruction.add_d.operands = + +instruction.increment_p.shortDescription = Increment value using number context +instruction.increment_p.description = +instruction.increment_p.stackBefore = value +instruction.increment_p.stackAfter = incrementedValue +instruction.increment_p.operands = numberContext + +instruction.inclocal_p.shortDescription = Increment local register using number context +instruction.inclocal_p.description = +instruction.inclocal_p.stackBefore = +instruction.inclocal_p.stackAfter = +instruction.inclocal_p.operands = numberContext, localRegister + +instruction.decrement_p.shortDescription = Decrement value using number context +instruction.decrement_p.description = +instruction.decrement_p.stackBefore = value +instruction.decrement_p.stackAfter = decrementedValue +instruction.decrement_p.operands = numberContext + +instruction.declocal_p.shortDescription = Decrement local register using number context +instruction.declocal_p.description = +instruction.declocal_p.stackBefore = +instruction.declocal_p.stackAfter = +instruction.declocal_p.operands = numberContext, localRegister + +instruction.add.shortDescription = Add two values +instruction.add.description = +instruction.add.stackBefore = value1, value2 +instruction.add.stackAfter = value3 +instruction.add.operands = + +instruction.subtract.shortDescription = Subtract two values +instruction.subtract.description = +instruction.subtract.stackBefore = value1, value2 +instruction.subtract.stackAfter = value3 +instruction.subtract.operands = + +instruction.multiply.shortDescription = Multiply two values +instruction.multiply.description = +instruction.multiply.stackBefore = value1, value2 +instruction.multiply.stackAfter = value3 +instruction.multiply.operands = + +instruction.divide.shortDescription = Divide two values +instruction.divide.description = +instruction.divide.stackBefore = value1, value2 +instruction.divide.stackAfter = value3 +instruction.divide.operands = + +instruction.modulo.shortDescription = Modulo divide two values +instruction.modulo.description = +instruction.modulo.stackBefore = value1, value2 +instruction.modulo.stackAfter = value3 +instruction.modulo.operands = + +instruction.lshift.shortDescription = Bitwise left shift +instruction.lshift.description = +instruction.lshift.stackBefore = value1, value2 +instruction.lshift.stackAfter = value3 +instruction.lshift.operands = + +instruction.rshift.shortDescription = Bitwise right shift +instruction.rshift.description = +instruction.rshift.stackBefore = value1, value2 +instruction.rshift.stackAfter = value3 +instruction.rshift.operands = + +instruction.urshift.shortDescription = Unsigned bitwise right shift +instruction.urshift.description = +instruction.urshift.stackBefore = value1, value2 +instruction.urshift.stackAfter = value3 +instruction.urshift.operands = + +instruction.bitand.shortDescription = Bitwise and +instruction.bitand.description = +instruction.bitand.stackBefore = value1, value2 +instruction.bitand.stackAfter = value3 +instruction.bitand.operands = + +instruction.bitor.shortDescription = Bitwise or +instruction.bitor.description = +instruction.bitor.stackBefore = value1, value2 +instruction.bitor.stackAfter = value3 +instruction.bitor.operands = + +instruction.bitxor.shortDescription = Bitwise xor +instruction.bitxor.description = +instruction.bitxor.stackBefore = value1, value2 +instruction.bitxor.stackAfter = value3 +instruction.bitxor.operands = + +instruction.equals.shortDescription = Compare two values +instruction.equals.description = +instruction.equals.stackBefore = value1, value2 +instruction.equals.stackAfter = booleanResult +instruction.equals.operands = + +instruction.strictequals.shortDescription = Strict compare two values +instruction.strictequals.description = +instruction.strictequals.stackBefore = value1, value2 +instruction.strictequals.stackAfter = booleanResult +instruction.strictequals.operands = + +instruction.lessthan.shortDescription = Check that value is less than other value +instruction.lessthan.description = +instruction.lessthan.stackBefore = value1, value2 +instruction.lessthan.stackAfter = booleanResult +instruction.lessthan.operands = + +instruction.lessequals.shortDescription = Check that value is less or equal than other value +instruction.lessequals.description = +instruction.lessequals.stackBefore = value1, value2 +instruction.lessequals.stackAfter = booleanResult +instruction.lessequals.operands = booleanResult + +instruction.greaterthan.shortDescription = Check that value is greater or equal than other value +instruction.greaterthan.description = +instruction.greaterthan.stackBefore = value1, value2 +instruction.greaterthan.stackAfter = booleanResult +instruction.greaterthan.operands = + +instruction.greaterequals.shortDescription = Check that value is greater or equal than other value +instruction.greaterequals.description = +instruction.greaterequals.stackBefore = value1, value2 +instruction.greaterequals.stackAfter = booleanResult +instruction.greaterequals.operands = + +instruction.instanceof.shortDescription = Check that type exists in object prototype chain +instruction.instanceof.description = +instruction.instanceof.stackBefore = value, type +instruction.instanceof.stackAfter = booleanResult +instruction.instanceof.operands = + +instruction.istype.shortDescription = Check that object is of specified type +instruction.istype.description = +instruction.istype.stackBefore = value +instruction.istype.stackAfter = booleanResult +instruction.istype.operands = type + +instruction.istypelate.shortDescription = Check that object is of specified type (stack based) +instruction.istypelate.description = +instruction.istypelate.stackBefore = value, type +instruction.istypelate.stackAfter = booleanResult +instruction.istypelate.operands = + +instruction.in.shortDescription = Check that object has named property +instruction.in.description = +instruction.in.stackBefore = name, obj +instruction.in.stackAfter = booleanResult +instruction.in.operands = + +instruction.add_p.shortDescription = Add two values using number context +instruction.add_p.description = +instruction.add_p.stackBefore = value1, value2 +instruction.add_p.stackAfter = value3 +instruction.add_p.operands = numberContext + +instruction.subtract_p.shortDescription = Subtract two values using number context +instruction.subtract_p.description = +instruction.subtract_p.stackBefore = value1, value2 +instruction.subtract_p.stackAfter = value3 +instruction.subtract_p.operands = numberContext + +instruction.multiply_p.shortDescription = Multiply two values using number context +instruction.multiply_p.description = +instruction.multiply_p.stackBefore = value1, value2 +instruction.multiply_p.stackAfter = value3 +instruction.multiply_p.operands = numberContext + +instruction.divide_p.shortDescription = Divide two values using number context +instruction.divide_p.description = +instruction.divide_p.stackBefore = value1, value2 +instruction.divide_p.stackAfter = value3 +instruction.divide_p.operands = numberContext + +instruction.modulo_p.shortDescription = Modulo divide two values using number context +instruction.modulo_p.description = +instruction.modulo_p.stackBefore = value1, value2 +instruction.modulo_p.stackAfter = value3 +instruction.modulo_p.operands = numberContext + +instruction.increment_i.shortDescription = Increment integer value +instruction.increment_i.description = +instruction.increment_i.stackBefore = value +instruction.increment_i.stackAfter = incrementedValue +instruction.increment_i.operands = + +instruction.decrement_i.shortDescription = Decrement integer value +instruction.decrement_i.description = +instruction.decrement_i.stackBefore = value +instruction.decrement_i.stackAfter = decrementedValue +instruction.decrement_i.operands = + +instruction.inclocal_i.shortDescription = Increment local register integer value +instruction.inclocal_i.description = +instruction.inclocal_i.stackBefore = +instruction.inclocal_i.stackAfter = +instruction.inclocal_i.operands = localRegister + +instruction.declocal_i.shortDescription = Decrement local register integer value +instruction.declocal_i.description = +instruction.declocal_i.stackBefore = +instruction.declocal_i.stackAfter = +instruction.declocal_i.operands = localRegister + +instruction.negate_i.shortDescription = Negate integer value +instruction.negate_i.description = +instruction.negate_i.stackBefore = value +instruction.negate_i.stackAfter = -value +instruction.negate_i.operands = + +instruction.add_i.shortDescription = Add two integer values +instruction.add_i.description = +instruction.add_i.stackBefore = value1, value2 +instruction.add_i.stackAfter = value3 +instruction.add_i.operands = + +instruction.subtract_i.shortDescription = Subtract two integer values +instruction.subtract_i.description = +instruction.subtract_i.stackBefore = value1, value2 +instruction.subtract_i.stackAfter = value3 +instruction.subtract_i.operands = + +instruction.multiply_i.shortDescription = Multiply two integer values +instruction.multiply_i.description = +instruction.multiply_i.stackBefore = value1, value2 +instruction.multiply_i.stackAfter = value3 +instruction.multiply_i.operands = + +instruction.getlocal_0.shortDescription = Get local register 0 +instruction.getlocal_0.description = +instruction.getlocal_0.stackBefore = +instruction.getlocal_0.stackAfter = value +instruction.getlocal_0.operands = + +instruction.getlocal_1.shortDescription = Get local register 1 +instruction.getlocal_1.description = +instruction.getlocal_1.stackBefore = +instruction.getlocal_1.stackAfter = value +instruction.getlocal_1.operands = + +instruction.getlocal_2.shortDescription = Get local register 2 +instruction.getlocal_2.description = +instruction.getlocal_2.stackBefore = +instruction.getlocal_2.stackAfter = value +instruction.getlocal_2.operands = + +instruction.getlocal_3.shortDescription = Get local register 3 +instruction.getlocal_3.description = +instruction.getlocal_3.stackBefore = +instruction.getlocal_3.stackAfter = value +instruction.getlocal_3.operands = + +instruction.setlocal_0.shortDescription = Set local register 0 +instruction.setlocal_0.description = +instruction.setlocal_0.stackBefore = value +instruction.setlocal_0.stackAfter = +instruction.setlocal_0.operands = + +instruction.setlocal_1.shortDescription = Set local register 1 +instruction.setlocal_1.description = +instruction.setlocal_1.stackBefore = value +instruction.setlocal_1.stackAfter = +instruction.setlocal_1.operands = + +instruction.setlocal_2.shortDescription = Set local register 2 +instruction.setlocal_2.description = +instruction.setlocal_2.stackBefore = value +instruction.setlocal_2.stackAfter = +instruction.setlocal_2.operands = + +instruction.setlocal_3.shortDescription = Set local register 3 +instruction.setlocal_3.description = +instruction.setlocal_3.stackBefore = value +instruction.setlocal_3.stackAfter = +instruction.setlocal_3.operands = + +#Undocumented: +instruction.invalid.shortDescription = Invalid +instruction.invalid.description = +#instruction.invalid.stackBefore = +#instruction.invalid.stackAfter = +#instruction.invalid.operands = + +#Undocumented: +instruction.abs_jump.shortDescription = Absolute jump +instruction.abs_jump.description = +#instruction.abs_jump.stackBefore = +#instruction.abs_jump.stackAfter = +#instruction.abs_jump.operands = + +instruction.debug.shortDescription = Debugging info +instruction.debug.description = +instruction.debug.stackBefore = +instruction.debug.stackAfter = +instruction.debug.operands = debugType, regName, localRegister, extra + +instruction.debugline.shortDescription = Debugging line number info +instruction.debugline.description = +instruction.debugline.stackBefore = +instruction.debugline.stackAfter = +instruction.debugline.operands = lineNumber + +instruction.debugfile.shortDescription = Debugging file info +instruction.debugfile.description = +instruction.debugfile.stackBefore = +instruction.debugfile.stackAfter = +instruction.debugfile.operands = fileName + +instruction.bkptline.shortDescription = Breakpoint on line +instruction.bkptline.description = +instruction.bkptline.stackBefore = +instruction.bkptline.stackAfter = +instruction.bkptline.operands = lineNumber + +#Undocumented: +instruction.timestamp.shortDescription = Timestamp +instruction.timestamp.description = +instruction.timestamp.stackBefore = +instruction.timestamp.stackAfter = +instruction.timestamp.operands = + +#Undocumented: +instruction.verifypass.shortDescription = Verify pass +instruction.verifypass.description = +#instruction.verifypass.stackBefore = +#instruction.verifypass.stackAfter = +#instruction.verifypass.operands = + +#Undocumented: +instruction.alloc.shortDescription = Alloc +instruction.alloc.description = +#instruction.alloc.stackBefore = +#instruction.alloc.stackAfter = +#instruction.alloc.operands = + +#Undocumented: +instruction.mark.shortDescription = Mark +instruction.mark.description = +#instruction.mark.stackBefore = +#instruction.mark.stackAfter = +#instruction.mark.operands = + +#Undocumented: +instruction.wb.shortDescription = Wb +instruction.wb.description = +#instruction.wb.stackBefore = +#instruction.wb.stackAfter = +#instruction.wb.operands = + +#Undocumented: +instruction.prologue.shortDescription = Prologue +instruction.prologue.description = +#instruction.prologue.stackBefore = +#instruction.prologue.stackAfter = +#instruction.prologue.operands = + +#Undocumented: +instruction.sendenter.shortDescription = Send enter +instruction.sendenter.description = +#instruction.sendenter.stackBefore = +#instruction.sendenter.stackAfter = +#instruction.sendenter.operands = + +#Undocumented: +instruction.doubletoatom.shortDescription = Double to atom +instruction.doubletoatom.description = +#instruction.doubletoatom.stackBefore = +#instruction.doubletoatom.stackAfter = +#instruction.doubletoatom.operands = + +#Undocumented: +instruction.sweep.shortDescription = Sweep +instruction.sweep.description = +#instruction.sweep.stackBefore = +#instruction.sweep.stackAfter = +#instruction.sweep.operands = + +#Undocumented: +instruction.codegenop.shortDescription = CodeGenOp +instruction.codegenop.description = +#instruction.codegenop.stackBefore = +#instruction.codegenop.stackAfter = +#instruction.codegenop.operands = + +#Undocumented: +instruction.verifyop.shortDescription = VerifyOp +instruction.verifyop.description = +#instruction.verifyop.stackBefore = +#instruction.verifyop.stackAfter = +#instruction.verifyop.operands = + +#Undocumented: +instruction.decode.shortDescription = Decode +instruction.decode.description = +#instruction.decode.stackBefore = +#instruction.decode.stackAfter = +#instruction.decode.operands = + + +instruction.unplus.shortDescription = Unary plus - coerce to numeric +instruction.unplus.description = +instruction.unplus.stackBefore = value +instruction.unplus.stackAfter = value +instruction.unplus.operands = + +instruction.pushconstant.shortDescription = Push constant value on stack +instruction.pushconstant.description = +#instruction.pushconstant.stackBefore = +#instruction.pushconstant.stackAfter = instruction.pushconstant.operands = value \ No newline at end of file diff --git a/src/com/jpexs/decompiler/flash/gui/ImagePanel.java b/src/com/jpexs/decompiler/flash/gui/ImagePanel.java index 08ec2452a..b75b8fcb4 100644 --- a/src/com/jpexs/decompiler/flash/gui/ImagePanel.java +++ b/src/com/jpexs/decompiler/flash/gui/ImagePanel.java @@ -1,1437 +1,1437 @@ -/* - * 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.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.action.Action; -import com.jpexs.decompiler.flash.action.LocalDataArea; -import com.jpexs.decompiler.flash.action.Stage; -import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.decompiler.flash.ecma.Undefined; -import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; -import com.jpexs.decompiler.flash.gui.player.MediaDisplay; -import com.jpexs.decompiler.flash.gui.player.MediaDisplayListener; -import com.jpexs.decompiler.flash.gui.player.Zoom; -import com.jpexs.decompiler.flash.tags.DefineButtonSoundTag; -import com.jpexs.decompiler.flash.tags.DoActionTag; -import com.jpexs.decompiler.flash.tags.base.BoundedTag; -import com.jpexs.decompiler.flash.tags.base.ButtonTag; -import com.jpexs.decompiler.flash.tags.base.CharacterTag; -import com.jpexs.decompiler.flash.tags.base.DrawableTag; -import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag; -import com.jpexs.decompiler.flash.tags.base.RenderContext; -import com.jpexs.decompiler.flash.tags.base.SoundTag; -import com.jpexs.decompiler.flash.tags.base.TextTag; -import com.jpexs.decompiler.flash.timeline.DepthState; -import com.jpexs.decompiler.flash.timeline.Frame; -import com.jpexs.decompiler.flash.timeline.Timeline; -import com.jpexs.decompiler.flash.timeline.Timelined; -import com.jpexs.decompiler.flash.types.ConstantColorColorTransform; -import com.jpexs.decompiler.flash.types.RECT; -import com.jpexs.decompiler.flash.types.SOUNDINFO; -import com.jpexs.helpers.ByteArrayRange; -import com.jpexs.helpers.Cache; -import com.jpexs.helpers.SerializableImage; -import com.jpexs.helpers.Stopwatch; -import java.awt.AlphaComposite; -import java.awt.BasicStroke; -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Cursor; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Point; -import java.awt.Rectangle; -import java.awt.Shape; -import java.awt.Transparency; -import java.awt.event.ComponentAdapter; -import java.awt.event.ComponentEvent; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; -import java.awt.event.MouseMotionAdapter; -import java.awt.event.MouseMotionListener; -import java.awt.geom.AffineTransform; -import java.awt.image.BufferedImage; -import java.awt.image.VolatileImage; -import java.io.IOException; -import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Timer; -import java.util.TimerTask; -import java.util.logging.Level; -import java.util.logging.Logger; -import javax.sound.sampled.LineUnavailableException; -import javax.sound.sampled.UnsupportedAudioFileException; -import javax.swing.JLabel; -import javax.swing.JPanel; - -/** - * - * @author JPEXS - */ -public final class ImagePanel extends JPanel implements MediaDisplay { - - private static final Logger logger = Logger.getLogger(ImagePanel.class.getName()); - - private final List listeners = new ArrayList<>(); - - private Timelined timelined; - - private boolean stillFrame = false; - - private Timer timer; - - private int frame = -1; - - private boolean loop; - - private LocalDataArea lda; - - private boolean zoomAvailable = false; - - private SWF swf; - - private boolean loaded; - - private int mouseButton; - - private final JLabel debugLabel = new JLabel("-"); - - private Point cursorPosition = null; - - private MouseEvent lastMouseEvent = null; - - private final List soundPlayers = new ArrayList<>(); - - private final Cache displayObjectCache = Cache.getInstance(false, false, "displayObject"); - - private final IconPanel iconPanel; - - private int time = 0; - - private int selectedDepth = -1; - - private Zoom zoom = new Zoom(); - - private final Object delayObject = new Object(); - - private boolean drawReady; - - private final int drawWaitLimit = 50; // ms - - private TextTag textTag; - - private TextTag newTextTag; - - private int msPerFrame; - - private final boolean lowQuality = false; - - private final double LQ_FACTOR = 2; - - public synchronized void selectDepth(int depth) { - if (depth != selectedDepth) { - this.selectedDepth = depth; - } - - hideMouseSelection(); - } - - 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); - } - - private class IconPanel extends JPanel { - - private SerializableImage _img; - - private Rectangle _rect = null; - - private ButtonTag mouseOverButton = null; - - private boolean autoFit = false; - - private boolean allowMove = true; - - private Point dragStart = null; - - private Point offsetPoint = new Point(0, 0); - - private synchronized SerializableImage getImg() { - return _img; - } - - public synchronized Rectangle getRect() { - return _rect; - } - - public boolean hasAllowMove() { - return allowMove; - } - - VolatileImage renderImage; - - public void render() { - SerializableImage img = getImg(); - Rectangle rect = getRect(); - if (img == null) { - return; - } - - Graphics2D g2 = null; - VolatileImage ri; - do { - ri = this.renderImage; - if (ri == null) { - return; - } - - int valid = ri.validate(View.getDefaultConfiguration()); - - if (valid == VolatileImage.IMAGE_INCOMPATIBLE) { - ri = View.createRenderImage(getWidth(), getHeight(), Transparency.TRANSLUCENT); - } - - try { - g2 = ri.createGraphics(); - g2.setPaint(View.transparentPaint); - g2.fill(new Rectangle(0, 0, getWidth(), getHeight())); - g2.setComposite(AlphaComposite.SrcOver); - g2.setPaint(View.getSwfBackgroundColor()); - g2.fill(new Rectangle(0, 0, getWidth(), getHeight())); - - g2.setComposite(AlphaComposite.SrcOver); - if (rect != null) { - g2.drawImage(img.getBufferedImage(), rect.x, rect.y, rect.x + rect.width, rect.y + rect.height, 0, 0, img.getWidth(), img.getHeight(), null); - } - } finally { - if (g2 != null) { - g2.dispose(); - } - } - - } while (ri.contentsLost()); - } - - public IconPanel() { - addComponentListener(new ComponentAdapter() { - @Override - public void componentResized(ComponentEvent e) { - int width = getWidth(); - int height = getHeight(); - if (width > 0 && height > 0) { - renderImage = View.createRenderImage(width, height, Transparency.TRANSLUCENT); - } else { - renderImage = null; - } - - if (_img != null) { - calcRect(); - render(); - } - repaint(); - } - }); - addMouseListener(new MouseAdapter() { - @Override - public void mousePressed(MouseEvent e) { - if (e.getButton() == MouseEvent.BUTTON1) { - dragStart = e.getPoint(); - } - } - - @Override - public void mouseReleased(MouseEvent e) { - if (e.getButton() == MouseEvent.BUTTON1) { - dragStart = null; - } - } - }); - addMouseMotionListener(new MouseMotionAdapter() { - @Override - public void mouseDragged(MouseEvent e) { - if (dragStart != null && allowMove) { - Point dragEnd = e.getPoint(); - Point delta = new Point(dragEnd.x - dragStart.x, dragEnd.y - dragStart.y); - offsetPoint.x += delta.x; - offsetPoint.y += delta.y; - dragStart = dragEnd; - repaint(); - } - } - }); - } - - public void setAutoFit(boolean autoFit) { - this.autoFit = autoFit; - repaint(); - } - - public synchronized BufferedImage getLastImage() { - if (_img == null) { - return null; - } - return _img.getBufferedImage(); - } - - public synchronized void setImg(SerializableImage img) { - this._img = img; - if (img != null) { - calcRect(); - render(); - } - repaint(); - } - - public synchronized Point toImagePoint(Point p) { - if (_img == null) { - return null; - } - - return new Point((p.x - _rect.x) * _img.getWidth() / _rect.width, (p.y - _rect.y) * _img.getHeight() / _rect.height); - } - - private void setAllowMove(boolean allowMove) { - this.allowMove = allowMove; - if (!allowMove) { - offsetPoint = new Point(); - } - } - - private synchronized void calcRect() { - if (_img != null) { - int w1 = (int) (_img.getWidth() * (lowQuality ? LQ_FACTOR : 1)); - int h1 = (int) (_img.getHeight() * (lowQuality ? LQ_FACTOR : 1)); - - int w2 = getWidth(); - int h2 = getHeight(); - - int w; - int h; - if (autoFit) { - if (w1 <= w2 && h1 <= h2) { - w = w1; - h = h1; - } else { - - h = h1 * w2 / w1; - if (h > h2) { - w = w1 * h2 / h1; - h = h2; - } else { - w = w2; - } - } - } else { - w = w1; - h = h1; - } - - setAllowMove(h > h2 || w > w2); - _rect = new Rectangle(getWidth() / 2 - w / 2 + offsetPoint.x, getHeight() / 2 - h / 2 + offsetPoint.y, w, h); - } else { - _rect = null; - } - } - - @Override - protected void paintComponent(Graphics g) { - Graphics2D g2d = (Graphics2D) g; - - VolatileImage ri = this.renderImage; - if (ri != null) { - calcRect(); - if (ri.validate(View.getDefaultConfiguration()) != VolatileImage.IMAGE_OK) { - ri = View.createRenderImage(getWidth(), getHeight(), Transparency.TRANSLUCENT); - render(); - } - - if (ri != null) { - g2d.drawImage(ri, 0, 0, null); - } - } - g2d.setColor(Color.red); - - DecimalFormat df = new DecimalFormat(); - df.setMaximumFractionDigits(2); - df.setMinimumFractionDigits(0); - df.setGroupingUsed(false); - - float frameLoss = 100 - (getFpsIs() / fpsShouldBe * 100); - - if (Configuration._debugMode.get()) { - g2d.drawString("frameLoss:" + df.format(frameLoss) + "%", 20, 20); - } - } - } - - @Override - public void setBackground(Color bg) { - if (iconPanel != null) { - iconPanel.setBackground(bg); - } - super.setBackground(bg); - } - - @Override - public synchronized void addMouseListener(MouseListener l) { - iconPanel.addMouseListener(l); - } - - @Override - public synchronized void removeMouseListener(MouseListener l) { - iconPanel.removeMouseListener(l); - } - - @Override - public synchronized void addMouseMotionListener(MouseMotionListener l) { - iconPanel.addMouseMotionListener(l); - } - - @Override - public synchronized void removeMouseMotionListener(MouseMotionListener l) { - iconPanel.removeMouseMotionListener(l); - } - - private void updatePos(Timelined timelined, MouseEvent lastMouseEvent, Timer thisTimer) { - if (timelined != null) { - - BoundedTag bounded = (BoundedTag) timelined; - RECT rect = bounded.getRect(); - int width = rect.getWidth(); - double scale = 1.0; - /*if (width > swf.displayRect.getWidth()) { - scale = (double) swf.displayRect.getWidth() / (double) width; - }*/ - Matrix m = Matrix.getTranslateInstance(-rect.Xmin, -rect.Ymin); - m.scale(scale); - - Point p = lastMouseEvent == null ? null : lastMouseEvent.getPoint(); - - synchronized (ImagePanel.class) { - if (timer == thisTimer) { - cursorPosition = p; - } - } - } - } - - private void showSelectedName() { - if (selectedDepth > -1 && frame > -1) { - DepthState ds = timelined.getTimeline().getFrame(frame).layers.get(selectedDepth); - if (ds != null) { - CharacterTag cht = timelined.getTimeline().swf.getCharacter(ds.characterId); - if (cht != null) { - debugLabel.setText(cht.getName()); - } - } - } - } - - public void hideMouseSelection() { - if (selectedDepth > -1) { - showSelectedName(); - } else { - debugLabel.setText(" - "); - } - } - - public ImagePanel() { - super(new BorderLayout()); - //iconPanel.setHorizontalAlignment(JLabel.CENTER); - setOpaque(true); - setBackground(View.getDefaultBackgroundColor()); - - loop = true; - iconPanel = new IconPanel(); - //labelPan.add(label, new GridBagConstraints()); - add(iconPanel, BorderLayout.CENTER); - add(debugLabel, BorderLayout.NORTH); - iconPanel.addMouseListener(new MouseAdapter() { - @Override - public void mouseEntered(MouseEvent e) { - synchronized (ImagePanel.class) { - lastMouseEvent = e; - redraw(); - } - } - - @Override - public void mouseExited(MouseEvent e) { - synchronized (ImagePanel.class) { - lastMouseEvent = null; - hideMouseSelection(); - redraw(); - } - } - - @Override - public void mousePressed(MouseEvent e) { - synchronized (ImagePanel.class) { - mouseButton = e.getButton(); - lastMouseEvent = e; - redraw(); - ButtonTag button = iconPanel.mouseOverButton; - if (button != null) { - DefineButtonSoundTag sounds = button.getSounds(); - if (sounds != null && sounds.buttonSoundChar2 != 0) { // OverUpToOverDown - playSound((SoundTag) swf.getCharacter(sounds.buttonSoundChar2), sounds.buttonSoundInfo2, timer); - } - } - } - } - - @Override - public void mouseReleased(MouseEvent e) { - synchronized (ImagePanel.class) { - mouseButton = 0; - lastMouseEvent = e; - redraw(); - ButtonTag button = iconPanel.mouseOverButton; - if (button != null) { - DefineButtonSoundTag sounds = button.getSounds(); - if (sounds != null && sounds.buttonSoundChar3 != 0) { // OverDownToOverUp - playSound((SoundTag) swf.getCharacter(sounds.buttonSoundChar3), sounds.buttonSoundInfo3, timer); - } - } - } - } - }); - iconPanel.addMouseMotionListener(new MouseMotionAdapter() { - @Override - public void mouseMoved(MouseEvent e) { - synchronized (ImagePanel.class) { - lastMouseEvent = e; - redraw(); - } - } - - @Override - public void mouseDragged(MouseEvent e) { - synchronized (ImagePanel.class) { - lastMouseEvent = e; - redraw(); - } - } - }); - } - - private synchronized void redraw() { - if (timer == null && timelined != null) { - startTimer(timelined.getTimeline(), false); - } - } - - @Override - public synchronized void zoom(Zoom zoom) { - boolean modified = this.zoom.value != zoom.value || this.zoom.fit != zoom.fit; - if (modified) { - this.zoom = zoom; - displayObjectCache.clear(); - redraw(); - if (textTag != null) { - setText(textTag, newTextTag); - } - - fireMediaDisplayStateChanged(); - } - } - - @Override - public synchronized BufferedImage printScreen() { - return iconPanel.getLastImage(); - } - - @Override - public synchronized double getZoomToFit() { - if (timelined != null) { - RECT bounds = timelined.getRect(); - double w1 = bounds.getWidth() / SWF.unitDivisor; - double h1 = bounds.getHeight() / SWF.unitDivisor; - - double w2 = getWidth(); - double h2 = getHeight(); - - double w; - double h; - h = h1 * w2 / w1; - if (h > h2) { - w = w1 * h2 / h1; - } else { - w = w2; - } - - if (w1 <= Double.MIN_NORMAL) { - return 1.0; - } - - return (double) w / (double) w1; - } - - return 1; - } - - @Override - public synchronized boolean zoomAvailable() { - return zoomAvailable; - } - - public void setTimelined(final Timelined drawable, final SWF swf, int frame) { - Stage stage = new Stage(drawable) { - @Override - public void callFrame(int frame) { - executeFrame(frame); - } - - @Override - public Object callFunction(long functionAddress, long functionLength, List args, Map regNames, Object thisObj) { - try { - SWFInputStream sis = new SWFInputStream(swf, swf.uncompressedData, functionAddress, (int) (functionAddress + functionLength)); - return execute(sis); - } catch (IOException ex) { - Logger.getLogger(ImagePanel.class.getName()).log(Level.SEVERE, null, ex); - } - return Undefined.INSTANCE; - } - - @Override - public int getCurrentFrame() { - return ImagePanel.this.getCurrentFrame(); - } - - @Override - public int getTotalFrames() { - return ImagePanel.this.getTotalFrames(); - } - - @Override - public void gotoFrame(int frame) { - ImagePanel.this.pause(); - ImagePanel.this.gotoFrame(frame); - } - - @Override - public void gotoLabel(String label) { - //TODO - } - - @Override - public void pause() { - ImagePanel.this.pause(); - } - - @Override - public void play() { - ImagePanel.this.play(); - } - - @Override - public void trace(Object... val) { - for (Object o : val) { - System.out.println("trace:" + o.toString()); - } - } - }; - lda = new LocalDataArea(stage); - synchronized (ImagePanel.class) { - stopInternal(); - if (drawable instanceof ButtonTag) { - frame = ButtonTag.FRAME_UP; - } - - displayObjectCache.clear(); - this.timelined = drawable; - this.swf = swf; - zoomAvailable = true; - timer = null; - if (frame > -1) { - this.frame = frame; - this.stillFrame = true; - } else { - this.frame = 0; - this.stillFrame = false; - } - - loaded = true; - - if (drawable.getTimeline().getFrameCount() == 0) { - clearImagePanel(); - return; - } - - time = 0; - drawReady = false; - redraw(); - play(); - } - - synchronized (delayObject) { - try { - delayObject.wait(drawWaitLimit); - } catch (InterruptedException ex) { - logger.log(Level.SEVERE, null, ex); - } - } - - synchronized (ImagePanel.class) { - if (!drawReady) { - clearImagePanel(); - } - } - - fireMediaDisplayStateChanged(); - } - - public synchronized void setImage(SerializableImage image) { - lda = null; - setBackground(View.getSwfBackgroundColor()); - clear(); - - timelined = null; - loaded = true; - stillFrame = true; - zoomAvailable = false; - iconPanel.setImg(image); - drawReady = true; - - fireMediaDisplayStateChanged(); - } - - public synchronized void setText(TextTag textTag, TextTag newTextTag) { - setBackground(View.getSwfBackgroundColor()); - clear(); - - lda = null; - timelined = null; - loaded = true; - stillFrame = true; - zoomAvailable = true; - - this.textTag = textTag; - this.newTextTag = newTextTag; - - double zoomDouble = zoom.fit ? getZoomToFit() : zoom.value; - - RECT rect = textTag.getRect(); - int width = (int) (rect.getWidth() * zoomDouble); - int height = (int) (rect.getHeight() * zoomDouble); - SerializableImage image = new SerializableImage((int) (width / SWF.unitDivisor) + 1, - (int) (height / SWF.unitDivisor) + 1, SerializableImage.TYPE_INT_ARGB); - image.fillTransparent(); - Matrix m = Matrix.getTranslateInstance(-rect.Xmin * zoomDouble, -rect.Ymin * zoomDouble); - m.scale(zoomDouble); - textTag.toImage(0, 0, 0, new RenderContext(), image, false, m, m, m, new ConstantColorColorTransform(0xFFC0C0C0)); - - if (newTextTag != null) { - newTextTag.toImage(0, 0, 0, new RenderContext(), image, false, m, m, m, new ConstantColorColorTransform(0xFF000000)); - } - - iconPanel.setImg(image); - drawReady = true; - - fireMediaDisplayStateChanged(); - } - - private synchronized void clearImagePanel() { - iconPanel.setImg(null); - } - - @Override - public synchronized int getCurrentFrame() { - return frame; - } - - @Override - public synchronized int getTotalFrames() { - if (timelined == null) { - return 0; - } - if (stillFrame) { - return 0; - } - return timelined.getTimeline().getFrameCount(); - } - - @Override - public void pause() { - stopInternal(); - redraw(); - } - - @Override - public void stop() { - stopInternal(); - rewind(); - redraw(); - } - - @Override - public void close() throws IOException { - stopInternal(); - } - - private void stopAllSounds() { - for (int i = soundPlayers.size() - 1; i >= 0; i--) { - SoundTagPlayer pl = soundPlayers.get(i); - pl.close(); - } - soundPlayers.clear(); - } - - private void clear() { - if (timer != null) { - timer.cancel(); - timer = null; - fireMediaDisplayStateChanged(); - } - - textTag = null; - newTextTag = null; - displayObjectCache.clear(); - } - - private void nextFrame(Timer thisTimer, final int cnt, final int timeShouldBe) { - drawFrame(thisTimer, true); - - synchronized (ImagePanel.class) { - if (timelined != null && timer == thisTimer) { - int frameCount = timelined.getTimeline().getFrameCount(); - - int oldFrame = frame; - for (int i = 0; i < cnt; i++) { - if (!stillFrame && frameCount > 0) { - frame = (frame + 1) % frameCount; - } - - if (!stillFrame && frame == frameCount - 1 && !loop) { - stopInternal(); - return; - } - - if (i < cnt - 1) { //skip not displayed frames, do not display, only play sounds, etc. - drawFrame(thisTimer, false); - } - } - if (frame != oldFrame) { - if (frame == 0) { - stopAllSounds(); - } - time = 0; - } else { - time = timeShouldBe; - } - } - } - - fireMediaDisplayStateChanged(); - } - - private static SerializableImage getFrame(SWF swf, int frame, int time, Timelined drawable, RenderContext renderContext, int selectedDepth, double zoom) { - Timeline timeline = drawable.getTimeline(); - //int mouseButton = renderContext.mouseButton; - //Point cursorPosition = renderContext.cursorPosition; - //String key = "drawable_" + frame + "_" + drawable.hashCode() + "_" + mouseButton + "_depth" + selectedDepth + "_" + (cursorPosition == null ? "out" : cursorPosition.hashCode()) + "_" + zoom + "_" + timeline.fontFrameNum; - SerializableImage img; - //SerializableImage img = swf.getFromCache(key); - //if (img == null) { - //boolean shouldCache = timeline.isSingleFrame(frame); - RECT rect = drawable.getRect(); - - int width = (int) (rect.getWidth() * zoom); - int height = (int) (rect.getHeight() * zoom); - SerializableImage image = new SerializableImage((int) Math.ceil(width / SWF.unitDivisor), - (int) Math.ceil(height / SWF.unitDivisor), SerializableImage.TYPE_INT_ARGB); - //renderContext.borderImage = new SerializableImage(image.getWidth(), image.getHeight(), SerializableImage.TYPE_INT_ARGB); - image.fillTransparent(); - Matrix m = new Matrix(); - m.translate(-rect.Xmin * zoom, -rect.Ymin * zoom); - m.scale(zoom); - timeline.toImage(frame, time, renderContext, image, false, m, m, m, null); - - Graphics2D gg = (Graphics2D) image.getGraphics(); - gg.setStroke(new BasicStroke(3)); - gg.setPaint(Color.green); - gg.setTransform(AffineTransform.getTranslateInstance(0, 0)); - DepthState ds = null; - if (timeline.getFrameCount() > frame) { - ds = timeline.getFrame(frame).layers.get(selectedDepth); - } - - if (ds != null) { - CharacterTag cht = swf.getCharacter(ds.characterId); - if (cht != null) { - if (cht instanceof DrawableTag) { - DrawableTag dt = (DrawableTag) cht; - int drawableFrameCount = dt.getNumFrames(); - if (drawableFrameCount == 0) { - drawableFrameCount = 1; - } - - int dframe = time % drawableFrameCount; - Shape outline = dt.getOutline(dframe, time, ds.ratio, renderContext, Matrix.getScaleInstance(1 / SWF.unitDivisor).concatenate(m.concatenate(new Matrix(ds.matrix))), true); - Rectangle bounds = outline.getBounds(); - gg.setStroke(new BasicStroke(2.0f, - BasicStroke.CAP_BUTT, - BasicStroke.JOIN_MITER, - 10.0f, new float[]{10.0f}, 0.0f)); - gg.setPaint(Color.red); - gg.draw(bounds); - } - } - } - - img = image; - - /*if (shouldCache) { - swf.putToCache(key, img); - }*/ - //} - return img; - } - - private Object execute(SWFInputStream sis) throws IOException { - if (!Configuration.internalFlashViewerExecuteAs12.get()) { - return Undefined.INSTANCE; - } - if (lda == null) { - return Undefined.INSTANCE; - } - long ip = sis.getPos(); - //System.err.println("============="); - Action a; - while ((a = sis.readAction()) != null) { - int actionLengthWithHeader = a.getTotalActionLength(); - a.setAddress(ip); - a.execute(lda); - /*System.err.print("" + a + ", stack: ["); - for (Object o : lda.stack) { - System.err.print("" + o + ","); - } - System.err.println("]");*/ - if (lda.returnValue != null) { - return lda.returnValue; - } - if (lda.jump != null) { - ip = lda.jump; - lda.jump = null; - } else { - ip += actionLengthWithHeader; - } - sis.seek(ip); - } - return Undefined.INSTANCE; - } - - private void executeFrame(int frame) { - if (!Configuration.internalFlashViewerExecuteAs12.get()) { - return; - } - if (timelined == null) { - return; - } - Frame f = timelined.getTimeline().getFrame(frame); - List actions = f.actions; - if (lda != null) { - lda.clear(); - } - for (DoActionTag src : actions) { - try { - ByteArrayRange actionBytes = src.getActionBytes(); - int prevLength = actionBytes.getPos(); - SWFInputStream rri = new SWFInputStream(swf, actionBytes.getArray(), 0, prevLength + actionBytes.getLength()); - if (prevLength != 0) { - rri.seek(prevLength); - } - execute(rri); - } catch (IOException ex) { - Logger.getLogger(ImagePanel.class.getName()).log(Level.SEVERE, null, ex); - } - - } - } - - private void drawFrame(Timer thisTimer, boolean display) { - Timelined timelined; - MouseEvent lastMouseEvent; - int frame; - int time; - Point cursorPosition; - int mouseButton; - int selectedDepth; - Zoom zoom; - SWF swf; - - synchronized (ImagePanel.class) { - timelined = this.timelined; - lastMouseEvent = this.lastMouseEvent; - } - - synchronized (ImagePanel.class) { - frame = this.frame; - time = this.time; - cursorPosition = this.cursorPosition; - if (cursorPosition != null) { - cursorPosition = iconPanel.toImagePoint(cursorPosition); - } - - mouseButton = this.mouseButton; - selectedDepth = this.selectedDepth; - zoom = this.zoom; - swf = this.swf; - } - - if (timelined == null) { - return; - } - - RenderContext renderContext = new RenderContext(); - renderContext.displayObjectCache = displayObjectCache; - if (cursorPosition != null) { - renderContext.cursorPosition = new Point((int) (cursorPosition.x * SWF.unitDivisor), (int) (cursorPosition.y * SWF.unitDivisor)); - } - - renderContext.mouseButton = mouseButton; - renderContext.stateUnderCursor = new ArrayList<>(); - - SerializableImage img; - try { - Timeline timeline = timelined.getTimeline(); - if (frame >= timeline.getFrameCount()) { - return; - } - - double zoomDouble = zoom.fit ? getZoomToFit() : zoom.value; - if (lowQuality) { - zoomDouble /= LQ_FACTOR; - } - updatePos(timelined, lastMouseEvent, thisTimer); - - Matrix mat = new Matrix(); - mat.translateX = swf.displayRect.Xmin; - mat.translateY = swf.displayRect.Ymin; - - img = null; - if (display) { - Stopwatch sw = Stopwatch.startNew(); - img = getFrame(swf, frame, time, timelined, renderContext, selectedDepth, zoomDouble); - sw.stop(); - if (sw.getElapsedMilliseconds() > 100) { - logger.log(Level.WARNING, "Slow rendering. {0}. frame, time={1}, {2}ms", new Object[]{frame, time, sw.getElapsedMilliseconds()}); - } - - if (renderContext.borderImage != null) { - img = renderContext.borderImage; - } - } - - List sounds = new ArrayList<>(); - List soundClasses = new ArrayList<>(); - timeline.getSounds(frame, time, renderContext.mouseOverButton, mouseButton, sounds, soundClasses); - for (int cid : swf.getCharacters().keySet()) { - CharacterTag c = swf.getCharacter(cid); - for (String cls : soundClasses) { - if (cls.equals(c.getClassName())) { - sounds.add(cid); - } - } - } - - for (int sndId : sounds) { - CharacterTag c = swf.getCharacter(sndId); - if (c instanceof SoundTag) { - SoundTag st = (SoundTag) c; - playSound(st, null, thisTimer); - } - } - executeFrame(frame); - } catch (Throwable ex) { - // swf was closed during the rendering probably - return; - } - if (display) { - - StringBuilder ret = new StringBuilder(); - - if (cursorPosition != null) { - ret.append(" [").append(cursorPosition.x).append(",").append(cursorPosition.y).append("] : "); - } - - boolean handCursor = renderContext.mouseOverButton != null; - boolean first = true; - for (int i = renderContext.stateUnderCursor.size() - 1; i >= 0; i--) { - DepthState ds = renderContext.stateUnderCursor.get(i); - if (!first) { - ret.append(", "); - } - - first = false; - CharacterTag c = swf.getCharacter(ds.characterId); - ret.append(c.toString()); - } - - if (first) { - ret.append(" - "); - } - - ButtonTag lastMouseOverButton; - synchronized (ImagePanel.class) { - if (timer == thisTimer) { - iconPanel.setImg(img); - lastMouseOverButton = iconPanel.mouseOverButton; - iconPanel.mouseOverButton = renderContext.mouseOverButton; - debugLabel.setText(ret.toString()); - if (handCursor) { - iconPanel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); - } else if (iconPanel.hasAllowMove()) { - iconPanel.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)); - } else { - iconPanel.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); - } - - if (lastMouseOverButton != renderContext.mouseOverButton) { - ButtonTag b = renderContext.mouseOverButton; - if (b != null) { - // New mouse entered - DefineButtonSoundTag sounds = b.getSounds(); - if (sounds != null && sounds.buttonSoundChar1 != 0) { // IdleToOverUp - playSound((SoundTag) swf.getCharacter(sounds.buttonSoundChar1), sounds.buttonSoundInfo1, timer); - } - } - - b = lastMouseOverButton; - if (b != null) { - // Old mouse leave - DefineButtonSoundTag sounds = b.getSounds(); - if (sounds != null && sounds.buttonSoundChar0 != 0) { // OverUpToIdle - playSound((SoundTag) swf.getCharacter(sounds.buttonSoundChar0), sounds.buttonSoundInfo0, timer); - } - } - } - - drawReady = true; - synchronized (delayObject) { - delayObject.notify(); - } - } - } - } - } - - private void playSound(SoundTag st, SOUNDINFO soundInfo, Timer thisTimer) { - final SoundTagPlayer sp; - try { - int loopCount = 1; - if (soundInfo != null && soundInfo.hasLoops) { - loopCount = Math.max(1, soundInfo.loopCount); - } - - sp = new SoundTagPlayer(st, loopCount, false); - sp.addEventListener(new MediaDisplayListener() { - @Override - public void mediaDisplayStateChanged(MediaDisplay source) { - } - - @Override - public void playingFinished(MediaDisplay source) { - synchronized (ImagePanel.class) { - sp.close(); - soundPlayers.remove(sp); - } - } - }); - - synchronized (ImagePanel.class) { - if (timer != null && timer == thisTimer) { - soundPlayers.add(sp); - sp.play(); - } else { - sp.close(); - } - } - } catch (LineUnavailableException | IOException | UnsupportedAudioFileException ex) { - logger.log(Level.SEVERE, "Error during playing sound", ex); - } - } - - public synchronized void clearAll() { - stopInternal(); - clearImagePanel(); - timelined = null; - swf = null; - - fireMediaDisplayStateChanged(); - } - - private synchronized void stopInternal() { - clear(); - stopAllSounds(); - } - - @Override - public synchronized void play() { - stopInternal(); - if (timelined != null) { - Timeline timeline = timelined.getTimeline(); - if (!stillFrame && frame == timeline.getFrameCount() - 1) { - frame = 0; - } - - startTimer(timeline, true); - } - } - - private synchronized void setMsPerFrame(int val) { - this.msPerFrame = val; - } - - private synchronized int getMsPerFrame() { - return this.msPerFrame; - } - - private long startRun = 0L; - - private final long startDrop = 0L; - - private int skippedFrames = 0; - - private float fpsShouldBe = 0; - - private float fpsIs = 0; - - private Timer fpsTimer; - - private int startFrame = 0; - - private synchronized void setFpsIs(float val) { - fpsIs = val; - } - - private synchronized float getFpsIs() { - return fpsIs; - } - - private synchronized void setSkippedFrames(int val) { - skippedFrames = val; - } - - private synchronized void addSkippedFrames(int val) { - skippedFrames += val; - } - - private synchronized int getSkippedFrames() { - return skippedFrames; - } - - private synchronized int getAndResetSkippedFrames() { - int ret = skippedFrames; - skippedFrames = 0; - return ret; - } - - private void scheduleTask(boolean singleFrame, long msDelay) { - TimerTask task = new TimerTask() { - public final Timer thisTimer = timer; - - public final boolean isSingleFrame = singleFrame; - - private long lastRun = 0L; - - @Override - public void run() { - try { - synchronized (ImagePanel.class) { - if (timer != thisTimer) { - return; - } - } - lastRun = System.currentTimeMillis(); - int curFrame = frame; - long delay = getMsPerFrame(); - if (isSingleFrame) { - drawFrame(thisTimer, true); - synchronized (ImagePanel.class) { - thisTimer.cancel(); - if (timer == thisTimer) { - timer = null; - } - } - - fireMediaDisplayStateChanged(); - } else { - //Time before drawing current frame - long frameTimeMsIs = System.currentTimeMillis(); - //Total number of frames in this timeline - int frameCount = timelined.getTimeline().getFrameCount(); - //How many ticks (= times where frame should be displayed in framerate) are there from hitting play button - int ticksFromStart = (int) Math.floor((frameTimeMsIs - startRun) / (double) getMsPerFrame()) + 1; - //Add ticks to first frame when hitting play button, ignoring total framecount => this value can be larger than number of frames in timeline - int frameOverMaxShouldBeNow = startFrame + ticksFromStart; - //Apply maximum frames repating, this is actual frame which should be drawed now - int frameShouldBeNow = frameOverMaxShouldBeNow % frameCount; - - //How many frames are there between last displayed frame and now. For perfect display(=no framedrop), value should be 1 - int skipFrames = frameShouldBeNow - curFrame; - //It is negative for some reason, this will display older frames. Add frameCount to stay in modulu framecount. - if (skipFrames < 0) { - skipFrames += frameCount; - } - //Change for more than 1 frame - if (skipFrames > 1) { - addSkippedFrames(skipFrames - 1); //drop those frames, draw only last one - } - //Frame "time" - ticks in current frame - int currentFrameTicks = 0; - if (frameCount == 1) { //We have only one frame, so the ticks on that frame equal ticks on whole timeline - currentFrameTicks = ticksFromStart; - } - nextFrame(thisTimer, skipFrames, currentFrameTicks); - - long afterDrawFrameTimeMsIs = System.currentTimeMillis(); - - int nextFrameOverMax = frameOverMaxShouldBeNow; - while (delay < 0) { //while the frame time already passed - nextFrameOverMax++; - long nextFrameOverMaxTimeMsShouldBe = startRun + getMsPerFrame() * nextFrameOverMax; - delay = nextFrameOverMaxTimeMsShouldBe - afterDrawFrameTimeMsIs; - } - } - //schedule next run of the task - scheduleTask(isSingleFrame, delay); - - } catch (Exception ex) { - logger.log(Level.SEVERE, "Frame drawing error", ex); - } - } - }; - if (timer != null) { - timer.schedule(task, msDelay); - } - } - - private synchronized void startTimer(Timeline timeline, boolean playing) { - - startRun = System.currentTimeMillis(); - startFrame = frame; - float frameRate = timeline.frameRate; - setMsPerFrame(frameRate == 0 ? 1000 : (int) (1000.0 / frameRate)); - final boolean singleFrame = !playing - || (stillFrame && timeline.isSingleFrame(frame)) - || (!stillFrame && timeline.getRealFrameCount() <= 1 && timeline.isSingleFrame()); - - if (fpsTimer == null) { - fpsTimer = new Timer(); - fpsTimer.schedule(new TimerTask() { - @Override - public void run() { - float skipped = getAndResetSkippedFrames(); - setFpsIs(fpsShouldBe - skipped); - } - }, 1000, 1000); - } - timer = new Timer(); - fpsShouldBe = timeline.frameRate; - fpsIs = fpsShouldBe; - scheduleTask(singleFrame, 0); - - } - - @Override - public synchronized void rewind() { - frame = 0; - fireMediaDisplayStateChanged(); - } - - @Override - public synchronized boolean isPlaying() { - if (timelined == null || stillFrame) { - return false; - } - - return (timelined.getTimeline().getFrameCount() <= 1) || (timer != null); - } - - @Override - public void setLoop(boolean loop) { - this.loop = loop; - } - - @Override - public synchronized void gotoFrame(int frame) { - if (timelined == null) { - return; - } - Timeline timeline = timelined.getTimeline(); - if (frame >= timeline.getFrameCount()) { - return; - } - if (frame < 0) { - return; - } - - this.frame = frame; - stopInternal(); - redraw(); - fireMediaDisplayStateChanged(); - } - - @Override - public synchronized float getFrameRate() { - if (timelined == null) { - return 1; - } - if (stillFrame) { - return 1; - } - return timelined.getTimeline().frameRate; - } - - @Override - public synchronized boolean isLoaded() { - return loaded; - } - - @Override - public boolean loopAvailable() { - return false; - } - - @Override - public boolean screenAvailable() { - return true; - } - - @Override - public synchronized Zoom getZoom() { - return zoom; - } -} +/* + * 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.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.action.Action; +import com.jpexs.decompiler.flash.action.LocalDataArea; +import com.jpexs.decompiler.flash.action.Stage; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.ecma.Undefined; +import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; +import com.jpexs.decompiler.flash.gui.player.MediaDisplay; +import com.jpexs.decompiler.flash.gui.player.MediaDisplayListener; +import com.jpexs.decompiler.flash.gui.player.Zoom; +import com.jpexs.decompiler.flash.tags.DefineButtonSoundTag; +import com.jpexs.decompiler.flash.tags.DoActionTag; +import com.jpexs.decompiler.flash.tags.base.BoundedTag; +import com.jpexs.decompiler.flash.tags.base.ButtonTag; +import com.jpexs.decompiler.flash.tags.base.CharacterTag; +import com.jpexs.decompiler.flash.tags.base.DrawableTag; +import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag; +import com.jpexs.decompiler.flash.tags.base.RenderContext; +import com.jpexs.decompiler.flash.tags.base.SoundTag; +import com.jpexs.decompiler.flash.tags.base.TextTag; +import com.jpexs.decompiler.flash.timeline.DepthState; +import com.jpexs.decompiler.flash.timeline.Frame; +import com.jpexs.decompiler.flash.timeline.Timeline; +import com.jpexs.decompiler.flash.timeline.Timelined; +import com.jpexs.decompiler.flash.types.ConstantColorColorTransform; +import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.decompiler.flash.types.SOUNDINFO; +import com.jpexs.helpers.ByteArrayRange; +import com.jpexs.helpers.Cache; +import com.jpexs.helpers.SerializableImage; +import com.jpexs.helpers.Stopwatch; +import java.awt.AlphaComposite; +import java.awt.BasicStroke; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Cursor; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.Transparency; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionAdapter; +import java.awt.event.MouseMotionListener; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.awt.image.VolatileImage; +import java.io.IOException; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.UnsupportedAudioFileException; +import javax.swing.JLabel; +import javax.swing.JPanel; + +/** + * + * @author JPEXS + */ +public final class ImagePanel extends JPanel implements MediaDisplay { + + private static final Logger logger = Logger.getLogger(ImagePanel.class.getName()); + + private final List listeners = new ArrayList<>(); + + private Timelined timelined; + + private boolean stillFrame = false; + + private Timer timer; + + private int frame = -1; + + private boolean loop; + + private LocalDataArea lda; + + private boolean zoomAvailable = false; + + private SWF swf; + + private boolean loaded; + + private int mouseButton; + + private final JLabel debugLabel = new JLabel("-"); + + private Point cursorPosition = null; + + private MouseEvent lastMouseEvent = null; + + private final List soundPlayers = new ArrayList<>(); + + private final Cache displayObjectCache = Cache.getInstance(false, false, "displayObject"); + + private final IconPanel iconPanel; + + private int time = 0; + + private int selectedDepth = -1; + + private Zoom zoom = new Zoom(); + + private final Object delayObject = new Object(); + + private boolean drawReady; + + private final int drawWaitLimit = 50; // ms + + private TextTag textTag; + + private TextTag newTextTag; + + private int msPerFrame; + + private final boolean lowQuality = false; + + private final double LQ_FACTOR = 2; + + public synchronized void selectDepth(int depth) { + if (depth != selectedDepth) { + this.selectedDepth = depth; + } + + hideMouseSelection(); + } + + 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); + } + + private class IconPanel extends JPanel { + + private SerializableImage _img; + + private Rectangle _rect = null; + + private ButtonTag mouseOverButton = null; + + private boolean autoFit = false; + + private boolean allowMove = true; + + private Point dragStart = null; + + private Point offsetPoint = new Point(0, 0); + + private synchronized SerializableImage getImg() { + return _img; + } + + public synchronized Rectangle getRect() { + return _rect; + } + + public boolean hasAllowMove() { + return allowMove; + } + + VolatileImage renderImage; + + public void render() { + SerializableImage img = getImg(); + Rectangle rect = getRect(); + if (img == null) { + return; + } + + Graphics2D g2 = null; + VolatileImage ri; + do { + ri = this.renderImage; + if (ri == null) { + return; + } + + int valid = ri.validate(View.getDefaultConfiguration()); + + if (valid == VolatileImage.IMAGE_INCOMPATIBLE) { + ri = View.createRenderImage(getWidth(), getHeight(), Transparency.TRANSLUCENT); + } + + try { + g2 = ri.createGraphics(); + g2.setPaint(View.transparentPaint); + g2.fill(new Rectangle(0, 0, getWidth(), getHeight())); + g2.setComposite(AlphaComposite.SrcOver); + g2.setPaint(View.getSwfBackgroundColor()); + g2.fill(new Rectangle(0, 0, getWidth(), getHeight())); + + g2.setComposite(AlphaComposite.SrcOver); + if (rect != null) { + g2.drawImage(img.getBufferedImage(), rect.x, rect.y, rect.x + rect.width, rect.y + rect.height, 0, 0, img.getWidth(), img.getHeight(), null); + } + } finally { + if (g2 != null) { + g2.dispose(); + } + } + + } while (ri.contentsLost()); + } + + public IconPanel() { + addComponentListener(new ComponentAdapter() { + @Override + public void componentResized(ComponentEvent e) { + int width = getWidth(); + int height = getHeight(); + if (width > 0 && height > 0) { + renderImage = View.createRenderImage(width, height, Transparency.TRANSLUCENT); + } else { + renderImage = null; + } + + if (_img != null) { + calcRect(); + render(); + } + repaint(); + } + }); + addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON1) { + dragStart = e.getPoint(); + } + } + + @Override + public void mouseReleased(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON1) { + dragStart = null; + } + } + }); + addMouseMotionListener(new MouseMotionAdapter() { + @Override + public void mouseDragged(MouseEvent e) { + if (dragStart != null && allowMove) { + Point dragEnd = e.getPoint(); + Point delta = new Point(dragEnd.x - dragStart.x, dragEnd.y - dragStart.y); + offsetPoint.x += delta.x; + offsetPoint.y += delta.y; + dragStart = dragEnd; + repaint(); + } + } + }); + } + + public void setAutoFit(boolean autoFit) { + this.autoFit = autoFit; + repaint(); + } + + public synchronized BufferedImage getLastImage() { + if (_img == null) { + return null; + } + return _img.getBufferedImage(); + } + + public synchronized void setImg(SerializableImage img) { + this._img = img; + if (img != null) { + calcRect(); + render(); + } + repaint(); + } + + public synchronized Point toImagePoint(Point p) { + if (_img == null) { + return null; + } + + return new Point((p.x - _rect.x) * _img.getWidth() / _rect.width, (p.y - _rect.y) * _img.getHeight() / _rect.height); + } + + private void setAllowMove(boolean allowMove) { + this.allowMove = allowMove; + if (!allowMove) { + offsetPoint = new Point(); + } + } + + private synchronized void calcRect() { + if (_img != null) { + int w1 = (int) (_img.getWidth() * (lowQuality ? LQ_FACTOR : 1)); + int h1 = (int) (_img.getHeight() * (lowQuality ? LQ_FACTOR : 1)); + + int w2 = getWidth(); + int h2 = getHeight(); + + int w; + int h; + if (autoFit) { + if (w1 <= w2 && h1 <= h2) { + w = w1; + h = h1; + } else { + + h = h1 * w2 / w1; + if (h > h2) { + w = w1 * h2 / h1; + h = h2; + } else { + w = w2; + } + } + } else { + w = w1; + h = h1; + } + + setAllowMove(h > h2 || w > w2); + _rect = new Rectangle(getWidth() / 2 - w / 2 + offsetPoint.x, getHeight() / 2 - h / 2 + offsetPoint.y, w, h); + } else { + _rect = null; + } + } + + @Override + protected void paintComponent(Graphics g) { + Graphics2D g2d = (Graphics2D) g; + + VolatileImage ri = this.renderImage; + if (ri != null) { + calcRect(); + if (ri.validate(View.getDefaultConfiguration()) != VolatileImage.IMAGE_OK) { + ri = View.createRenderImage(getWidth(), getHeight(), Transparency.TRANSLUCENT); + render(); + } + + if (ri != null) { + g2d.drawImage(ri, 0, 0, null); + } + } + g2d.setColor(Color.red); + + DecimalFormat df = new DecimalFormat(); + df.setMaximumFractionDigits(2); + df.setMinimumFractionDigits(0); + df.setGroupingUsed(false); + + float frameLoss = 100 - (getFpsIs() / fpsShouldBe * 100); + + if (Configuration._debugMode.get()) { + g2d.drawString("frameLoss:" + df.format(frameLoss) + "%", 20, 20); + } + } + } + + @Override + public void setBackground(Color bg) { + if (iconPanel != null) { + iconPanel.setBackground(bg); + } + super.setBackground(bg); + } + + @Override + public synchronized void addMouseListener(MouseListener l) { + iconPanel.addMouseListener(l); + } + + @Override + public synchronized void removeMouseListener(MouseListener l) { + iconPanel.removeMouseListener(l); + } + + @Override + public synchronized void addMouseMotionListener(MouseMotionListener l) { + iconPanel.addMouseMotionListener(l); + } + + @Override + public synchronized void removeMouseMotionListener(MouseMotionListener l) { + iconPanel.removeMouseMotionListener(l); + } + + private void updatePos(Timelined timelined, MouseEvent lastMouseEvent, Timer thisTimer) { + if (timelined != null) { + + BoundedTag bounded = (BoundedTag) timelined; + RECT rect = bounded.getRect(); + int width = rect.getWidth(); + double scale = 1.0; + /*if (width > swf.displayRect.getWidth()) { + scale = (double) swf.displayRect.getWidth() / (double) width; + }*/ + Matrix m = Matrix.getTranslateInstance(-rect.Xmin, -rect.Ymin); + m.scale(scale); + + Point p = lastMouseEvent == null ? null : lastMouseEvent.getPoint(); + + synchronized (ImagePanel.class) { + if (timer == thisTimer) { + cursorPosition = p; + } + } + } + } + + private void showSelectedName() { + if (selectedDepth > -1 && frame > -1) { + DepthState ds = timelined.getTimeline().getFrame(frame).layers.get(selectedDepth); + if (ds != null) { + CharacterTag cht = timelined.getTimeline().swf.getCharacter(ds.characterId); + if (cht != null) { + debugLabel.setText(cht.getName()); + } + } + } + } + + public void hideMouseSelection() { + if (selectedDepth > -1) { + showSelectedName(); + } else { + debugLabel.setText(" - "); + } + } + + public ImagePanel() { + super(new BorderLayout()); + //iconPanel.setHorizontalAlignment(JLabel.CENTER); + setOpaque(true); + setBackground(View.getDefaultBackgroundColor()); + + loop = true; + iconPanel = new IconPanel(); + //labelPan.add(label, new GridBagConstraints()); + add(iconPanel, BorderLayout.CENTER); + add(debugLabel, BorderLayout.NORTH); + iconPanel.addMouseListener(new MouseAdapter() { + @Override + public void mouseEntered(MouseEvent e) { + synchronized (ImagePanel.class) { + lastMouseEvent = e; + redraw(); + } + } + + @Override + public void mouseExited(MouseEvent e) { + synchronized (ImagePanel.class) { + lastMouseEvent = null; + hideMouseSelection(); + redraw(); + } + } + + @Override + public void mousePressed(MouseEvent e) { + synchronized (ImagePanel.class) { + mouseButton = e.getButton(); + lastMouseEvent = e; + redraw(); + ButtonTag button = iconPanel.mouseOverButton; + if (button != null) { + DefineButtonSoundTag sounds = button.getSounds(); + if (sounds != null && sounds.buttonSoundChar2 != 0) { // OverUpToOverDown + playSound((SoundTag) swf.getCharacter(sounds.buttonSoundChar2), sounds.buttonSoundInfo2, timer); + } + } + } + } + + @Override + public void mouseReleased(MouseEvent e) { + synchronized (ImagePanel.class) { + mouseButton = 0; + lastMouseEvent = e; + redraw(); + ButtonTag button = iconPanel.mouseOverButton; + if (button != null) { + DefineButtonSoundTag sounds = button.getSounds(); + if (sounds != null && sounds.buttonSoundChar3 != 0) { // OverDownToOverUp + playSound((SoundTag) swf.getCharacter(sounds.buttonSoundChar3), sounds.buttonSoundInfo3, timer); + } + } + } + } + }); + iconPanel.addMouseMotionListener(new MouseMotionAdapter() { + @Override + public void mouseMoved(MouseEvent e) { + synchronized (ImagePanel.class) { + lastMouseEvent = e; + redraw(); + } + } + + @Override + public void mouseDragged(MouseEvent e) { + synchronized (ImagePanel.class) { + lastMouseEvent = e; + redraw(); + } + } + }); + } + + private synchronized void redraw() { + if (timer == null && timelined != null) { + startTimer(timelined.getTimeline(), false); + } + } + + @Override + public synchronized void zoom(Zoom zoom) { + boolean modified = this.zoom.value != zoom.value || this.zoom.fit != zoom.fit; + if (modified) { + this.zoom = zoom; + displayObjectCache.clear(); + redraw(); + if (textTag != null) { + setText(textTag, newTextTag); + } + + fireMediaDisplayStateChanged(); + } + } + + @Override + public synchronized BufferedImage printScreen() { + return iconPanel.getLastImage(); + } + + @Override + public synchronized double getZoomToFit() { + if (timelined != null) { + RECT bounds = timelined.getRect(); + double w1 = bounds.getWidth() / SWF.unitDivisor; + double h1 = bounds.getHeight() / SWF.unitDivisor; + + double w2 = getWidth(); + double h2 = getHeight(); + + double w; + double h; + h = h1 * w2 / w1; + if (h > h2) { + w = w1 * h2 / h1; + } else { + w = w2; + } + + if (w1 <= Double.MIN_NORMAL) { + return 1.0; + } + + return (double) w / (double) w1; + } + + return 1; + } + + @Override + public synchronized boolean zoomAvailable() { + return zoomAvailable; + } + + public void setTimelined(final Timelined drawable, final SWF swf, int frame) { + Stage stage = new Stage(drawable) { + @Override + public void callFrame(int frame) { + executeFrame(frame); + } + + @Override + public Object callFunction(long functionAddress, long functionLength, List args, Map regNames, Object thisObj) { + try { + SWFInputStream sis = new SWFInputStream(swf, swf.uncompressedData, functionAddress, (int) (functionAddress + functionLength)); + return execute(sis); + } catch (IOException ex) { + Logger.getLogger(ImagePanel.class.getName()).log(Level.SEVERE, null, ex); + } + return Undefined.INSTANCE; + } + + @Override + public int getCurrentFrame() { + return ImagePanel.this.getCurrentFrame(); + } + + @Override + public int getTotalFrames() { + return ImagePanel.this.getTotalFrames(); + } + + @Override + public void gotoFrame(int frame) { + ImagePanel.this.pause(); + ImagePanel.this.gotoFrame(frame); + } + + @Override + public void gotoLabel(String label) { + //TODO + } + + @Override + public void pause() { + ImagePanel.this.pause(); + } + + @Override + public void play() { + ImagePanel.this.play(); + } + + @Override + public void trace(Object... val) { + for (Object o : val) { + System.out.println("trace:" + o.toString()); + } + } + }; + lda = new LocalDataArea(stage); + synchronized (ImagePanel.class) { + stopInternal(); + if (drawable instanceof ButtonTag) { + frame = ButtonTag.FRAME_UP; + } + + displayObjectCache.clear(); + this.timelined = drawable; + this.swf = swf; + zoomAvailable = true; + timer = null; + if (frame > -1) { + this.frame = frame; + this.stillFrame = true; + } else { + this.frame = 0; + this.stillFrame = false; + } + + loaded = true; + + if (drawable.getTimeline().getFrameCount() == 0) { + clearImagePanel(); + return; + } + + time = 0; + drawReady = false; + redraw(); + play(); + } + + synchronized (delayObject) { + try { + delayObject.wait(drawWaitLimit); + } catch (InterruptedException ex) { + logger.log(Level.SEVERE, null, ex); + } + } + + synchronized (ImagePanel.class) { + if (!drawReady) { + clearImagePanel(); + } + } + + fireMediaDisplayStateChanged(); + } + + public synchronized void setImage(SerializableImage image) { + lda = null; + setBackground(View.getSwfBackgroundColor()); + clear(); + + timelined = null; + loaded = true; + stillFrame = true; + zoomAvailable = false; + iconPanel.setImg(image); + drawReady = true; + + fireMediaDisplayStateChanged(); + } + + public synchronized void setText(TextTag textTag, TextTag newTextTag) { + setBackground(View.getSwfBackgroundColor()); + clear(); + + lda = null; + timelined = null; + loaded = true; + stillFrame = true; + zoomAvailable = true; + + this.textTag = textTag; + this.newTextTag = newTextTag; + + double zoomDouble = zoom.fit ? getZoomToFit() : zoom.value; + + RECT rect = textTag.getRect(); + int width = (int) (rect.getWidth() * zoomDouble); + int height = (int) (rect.getHeight() * zoomDouble); + SerializableImage image = new SerializableImage((int) (width / SWF.unitDivisor) + 1, + (int) (height / SWF.unitDivisor) + 1, SerializableImage.TYPE_INT_ARGB); + image.fillTransparent(); + Matrix m = Matrix.getTranslateInstance(-rect.Xmin * zoomDouble, -rect.Ymin * zoomDouble); + m.scale(zoomDouble); + textTag.toImage(0, 0, 0, new RenderContext(), image, false, m, m, m, new ConstantColorColorTransform(0xFFC0C0C0)); + + if (newTextTag != null) { + newTextTag.toImage(0, 0, 0, new RenderContext(), image, false, m, m, m, new ConstantColorColorTransform(0xFF000000)); + } + + iconPanel.setImg(image); + drawReady = true; + + fireMediaDisplayStateChanged(); + } + + private synchronized void clearImagePanel() { + iconPanel.setImg(null); + } + + @Override + public synchronized int getCurrentFrame() { + return frame; + } + + @Override + public synchronized int getTotalFrames() { + if (timelined == null) { + return 0; + } + if (stillFrame) { + return 0; + } + return timelined.getTimeline().getFrameCount(); + } + + @Override + public void pause() { + stopInternal(); + redraw(); + } + + @Override + public void stop() { + stopInternal(); + rewind(); + redraw(); + } + + @Override + public void close() throws IOException { + stopInternal(); + } + + private void stopAllSounds() { + for (int i = soundPlayers.size() - 1; i >= 0; i--) { + SoundTagPlayer pl = soundPlayers.get(i); + pl.close(); + } + soundPlayers.clear(); + } + + private void clear() { + if (timer != null) { + timer.cancel(); + timer = null; + fireMediaDisplayStateChanged(); + } + + textTag = null; + newTextTag = null; + displayObjectCache.clear(); + } + + private void nextFrame(Timer thisTimer, final int cnt, final int timeShouldBe) { + drawFrame(thisTimer, true); + + synchronized (ImagePanel.class) { + if (timelined != null && timer == thisTimer) { + int frameCount = timelined.getTimeline().getFrameCount(); + + int oldFrame = frame; + for (int i = 0; i < cnt; i++) { + if (!stillFrame && frameCount > 0) { + frame = (frame + 1) % frameCount; + } + + if (!stillFrame && frame == frameCount - 1 && !loop) { + stopInternal(); + return; + } + + if (i < cnt - 1) { //skip not displayed frames, do not display, only play sounds, etc. + drawFrame(thisTimer, false); + } + } + if (frame != oldFrame) { + if (frame == 0) { + stopAllSounds(); + } + time = 0; + } else { + time = timeShouldBe; + } + } + } + + fireMediaDisplayStateChanged(); + } + + private static SerializableImage getFrame(SWF swf, int frame, int time, Timelined drawable, RenderContext renderContext, int selectedDepth, double zoom) { + Timeline timeline = drawable.getTimeline(); + //int mouseButton = renderContext.mouseButton; + //Point cursorPosition = renderContext.cursorPosition; + //String key = "drawable_" + frame + "_" + drawable.hashCode() + "_" + mouseButton + "_depth" + selectedDepth + "_" + (cursorPosition == null ? "out" : cursorPosition.hashCode()) + "_" + zoom + "_" + timeline.fontFrameNum; + SerializableImage img; + //SerializableImage img = swf.getFromCache(key); + //if (img == null) { + //boolean shouldCache = timeline.isSingleFrame(frame); + RECT rect = drawable.getRect(); + + int width = (int) (rect.getWidth() * zoom); + int height = (int) (rect.getHeight() * zoom); + SerializableImage image = new SerializableImage((int) Math.ceil(width / SWF.unitDivisor), + (int) Math.ceil(height / SWF.unitDivisor), SerializableImage.TYPE_INT_ARGB); + //renderContext.borderImage = new SerializableImage(image.getWidth(), image.getHeight(), SerializableImage.TYPE_INT_ARGB); + image.fillTransparent(); + Matrix m = new Matrix(); + m.translate(-rect.Xmin * zoom, -rect.Ymin * zoom); + m.scale(zoom); + timeline.toImage(frame, time, renderContext, image, false, m, m, m, null); + + Graphics2D gg = (Graphics2D) image.getGraphics(); + gg.setStroke(new BasicStroke(3)); + gg.setPaint(Color.green); + gg.setTransform(AffineTransform.getTranslateInstance(0, 0)); + DepthState ds = null; + if (timeline.getFrameCount() > frame) { + ds = timeline.getFrame(frame).layers.get(selectedDepth); + } + + if (ds != null) { + CharacterTag cht = swf.getCharacter(ds.characterId); + if (cht != null) { + if (cht instanceof DrawableTag) { + DrawableTag dt = (DrawableTag) cht; + int drawableFrameCount = dt.getNumFrames(); + if (drawableFrameCount == 0) { + drawableFrameCount = 1; + } + + int dframe = time % drawableFrameCount; + Shape outline = dt.getOutline(dframe, time, ds.ratio, renderContext, Matrix.getScaleInstance(1 / SWF.unitDivisor).concatenate(m.concatenate(new Matrix(ds.matrix))), true); + Rectangle bounds = outline.getBounds(); + gg.setStroke(new BasicStroke(2.0f, + BasicStroke.CAP_BUTT, + BasicStroke.JOIN_MITER, + 10.0f, new float[]{10.0f}, 0.0f)); + gg.setPaint(Color.red); + gg.draw(bounds); + } + } + } + + img = image; + + /*if (shouldCache) { + swf.putToCache(key, img); + }*/ + //} + return img; + } + + private Object execute(SWFInputStream sis) throws IOException { + if (!Configuration.internalFlashViewerExecuteAs12.get()) { + return Undefined.INSTANCE; + } + if (lda == null) { + return Undefined.INSTANCE; + } + long ip = sis.getPos(); + //System.err.println("============="); + Action a; + while ((a = sis.readAction()) != null) { + int actionLengthWithHeader = a.getTotalActionLength(); + a.setAddress(ip); + a.execute(lda); + /*System.err.print("" + a + ", stack: ["); + for (Object o : lda.stack) { + System.err.print("" + o + ","); + } + System.err.println("]");*/ + if (lda.returnValue != null) { + return lda.returnValue; + } + if (lda.jump != null) { + ip = lda.jump; + lda.jump = null; + } else { + ip += actionLengthWithHeader; + } + sis.seek(ip); + } + return Undefined.INSTANCE; + } + + private void executeFrame(int frame) { + if (!Configuration.internalFlashViewerExecuteAs12.get()) { + return; + } + if (timelined == null) { + return; + } + Frame f = timelined.getTimeline().getFrame(frame); + List actions = f.actions; + if (lda != null) { + lda.clear(); + } + for (DoActionTag src : actions) { + try { + ByteArrayRange actionBytes = src.getActionBytes(); + int prevLength = actionBytes.getPos(); + SWFInputStream rri = new SWFInputStream(swf, actionBytes.getArray(), 0, prevLength + actionBytes.getLength()); + if (prevLength != 0) { + rri.seek(prevLength); + } + execute(rri); + } catch (IOException ex) { + Logger.getLogger(ImagePanel.class.getName()).log(Level.SEVERE, null, ex); + } + + } + } + + private void drawFrame(Timer thisTimer, boolean display) { + Timelined timelined; + MouseEvent lastMouseEvent; + int frame; + int time; + Point cursorPosition; + int mouseButton; + int selectedDepth; + Zoom zoom; + SWF swf; + + synchronized (ImagePanel.class) { + timelined = this.timelined; + lastMouseEvent = this.lastMouseEvent; + } + + synchronized (ImagePanel.class) { + frame = this.frame; + time = this.time; + cursorPosition = this.cursorPosition; + if (cursorPosition != null) { + cursorPosition = iconPanel.toImagePoint(cursorPosition); + } + + mouseButton = this.mouseButton; + selectedDepth = this.selectedDepth; + zoom = this.zoom; + swf = this.swf; + } + + if (timelined == null) { + return; + } + + RenderContext renderContext = new RenderContext(); + renderContext.displayObjectCache = displayObjectCache; + if (cursorPosition != null) { + renderContext.cursorPosition = new Point((int) (cursorPosition.x * SWF.unitDivisor), (int) (cursorPosition.y * SWF.unitDivisor)); + } + + renderContext.mouseButton = mouseButton; + renderContext.stateUnderCursor = new ArrayList<>(); + + SerializableImage img; + try { + Timeline timeline = timelined.getTimeline(); + if (frame >= timeline.getFrameCount()) { + return; + } + + double zoomDouble = zoom.fit ? getZoomToFit() : zoom.value; + if (lowQuality) { + zoomDouble /= LQ_FACTOR; + } + updatePos(timelined, lastMouseEvent, thisTimer); + + Matrix mat = new Matrix(); + mat.translateX = swf.displayRect.Xmin; + mat.translateY = swf.displayRect.Ymin; + + img = null; + if (display) { + Stopwatch sw = Stopwatch.startNew(); + img = getFrame(swf, frame, time, timelined, renderContext, selectedDepth, zoomDouble); + sw.stop(); + if (sw.getElapsedMilliseconds() > 100) { + logger.log(Level.WARNING, "Slow rendering. {0}. frame, time={1}, {2}ms", new Object[]{frame, time, sw.getElapsedMilliseconds()}); + } + + if (renderContext.borderImage != null) { + img = renderContext.borderImage; + } + } + + List sounds = new ArrayList<>(); + List soundClasses = new ArrayList<>(); + timeline.getSounds(frame, time, renderContext.mouseOverButton, mouseButton, sounds, soundClasses); + for (int cid : swf.getCharacters().keySet()) { + CharacterTag c = swf.getCharacter(cid); + for (String cls : soundClasses) { + if (cls.equals(c.getClassName())) { + sounds.add(cid); + } + } + } + + for (int sndId : sounds) { + CharacterTag c = swf.getCharacter(sndId); + if (c instanceof SoundTag) { + SoundTag st = (SoundTag) c; + playSound(st, null, thisTimer); + } + } + executeFrame(frame); + } catch (Throwable ex) { + // swf was closed during the rendering probably + return; + } + if (display) { + + StringBuilder ret = new StringBuilder(); + + if (cursorPosition != null) { + ret.append(" [").append(cursorPosition.x).append(",").append(cursorPosition.y).append("] : "); + } + + boolean handCursor = renderContext.mouseOverButton != null; + boolean first = true; + for (int i = renderContext.stateUnderCursor.size() - 1; i >= 0; i--) { + DepthState ds = renderContext.stateUnderCursor.get(i); + if (!first) { + ret.append(", "); + } + + first = false; + CharacterTag c = swf.getCharacter(ds.characterId); + ret.append(c.toString()); + } + + if (first) { + ret.append(" - "); + } + + ButtonTag lastMouseOverButton; + synchronized (ImagePanel.class) { + if (timer == thisTimer) { + iconPanel.setImg(img); + lastMouseOverButton = iconPanel.mouseOverButton; + iconPanel.mouseOverButton = renderContext.mouseOverButton; + debugLabel.setText(ret.toString()); + if (handCursor) { + iconPanel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + } else if (iconPanel.hasAllowMove()) { + iconPanel.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)); + } else { + iconPanel.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + } + + if (lastMouseOverButton != renderContext.mouseOverButton) { + ButtonTag b = renderContext.mouseOverButton; + if (b != null) { + // New mouse entered + DefineButtonSoundTag sounds = b.getSounds(); + if (sounds != null && sounds.buttonSoundChar1 != 0) { // IdleToOverUp + playSound((SoundTag) swf.getCharacter(sounds.buttonSoundChar1), sounds.buttonSoundInfo1, timer); + } + } + + b = lastMouseOverButton; + if (b != null) { + // Old mouse leave + DefineButtonSoundTag sounds = b.getSounds(); + if (sounds != null && sounds.buttonSoundChar0 != 0) { // OverUpToIdle + playSound((SoundTag) swf.getCharacter(sounds.buttonSoundChar0), sounds.buttonSoundInfo0, timer); + } + } + } + + drawReady = true; + synchronized (delayObject) { + delayObject.notify(); + } + } + } + } + } + + private void playSound(SoundTag st, SOUNDINFO soundInfo, Timer thisTimer) { + final SoundTagPlayer sp; + try { + int loopCount = 1; + if (soundInfo != null && soundInfo.hasLoops) { + loopCount = Math.max(1, soundInfo.loopCount); + } + + sp = new SoundTagPlayer(st, loopCount, false); + sp.addEventListener(new MediaDisplayListener() { + @Override + public void mediaDisplayStateChanged(MediaDisplay source) { + } + + @Override + public void playingFinished(MediaDisplay source) { + synchronized (ImagePanel.class) { + sp.close(); + soundPlayers.remove(sp); + } + } + }); + + synchronized (ImagePanel.class) { + if (timer != null && timer == thisTimer) { + soundPlayers.add(sp); + sp.play(); + } else { + sp.close(); + } + } + } catch (LineUnavailableException | IOException | UnsupportedAudioFileException ex) { + logger.log(Level.SEVERE, "Error during playing sound", ex); + } + } + + public synchronized void clearAll() { + stopInternal(); + clearImagePanel(); + timelined = null; + swf = null; + + fireMediaDisplayStateChanged(); + } + + private synchronized void stopInternal() { + clear(); + stopAllSounds(); + } + + @Override + public synchronized void play() { + stopInternal(); + if (timelined != null) { + Timeline timeline = timelined.getTimeline(); + if (!stillFrame && frame == timeline.getFrameCount() - 1) { + frame = 0; + } + + startTimer(timeline, true); + } + } + + private synchronized void setMsPerFrame(int val) { + this.msPerFrame = val; + } + + private synchronized int getMsPerFrame() { + return this.msPerFrame; + } + + private long startRun = 0L; + + private final long startDrop = 0L; + + private int skippedFrames = 0; + + private float fpsShouldBe = 0; + + private float fpsIs = 0; + + private Timer fpsTimer; + + private int startFrame = 0; + + private synchronized void setFpsIs(float val) { + fpsIs = val; + } + + private synchronized float getFpsIs() { + return fpsIs; + } + + private synchronized void setSkippedFrames(int val) { + skippedFrames = val; + } + + private synchronized void addSkippedFrames(int val) { + skippedFrames += val; + } + + private synchronized int getSkippedFrames() { + return skippedFrames; + } + + private synchronized int getAndResetSkippedFrames() { + int ret = skippedFrames; + skippedFrames = 0; + return ret; + } + + private void scheduleTask(boolean singleFrame, long msDelay) { + TimerTask task = new TimerTask() { + public final Timer thisTimer = timer; + + public final boolean isSingleFrame = singleFrame; + + private long lastRun = 0L; + + @Override + public void run() { + try { + synchronized (ImagePanel.class) { + if (timer != thisTimer) { + return; + } + } + lastRun = System.currentTimeMillis(); + int curFrame = frame; + long delay = getMsPerFrame(); + if (isSingleFrame) { + drawFrame(thisTimer, true); + synchronized (ImagePanel.class) { + thisTimer.cancel(); + if (timer == thisTimer) { + timer = null; + } + } + + fireMediaDisplayStateChanged(); + } else { + //Time before drawing current frame + long frameTimeMsIs = System.currentTimeMillis(); + //Total number of frames in this timeline + int frameCount = timelined.getTimeline().getFrameCount(); + //How many ticks (= times where frame should be displayed in framerate) are there from hitting play button + int ticksFromStart = (int) Math.floor((frameTimeMsIs - startRun) / (double) getMsPerFrame()) + 1; + //Add ticks to first frame when hitting play button, ignoring total framecount => this value can be larger than number of frames in timeline + int frameOverMaxShouldBeNow = startFrame + ticksFromStart; + //Apply maximum frames repating, this is actual frame which should be drawed now + int frameShouldBeNow = frameOverMaxShouldBeNow % frameCount; + + //How many frames are there between last displayed frame and now. For perfect display(=no framedrop), value should be 1 + int skipFrames = frameShouldBeNow - curFrame; + //It is negative for some reason, this will display older frames. Add frameCount to stay in modulu framecount. + if (skipFrames < 0) { + skipFrames += frameCount; + } + //Change for more than 1 frame + if (skipFrames > 1) { + addSkippedFrames(skipFrames - 1); //drop those frames, draw only last one + } + //Frame "time" - ticks in current frame + int currentFrameTicks = 0; + if (frameCount == 1) { //We have only one frame, so the ticks on that frame equal ticks on whole timeline + currentFrameTicks = ticksFromStart; + } + nextFrame(thisTimer, skipFrames, currentFrameTicks); + + long afterDrawFrameTimeMsIs = System.currentTimeMillis(); + + int nextFrameOverMax = frameOverMaxShouldBeNow; + while (delay < 0) { //while the frame time already passed + nextFrameOverMax++; + long nextFrameOverMaxTimeMsShouldBe = startRun + getMsPerFrame() * nextFrameOverMax; + delay = nextFrameOverMaxTimeMsShouldBe - afterDrawFrameTimeMsIs; + } + } + //schedule next run of the task + scheduleTask(isSingleFrame, delay); + + } catch (Exception ex) { + logger.log(Level.SEVERE, "Frame drawing error", ex); + } + } + }; + if (timer != null) { + timer.schedule(task, msDelay); + } + } + + private synchronized void startTimer(Timeline timeline, boolean playing) { + + startRun = System.currentTimeMillis(); + startFrame = frame; + float frameRate = timeline.frameRate; + setMsPerFrame(frameRate == 0 ? 1000 : (int) (1000.0 / frameRate)); + final boolean singleFrame = !playing + || (stillFrame && timeline.isSingleFrame(frame)) + || (!stillFrame && timeline.getRealFrameCount() <= 1 && timeline.isSingleFrame()); + + if (fpsTimer == null) { + fpsTimer = new Timer(); + fpsTimer.schedule(new TimerTask() { + @Override + public void run() { + float skipped = getAndResetSkippedFrames(); + setFpsIs(fpsShouldBe - skipped); + } + }, 1000, 1000); + } + timer = new Timer(); + fpsShouldBe = timeline.frameRate; + fpsIs = fpsShouldBe; + scheduleTask(singleFrame, 0); + + } + + @Override + public synchronized void rewind() { + frame = 0; + fireMediaDisplayStateChanged(); + } + + @Override + public synchronized boolean isPlaying() { + if (timelined == null || stillFrame) { + return false; + } + + return (timelined.getTimeline().getFrameCount() <= 1) || (timer != null); + } + + @Override + public void setLoop(boolean loop) { + this.loop = loop; + } + + @Override + public synchronized void gotoFrame(int frame) { + if (timelined == null) { + return; + } + Timeline timeline = timelined.getTimeline(); + if (frame >= timeline.getFrameCount()) { + return; + } + if (frame < 0) { + return; + } + + this.frame = frame; + stopInternal(); + redraw(); + fireMediaDisplayStateChanged(); + } + + @Override + public synchronized float getFrameRate() { + if (timelined == null) { + return 1; + } + if (stillFrame) { + return 1; + } + return timelined.getTimeline().frameRate; + } + + @Override + public synchronized boolean isLoaded() { + return loaded; + } + + @Override + public boolean loopAvailable() { + return false; + } + + @Override + public boolean screenAvailable() { + return true; + } + + @Override + public synchronized Zoom getZoom() { + return zoom; + } +} diff --git a/src/com/jpexs/decompiler/flash/gui/Main.java b/src/com/jpexs/decompiler/flash/gui/Main.java index 0bde11431..d4355780f 100644 --- a/src/com/jpexs/decompiler/flash/gui/Main.java +++ b/src/com/jpexs/decompiler/flash/gui/Main.java @@ -1,2377 +1,2377 @@ -/* - * 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.debugger.flash.Debugger; -import com.jpexs.debugger.flash.DebuggerCommands; -import com.jpexs.debugger.flash.Variable; -import com.jpexs.debugger.flash.VariableType; -import com.jpexs.debugger.flash.messages.in.InCallFunction; -import com.jpexs.decompiler.flash.ApplicationInfo; -import com.jpexs.decompiler.flash.EventListener; -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFBundle; -import com.jpexs.decompiler.flash.SWFSourceInfo; -import com.jpexs.decompiler.flash.SearchMode; -import com.jpexs.decompiler.flash.SwfOpenException; -import com.jpexs.decompiler.flash.UrlResolver; -import com.jpexs.decompiler.flash.Version; -import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; -import com.jpexs.decompiler.flash.abc.avm2.parser.script.Reference; -import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.decompiler.flash.configuration.SwfSpecificConfiguration; -import com.jpexs.decompiler.flash.console.CommandLineArgumentParser; -import com.jpexs.decompiler.flash.console.ContextMenuTools; -import com.jpexs.decompiler.flash.exporters.modes.ExeExportMode; -import com.jpexs.decompiler.flash.gui.debugger.DebugListener; -import com.jpexs.decompiler.flash.gui.debugger.DebuggerTools; -import com.jpexs.decompiler.flash.gui.pipes.FirstInstance; -import com.jpexs.decompiler.flash.gui.proxy.ProxyFrame; -import com.jpexs.decompiler.flash.helpers.SWFDecompilerPlugin; -import com.jpexs.decompiler.flash.tags.Tag; -import com.jpexs.decompiler.flash.tags.base.FontTag; -import com.jpexs.decompiler.flash.tags.base.ImportTag; -import com.jpexs.decompiler.flash.treeitems.SWFList; -import com.jpexs.helpers.Cache; -import com.jpexs.helpers.CancellableWorker; -import com.jpexs.helpers.Helper; -import com.jpexs.helpers.Path; -import com.jpexs.helpers.ProgressListener; -import com.jpexs.helpers.Stopwatch; -import com.jpexs.helpers.streams.SeekableInputStream; -import com.sun.jna.Platform; -import com.sun.jna.platform.win32.Advapi32Util; -import com.sun.jna.platform.win32.Kernel32; -import com.sun.jna.platform.win32.WinReg; -import java.awt.AWTException; -import java.awt.Frame; -import java.awt.GraphicsEnvironment; -import java.awt.MenuItem; -import java.awt.PopupMenu; -import java.awt.SystemTray; -import java.awt.TrayIcon; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.FilenameFilter; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.lang.reflect.Field; -import java.net.InetSocketAddress; -import java.net.Proxy; -import java.net.URL; -import java.net.URLConnection; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Date; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Objects; -import java.util.Set; -import java.util.concurrent.CancellationException; -import java.util.concurrent.ExecutionException; -import java.util.logging.ConsoleHandler; -import java.util.logging.FileHandler; -import java.util.logging.Formatter; -import java.util.logging.Handler; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.logging.SimpleFormatter; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import javax.swing.JFileChooser; -import javax.swing.JFrame; -import javax.swing.JOptionPane; -import javax.swing.SwingWorker; -import javax.swing.UIManager; -import javax.swing.UnsupportedLookAndFeelException; -import javax.swing.filechooser.FileFilter; -import org.pushingpixels.substance.api.SubstanceLookAndFeel; - -/** - * Main executable class - * - * @author JPEXS - */ -public class Main { - - protected static ProxyFrame proxyFrame; - - private static List sourceInfos = new ArrayList<>(); - - public static LoadingDialog loadingDialog; - - private static boolean working = false; - - private static TrayIcon trayIcon; - - private static MenuItem stopMenuItem; - - private static volatile MainFrame mainFrame; - - public static final int UPDATE_SYSTEM_MAJOR = 1; - - public static final int UPDATE_SYSTEM_MINOR = 3; - - private static LoadFromMemoryFrame loadFromMemoryFrame; - - private static LoadFromCacheFrame loadFromCacheFrame; - - private static final Logger logger = Logger.getLogger(Main.class.getName()); - - public static DebugLogDialog debugDialog; - - public static boolean shouldCloseWhenClosingLoadingDialog; - - private static Debugger flashDebugger; - - private static DebuggerHandler debugHandler = null; - - //private static int ip = 0; - //private static String ipClass = null; - private static Process runProcess; - - private static boolean runProcessDebug; - - private static boolean runProcessDebugPCode; - - private static boolean inited = false; - - private static File runTempFile; - - private static List runTempFiles = new ArrayList<>(); - - public static void freeRun() { - synchronized (Main.class) { - if (runTempFile != null) { - runTempFile.delete(); - runTempFile = null; - } - for (File f : runTempFiles) { - f.delete(); - } - runTempFiles.clear(); - - runProcess = null; - } - if (mainFrame != null && mainFrame.getPanel() != null) { - mainFrame.getPanel().clearDebuggerColors(); - } - if (runProcessDebug) { - Main.getDebugHandler().disconnect(); - } - } - - public static synchronized boolean isDebugPaused() { - return runProcess != null && runProcessDebug && getDebugHandler().isPaused(); - } - - public static synchronized boolean isDebugRunning() { - return runProcess != null && runProcessDebug; - } - - public static synchronized boolean isDebugPCode() { - return runProcessDebugPCode; - } - - public static synchronized boolean isDebugConnected() { - return getDebugHandler().isConnected(); - } - - public static synchronized boolean isRunning() { - return runProcess != null && !runProcessDebug; - } - - /** - * FIXME! - * - * @param v - */ - public static synchronized void dumpBytes(Variable v) { - InCallFunction icf; - try { - long objectId = 0l; - if ((v.vType == VariableType.OBJECT || v.vType == VariableType.MOVIECLIP)) { - objectId = (Long) v.value; - } - Object oldPos = getDebugHandler().getVariable(objectId, "position", true).parent.value; - getDebugHandler().setVariable(objectId, "position", VariableType.NUMBER, 0); - icf = getDebugHandler().callFunction(false, "readUTF", v, new ArrayList<>()); - System.out.println("Result=" + icf.variables.get(0).value); - getDebugHandler().setVariable(objectId, "position", VariableType.NUMBER, oldPos); - } catch (DebuggerHandler.ActionScriptException ex) { - Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); - } - - } - - public static synchronized boolean addWatch(Variable v, long v_id, boolean watchRead, boolean watchWrite) { - DebuggerCommands.Watch w = getDebugHandler().addWatch(v, v_id, watchRead, watchWrite); - return w != null; - } - - public static void runPlayer(String title, final String exePath, String file, String flashVars) { - if (!new File(file).exists()) { - return; - } - if (flashVars != null && !flashVars.isEmpty()) { - file += "?" + flashVars; - } - final String ffile = file; - - CancellableWorker runWorker = new CancellableWorker() { - @Override - protected Object doInBackground() throws Exception { - Process proc; - try { - proc = Runtime.getRuntime().exec(new String[]{exePath, ffile}); - } catch (IOException ex) { - logger.log(Level.SEVERE, null, ex); - return null; - } - boolean isDebug; - - synchronized (Main.class) { - runProcess = proc; - isDebug = runProcessDebug; - } - if (isDebug) { - mainFrame.getMenu().hilightPath("/debugging"); - } - mainFrame.getMenu().updateComponents(); - try { - if (proc != null) { - proc.waitFor(); - } - } catch (InterruptedException ex) { - if (proc != null) { - try { - proc.destroy(); - } catch (Exception ex2) { - //ignore - } - } - } - freeRun(); - stopDebugger(); - mainFrame.getMenu().updateComponents(); - return null; - } - - @Override - protected void done() { - Main.stopWork(); - } - - @Override - public void workerCancelled() { - Main.stopWork(); - synchronized (Main.class) { - if (runProcess != null) { - try { - runProcess.destroy(); - } catch (Exception ex) { - - } - } - } - freeRun(); - mainFrame.getMenu().updateComponents(); - } - }; - - mainFrame.getMenu().updateComponents(); - Main.startWork(title + "...", runWorker); - runWorker.execute(); - } - - public static void stopRun() { - - synchronized (Main.class) { - if (runProcess != null) { - runProcess.destroy(); - } - } - freeRun(); - stopDebugger(); - mainFrame.getMenu().updateComponents(); - } - - private static interface SwfPreparation { - - public SWF prepare(SWF swf); - } - - private static class SwfRunPrepare implements SwfPreparation { - - @Override - public SWF prepare(SWF swf) { - if (Configuration.autoOpenLoadedSWFs.get()) { - if (!DebuggerTools.hasDebugger(swf)) { - DebuggerTools.switchDebugger(swf); - } - DebuggerTools.injectDebugLoader(swf); - } - return swf; - } - } - - private static class SwfDebugPrepare extends SwfRunPrepare { - - private boolean doPCode; - - public SwfDebugPrepare(boolean doPCode) { - this.doPCode = doPCode; - } - - @Override - public SWF prepare(SWF instrSWF) { - instrSWF = super.prepare(instrSWF); - try { - File fTempFile = new File(instrSWF.getFile()); - instrSWF.enableDebugging(true, new File("."), true, doPCode); - FileOutputStream fos = new FileOutputStream(fTempFile); - instrSWF.saveTo(fos); - fos.close(); - if (!instrSWF.isAS3()) { - //Read again, because line file offsets changed with adding debug tags - //TODO: handle somehow without rereading? - instrSWF = null; - try (FileInputStream fis = new FileInputStream(fTempFile)) { - instrSWF = new SWF(fis, false, false); - } catch (InterruptedException ex) { - logger.log(Level.SEVERE, null, ex); - } - if (instrSWF != null) { - String swfFileName = fTempFile.getAbsolutePath(); - if (swfFileName.toLowerCase().endsWith(".swf")) { - swfFileName = swfFileName.substring(0, swfFileName.length() - 4) + ".swd"; - } else { - swfFileName = swfFileName + ".swd"; - } - File swdFile = new File(swfFileName); - if (doPCode) { - instrSWF.generatePCodeSwdFile(swdFile, getPackBreakPoints(true)); - } else { - instrSWF.generateSwdFile(swdFile, getPackBreakPoints(true)); - } - } - } - } catch (IOException ex) { - //ignore, return instrSWF - } - return instrSWF; - } - } - - private static void prepareSwf(SwfPreparation prep, File toPrepareFile, File origFile, List tempFiles) throws IOException { - SWF instrSWF = null; - try (FileInputStream fis = new FileInputStream(toPrepareFile)) { - instrSWF = new SWF(fis, toPrepareFile.getAbsolutePath(), origFile.getName(), false); - } catch (InterruptedException ex) { - logger.log(Level.SEVERE, null, ex); - } - if (instrSWF != null) { - for (Tag t : instrSWF.getLocalTags()) { - if (t instanceof ImportTag) { - ImportTag it = (ImportTag) t; - String url = it.getUrl(); - File importedFile = new File(origFile.getParentFile(), url); - if (importedFile.exists()) { - File newTempFile = File.createTempFile("ffdec_run_import_", ".swf"); - it.setUrl("./" + newTempFile.getName()); - byte[] impData = Helper.readFile(importedFile.getAbsolutePath()); - Helper.writeFile(newTempFile.getAbsolutePath(), impData); - tempFiles.add(newTempFile); - prepareSwf(prep, newTempFile, importedFile, tempFiles); - } - } - } - if (prep != null) { - instrSWF = prep.prepare(instrSWF); - } - try (FileOutputStream fos = new FileOutputStream(toPrepareFile)) { - instrSWF.saveTo(fos); - } - } - } - - public static void run(SWF swf) { - String flashVars = "";//key=val&key2=val2 - String playerLocation = Configuration.playerLocation.get(); - if (playerLocation.isEmpty() || (!new File(playerLocation).exists())) { - View.showMessageDialog(null, AppStrings.translate("message.playerpath.notset"), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE); - advancedSettings("paths"); - return; - } - if (swf == null) { - return; - } - File tempFile; - List tempFiles = new ArrayList<>(); - try { - tempFile = File.createTempFile("ffdec_run_", ".swf"); - - try (FileOutputStream fos = new FileOutputStream(tempFile)) { - swf.saveTo(fos); - } - - prepareSwf(new SwfRunPrepare(), tempFile, new File(swf.getFile()), tempFiles); - - } catch (IOException ex) { - return; - - } - if (tempFile != null) { - synchronized (Main.class) { - runTempFile = tempFile; - runTempFiles = tempFiles; - runProcessDebug = false; - } - runPlayer(AppStrings.translate("work.running"), playerLocation, tempFile.getAbsolutePath(), flashVars); - } - } - - public static void runDebug(SWF swf, final boolean doPCode) { - String flashVars = "";//key=val&key2=val2 - String playerLocation = Configuration.playerDebugLocation.get(); - if (playerLocation.isEmpty() || (!new File(playerLocation).exists())) { - View.showMessageDialog(null, AppStrings.translate("message.playerpath.debug.notset"), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE); - Main.advancedSettings("paths"); - return; - } - if (swf == null) { - return; - } - File tempFile = null; - - try { - tempFile = File.createTempFile("ffdec_debug_", ".swf"); - } catch (Exception ex) { - - } - - if (tempFile != null) { - final File fTempFile = tempFile; - final List tempFiles = new ArrayList<>(); - CancellableWorker instrumentWorker = new CancellableWorker() { - @Override - protected Object doInBackground() throws Exception { - - try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(fTempFile))) { - swf.saveTo(fos); - } - prepareSwf(new SwfDebugPrepare(doPCode), fTempFile, new File(swf.getFile()), tempFiles); - return null; - } - - @Override - public void workerCancelled() { - Main.stopWork(); - } - - @Override - protected void done() { - synchronized (Main.class) { - runTempFile = fTempFile; - runProcessDebug = true; - runProcessDebugPCode = doPCode; - runTempFiles = tempFiles; - } - Main.stopWork(); - Main.startDebugger(); - runPlayer(AppStrings.translate("work.debugging.wait"), playerLocation, fTempFile.getAbsolutePath(), flashVars); - } - }; - - Main.startWork(AppStrings.translate("work.debugging.instrumenting"), instrumentWorker); - instrumentWorker.execute(); - } - } - - /* public static void debuggerNotSuspended() { - - }*/ - public static boolean isDebugging() { - return isDebugRunning(); - } - - public synchronized static int getIp(Object pack) { - return getDebugHandler().getBreakIp(); - } - - public synchronized static String getIpClass() { - return getDebugHandler().getBreakScriptName(); - } - - public static synchronized boolean isBreakPointValid(String scriptName, int line) { - return !getDebugHandler().isBreakpointInvalid(scriptName, line); - } - - public synchronized static void addBreakPoint(String scriptName, int line) { - getDebugHandler().addBreakPoint(scriptName, line); - } - - public synchronized static void removeBreakPoint(String scriptName, int line) { - getDebugHandler().removeBreakPoint(scriptName, line); - } - - public synchronized static boolean toggleBreakPoint(String scriptName, int line) { - if (getDebugHandler().isBreakpointToAdd(scriptName, line) || getDebugHandler().isBreakpointConfirmed(scriptName, line) || getDebugHandler().isBreakpointInvalid(scriptName, line)) { - getDebugHandler().removeBreakPoint(scriptName, line); - return false; - } else { - getDebugHandler().addBreakPoint(scriptName, line); - return true; - } - } - - public synchronized static Map> getPackBreakPoints(boolean validOnly) { - return getDebugHandler().getAllBreakPoints(validOnly); - } - - public synchronized static Set getScriptBreakPoints(String pack, boolean onlyValid) { - return getDebugHandler().getBreakPoints(pack, onlyValid); - } - - public static DebuggerHandler getDebugHandler() { - return debugHandler; - } - - public static void ensureMainFrame() { - if (mainFrame == null) { - synchronized (Main.class) { - if (mainFrame == null) { - MainFrame frame; - if (Configuration.useRibbonInterface.get()) { - frame = new MainFrameRibbon(); - } else { - frame = new MainFrameClassic(); - } - frame.getPanel().setErrorState(ErrorLogFrame.getInstance().getErrorState()); - mainFrame = frame; - } - } - } - } - - public static MainFrame getMainFrame() { - return mainFrame; - } - - public static void loadFromCache() { - if (loadFromCacheFrame == null) { - loadFromCacheFrame = new LoadFromCacheFrame(); - } - loadFromCacheFrame.setVisible(true); - } - - public static void loadFromMemory() { - if (loadFromMemoryFrame == null) { - loadFromMemoryFrame = new LoadFromMemoryFrame(mainFrame); - } - loadFromMemoryFrame.setVisible(true); - } - - public static void setVariable(long parentId, String varName, int valueType, Object value) { - getDebugHandler().setVariable(parentId, varName, valueType, value); - } - - public static void setSubLimiter(boolean value) { - if (value) { - AVM2Code.toSourceLimit = Configuration.sublimiter.get(); - } else { - AVM2Code.toSourceLimit = -1; - } - } - - public synchronized static boolean isInited() { - return inited; - } - - public synchronized static void setSessionLoaded(boolean v) { - inited = v; - } - - public static boolean isWorking() { - return working; - } - - public static void startProxy(int port) { - if (proxyFrame == null) { - proxyFrame = new ProxyFrame(mainFrame); - } - - proxyFrame.setPort(port); - addTrayIcon(); - switchProxy(); - } - - public static void showProxy() { - if (proxyFrame == null) { - proxyFrame = new ProxyFrame(mainFrame); - } - proxyFrame.setVisible(true); - proxyFrame.setState(Frame.NORMAL); - } - - public static void startWork(String name, CancellableWorker worker) { - startWork(name, -1, worker); - } - - public static void startWork(final String name, final int percent, final CancellableWorker worker) { - working = true; - View.execInEventDispatchLater(() -> { - if (mainFrame != null) { - mainFrame.getPanel().setWorkStatus(name, worker); - if (percent == -1) { - mainFrame.getPanel().hidePercent(); - } else { - mainFrame.getPanel().setPercent(percent); - } - } - if (loadingDialog != null) { - loadingDialog.setDetail(name); - loadingDialog.setPercent(percent); - } - if (CommandLineArgumentParser.isCommandLineMode()) { - System.out.println(name); - } - }); - } - - public static void stopWork() { - working = false; - View.execInEventDispatchLater(() -> { - if (mainFrame != null) { - mainFrame.getPanel().setWorkStatus("", null); - } - if (loadingDialog != null) { - loadingDialog.setDetail(""); - } - }); - } - - public static SWFList parseSWF(SWFSourceInfo sourceInfo) throws Exception { - SWFList result = new SWFList(); - - InputStream inputStream = sourceInfo.getInputStream(); - SWFBundle bundle = null; - FileInputStream fis = null; - if (inputStream == null) { - inputStream = new BufferedInputStream(fis = new FileInputStream(sourceInfo.getFile())); - bundle = sourceInfo.getBundle(false, SearchMode.ALL); - logger.log(Level.INFO, "Load file: {0}", sourceInfo.getFile()); - } else if (inputStream instanceof SeekableInputStream - || inputStream instanceof BufferedInputStream) { - try { - inputStream.reset(); - } catch (IOException ex) { - logger.log(Level.SEVERE, null, ex); - } - logger.log(Level.INFO, "Load stream: {0}", sourceInfo.getFileTitle()); - } - - Stopwatch sw = Stopwatch.startNew(); - if (bundle != null) { - result.bundle = bundle; - result.name = new File(sourceInfo.getFileTitleOrName()).getName(); - for (Entry streamEntry : bundle.getAll().entrySet()) { - InputStream stream = streamEntry.getValue(); - stream.reset(); - CancellableWorker worker = new CancellableWorker() { - @Override - public SWF doInBackground() throws Exception { - final CancellableWorker worker = this; - SWF swf = new SWF(stream, null, streamEntry.getKey(), new ProgressListener() { - @Override - public void progress(int p) { - startWork(AppStrings.translate("work.reading.swf"), p, worker); - } - }, Configuration.parallelSpeedUp.get()); - return swf; - } - }; - loadingDialog.setWroker(worker); - worker.execute(); - - try { - result.add(worker.get()); - } catch (CancellationException ex) { - logger.log(Level.WARNING, "Loading SWF {0} was cancelled.", streamEntry.getKey()); - } - } - } else { - InputStream fInputStream = inputStream; - - final String[] yesno = new String[]{AppStrings.translate("button.yes"), AppStrings.translate("button.no"), AppStrings.translate("button.yes.all"), AppStrings.translate("button.no.all")}; - - CancellableWorker worker = new CancellableWorker() { - private boolean yestoall = false; - - private boolean notoall = false; - - private SWF open(InputStream is, String file, String fileTitle) throws IOException, InterruptedException { - final CancellableWorker worker = this; - - SWF swf = new SWF(is, file, fileTitle, new ProgressListener() { - @Override - public void progress(int p) { - startWork(AppStrings.translate("work.reading.swf"), p, worker); - } - }, Configuration.parallelSpeedUp.get(), false, true, new UrlResolver() { - @Override - public SWF resolveUrl(final String url) { - int opt = -1; - if (!(yestoall || notoall)) { - opt = View.showOptionDialog(null, AppStrings.translate("message.imported.swf").replace("%url%", url), AppStrings.translate("message.warning"), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, yesno, AppStrings.translate("button.yes")); - if (opt == 2) { - yestoall = true; - } - if (opt == 3) { - notoall = true; - } - } - - if (yestoall) { - opt = 0; // yes - } else if (notoall) { - opt = 1; // no - } - - if (opt == 1) //no - { - return null; - } - - if (url.startsWith("http://") || url.startsWith("https://")) { - try { - URL u = new URL(url); - return open(u.openStream(), null, url); //? - } catch (Exception ex) { - //ignore - } - } else { - File f = new File(new File(file).getParentFile(), url); - if (f.exists()) { - try { - return open(new FileInputStream(f), f.getAbsolutePath(), f.getName()); - } catch (Exception ex) { - //ignore - } - } - } - Reference ret = new Reference<>(null); - View.execInEventDispatch(new Runnable() { - @Override - public void run() { - - while (JOptionPane.YES_OPTION == View.showConfirmDialog(null, AppStrings.translate("message.imported.swf.manually").replace("%url%", url), AppStrings.translate("error"), JOptionPane.YES_NO_OPTION, JOptionPane.ERROR_MESSAGE)) { - - JFileChooser fc = new JFileChooser(); - fc.setCurrentDirectory(new File(Configuration.lastOpenDir.get())); - FileFilter allSupportedFilter = new FileFilter() { - private final String[] supportedExtensions = new String[]{".swf", ".gfx"}; - - @Override - public boolean accept(File f) { - String name = f.getName().toLowerCase(); - for (String ext : supportedExtensions) { - if (name.endsWith(ext)) { - return true; - } - } - return f.isDirectory(); - } - - @Override - public String getDescription() { - String exts = Helper.joinStrings(supportedExtensions, "*%s", "; "); - return AppStrings.translate("filter.supported") + " (" + exts + ")"; - } - }; - fc.setFileFilter(allSupportedFilter); - FileFilter swfFilter = new FileFilter() { - @Override - public boolean accept(File f) { - return (f.getName().toLowerCase().endsWith(".swf")) || (f.isDirectory()); - } - - @Override - public String getDescription() { - return AppStrings.translate("filter.swf"); - } - }; - fc.addChoosableFileFilter(swfFilter); - - FileFilter gfxFilter = new FileFilter() { - @Override - public boolean accept(File f) { - return (f.getName().toLowerCase().endsWith(".gfx")) || (f.isDirectory()); - } - - @Override - public String getDescription() { - return AppStrings.translate("filter.gfx"); - } - }; - fc.addChoosableFileFilter(gfxFilter); - fc.setAcceptAllFileFilterUsed(false); - JFrame f = new JFrame(); - View.setWindowIcon(f); - int returnVal = fc.showOpenDialog(f); - if (returnVal == JFileChooser.APPROVE_OPTION) { - Configuration.lastOpenDir.set(Helper.fixDialogFile(fc.getSelectedFile()).getParentFile().getAbsolutePath()); - File selFile = Helper.fixDialogFile(fc.getSelectedFile()); - try { - ret.setVal(open(new FileInputStream(selFile), selFile.getAbsolutePath(), selFile.getName())); - break; - } catch (Exception ex) { - //ignore; - } - } else { - break; - } - } - } - }); - return ret.getVal(); - } - }); - return swf; - } - - @Override - public SWF doInBackground() throws Exception { - return open(fInputStream, sourceInfo.getFile(), sourceInfo.getFileTitle()); - } - }; - if (loadingDialog != null) { - loadingDialog.setWroker(worker); - } - worker.execute(); - - try { - result.add(worker.get()); - } catch (CancellationException ex) { - logger.log(Level.WARNING, "Loading SWF {0} was cancelled.", sourceInfo.getFileTitleOrName()); - } - } - - if (fis != null) { - logger.log(Level.INFO, "File loaded in {0} seconds.", (sw.getElapsedMilliseconds() / 1000)); - fis.close(); - } else { - logger.log(Level.INFO, "Stream loaded in {0} seconds.", (sw.getElapsedMilliseconds() / 1000)); - } - - result.sourceInfo = sourceInfo; - for (SWF swf : result) { - logger.log(Level.INFO, ""); - logger.log(Level.INFO, "== File information =="); - logger.log(Level.INFO, "Size: {0}", Helper.formatFileSize(swf.fileSize)); - logger.log(Level.INFO, "Flash version: {0}", swf.version); - int width = (int) ((swf.displayRect.Xmax - swf.displayRect.Xmin) / SWF.unitDivisor); - int height = (int) ((swf.displayRect.Ymax - swf.displayRect.Ymin) / SWF.unitDivisor); - logger.log(Level.INFO, "Width: {0}", width); - logger.log(Level.INFO, "Height: {0}", height); - - swf.swfList = result; - swf.addEventListener(new EventListener() { - @Override - public void handleExportingEvent(String type, int index, int count, Object data) { - String text = AppStrings.translate("work.exporting"); - if (type != null && type.length() > 0) { - text += " " + type; - } - - startWork(text + " " + index + "/" + count + " " + data, null); - } - - @Override - public void handleExportedEvent(String type, int index, int count, Object data) { - String text = AppStrings.translate("work.exported"); - if (type != null && type.length() > 0) { - text += " " + type; - } - - startWork(text + " " + index + "/" + count + " " + data, null); - } - - @Override - public void handleEvent(String event, Object data) { - if (event.equals("exporting") || event.equals("exported")) { - throw new Error("Event is not supported by this handler."); - } - if (event.equals("getVariables")) { - startWork(AppStrings.translate("work.gettingvariables") + "..." + (String) data, null); - } - if (event.equals("deobfuscate")) { - startWork(AppStrings.translate("work.deobfuscating") + "..." + (String) data, null); - } - if (event.equals("rename")) { - startWork(AppStrings.translate("work.renaming") + "..." + (String) data, null); - } - } - }); - } - - return result; - } - - public static void saveFile(SWF swf, String outfile) throws IOException { - saveFile(swf, outfile, SaveFileMode.SAVE, null); - } - - public static void saveFile(SWF swf, String outfile, SaveFileMode mode, ExeExportMode exeExportMode) throws IOException { - if (mode == SaveFileMode.SAVEAS && !swf.swfList.isBundle()) { - swf.setFile(outfile); - swf.swfList.sourceInfo.setFile(outfile); - } - File outfileF = new File(outfile); - File tmpFile = new File(outfile + ".tmp"); - try (FileOutputStream fos = new FileOutputStream(tmpFile); - BufferedOutputStream bos = new BufferedOutputStream(fos)) { - if (mode == SaveFileMode.EXE) { - switch (exeExportMode) { - case WRAPPER: - InputStream exeStream = View.class.getClassLoader().getResourceAsStream("com/jpexs/helpers/resource/Swf2Exe.bin"); - Helper.copyStream(exeStream, bos); - int width = swf.displayRect.Xmax - swf.displayRect.Xmin; - int height = swf.displayRect.Ymax - swf.displayRect.Ymin; - bos.write(width & 0xff); - bos.write((width >> 8) & 0xff); - bos.write((width >> 16) & 0xff); - bos.write((width >> 24) & 0xff); - bos.write(height & 0xff); - bos.write((height >> 8) & 0xff); - bos.write((height >> 16) & 0xff); - bos.write((height >> 24) & 0xff); - bos.write(Configuration.saveAsExeScaleMode.get()); - break; - case PROJECTOR_WIN: - case PROJECTOR_MAC: - case PROJECTOR_LINUX: - File projectorFile = Configuration.getProjectorFile(exeExportMode); - if (projectorFile == null) { - String message = "Projector not found, please place it to " + Configuration.getProjectorPath(); - logger.log(Level.SEVERE, message); - throw new IOException(message); - } - Helper.copyStream(new FileInputStream(projectorFile), bos); - bos.flush(); - break; - } - } - - long pos = fos.getChannel().position(); - swf.saveTo(bos); - - if (mode == SaveFileMode.EXE) { - switch (exeExportMode) { - case PROJECTOR_WIN: - case PROJECTOR_MAC: - case PROJECTOR_LINUX: - bos.flush(); - int swfSize = (int) (fos.getChannel().position() - pos); - - // write magic number - bos.write(0x56); - bos.write(0x34); - bos.write(0x12); - bos.write(0xfa); - - bos.write(swfSize & 0xff); - bos.write((swfSize >> 8) & 0xff); - bos.write((swfSize >> 16) & 0xff); - bos.write((swfSize >> 24) & 0xff); - } - } - } - if (tmpFile.exists()) { - if (tmpFile.length() > 0) { - outfileF.delete(); - if (!tmpFile.renameTo(outfileF)) { - tmpFile.delete(); - throw new IOException("Cannot access " + outfile); - } - } else { - throw new IOException("Output is empty"); - } - } else { - throw new IOException("Output not found"); - } - } - - private static class OpenFileWorker extends SwingWorker { - - private final SWFSourceInfo[] sourceInfos; - - private final Runnable executeAfterOpen; - - private final int[] reloadIndices; - - public OpenFileWorker(SWFSourceInfo sourceInfo) { - this(sourceInfo, -1); - } - - public OpenFileWorker(SWFSourceInfo sourceInfo, int reloadIndex) { - this(sourceInfo, null, reloadIndex); - } - - public OpenFileWorker(SWFSourceInfo sourceInfo, Runnable executeAfterOpen) { - this(sourceInfo, executeAfterOpen, -1); - } - - public OpenFileWorker(SWFSourceInfo sourceInfo, Runnable executeAfterOpen, int reloadIndex) { - this.sourceInfos = new SWFSourceInfo[]{sourceInfo}; - this.executeAfterOpen = executeAfterOpen; - this.reloadIndices = new int[]{reloadIndex}; - } - - public OpenFileWorker(SWFSourceInfo[] sourceInfos) { - this(sourceInfos, null, null); - } - - public OpenFileWorker(SWFSourceInfo[] sourceInfos, Runnable executeAfterOpen) { - this(sourceInfos, executeAfterOpen, null); - } - - public OpenFileWorker(SWFSourceInfo[] sourceInfos, Runnable executeAfterOpen, int[] reloadIndices) { - this.sourceInfos = sourceInfos; - this.executeAfterOpen = executeAfterOpen; - int[] indices = new int[sourceInfos.length]; - for (int i = 0; i < indices.length; i++) { - indices[i] = -1; - } - this.reloadIndices = reloadIndices == null ? indices : reloadIndices; - } - - @Override - protected Object doInBackground() throws Exception { - boolean first = true; - SWF firstSWF = null; - for (int index = 0; index < sourceInfos.length; index++) { - SWFSourceInfo sourceInfo = sourceInfos[index]; - SWFList swfs = null; - try { - Main.startWork(AppStrings.translate("work.reading.swf") + "...", null); - try { - swfs = parseSWF(sourceInfo); - } catch (ExecutionException ex) { - Throwable cause = ex.getCause(); - if (cause instanceof SwfOpenException) { - throw (SwfOpenException) cause; - } - - throw ex; - } - } catch (OutOfMemoryError ex) { - logger.log(Level.SEVERE, null, ex); - View.showMessageDialog(null, "Cannot load SWF file. Out of memory."); - continue; - } catch (SwfOpenException ex) { - logger.log(Level.SEVERE, null, ex); - View.showMessageDialog(null, ex.getMessage()); - continue; - } catch (Exception ex) { - logger.log(Level.SEVERE, null, ex); - View.showMessageDialog(null, "Cannot load SWF file."); - continue; - } - - final SWFList swfs1 = swfs; - final boolean first1 = first; - first = false; - if (firstSWF == null && swfs1.size() > 0) { - firstSWF = swfs1.get(0); - } - - final int findex = index; - try { - View.execInEventDispatch(() -> { - Main.startWork(AppStrings.translate("work.creatingwindow") + "...", null); - ensureMainFrame(); - if (reloadIndices[findex] > -1) { - mainFrame.getPanel().loadSwfAtPos(swfs1, reloadIndices[findex]); - } else { - mainFrame.getPanel().load(swfs1, first1); - } - }); - } catch (Exception ex) { - logger.log(Level.SEVERE, null, ex); - } - } - - loadingDialog.setVisible(false); - shouldCloseWhenClosingLoadingDialog = false; - - final SWF fswf = firstSWF; - View.execInEventDispatch(() -> { - if (mainFrame != null) { - mainFrame.setVisible(true); - } - - Main.stopWork(); - - if (mainFrame != null && Configuration.gotoMainClassOnStartup.get()) { - mainFrame.getPanel().gotoDocumentClass(fswf); - } - - if (mainFrame != null && fswf != null) { - SwfSpecificConfiguration swfConf = Configuration.getSwfSpecificConfiguration(fswf.getShortFileName()); - if (swfConf != null) { - String pathStr = swfConf.lastSelectedPath; - mainFrame.getPanel().tagTree.setSelectionPathString(pathStr); - } - } - - if (executeAfterOpen != null) { - executeAfterOpen.run(); - } - }); - - return true; - } - } - - public static boolean reloadSWFs() { - CancellableWorker.cancelBackgroundThreads(); - if (Main.sourceInfos.isEmpty()) { - Helper.freeMem(); - showModeFrame(); - return true; - } else { - SWFSourceInfo[] sourceInfosCopy = new SWFSourceInfo[sourceInfos.size()]; - sourceInfos.toArray(sourceInfosCopy); - sourceInfos.clear(); - openFile(sourceInfosCopy); - return true; - } - } - - public static void reloadApp() { - if (debugDialog != null) { - debugDialog.setVisible(false); - debugDialog.dispose(); - debugDialog = null; - } - if (loadingDialog != null) { - synchronized (Main.class) { - if (loadingDialog != null) { - loadingDialog.setVisible(false); - loadingDialog.dispose(); - loadingDialog = null; - } - } - } - if (proxyFrame != null) { - proxyFrame.setVisible(false); - proxyFrame.dispose(); - proxyFrame = null; - } - if (loadFromMemoryFrame != null) { - loadFromMemoryFrame.setVisible(false); - loadFromMemoryFrame.dispose(); - loadFromMemoryFrame = null; - } - if (loadFromCacheFrame != null) { - loadFromCacheFrame.setVisible(false); - loadFromCacheFrame.dispose(); - loadFromCacheFrame = null; - } - if (mainFrame != null) { - mainFrame.setVisible(false); - mainFrame.getPanel().closeAll(false); - mainFrame.dispose(); - mainFrame = null; - } - FontTag.reload(); - Cache.clearAll(); - initGui(); - reloadSWFs(); - } - - public static OpenFileResult openFile(String swfFile, String fileTitle) { - return openFile(swfFile, fileTitle, null); - } - - public static OpenFileResult openFile(String swfFile, String fileTitle, Runnable executeAfterOpen) { - try { - File file = new File(swfFile); - if (!file.exists()) { - View.showMessageDialog(null, AppStrings.translate("open.error.fileNotFound"), AppStrings.translate("open.error"), JOptionPane.ERROR_MESSAGE); - return OpenFileResult.NOT_FOUND; - } - swfFile = file.getCanonicalPath(); - SWFSourceInfo sourceInfo = new SWFSourceInfo(null, swfFile, fileTitle); - OpenFileResult openResult = openFile(sourceInfo); - return openResult; - } catch (IOException ex) { - View.showMessageDialog(null, AppStrings.translate("open.error.cannotOpen"), AppStrings.translate("open.error"), JOptionPane.ERROR_MESSAGE); - return OpenFileResult.ERROR; - } - } - - public static OpenFileResult openFile(SWFSourceInfo sourceInfo) { - return openFile(new SWFSourceInfo[]{sourceInfo}); - } - - public static OpenFileResult openFile(SWFSourceInfo sourceInfo, Runnable executeAfterOpen) { - return openFile(new SWFSourceInfo[]{sourceInfo}, executeAfterOpen); - } - - public static OpenFileResult openFile(SWFSourceInfo sourceInfo, Runnable executeAfterOpen, int reloadIndex) { - return openFile(new SWFSourceInfo[]{sourceInfo}, executeAfterOpen, new int[]{reloadIndex}); - } - - public static OpenFileResult openFile(SWFSourceInfo[] newSourceInfos) { - return openFile(newSourceInfos, null); - } - - public static OpenFileResult openFile(SWFSourceInfo[] newSourceInfos, Runnable executeAfterOpen) { - return openFile(newSourceInfos, executeAfterOpen, null); - } - - public static OpenFileResult openFile(SWFSourceInfo[] newSourceInfos, Runnable executeAfterOpen, int[] reloadIndices) { - if (mainFrame != null && !Configuration.openMultipleFiles.get()) { - sourceInfos.clear(); - mainFrame.getPanel().closeAll(false); - mainFrame.setVisible(false); - Helper.freeMem(); - reloadIndices = null; - } - - loadingDialog.setVisible(true); - - for (int i = 0; i < sourceInfos.size(); i++) { - SWFSourceInfo si = newSourceInfos[i]; - String fileName = si.getFile(); - if (fileName != null) { - Configuration.addRecentFile(fileName); - } - } - - OpenFileWorker wrk = new OpenFileWorker(newSourceInfos, executeAfterOpen, reloadIndices); - wrk.execute(); - if (reloadIndices == null) { - sourceInfos.addAll(Arrays.asList(newSourceInfos)); - } else { - for (int i = 0; i < reloadIndices.length; i++) { - sourceInfos.set(reloadIndices[i], newSourceInfos[i]); - } - } - return OpenFileResult.OK; - } - - public static void closeFile(SWFList swf) { - sourceInfos.remove(swf.sourceInfo); - mainFrame.getPanel().close(swf); - } - - public static void reloadFile(SWFList swf) { - //mainFrame.getPanel().close(swf); - openFile(swf.sourceInfo, null, sourceInfos.indexOf(swf.sourceInfo)); - } - - public static boolean closeAll() { - boolean closeResult = mainFrame.getPanel().closeAll(true); - if (closeResult) { - sourceInfos.clear(); - } - - return closeResult; - } - - public static boolean saveFileDialog(SWF swf, final SaveFileMode mode) { - JFileChooser fc = new JFileChooser(); - fc.setCurrentDirectory(new File(Configuration.lastSaveDir.get())); - String ext = ".swf"; - switch (mode) { - case SAVE: - case SAVEAS: - if (swf.getFile() != null) { - ext = Path.getExtension(swf.getFile()); - } - break; - case EXE: - ext = ".exe"; - break; - } - - FileFilter swfFilter = new FileFilter() { - @Override - public boolean accept(File f) { - return (f.getName().toLowerCase().endsWith(".swf")) || (f.isDirectory()); - } - - @Override - public String getDescription() { - return AppStrings.translate("filter.swf"); - } - }; - - FileFilter gfxFilter = new FileFilter() { - @Override - public boolean accept(File f) { - return (f.getName().toLowerCase().endsWith(".gfx")) || (f.isDirectory()); - } - - @Override - public String getDescription() { - return AppStrings.translate("filter.gfx"); - } - }; - - ExeExportMode exeExportMode = null; - if (mode == SaveFileMode.EXE) { - exeExportMode = Configuration.exeExportMode.get(); - if (exeExportMode == null) { - exeExportMode = ExeExportMode.WRAPPER; - } - String filterDescription = null; - switch (exeExportMode) { - case WRAPPER: - case PROJECTOR_WIN: - ext = ".exe"; - filterDescription = "filter.exe"; - break; - case PROJECTOR_MAC: - ext = ".dmg"; - filterDescription = "filter.dmg"; - break; - case PROJECTOR_LINUX: - // linux projector is compressed with tar.gz - // todo: decompress - ext = ""; - filterDescription = "filter.linuxExe"; - break; - } - - String fext = ext; - String ffilterDescription = filterDescription; - FileFilter exeFilter = new FileFilter() { - @Override - public boolean accept(File f) { - return (f.getName().toLowerCase().endsWith(fext)) || (f.isDirectory()); - } - - @Override - public String getDescription() { - return AppStrings.translate(ffilterDescription); - } - }; - fc.setFileFilter(exeFilter); - } else if (swf.gfx) { - fc.addChoosableFileFilter(swfFilter); - fc.setFileFilter(gfxFilter); - } else { - fc.setFileFilter(swfFilter); - fc.addChoosableFileFilter(gfxFilter); - } - final String extension = ext; - fc.setAcceptAllFileFilterUsed(false); - JFrame f = new JFrame(); - View.setWindowIcon(f); - if (fc.showSaveDialog(f) == JFileChooser.APPROVE_OPTION) { - File file = Helper.fixDialogFile(fc.getSelectedFile()); - FileFilter selFilter = fc.getFileFilter(); - try { - String fileName = file.getAbsolutePath(); - if (selFilter == swfFilter) { - if (!fileName.toLowerCase().endsWith(extension)) { - fileName += extension; - } - swf.gfx = false; - } - if (selFilter == gfxFilter) { - if (!fileName.toLowerCase().endsWith(".gfx")) { - fileName += ".gfx"; - } - swf.gfx = true; - } - Main.saveFile(swf, fileName, mode, exeExportMode); - Configuration.lastSaveDir.set(file.getParentFile().getAbsolutePath()); - return true; - } catch (IOException ex) { - View.showMessageDialog(null, AppStrings.translate("error.file.write")); - } - } - return false; - } - - public static boolean openFileDialog() { - JFileChooser fc = new JFileChooser(); - if (Configuration.openMultipleFiles.get()) { - fc.setMultiSelectionEnabled(true); - } - fc.setCurrentDirectory(new File(Configuration.lastOpenDir.get())); - FileFilter allSupportedFilter = new FileFilter() { - private final String[] supportedExtensions = new String[]{".swf", ".gfx", ".swc", ".zip"}; - - @Override - public boolean accept(File f) { - String name = f.getName().toLowerCase(); - for (String ext : supportedExtensions) { - if (name.endsWith(ext)) { - return true; - } - } - return f.isDirectory(); - } - - @Override - public String getDescription() { - String exts = Helper.joinStrings(supportedExtensions, "*%s", "; "); - return AppStrings.translate("filter.supported") + " (" + exts + ")"; - } - }; - fc.setFileFilter(allSupportedFilter); - FileFilter swfFilter = new FileFilter() { - @Override - public boolean accept(File f) { - return (f.getName().toLowerCase().endsWith(".swf")) || (f.isDirectory()); - } - - @Override - public String getDescription() { - return AppStrings.translate("filter.swf"); - } - }; - fc.addChoosableFileFilter(swfFilter); - - FileFilter swcFilter = new FileFilter() { - @Override - public boolean accept(File f) { - return (f.getName().toLowerCase().endsWith(".swc")) || (f.isDirectory()); - } - - @Override - public String getDescription() { - return AppStrings.translate("filter.swc"); - } - }; - fc.addChoosableFileFilter(swcFilter); - - FileFilter gfxFilter = new FileFilter() { - @Override - public boolean accept(File f) { - return (f.getName().toLowerCase().endsWith(".gfx")) || (f.isDirectory()); - } - - @Override - public String getDescription() { - return AppStrings.translate("filter.gfx"); - } - }; - fc.addChoosableFileFilter(gfxFilter); - - FileFilter zipFilter = new FileFilter() { - @Override - public boolean accept(File f) { - return (f.getName().toLowerCase().endsWith(".zip")) || (f.isDirectory()); - } - - @Override - public String getDescription() { - return AppStrings.translate("filter.zip"); - } - }; - fc.addChoosableFileFilter(zipFilter); - - FileFilter binaryFilter = new FileFilter() { - @Override - public boolean accept(File f) { - return true; - } - - @Override - public String getDescription() { - return AppStrings.translate("filter.binary"); - } - }; - fc.addChoosableFileFilter(binaryFilter); - - fc.setAcceptAllFileFilterUsed(false); - JFrame f = new JFrame(); - View.setWindowIcon(f); - int returnVal = fc.showOpenDialog(f); - if (returnVal == JFileChooser.APPROVE_OPTION) { - Configuration.lastOpenDir.set(Helper.fixDialogFile(fc.getSelectedFile()).getParentFile().getAbsolutePath()); - File[] selFiles = fc.getSelectedFiles(); - for (File file : selFiles) { - File selfile = Helper.fixDialogFile(file); - Main.openFile(selfile.getAbsolutePath(), null); - } - return true; - } else { - return false; - } - } - - public static void displayErrorFrame() { - ErrorLogFrame.getInstance().setVisible(true); - } - - private static String md5(byte data[]) { - try { - java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5"); - byte[] array = md.digest(data); - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < array.length; ++i) { - sb.append(Integer.toHexString((array[i] & 0xFF) | 0x100).substring(1, 3)); - } - return sb.toString(); - } catch (java.security.NoSuchAlgorithmException e) { - } - return null; - } - - private static void initGui() { - if (GraphicsEnvironment.isHeadless()) { - System.err.println("Error: Your system does not support Graphic User Interface"); - exit(); - } - - System.setProperty("sun.java2d.d3d", "false"); - System.setProperty("sun.java2d.noddraw", "true"); - - if (Configuration.hwAcceleratedGraphics.get()) { - System.setProperty("sun.java2d.opengl", Configuration._debugMode.get() ? "True" : "true"); - } else { - System.setProperty("sun.java2d.opengl", "false"); - } - - initUiLang(); - - if (Configuration.useRibbonInterface.get()) { - View.setLookAndFeel(); - } else { - try { - UIManager.put(SubstanceLookAndFeel.COLORIZATION_FACTOR, null); - UIManager.put("Tree.expandedIcon", null); - UIManager.put("Tree.collapsedIcon", null); - UIManager.put("ColorChooserUI", null); - UIManager.put("ColorChooser.swatchesRecentSwatchSize", null); - UIManager.put("ColorChooser.swatchesSwatchSize", null); - UIManager.put("RibbonApplicationMenuPopupPanelUI", null); - UIManager.put("RibbonApplicationMenuButtonUI", null); - UIManager.put("ProgressBarUI", null); - UIManager.put("TextField.background", null); - UIManager.put("FormattedTextField.background", null); - UIManager.put("CommandButtonUI", null); - UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { - logger.log(Level.SEVERE, null, ex); - } - } - - View.execInEventDispatch(() -> { - ErrorLogFrame.createNewInstance(); - - autoCheckForUpdates(); - offerAssociation(); - loadingDialog = new LoadingDialog(); - - DebuggerTools.initDebugger().addMessageListener(new DebugListener() { - @Override - public void onMessage(String clientId, String msg) { - } - - @Override - public void onLoaderURL(String clientId, String url) { - } - - @Override - public void onLoaderBytes(String clientId, byte[] data) { - String hash = md5(data); - for (SWFList sl : Main.getMainFrame().getPanel().getSwfs()) { - for (int s = 0; s < sl.size(); s++) { - String t = sl.get(s).getFileTitle(); - if (t == null) { - t = ""; - } - if (t.endsWith(":" + hash)) { //this one is already opened - return; - } - } - } - SWF swf = Main.getMainFrame().getPanel().getCurrentSwf(); - - String title = swf == null ? "?" : swf.getFileTitle(); - title = title + ":" + hash; - String tfile; - try { - tfile = tempFile(title); - Helper.writeFile(tfile, data); - openFile(new SWFSourceInfo(null, tfile, title)); - } catch (IOException ex) { - logger.log(Level.SEVERE, "Cannot create tempfile"); - } - } - - @Override - public void onFinish(String clientId) { - } - }); - - try { - flashDebugger = new Debugger(); - debugHandler = new DebuggerHandler(); - debugHandler.addBreakListener(new DebuggerHandler.BreakListener() { - @Override - public void doContinue() { - mainFrame.getPanel().clearDebuggerColors(); - } - - @Override - public void breakAt(String scriptName, int line, final int classIndex, final int traitIndex, final int methodIndex) { - View.execInEventDispatch(new Runnable() { - @Override - public void run() { - mainFrame.getPanel().gotoScriptLine(getMainFrame().getPanel().getCurrentSwf(), scriptName, line, classIndex, traitIndex, methodIndex); - } - }); - } - }); - debugHandler.addConnectionListener(new DebuggerHandler.ConnectionListener() { - @Override - public void connected() { - Main.mainFrame.getMenu().updateComponents(); - } - - @Override - public void disconnected() { - if (Main.mainFrame != null && Main.mainFrame.getPanel() != null) { - Main.mainFrame.getPanel().refreshBreakPoints(); - } - } - }); - flashDebugger.addConnectionListener(debugHandler); - } catch (IOException ex) { - logger.log(Level.SEVERE, "eeex", ex); - } - }); - } - - public static void startDebugger() { - flashDebugger.startDebugger(); - } - - public static void stopDebugger() { - flashDebugger.stopDebugger(); - } - - public static void showModeFrame() { - ensureMainFrame(); - mainFrame.setVisible(true); - } - - private static void offerAssociation() { - boolean offered = Configuration.offeredAssociation.get(); - if (!offered) { - if (Platform.isWindows()) { - if ((!ContextMenuTools.isAddedToContextMenu()) && View.showConfirmDialog(null, "Do you want to add FFDec to context menu of SWF files?\n(Can be changed later from main menu)", "Context menu", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) { - ContextMenuTools.addToContextMenu(true, false); - } - } - - Configuration.offeredAssociation.set(true); - } - } - - public static void initUiLang() { - if (GraphicsEnvironment.isHeadless()) { //No GUI in OS - return; - } - try { - Class cl = Class.forName("org.pushingpixels.substance.api.SubstanceLookAndFeel"); - Field field = cl.getDeclaredField("LABEL_BUNDLE"); - field.setAccessible(true); - field.set(null, null); - } catch (Throwable ex) { - logger.log(Level.SEVERE, null, ex); - } - - UIManager.put("OptionPane.okButtonText", AppStrings.translate("button.ok")); - UIManager.put("OptionPane.yesButtonText", AppStrings.translate("button.yes")); - UIManager.put("OptionPane.noButtonText", AppStrings.translate("button.no")); - UIManager.put("OptionPane.cancelButtonText", AppStrings.translate("button.cancel")); - UIManager.put("OptionPane.messageDialogTitle", AppStrings.translate("dialog.message.title")); - UIManager.put("OptionPane.titleText", AppStrings.translate("dialog.select.title")); - - UIManager.put("FileChooser.acceptAllFileFilterText", AppStrings.translate("FileChooser.acceptAllFileFilterText")); - UIManager.put("FileChooser.lookInLabelText", AppStrings.translate("FileChooser.lookInLabelText")); - UIManager.put("FileChooser.cancelButtonText", AppStrings.translate("button.cancel")); - UIManager.put("FileChooser.cancelButtonToolTipText", AppStrings.translate("button.cancel")); - UIManager.put("FileChooser.openButtonText", AppStrings.translate("FileChooser.openButtonText")); - UIManager.put("FileChooser.openButtonToolTipText", AppStrings.translate("FileChooser.openButtonToolTipText")); - UIManager.put("FileChooser.filesOfTypeLabelText", AppStrings.translate("FileChooser.filesOfTypeLabelText")); - UIManager.put("FileChooser.fileNameLabelText", AppStrings.translate("FileChooser.fileNameLabelText")); - UIManager.put("FileChooser.listViewButtonToolTipText", AppStrings.translate("FileChooser.listViewButtonToolTipText")); - UIManager.put("FileChooser.listViewButtonAccessibleName", AppStrings.translate("FileChooser.listViewButtonAccessibleName")); - UIManager.put("FileChooser.detailsViewButtonToolTipText", AppStrings.translate("FileChooser.detailsViewButtonToolTipText")); - UIManager.put("FileChooser.detailsViewButtonAccessibleName", AppStrings.translate("FileChooser.detailsViewButtonAccessibleName")); - UIManager.put("FileChooser.upFolderToolTipText", AppStrings.translate("FileChooser.upFolderToolTipText")); - UIManager.put("FileChooser.upFolderAccessibleName", AppStrings.translate("FileChooser.upFolderAccessibleName")); - UIManager.put("FileChooser.homeFolderToolTipText", AppStrings.translate("FileChooser.homeFolderToolTipText")); - UIManager.put("FileChooser.homeFolderAccessibleName", AppStrings.translate("FileChooser.homeFolderAccessibleName")); - UIManager.put("FileChooser.fileNameHeaderText", AppStrings.translate("FileChooser.fileNameHeaderText")); - UIManager.put("FileChooser.fileSizeHeaderText", AppStrings.translate("FileChooser.fileSizeHeaderText")); - UIManager.put("FileChooser.fileTypeHeaderText", AppStrings.translate("FileChooser.fileTypeHeaderText")); - UIManager.put("FileChooser.fileDateHeaderText", AppStrings.translate("FileChooser.fileDateHeaderText")); - UIManager.put("FileChooser.fileAttrHeaderText", AppStrings.translate("FileChooser.fileAttrHeaderText")); - UIManager.put("FileChooser.openDialogTitleText", AppStrings.translate("FileChooser.openDialogTitleText")); - UIManager.put("FileChooser.directoryDescriptionText", AppStrings.translate("FileChooser.directoryDescriptionText")); - UIManager.put("FileChooser.directoryOpenButtonText", AppStrings.translate("FileChooser.directoryOpenButtonText")); - UIManager.put("FileChooser.directoryOpenButtonToolTipText", AppStrings.translate("FileChooser.directoryOpenButtonToolTipText")); - UIManager.put("FileChooser.fileDescriptionText", AppStrings.translate("FileChooser.fileDescriptionText")); - UIManager.put("FileChooser.fileNameLabelText", AppStrings.translate("FileChooser.fileNameLabelText")); - UIManager.put("FileChooser.helpButtonText", AppStrings.translate("FileChooser.helpButtonText")); - UIManager.put("FileChooser.helpButtonToolTipText", AppStrings.translate("FileChooser.helpButtonToolTipText")); - UIManager.put("FileChooser.newFolderAccessibleName", AppStrings.translate("FileChooser.newFolderAccessibleName")); - UIManager.put("FileChooser.newFolderErrorText", AppStrings.translate("FileChooser.newFolderErrorText")); - UIManager.put("FileChooser.newFolderToolTipText", AppStrings.translate("FileChooser.newFolderToolTipText")); - UIManager.put("FileChooser.other.newFolder", AppStrings.translate("FileChooser.other.newFolder")); - UIManager.put("FileChooser.other.newFolder.subsequent", AppStrings.translate("FileChooser.other.newFolder.subsequent")); - UIManager.put("FileChooser.win32.newFolder", AppStrings.translate("FileChooser.win32.newFolder")); - UIManager.put("FileChooser.win32.newFolder.subsequent", AppStrings.translate("FileChooser.win32.newFolder.subsequent")); - UIManager.put("FileChooser.saveButtonText", AppStrings.translate("FileChooser.saveButtonText")); - UIManager.put("FileChooser.saveButtonToolTipText", AppStrings.translate("FileChooser.saveButtonToolTipText")); - UIManager.put("FileChooser.saveDialogTitleText", AppStrings.translate("FileChooser.saveDialogTitleText")); - UIManager.put("FileChooser.saveInLabelText", AppStrings.translate("FileChooser.saveInLabelText")); - UIManager.put("FileChooser.updateButtonText", AppStrings.translate("FileChooser.updateButtonText")); - UIManager.put("FileChooser.updateButtonToolTipText", AppStrings.translate("FileChooser.updateButtonToolTipText")); - - UIManager.put("FileChooser.detailsViewActionLabel.textAndMnemonic", AppStrings.translate("FileChooser.detailsViewActionLabel.textAndMnemonic")); - UIManager.put("FileChooser.detailsViewButtonToolTip.textAndMnemonic", AppStrings.translate("FileChooser.detailsViewButtonToolTip.textAndMnemonic")); - UIManager.put("FileChooser.fileAttrHeader.textAndMnemonic", AppStrings.translate("FileChooser.fileAttrHeader.textAndMnemonic")); - UIManager.put("FileChooser.fileDateHeader.textAndMnemonic", AppStrings.translate("FileChooser.fileDateHeader.textAndMnemonic")); - UIManager.put("FileChooser.fileNameHeader.textAndMnemonic", AppStrings.translate("FileChooser.fileNameHeader.textAndMnemonic")); - UIManager.put("FileChooser.fileNameLabel.textAndMnemonic", AppStrings.translate("FileChooser.fileNameLabel.textAndMnemonic")); - UIManager.put("FileChooser.fileSizeHeader.textAndMnemonic", AppStrings.translate("FileChooser.fileSizeHeader.textAndMnemonic")); - UIManager.put("FileChooser.fileTypeHeader.textAndMnemonic", AppStrings.translate("FileChooser.fileTypeHeader.textAndMnemonic")); - UIManager.put("FileChooser.filesOfTypeLabel.textAndMnemonic", AppStrings.translate("FileChooser.filesOfTypeLabel.textAndMnemonic")); - UIManager.put("FileChooser.folderNameLabel.textAndMnemonic", AppStrings.translate("FileChooser.folderNameLabel.textAndMnemonic")); - UIManager.put("FileChooser.homeFolderToolTip.textAndMnemonic", AppStrings.translate("FileChooser.homeFolderToolTip.textAndMnemonic")); - UIManager.put("FileChooser.listViewActionLabel.textAndMnemonic", AppStrings.translate("FileChooser.listViewActionLabel.textAndMnemonic")); - UIManager.put("FileChooser.listViewButtonToolTip.textAndMnemonic", AppStrings.translate("FileChooser.listViewButtonToolTip.textAndMnemonic")); - UIManager.put("FileChooser.lookInLabel.textAndMnemonic", AppStrings.translate("FileChooser.lookInLabel.textAndMnemonic")); - UIManager.put("FileChooser.newFolderActionLabel.textAndMnemonic", AppStrings.translate("FileChooser.newFolderActionLabel.textAndMnemonic")); - UIManager.put("FileChooser.newFolderToolTip.textAndMnemonic", AppStrings.translate("FileChooser.newFolderToolTip.textAndMnemonic")); - UIManager.put("FileChooser.refreshActionLabel.textAndMnemonic", AppStrings.translate("FileChooser.refreshActionLabel.textAndMnemonic")); - UIManager.put("FileChooser.saveInLabel.textAndMnemonic", AppStrings.translate("FileChooser.saveInLabel.textAndMnemonic")); - UIManager.put("FileChooser.upFolderToolTip.textAndMnemonic", AppStrings.translate("FileChooser.upFolderToolTip.textAndMnemonic")); - UIManager.put("FileChooser.viewMenuButtonAccessibleName", AppStrings.translate("FileChooser.viewMenuButtonAccessibleName")); - UIManager.put("FileChooser.viewMenuButtonToolTipText", AppStrings.translate("FileChooser.viewMenuButtonToolTipText")); - UIManager.put("FileChooser.viewMenuLabel.textAndMnemonic", AppStrings.translate("FileChooser.viewMenuLabel.textAndMnemonic")); - UIManager.put("FileChooser.newFolderActionLabelText", AppStrings.translate("FileChooser.newFolderActionLabelText")); - UIManager.put("FileChooser.listViewActionLabelText", AppStrings.translate("FileChooser.listViewActionLabelText")); - UIManager.put("FileChooser.detailsViewActionLabelText", AppStrings.translate("FileChooser.detailsViewActionLabelText")); - UIManager.put("FileChooser.refreshActionLabelText", AppStrings.translate("FileChooser.refreshActionLabelText")); - UIManager.put("FileChooser.sortMenuLabelText", AppStrings.translate("FileChooser.sortMenuLabelText")); - UIManager.put("FileChooser.viewMenuLabelText", AppStrings.translate("FileChooser.viewMenuLabelText")); - UIManager.put("FileChooser.fileSizeKiloBytes", AppStrings.translate("FileChooser.fileSizeKiloBytes")); - UIManager.put("FileChooser.fileSizeMegaBytes", AppStrings.translate("FileChooser.fileSizeMegaBytes")); - UIManager.put("FileChooser.fileSizeGigaBytes", AppStrings.translate("FileChooser.fileSizeGigaBytes")); - UIManager.put("FileChooser.folderNameLabelText", AppStrings.translate("FileChooser.folderNameLabelText")); - - UIManager.put("ColorChooser.okText", AppStrings.translate("ColorChooser.okText")); - UIManager.put("ColorChooser.cancelText", AppStrings.translate("ColorChooser.cancelText")); - UIManager.put("ColorChooser.resetText", AppStrings.translate("ColorChooser.resetText")); - UIManager.put("ColorChooser.previewText", AppStrings.translate("ColorChooser.previewText")); - UIManager.put("ColorChooser.swatchesNameText", AppStrings.translate("ColorChooser.swatchesNameText")); - UIManager.put("ColorChooser.swatchesRecentText", AppStrings.translate("ColorChooser.swatchesRecentText")); - UIManager.put("ColorChooser.sampleText", AppStrings.translate("ColorChooser.sampleText")); - - } - - public static void initLang() { - if (!Configuration.locale.hasValue()) { - if (Platform.isWindows()) { - //Load from Installer - String uninstKey = "{E618D276-6596-41F4-8A98-447D442A77DB}_is1"; - uninstKey = "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\" + uninstKey; - try { - if (Advapi32Util.registryKeyExists(WinReg.HKEY_LOCAL_MACHINE, uninstKey)) { - if (Advapi32Util.registryValueExists(WinReg.HKEY_LOCAL_MACHINE, uninstKey, "NSIS: Language")) { - String installedLoc = Advapi32Util.registryGetStringValue(WinReg.HKEY_LOCAL_MACHINE, uninstKey, "NSIS: Language"); - int lcid = Integer.parseInt(installedLoc); - char[] buf = new char[9]; - int cnt = Kernel32.INSTANCE.GetLocaleInfo(lcid, Kernel32.LOCALE_SISO639LANGNAME, buf, 9); - String langCode = new String(buf, 0, cnt).trim().toLowerCase(); - - cnt = Kernel32.INSTANCE.GetLocaleInfo(lcid, Kernel32.LOCALE_SISO3166CTRYNAME, buf, 9); - String countryCode = new String(buf, 0, cnt).trim().toLowerCase(); - - List langs = Arrays.asList(SelectLanguageDialog.getAvailableLanguages()); - for (int i = 0; i < langs.size(); i++) { - langs.set(i, langs.get(i).toLowerCase()); - } - - String selectedLang = null; - - if (langs.contains(langCode + "-" + countryCode)) { - selectedLang = SelectLanguageDialog.getAvailableLanguages()[langs.indexOf(langCode + "-" + countryCode)]; - } else if (langs.contains(langCode)) { - selectedLang = SelectLanguageDialog.getAvailableLanguages()[langs.indexOf(langCode)]; - } - if (selectedLang != null) { - Configuration.locale.set(selectedLang); - } - } - } - } catch (Exception ex) { - //ignore - } - } - } - Locale.setDefault(Locale.forLanguageTag(Configuration.locale.get())); - AppStrings.updateLanguage(); - - Helper.decompilationErrorAdd = AppStrings.translate(Configuration.autoDeobfuscate.get() ? "deobfuscation.comment.failed" : "deobfuscation.comment.tryenable"); - } - - /** - * Clear old FFDec/JavactiveX temp files - */ - private static void clearTemp() { - String tempDirPath = System.getProperty("java.io.tmpdir"); - if (tempDirPath == null) { - return; - } - File tempDir = new File(tempDirPath); - if (!tempDir.exists()) { - return; - } - File[] delFiles = tempDir.listFiles(new FilenameFilter() { - @Override - public boolean accept(File dir, String name) { - return name.matches("ffdec_cache.*\\.tmp") || name.matches("javactivex_.*\\.exe") || name.matches("temp[0-9]+\\.swf") || name.matches("ffdec_view_.*\\.swf"); - } - }); - - if (delFiles != null) { - for (File f : delFiles) { - try { - f.delete(); - } catch (Exception ex) { - //ignore - } - } - } - } - - /** - * @param args the command line arguments - * @throws IOException On error - */ - public static void main(String[] args) throws IOException { - setSessionLoaded(false); - clearTemp(); - - try { - SWFDecompilerPlugin.loadPlugins(); - } catch (Throwable ex) { - logger.log(Level.SEVERE, "Failed to load plugins", ex); - } - - AppStrings.setResourceClass(MainFrame.class); - initLogging(Configuration._debugMode.get()); - - initLang(); - - if (Configuration.cacheOnDisk.get()) { - Cache.setStorageType(Cache.STORAGE_FILES); - } else { - Cache.setStorageType(Cache.STORAGE_MEMORY); - } - - if (args.length == 0) { - initGui(); - checkLibraryVersion(); - View.execInEventDispatch(() -> { - if (Configuration.allowOnlyOneInstance.get() && FirstInstance.focus()) { //Try to focus first instance - Main.exit(); - } else { - showModeFrame(); - reloadLastSession(); - } - }); - } else { - checkLibraryVersion(); - setSessionLoaded(true); - String[] filesToOpen = CommandLineArgumentParser.parseArguments(args); - if (filesToOpen != null && filesToOpen.length > 0) { - View.execInEventDispatch(() -> { - initGui(); - shouldCloseWhenClosingLoadingDialog = true; - if (Configuration.allowOnlyOneInstance.get() && FirstInstance.openFiles(Arrays.asList(filesToOpen))) { //Try to open in first instance - Main.exit(); - } else { - for (String fileToOpen : filesToOpen) { - openFile(fileToOpen, null); - } - } - }); - } - } - } - - private static void checkLibraryVersion() { - if (!ApplicationInfo.version.equals("unknown") && !ApplicationInfo.libraryVersion.equals("unknown") - && !Objects.equals(ApplicationInfo.version, ApplicationInfo.libraryVersion)) { - logger.log(Level.WARNING, "Application version is different from library version. FFDec may not work properly."); - } - } - - private static void reloadLastSession() { - boolean openingFiles = false; - if (Configuration.saveSessionOnExit.get()) { - String lastSession = Configuration.lastSessionFiles.get(); - if (lastSession != null && lastSession.length() > 0) { - String[] filesToOpen = lastSession.split(File.pathSeparator, -1); - List exfiles = new ArrayList<>(); - List extitles = new ArrayList<>(); - String lastSessionTitles = Configuration.lastSessionFileTitles.get(); - String[] fileTitles = new String[0]; - if (lastSessionTitles != null && !lastSessionTitles.isEmpty()) { - fileTitles = lastSessionTitles.split(File.pathSeparator, -1); - } - for (int i = 0; i < filesToOpen.length; i++) { - if (new File(filesToOpen[i]).exists()) { - exfiles.add(filesToOpen[i]); - if (fileTitles.length > i) { - extitles.add(fileTitles[i]); - } else { - extitles.add(null); - } - } - } - SWFSourceInfo[] sourceInfos = new SWFSourceInfo[exfiles.size()]; - for (int i = 0; i < exfiles.size(); i++) { - String extitle = extitles.get(i); - sourceInfos[i] = new SWFSourceInfo(null, exfiles.get(i), extitle == null || extitle.isEmpty() ? null : extitle); - } - if (sourceInfos.length > 0) { - openingFiles = true; - openFile(sourceInfos, () -> { - mainFrame.getPanel().tagTree.setSelectionPathString(Configuration.lastSessionSelection.get()); - setSessionLoaded(true); - }); - } - } - } - - if (!openingFiles) { - setSessionLoaded(true); - } - } - - public static String tempFile(String url) throws IOException { - File f = new File(Configuration.getFFDecHome() + "saved" + File.separator); - Path.createDirectorySafe(f); - return Configuration.getFFDecHome() + "saved" + File.separator + "asdec_" + Integer.toHexString(url.hashCode()) + ".tmp"; - } - - public static void removeTrayIcon() { - if (SystemTray.isSupported()) { - SystemTray tray = SystemTray.getSystemTray(); - if (trayIcon != null) { - tray.remove(trayIcon); - trayIcon = null; - } - } - } - - public static void switchProxy() { - proxyFrame.switchState(); - if (stopMenuItem != null) { - if (proxyFrame.isRunning()) { - stopMenuItem.setLabel(AppStrings.translate("proxy.stop")); - } else { - stopMenuItem.setLabel(AppStrings.translate("proxy.start")); - } - } - } - - public static void addTrayIcon() { - if (trayIcon != null) { - return; - } - if (SystemTray.isSupported()) { - SystemTray tray = SystemTray.getSystemTray(); - trayIcon = new TrayIcon(View.loadImage("proxy16"), ApplicationInfo.VENDOR + " " + ApplicationInfo.SHORT_APPLICATION_NAME + " " + AppStrings.translate("proxy")); - trayIcon.setImageAutoSize(true); - PopupMenu trayPopup = new PopupMenu(); - - ActionListener trayListener = new ActionListener() { - /** - * Invoked when an action occurs. - */ - @Override - public void actionPerformed(ActionEvent e) { - if (e.getActionCommand().equals("EXIT")) { - Main.exit(); - } - if (e.getActionCommand().equals("SHOW")) { - Main.showProxy(); - } - if (e.getActionCommand().equals("SWITCH")) { - Main.switchProxy(); - } - } - }; - - MenuItem showMenuItem = new MenuItem(AppStrings.translate("proxy.show")); - showMenuItem.setActionCommand("SHOW"); - showMenuItem.addActionListener(trayListener); - trayPopup.add(showMenuItem); - stopMenuItem = new MenuItem(AppStrings.translate("proxy.start")); - stopMenuItem.setActionCommand("SWITCH"); - stopMenuItem.addActionListener(trayListener); - trayPopup.add(stopMenuItem); - trayPopup.addSeparator(); - MenuItem exitMenuItem = new MenuItem(AppStrings.translate("exit")); - exitMenuItem.setActionCommand("EXIT"); - exitMenuItem.addActionListener(trayListener); - trayPopup.add(exitMenuItem); - - trayIcon.setPopupMenu(trayPopup); - trayIcon.addMouseListener(new MouseAdapter() { - /** - * {@inheritDoc} - */ - @Override - public void mouseClicked(MouseEvent e) { - if (e.getButton() == MouseEvent.BUTTON1) { - Main.showProxy(); - } - } - }); - try { - tray.add(trayIcon); - } catch (AWTException ex) { - } - } - } - - public static void exit() { - Configuration.saveConfig(); - if (mainFrame != null && mainFrame.getPanel() != null) { - mainFrame.getPanel().unloadFlashPlayer(); - mainFrame.dispose(); - } - if (fileTxt != null) { - try { - fileTxt.flush(); - fileTxt.close(); - } catch (Exception ex) { - //ignore - } - } - System.exit(0); - } - - public static void about() { - (new AboutDialog()).setVisible(true); - } - - public static void advancedSettings() { - advancedSettings(null); - } - - public static void advancedSettings(String category) { - (new AdvancedSettingsDialog(category)).setVisible(true); - } - - public static void autoCheckForUpdates() { - if (Configuration.checkForUpdatesAuto.get()) { - Calendar lastUpdatesCheckDate = Configuration.lastUpdatesCheckDate.get(); - if ((lastUpdatesCheckDate == null) || (lastUpdatesCheckDate.getTime().getTime() < Calendar.getInstance().getTime().getTime() - Configuration.checkForUpdatesDelay.get())) { - new SwingWorker() { - @Override - protected Object doInBackground() throws Exception { - checkForUpdates(); - return null; - } - }.execute(); - } - } - } - - public static boolean checkForUpdates() { - String currentVersion = ApplicationInfo.version; - if (currentVersion.equals("unknown")) { - // sometimes during development the version information is not available - return false; - } - - List accepted = new ArrayList<>(); - if (Configuration.checkForUpdatesStable.get()) { - accepted.add("stable"); - } - if (Configuration.checkForUpdatesNightly.get()) { - accepted.add("nightly"); - } - - if (accepted.isEmpty()) { - return false; - } - - String acceptVersions = String.join(",", accepted); - try { - String proxyAddress = Configuration.updateProxyAddress.get(); - URL url = new URL(ApplicationInfo.updateCheckUrl); - - URLConnection uc; - if (proxyAddress != null && !proxyAddress.isEmpty()) { - int port = 8080; - if (proxyAddress.contains(":")) { - String[] parts = proxyAddress.split(":"); - port = Integer.parseInt(parts[1]); - proxyAddress = parts[0]; - } - - uc = url.openConnection(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyAddress, port))); - } else { - uc = url.openConnection(); - } - uc.setRequestProperty("X-Accept-Versions", acceptVersions); - uc.setRequestProperty("X-Update-Major", "" + UPDATE_SYSTEM_MAJOR); - uc.setRequestProperty("X-Update-Minor", "" + UPDATE_SYSTEM_MINOR); - uc.setRequestProperty("User-Agent", ApplicationInfo.shortApplicationVerName); - String currentLoc = Configuration.locale.get("en"); - uc.setRequestProperty("Accept-Language", currentLoc + ("en".equals(currentLoc) ? "" : ", en;q=0.8")); - - uc.connect(); - - BufferedReader br = new BufferedReader(new InputStreamReader(uc.getInputStream())); - String s; - final java.util.List versions = new ArrayList<>(); - String header = ""; - Pattern headerPat = Pattern.compile("\\[([a-zA-Z0-9]+)\\]"); - int updateMajor; - int updateMinor; - Version ver = null; - while ((s = br.readLine()) != null) { - - Matcher m = headerPat.matcher(s); - if (m.matches()) { - header = m.group(1); - if (header.equals("version")) { - ver = new Version(); - versions.add(ver); - } - if (header.equals("noversion")) { - break; - } - } else if (s.contains("=")) { - String key = s.substring(0, s.indexOf('=')); - String val = s.substring(s.indexOf('=') + 1); - if ("updateSystem".equals(header)) { - if (key.equals("majorVersion")) { - updateMajor = Integer.parseInt(val); - if (updateMajor > UPDATE_SYSTEM_MAJOR) { - break; - } - } - if (key.equals("minorVersion")) { - updateMinor = Integer.parseInt(val); - } - } - if ("version".equals(header) && (ver != null)) { - if (key.equals("versionId")) { - ver.versionId = Integer.parseInt(val); - } - if (key.equals("versionName")) { - ver.versionName = val; - } - if (key.equals("nightly")) { - ver.nightly = val.equals("true"); - } - if (key.equals("revision")) { - ver.revision = val; - } - if (key.equals("build")) { - ver.build = Integer.parseInt(val); - } - if (key.equals("major")) { - ver.major = Integer.parseInt(val); - } - if (key.equals("minor")) { - ver.minor = Integer.parseInt(val); - } - if (key.equals("release")) { - ver.release = Integer.parseInt(val); - } - if (key.equals("longVersionName")) { - ver.longVersionName = val; - } - if (key.equals("releaseDate")) { - ver.releaseDate = val; - } - if (key.equals("appName")) { - ver.appName = val; - } - if (key.equals("appFullName")) { - ver.appFullName = val; - } - if (key.equals("updateLink")) { - ver.updateLink = val; - } - if (key.equals("change[]")) { - String changeType = val.substring(0, val.indexOf('|')); - String change = val.substring(val.indexOf('|') + 1); - if (!ver.changes.containsKey(changeType)) { - ver.changes.put(changeType, new ArrayList<>()); - } - List chlist = ver.changes.get(changeType); - chlist.add(change); - } - } - } - } - - if (!versions.isEmpty()) { - View.execInEventDispatch(() -> { - NewVersionDialog newVersionDialog = new NewVersionDialog(versions); - newVersionDialog.setVisible(true); - Configuration.lastUpdatesCheckDate.set(Calendar.getInstance()); - }); - - return true; - } - } catch (IOException | NumberFormatException ex) { - return false; - } - Configuration.lastUpdatesCheckDate.set(Calendar.getInstance()); - return false; - } - - private static FileHandler fileTxt; - - public static void clearLogFile() { - Logger logger = Logger.getLogger(""); - - FileHandler oldFileTxt = fileTxt; - fileTxt = null; - if (oldFileTxt != null) { - logger.removeHandler(fileTxt); - oldFileTxt.flush(); - oldFileTxt.close(); - } - - String fileName = null; - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-hh-mm-ss"); - - try { - fileName = Configuration.getFFDecHome() + "logs" + File.separator; - if (Configuration.useDetailedLogging.get()) { - fileName += "log-" + sdf.format(new Date()) + ".txt"; - } else { - fileName += "log.txt"; - } - File f = new File(fileName).getParentFile(); - if (!f.exists()) { - f.mkdir(); - } - fileTxt = new FileHandler(fileName); - } catch (IOException | SecurityException ex) { - //cannot get lock error - if (ex.getMessage().contains("lock for")) { - //remove all old log files and their .lck - for (int i = 0; i <= 100; i++) { - File flog = new File(fileName + (i == 0 ? "" : "." + i)); - File flog_lock = new File(fileName + (i == 0 ? "" : "." + i) + ".lck"); - flog.delete(); - flog_lock.delete(); - } - try { - fileTxt = new FileHandler(fileName); - } catch (IOException | SecurityException ex1) { - logger.log(Level.SEVERE, "Cannot initialize logging", ex); - } - } else { - logger.log(Level.SEVERE, "Cannot initialize logging", ex); - } - } - - Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { - @Override - public void uncaughtException(Thread t, Throwable e) { - logger.log(Level.SEVERE, "Uncaught exception in thread: " + t.getName(), e); - if (e instanceof OutOfMemoryError || !Helper.is64BitJre() && Helper.is64BitOs()) { - View.showMessageDialog(null, AppStrings.translate("message.warning.outOfMemory32BitJre"), AppStrings.translate("message.warning"), JOptionPane.WARNING_MESSAGE); - } - } - }); - - Formatter formatterTxt = new LogFormatter(); - if (fileTxt != null) { - fileTxt.setFormatter(formatterTxt); - logger.addHandler(fileTxt); - } - - if (!GraphicsEnvironment.isHeadless() && ErrorLogFrame.hasInstance()) { - ErrorLogFrame.getInstance().clearErrorState(); - } - - sdf = new SimpleDateFormat("yyyy-MM-dd"); - logger.log(Level.INFO, "Date: {0}", sdf.format(new Date())); - logger.log(Level.INFO, ApplicationInfo.applicationVerName); - logger.log(Level.INFO, "{0} {1} {2}", new Object[]{ - System.getProperty("os.name"), System.getProperty("os.version"), System.getProperty("os.arch")}); - logger.log(Level.INFO, "{0} {1} {2}", new Object[]{ - System.getProperty("java.version"), System.getProperty("java.vendor"), System.getProperty("os.arch")}); - } - - public static void initLogging(boolean debug) { - try { - Logger logger = Logger.getLogger(""); - logger.setLevel(Configuration.logLevel); - - Handler[] handlers = logger.getHandlers(); - for (int i = handlers.length - 1; i >= 0; i--) { - logger.removeHandler(handlers[i]); - } - - ConsoleHandler conHan = new ConsoleHandler(); - conHan.setLevel(debug ? Level.CONFIG : Level.WARNING); - SimpleFormatter formatterTxt = new SimpleFormatter(); - conHan.setFormatter(formatterTxt); - logger.addHandler(conHan); - clearLogFile(); - - } catch (Exception ex) { - throw new RuntimeException("Problems with creating the log files"); - } - } -} +/* + * 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.debugger.flash.Debugger; +import com.jpexs.debugger.flash.DebuggerCommands; +import com.jpexs.debugger.flash.Variable; +import com.jpexs.debugger.flash.VariableType; +import com.jpexs.debugger.flash.messages.in.InCallFunction; +import com.jpexs.decompiler.flash.ApplicationInfo; +import com.jpexs.decompiler.flash.EventListener; +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFBundle; +import com.jpexs.decompiler.flash.SWFSourceInfo; +import com.jpexs.decompiler.flash.SearchMode; +import com.jpexs.decompiler.flash.SwfOpenException; +import com.jpexs.decompiler.flash.UrlResolver; +import com.jpexs.decompiler.flash.Version; +import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; +import com.jpexs.decompiler.flash.abc.avm2.parser.script.Reference; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.configuration.SwfSpecificConfiguration; +import com.jpexs.decompiler.flash.console.CommandLineArgumentParser; +import com.jpexs.decompiler.flash.console.ContextMenuTools; +import com.jpexs.decompiler.flash.exporters.modes.ExeExportMode; +import com.jpexs.decompiler.flash.gui.debugger.DebugListener; +import com.jpexs.decompiler.flash.gui.debugger.DebuggerTools; +import com.jpexs.decompiler.flash.gui.pipes.FirstInstance; +import com.jpexs.decompiler.flash.gui.proxy.ProxyFrame; +import com.jpexs.decompiler.flash.helpers.SWFDecompilerPlugin; +import com.jpexs.decompiler.flash.tags.Tag; +import com.jpexs.decompiler.flash.tags.base.FontTag; +import com.jpexs.decompiler.flash.tags.base.ImportTag; +import com.jpexs.decompiler.flash.treeitems.SWFList; +import com.jpexs.helpers.Cache; +import com.jpexs.helpers.CancellableWorker; +import com.jpexs.helpers.Helper; +import com.jpexs.helpers.Path; +import com.jpexs.helpers.ProgressListener; +import com.jpexs.helpers.Stopwatch; +import com.jpexs.helpers.streams.SeekableInputStream; +import com.sun.jna.Platform; +import com.sun.jna.platform.win32.Advapi32Util; +import com.sun.jna.platform.win32.Kernel32; +import com.sun.jna.platform.win32.WinReg; +import java.awt.AWTException; +import java.awt.Frame; +import java.awt.GraphicsEnvironment; +import java.awt.MenuItem; +import java.awt.PopupMenu; +import java.awt.SystemTray; +import java.awt.TrayIcon; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.lang.reflect.Field; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.URL; +import java.net.URLConnection; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; +import java.util.logging.ConsoleHandler; +import java.util.logging.FileHandler; +import java.util.logging.Formatter; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.logging.SimpleFormatter; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.swing.JFileChooser; +import javax.swing.JFrame; +import javax.swing.JOptionPane; +import javax.swing.SwingWorker; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; +import javax.swing.filechooser.FileFilter; +import org.pushingpixels.substance.api.SubstanceLookAndFeel; + +/** + * Main executable class + * + * @author JPEXS + */ +public class Main { + + protected static ProxyFrame proxyFrame; + + private static List sourceInfos = new ArrayList<>(); + + public static LoadingDialog loadingDialog; + + private static boolean working = false; + + private static TrayIcon trayIcon; + + private static MenuItem stopMenuItem; + + private static volatile MainFrame mainFrame; + + public static final int UPDATE_SYSTEM_MAJOR = 1; + + public static final int UPDATE_SYSTEM_MINOR = 3; + + private static LoadFromMemoryFrame loadFromMemoryFrame; + + private static LoadFromCacheFrame loadFromCacheFrame; + + private static final Logger logger = Logger.getLogger(Main.class.getName()); + + public static DebugLogDialog debugDialog; + + public static boolean shouldCloseWhenClosingLoadingDialog; + + private static Debugger flashDebugger; + + private static DebuggerHandler debugHandler = null; + + //private static int ip = 0; + //private static String ipClass = null; + private static Process runProcess; + + private static boolean runProcessDebug; + + private static boolean runProcessDebugPCode; + + private static boolean inited = false; + + private static File runTempFile; + + private static List runTempFiles = new ArrayList<>(); + + public static void freeRun() { + synchronized (Main.class) { + if (runTempFile != null) { + runTempFile.delete(); + runTempFile = null; + } + for (File f : runTempFiles) { + f.delete(); + } + runTempFiles.clear(); + + runProcess = null; + } + if (mainFrame != null && mainFrame.getPanel() != null) { + mainFrame.getPanel().clearDebuggerColors(); + } + if (runProcessDebug) { + Main.getDebugHandler().disconnect(); + } + } + + public static synchronized boolean isDebugPaused() { + return runProcess != null && runProcessDebug && getDebugHandler().isPaused(); + } + + public static synchronized boolean isDebugRunning() { + return runProcess != null && runProcessDebug; + } + + public static synchronized boolean isDebugPCode() { + return runProcessDebugPCode; + } + + public static synchronized boolean isDebugConnected() { + return getDebugHandler().isConnected(); + } + + public static synchronized boolean isRunning() { + return runProcess != null && !runProcessDebug; + } + + /** + * FIXME! + * + * @param v + */ + public static synchronized void dumpBytes(Variable v) { + InCallFunction icf; + try { + long objectId = 0l; + if ((v.vType == VariableType.OBJECT || v.vType == VariableType.MOVIECLIP)) { + objectId = (Long) v.value; + } + Object oldPos = getDebugHandler().getVariable(objectId, "position", true).parent.value; + getDebugHandler().setVariable(objectId, "position", VariableType.NUMBER, 0); + icf = getDebugHandler().callFunction(false, "readUTF", v, new ArrayList<>()); + System.out.println("Result=" + icf.variables.get(0).value); + getDebugHandler().setVariable(objectId, "position", VariableType.NUMBER, oldPos); + } catch (DebuggerHandler.ActionScriptException ex) { + Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); + } + + } + + public static synchronized boolean addWatch(Variable v, long v_id, boolean watchRead, boolean watchWrite) { + DebuggerCommands.Watch w = getDebugHandler().addWatch(v, v_id, watchRead, watchWrite); + return w != null; + } + + public static void runPlayer(String title, final String exePath, String file, String flashVars) { + if (!new File(file).exists()) { + return; + } + if (flashVars != null && !flashVars.isEmpty()) { + file += "?" + flashVars; + } + final String ffile = file; + + CancellableWorker runWorker = new CancellableWorker() { + @Override + protected Object doInBackground() throws Exception { + Process proc; + try { + proc = Runtime.getRuntime().exec(new String[]{exePath, ffile}); + } catch (IOException ex) { + logger.log(Level.SEVERE, null, ex); + return null; + } + boolean isDebug; + + synchronized (Main.class) { + runProcess = proc; + isDebug = runProcessDebug; + } + if (isDebug) { + mainFrame.getMenu().hilightPath("/debugging"); + } + mainFrame.getMenu().updateComponents(); + try { + if (proc != null) { + proc.waitFor(); + } + } catch (InterruptedException ex) { + if (proc != null) { + try { + proc.destroy(); + } catch (Exception ex2) { + //ignore + } + } + } + freeRun(); + stopDebugger(); + mainFrame.getMenu().updateComponents(); + return null; + } + + @Override + protected void done() { + Main.stopWork(); + } + + @Override + public void workerCancelled() { + Main.stopWork(); + synchronized (Main.class) { + if (runProcess != null) { + try { + runProcess.destroy(); + } catch (Exception ex) { + + } + } + } + freeRun(); + mainFrame.getMenu().updateComponents(); + } + }; + + mainFrame.getMenu().updateComponents(); + Main.startWork(title + "...", runWorker); + runWorker.execute(); + } + + public static void stopRun() { + + synchronized (Main.class) { + if (runProcess != null) { + runProcess.destroy(); + } + } + freeRun(); + stopDebugger(); + mainFrame.getMenu().updateComponents(); + } + + private static interface SwfPreparation { + + public SWF prepare(SWF swf); + } + + private static class SwfRunPrepare implements SwfPreparation { + + @Override + public SWF prepare(SWF swf) { + if (Configuration.autoOpenLoadedSWFs.get()) { + if (!DebuggerTools.hasDebugger(swf)) { + DebuggerTools.switchDebugger(swf); + } + DebuggerTools.injectDebugLoader(swf); + } + return swf; + } + } + + private static class SwfDebugPrepare extends SwfRunPrepare { + + private boolean doPCode; + + public SwfDebugPrepare(boolean doPCode) { + this.doPCode = doPCode; + } + + @Override + public SWF prepare(SWF instrSWF) { + instrSWF = super.prepare(instrSWF); + try { + File fTempFile = new File(instrSWF.getFile()); + instrSWF.enableDebugging(true, new File("."), true, doPCode); + FileOutputStream fos = new FileOutputStream(fTempFile); + instrSWF.saveTo(fos); + fos.close(); + if (!instrSWF.isAS3()) { + //Read again, because line file offsets changed with adding debug tags + //TODO: handle somehow without rereading? + instrSWF = null; + try (FileInputStream fis = new FileInputStream(fTempFile)) { + instrSWF = new SWF(fis, false, false); + } catch (InterruptedException ex) { + logger.log(Level.SEVERE, null, ex); + } + if (instrSWF != null) { + String swfFileName = fTempFile.getAbsolutePath(); + if (swfFileName.toLowerCase().endsWith(".swf")) { + swfFileName = swfFileName.substring(0, swfFileName.length() - 4) + ".swd"; + } else { + swfFileName = swfFileName + ".swd"; + } + File swdFile = new File(swfFileName); + if (doPCode) { + instrSWF.generatePCodeSwdFile(swdFile, getPackBreakPoints(true)); + } else { + instrSWF.generateSwdFile(swdFile, getPackBreakPoints(true)); + } + } + } + } catch (IOException ex) { + //ignore, return instrSWF + } + return instrSWF; + } + } + + private static void prepareSwf(SwfPreparation prep, File toPrepareFile, File origFile, List tempFiles) throws IOException { + SWF instrSWF = null; + try (FileInputStream fis = new FileInputStream(toPrepareFile)) { + instrSWF = new SWF(fis, toPrepareFile.getAbsolutePath(), origFile.getName(), false); + } catch (InterruptedException ex) { + logger.log(Level.SEVERE, null, ex); + } + if (instrSWF != null) { + for (Tag t : instrSWF.getLocalTags()) { + if (t instanceof ImportTag) { + ImportTag it = (ImportTag) t; + String url = it.getUrl(); + File importedFile = new File(origFile.getParentFile(), url); + if (importedFile.exists()) { + File newTempFile = File.createTempFile("ffdec_run_import_", ".swf"); + it.setUrl("./" + newTempFile.getName()); + byte[] impData = Helper.readFile(importedFile.getAbsolutePath()); + Helper.writeFile(newTempFile.getAbsolutePath(), impData); + tempFiles.add(newTempFile); + prepareSwf(prep, newTempFile, importedFile, tempFiles); + } + } + } + if (prep != null) { + instrSWF = prep.prepare(instrSWF); + } + try (FileOutputStream fos = new FileOutputStream(toPrepareFile)) { + instrSWF.saveTo(fos); + } + } + } + + public static void run(SWF swf) { + String flashVars = "";//key=val&key2=val2 + String playerLocation = Configuration.playerLocation.get(); + if (playerLocation.isEmpty() || (!new File(playerLocation).exists())) { + View.showMessageDialog(null, AppStrings.translate("message.playerpath.notset"), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE); + advancedSettings("paths"); + return; + } + if (swf == null) { + return; + } + File tempFile; + List tempFiles = new ArrayList<>(); + try { + tempFile = File.createTempFile("ffdec_run_", ".swf"); + + try (FileOutputStream fos = new FileOutputStream(tempFile)) { + swf.saveTo(fos); + } + + prepareSwf(new SwfRunPrepare(), tempFile, new File(swf.getFile()), tempFiles); + + } catch (IOException ex) { + return; + + } + if (tempFile != null) { + synchronized (Main.class) { + runTempFile = tempFile; + runTempFiles = tempFiles; + runProcessDebug = false; + } + runPlayer(AppStrings.translate("work.running"), playerLocation, tempFile.getAbsolutePath(), flashVars); + } + } + + public static void runDebug(SWF swf, final boolean doPCode) { + String flashVars = "";//key=val&key2=val2 + String playerLocation = Configuration.playerDebugLocation.get(); + if (playerLocation.isEmpty() || (!new File(playerLocation).exists())) { + View.showMessageDialog(null, AppStrings.translate("message.playerpath.debug.notset"), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE); + Main.advancedSettings("paths"); + return; + } + if (swf == null) { + return; + } + File tempFile = null; + + try { + tempFile = File.createTempFile("ffdec_debug_", ".swf"); + } catch (Exception ex) { + + } + + if (tempFile != null) { + final File fTempFile = tempFile; + final List tempFiles = new ArrayList<>(); + CancellableWorker instrumentWorker = new CancellableWorker() { + @Override + protected Object doInBackground() throws Exception { + + try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(fTempFile))) { + swf.saveTo(fos); + } + prepareSwf(new SwfDebugPrepare(doPCode), fTempFile, new File(swf.getFile()), tempFiles); + return null; + } + + @Override + public void workerCancelled() { + Main.stopWork(); + } + + @Override + protected void done() { + synchronized (Main.class) { + runTempFile = fTempFile; + runProcessDebug = true; + runProcessDebugPCode = doPCode; + runTempFiles = tempFiles; + } + Main.stopWork(); + Main.startDebugger(); + runPlayer(AppStrings.translate("work.debugging.wait"), playerLocation, fTempFile.getAbsolutePath(), flashVars); + } + }; + + Main.startWork(AppStrings.translate("work.debugging.instrumenting"), instrumentWorker); + instrumentWorker.execute(); + } + } + + /* public static void debuggerNotSuspended() { + + }*/ + public static boolean isDebugging() { + return isDebugRunning(); + } + + public synchronized static int getIp(Object pack) { + return getDebugHandler().getBreakIp(); + } + + public synchronized static String getIpClass() { + return getDebugHandler().getBreakScriptName(); + } + + public static synchronized boolean isBreakPointValid(String scriptName, int line) { + return !getDebugHandler().isBreakpointInvalid(scriptName, line); + } + + public synchronized static void addBreakPoint(String scriptName, int line) { + getDebugHandler().addBreakPoint(scriptName, line); + } + + public synchronized static void removeBreakPoint(String scriptName, int line) { + getDebugHandler().removeBreakPoint(scriptName, line); + } + + public synchronized static boolean toggleBreakPoint(String scriptName, int line) { + if (getDebugHandler().isBreakpointToAdd(scriptName, line) || getDebugHandler().isBreakpointConfirmed(scriptName, line) || getDebugHandler().isBreakpointInvalid(scriptName, line)) { + getDebugHandler().removeBreakPoint(scriptName, line); + return false; + } else { + getDebugHandler().addBreakPoint(scriptName, line); + return true; + } + } + + public synchronized static Map> getPackBreakPoints(boolean validOnly) { + return getDebugHandler().getAllBreakPoints(validOnly); + } + + public synchronized static Set getScriptBreakPoints(String pack, boolean onlyValid) { + return getDebugHandler().getBreakPoints(pack, onlyValid); + } + + public static DebuggerHandler getDebugHandler() { + return debugHandler; + } + + public static void ensureMainFrame() { + if (mainFrame == null) { + synchronized (Main.class) { + if (mainFrame == null) { + MainFrame frame; + if (Configuration.useRibbonInterface.get()) { + frame = new MainFrameRibbon(); + } else { + frame = new MainFrameClassic(); + } + frame.getPanel().setErrorState(ErrorLogFrame.getInstance().getErrorState()); + mainFrame = frame; + } + } + } + } + + public static MainFrame getMainFrame() { + return mainFrame; + } + + public static void loadFromCache() { + if (loadFromCacheFrame == null) { + loadFromCacheFrame = new LoadFromCacheFrame(); + } + loadFromCacheFrame.setVisible(true); + } + + public static void loadFromMemory() { + if (loadFromMemoryFrame == null) { + loadFromMemoryFrame = new LoadFromMemoryFrame(mainFrame); + } + loadFromMemoryFrame.setVisible(true); + } + + public static void setVariable(long parentId, String varName, int valueType, Object value) { + getDebugHandler().setVariable(parentId, varName, valueType, value); + } + + public static void setSubLimiter(boolean value) { + if (value) { + AVM2Code.toSourceLimit = Configuration.sublimiter.get(); + } else { + AVM2Code.toSourceLimit = -1; + } + } + + public synchronized static boolean isInited() { + return inited; + } + + public synchronized static void setSessionLoaded(boolean v) { + inited = v; + } + + public static boolean isWorking() { + return working; + } + + public static void startProxy(int port) { + if (proxyFrame == null) { + proxyFrame = new ProxyFrame(mainFrame); + } + + proxyFrame.setPort(port); + addTrayIcon(); + switchProxy(); + } + + public static void showProxy() { + if (proxyFrame == null) { + proxyFrame = new ProxyFrame(mainFrame); + } + proxyFrame.setVisible(true); + proxyFrame.setState(Frame.NORMAL); + } + + public static void startWork(String name, CancellableWorker worker) { + startWork(name, -1, worker); + } + + public static void startWork(final String name, final int percent, final CancellableWorker worker) { + working = true; + View.execInEventDispatchLater(() -> { + if (mainFrame != null) { + mainFrame.getPanel().setWorkStatus(name, worker); + if (percent == -1) { + mainFrame.getPanel().hidePercent(); + } else { + mainFrame.getPanel().setPercent(percent); + } + } + if (loadingDialog != null) { + loadingDialog.setDetail(name); + loadingDialog.setPercent(percent); + } + if (CommandLineArgumentParser.isCommandLineMode()) { + System.out.println(name); + } + }); + } + + public static void stopWork() { + working = false; + View.execInEventDispatchLater(() -> { + if (mainFrame != null) { + mainFrame.getPanel().setWorkStatus("", null); + } + if (loadingDialog != null) { + loadingDialog.setDetail(""); + } + }); + } + + public static SWFList parseSWF(SWFSourceInfo sourceInfo) throws Exception { + SWFList result = new SWFList(); + + InputStream inputStream = sourceInfo.getInputStream(); + SWFBundle bundle = null; + FileInputStream fis = null; + if (inputStream == null) { + inputStream = new BufferedInputStream(fis = new FileInputStream(sourceInfo.getFile())); + bundle = sourceInfo.getBundle(false, SearchMode.ALL); + logger.log(Level.INFO, "Load file: {0}", sourceInfo.getFile()); + } else if (inputStream instanceof SeekableInputStream + || inputStream instanceof BufferedInputStream) { + try { + inputStream.reset(); + } catch (IOException ex) { + logger.log(Level.SEVERE, null, ex); + } + logger.log(Level.INFO, "Load stream: {0}", sourceInfo.getFileTitle()); + } + + Stopwatch sw = Stopwatch.startNew(); + if (bundle != null) { + result.bundle = bundle; + result.name = new File(sourceInfo.getFileTitleOrName()).getName(); + for (Entry streamEntry : bundle.getAll().entrySet()) { + InputStream stream = streamEntry.getValue(); + stream.reset(); + CancellableWorker worker = new CancellableWorker() { + @Override + public SWF doInBackground() throws Exception { + final CancellableWorker worker = this; + SWF swf = new SWF(stream, null, streamEntry.getKey(), new ProgressListener() { + @Override + public void progress(int p) { + startWork(AppStrings.translate("work.reading.swf"), p, worker); + } + }, Configuration.parallelSpeedUp.get()); + return swf; + } + }; + loadingDialog.setWroker(worker); + worker.execute(); + + try { + result.add(worker.get()); + } catch (CancellationException ex) { + logger.log(Level.WARNING, "Loading SWF {0} was cancelled.", streamEntry.getKey()); + } + } + } else { + InputStream fInputStream = inputStream; + + final String[] yesno = new String[]{AppStrings.translate("button.yes"), AppStrings.translate("button.no"), AppStrings.translate("button.yes.all"), AppStrings.translate("button.no.all")}; + + CancellableWorker worker = new CancellableWorker() { + private boolean yestoall = false; + + private boolean notoall = false; + + private SWF open(InputStream is, String file, String fileTitle) throws IOException, InterruptedException { + final CancellableWorker worker = this; + + SWF swf = new SWF(is, file, fileTitle, new ProgressListener() { + @Override + public void progress(int p) { + startWork(AppStrings.translate("work.reading.swf"), p, worker); + } + }, Configuration.parallelSpeedUp.get(), false, true, new UrlResolver() { + @Override + public SWF resolveUrl(final String url) { + int opt = -1; + if (!(yestoall || notoall)) { + opt = View.showOptionDialog(null, AppStrings.translate("message.imported.swf").replace("%url%", url), AppStrings.translate("message.warning"), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, yesno, AppStrings.translate("button.yes")); + if (opt == 2) { + yestoall = true; + } + if (opt == 3) { + notoall = true; + } + } + + if (yestoall) { + opt = 0; // yes + } else if (notoall) { + opt = 1; // no + } + + if (opt == 1) //no + { + return null; + } + + if (url.startsWith("http://") || url.startsWith("https://")) { + try { + URL u = new URL(url); + return open(u.openStream(), null, url); //? + } catch (Exception ex) { + //ignore + } + } else { + File f = new File(new File(file).getParentFile(), url); + if (f.exists()) { + try { + return open(new FileInputStream(f), f.getAbsolutePath(), f.getName()); + } catch (Exception ex) { + //ignore + } + } + } + Reference ret = new Reference<>(null); + View.execInEventDispatch(new Runnable() { + @Override + public void run() { + + while (JOptionPane.YES_OPTION == View.showConfirmDialog(null, AppStrings.translate("message.imported.swf.manually").replace("%url%", url), AppStrings.translate("error"), JOptionPane.YES_NO_OPTION, JOptionPane.ERROR_MESSAGE)) { + + JFileChooser fc = new JFileChooser(); + fc.setCurrentDirectory(new File(Configuration.lastOpenDir.get())); + FileFilter allSupportedFilter = new FileFilter() { + private final String[] supportedExtensions = new String[]{".swf", ".gfx"}; + + @Override + public boolean accept(File f) { + String name = f.getName().toLowerCase(); + for (String ext : supportedExtensions) { + if (name.endsWith(ext)) { + return true; + } + } + return f.isDirectory(); + } + + @Override + public String getDescription() { + String exts = Helper.joinStrings(supportedExtensions, "*%s", "; "); + return AppStrings.translate("filter.supported") + " (" + exts + ")"; + } + }; + fc.setFileFilter(allSupportedFilter); + FileFilter swfFilter = new FileFilter() { + @Override + public boolean accept(File f) { + return (f.getName().toLowerCase().endsWith(".swf")) || (f.isDirectory()); + } + + @Override + public String getDescription() { + return AppStrings.translate("filter.swf"); + } + }; + fc.addChoosableFileFilter(swfFilter); + + FileFilter gfxFilter = new FileFilter() { + @Override + public boolean accept(File f) { + return (f.getName().toLowerCase().endsWith(".gfx")) || (f.isDirectory()); + } + + @Override + public String getDescription() { + return AppStrings.translate("filter.gfx"); + } + }; + fc.addChoosableFileFilter(gfxFilter); + fc.setAcceptAllFileFilterUsed(false); + JFrame f = new JFrame(); + View.setWindowIcon(f); + int returnVal = fc.showOpenDialog(f); + if (returnVal == JFileChooser.APPROVE_OPTION) { + Configuration.lastOpenDir.set(Helper.fixDialogFile(fc.getSelectedFile()).getParentFile().getAbsolutePath()); + File selFile = Helper.fixDialogFile(fc.getSelectedFile()); + try { + ret.setVal(open(new FileInputStream(selFile), selFile.getAbsolutePath(), selFile.getName())); + break; + } catch (Exception ex) { + //ignore; + } + } else { + break; + } + } + } + }); + return ret.getVal(); + } + }); + return swf; + } + + @Override + public SWF doInBackground() throws Exception { + return open(fInputStream, sourceInfo.getFile(), sourceInfo.getFileTitle()); + } + }; + if (loadingDialog != null) { + loadingDialog.setWroker(worker); + } + worker.execute(); + + try { + result.add(worker.get()); + } catch (CancellationException ex) { + logger.log(Level.WARNING, "Loading SWF {0} was cancelled.", sourceInfo.getFileTitleOrName()); + } + } + + if (fis != null) { + logger.log(Level.INFO, "File loaded in {0} seconds.", (sw.getElapsedMilliseconds() / 1000)); + fis.close(); + } else { + logger.log(Level.INFO, "Stream loaded in {0} seconds.", (sw.getElapsedMilliseconds() / 1000)); + } + + result.sourceInfo = sourceInfo; + for (SWF swf : result) { + logger.log(Level.INFO, ""); + logger.log(Level.INFO, "== File information =="); + logger.log(Level.INFO, "Size: {0}", Helper.formatFileSize(swf.fileSize)); + logger.log(Level.INFO, "Flash version: {0}", swf.version); + int width = (int) ((swf.displayRect.Xmax - swf.displayRect.Xmin) / SWF.unitDivisor); + int height = (int) ((swf.displayRect.Ymax - swf.displayRect.Ymin) / SWF.unitDivisor); + logger.log(Level.INFO, "Width: {0}", width); + logger.log(Level.INFO, "Height: {0}", height); + + swf.swfList = result; + swf.addEventListener(new EventListener() { + @Override + public void handleExportingEvent(String type, int index, int count, Object data) { + String text = AppStrings.translate("work.exporting"); + if (type != null && type.length() > 0) { + text += " " + type; + } + + startWork(text + " " + index + "/" + count + " " + data, null); + } + + @Override + public void handleExportedEvent(String type, int index, int count, Object data) { + String text = AppStrings.translate("work.exported"); + if (type != null && type.length() > 0) { + text += " " + type; + } + + startWork(text + " " + index + "/" + count + " " + data, null); + } + + @Override + public void handleEvent(String event, Object data) { + if (event.equals("exporting") || event.equals("exported")) { + throw new Error("Event is not supported by this handler."); + } + if (event.equals("getVariables")) { + startWork(AppStrings.translate("work.gettingvariables") + "..." + (String) data, null); + } + if (event.equals("deobfuscate")) { + startWork(AppStrings.translate("work.deobfuscating") + "..." + (String) data, null); + } + if (event.equals("rename")) { + startWork(AppStrings.translate("work.renaming") + "..." + (String) data, null); + } + } + }); + } + + return result; + } + + public static void saveFile(SWF swf, String outfile) throws IOException { + saveFile(swf, outfile, SaveFileMode.SAVE, null); + } + + public static void saveFile(SWF swf, String outfile, SaveFileMode mode, ExeExportMode exeExportMode) throws IOException { + if (mode == SaveFileMode.SAVEAS && !swf.swfList.isBundle()) { + swf.setFile(outfile); + swf.swfList.sourceInfo.setFile(outfile); + } + File outfileF = new File(outfile); + File tmpFile = new File(outfile + ".tmp"); + try (FileOutputStream fos = new FileOutputStream(tmpFile); + BufferedOutputStream bos = new BufferedOutputStream(fos)) { + if (mode == SaveFileMode.EXE) { + switch (exeExportMode) { + case WRAPPER: + InputStream exeStream = View.class.getClassLoader().getResourceAsStream("com/jpexs/helpers/resource/Swf2Exe.bin"); + Helper.copyStream(exeStream, bos); + int width = swf.displayRect.Xmax - swf.displayRect.Xmin; + int height = swf.displayRect.Ymax - swf.displayRect.Ymin; + bos.write(width & 0xff); + bos.write((width >> 8) & 0xff); + bos.write((width >> 16) & 0xff); + bos.write((width >> 24) & 0xff); + bos.write(height & 0xff); + bos.write((height >> 8) & 0xff); + bos.write((height >> 16) & 0xff); + bos.write((height >> 24) & 0xff); + bos.write(Configuration.saveAsExeScaleMode.get()); + break; + case PROJECTOR_WIN: + case PROJECTOR_MAC: + case PROJECTOR_LINUX: + File projectorFile = Configuration.getProjectorFile(exeExportMode); + if (projectorFile == null) { + String message = "Projector not found, please place it to " + Configuration.getProjectorPath(); + logger.log(Level.SEVERE, message); + throw new IOException(message); + } + Helper.copyStream(new FileInputStream(projectorFile), bos); + bos.flush(); + break; + } + } + + long pos = fos.getChannel().position(); + swf.saveTo(bos); + + if (mode == SaveFileMode.EXE) { + switch (exeExportMode) { + case PROJECTOR_WIN: + case PROJECTOR_MAC: + case PROJECTOR_LINUX: + bos.flush(); + int swfSize = (int) (fos.getChannel().position() - pos); + + // write magic number + bos.write(0x56); + bos.write(0x34); + bos.write(0x12); + bos.write(0xfa); + + bos.write(swfSize & 0xff); + bos.write((swfSize >> 8) & 0xff); + bos.write((swfSize >> 16) & 0xff); + bos.write((swfSize >> 24) & 0xff); + } + } + } + if (tmpFile.exists()) { + if (tmpFile.length() > 0) { + outfileF.delete(); + if (!tmpFile.renameTo(outfileF)) { + tmpFile.delete(); + throw new IOException("Cannot access " + outfile); + } + } else { + throw new IOException("Output is empty"); + } + } else { + throw new IOException("Output not found"); + } + } + + private static class OpenFileWorker extends SwingWorker { + + private final SWFSourceInfo[] sourceInfos; + + private final Runnable executeAfterOpen; + + private final int[] reloadIndices; + + public OpenFileWorker(SWFSourceInfo sourceInfo) { + this(sourceInfo, -1); + } + + public OpenFileWorker(SWFSourceInfo sourceInfo, int reloadIndex) { + this(sourceInfo, null, reloadIndex); + } + + public OpenFileWorker(SWFSourceInfo sourceInfo, Runnable executeAfterOpen) { + this(sourceInfo, executeAfterOpen, -1); + } + + public OpenFileWorker(SWFSourceInfo sourceInfo, Runnable executeAfterOpen, int reloadIndex) { + this.sourceInfos = new SWFSourceInfo[]{sourceInfo}; + this.executeAfterOpen = executeAfterOpen; + this.reloadIndices = new int[]{reloadIndex}; + } + + public OpenFileWorker(SWFSourceInfo[] sourceInfos) { + this(sourceInfos, null, null); + } + + public OpenFileWorker(SWFSourceInfo[] sourceInfos, Runnable executeAfterOpen) { + this(sourceInfos, executeAfterOpen, null); + } + + public OpenFileWorker(SWFSourceInfo[] sourceInfos, Runnable executeAfterOpen, int[] reloadIndices) { + this.sourceInfos = sourceInfos; + this.executeAfterOpen = executeAfterOpen; + int[] indices = new int[sourceInfos.length]; + for (int i = 0; i < indices.length; i++) { + indices[i] = -1; + } + this.reloadIndices = reloadIndices == null ? indices : reloadIndices; + } + + @Override + protected Object doInBackground() throws Exception { + boolean first = true; + SWF firstSWF = null; + for (int index = 0; index < sourceInfos.length; index++) { + SWFSourceInfo sourceInfo = sourceInfos[index]; + SWFList swfs = null; + try { + Main.startWork(AppStrings.translate("work.reading.swf") + "...", null); + try { + swfs = parseSWF(sourceInfo); + } catch (ExecutionException ex) { + Throwable cause = ex.getCause(); + if (cause instanceof SwfOpenException) { + throw (SwfOpenException) cause; + } + + throw ex; + } + } catch (OutOfMemoryError ex) { + logger.log(Level.SEVERE, null, ex); + View.showMessageDialog(null, "Cannot load SWF file. Out of memory."); + continue; + } catch (SwfOpenException ex) { + logger.log(Level.SEVERE, null, ex); + View.showMessageDialog(null, ex.getMessage()); + continue; + } catch (Exception ex) { + logger.log(Level.SEVERE, null, ex); + View.showMessageDialog(null, "Cannot load SWF file."); + continue; + } + + final SWFList swfs1 = swfs; + final boolean first1 = first; + first = false; + if (firstSWF == null && swfs1.size() > 0) { + firstSWF = swfs1.get(0); + } + + final int findex = index; + try { + View.execInEventDispatch(() -> { + Main.startWork(AppStrings.translate("work.creatingwindow") + "...", null); + ensureMainFrame(); + if (reloadIndices[findex] > -1) { + mainFrame.getPanel().loadSwfAtPos(swfs1, reloadIndices[findex]); + } else { + mainFrame.getPanel().load(swfs1, first1); + } + }); + } catch (Exception ex) { + logger.log(Level.SEVERE, null, ex); + } + } + + loadingDialog.setVisible(false); + shouldCloseWhenClosingLoadingDialog = false; + + final SWF fswf = firstSWF; + View.execInEventDispatch(() -> { + if (mainFrame != null) { + mainFrame.setVisible(true); + } + + Main.stopWork(); + + if (mainFrame != null && Configuration.gotoMainClassOnStartup.get()) { + mainFrame.getPanel().gotoDocumentClass(fswf); + } + + if (mainFrame != null && fswf != null) { + SwfSpecificConfiguration swfConf = Configuration.getSwfSpecificConfiguration(fswf.getShortFileName()); + if (swfConf != null) { + String pathStr = swfConf.lastSelectedPath; + mainFrame.getPanel().tagTree.setSelectionPathString(pathStr); + } + } + + if (executeAfterOpen != null) { + executeAfterOpen.run(); + } + }); + + return true; + } + } + + public static boolean reloadSWFs() { + CancellableWorker.cancelBackgroundThreads(); + if (Main.sourceInfos.isEmpty()) { + Helper.freeMem(); + showModeFrame(); + return true; + } else { + SWFSourceInfo[] sourceInfosCopy = new SWFSourceInfo[sourceInfos.size()]; + sourceInfos.toArray(sourceInfosCopy); + sourceInfos.clear(); + openFile(sourceInfosCopy); + return true; + } + } + + public static void reloadApp() { + if (debugDialog != null) { + debugDialog.setVisible(false); + debugDialog.dispose(); + debugDialog = null; + } + if (loadingDialog != null) { + synchronized (Main.class) { + if (loadingDialog != null) { + loadingDialog.setVisible(false); + loadingDialog.dispose(); + loadingDialog = null; + } + } + } + if (proxyFrame != null) { + proxyFrame.setVisible(false); + proxyFrame.dispose(); + proxyFrame = null; + } + if (loadFromMemoryFrame != null) { + loadFromMemoryFrame.setVisible(false); + loadFromMemoryFrame.dispose(); + loadFromMemoryFrame = null; + } + if (loadFromCacheFrame != null) { + loadFromCacheFrame.setVisible(false); + loadFromCacheFrame.dispose(); + loadFromCacheFrame = null; + } + if (mainFrame != null) { + mainFrame.setVisible(false); + mainFrame.getPanel().closeAll(false); + mainFrame.dispose(); + mainFrame = null; + } + FontTag.reload(); + Cache.clearAll(); + initGui(); + reloadSWFs(); + } + + public static OpenFileResult openFile(String swfFile, String fileTitle) { + return openFile(swfFile, fileTitle, null); + } + + public static OpenFileResult openFile(String swfFile, String fileTitle, Runnable executeAfterOpen) { + try { + File file = new File(swfFile); + if (!file.exists()) { + View.showMessageDialog(null, AppStrings.translate("open.error.fileNotFound"), AppStrings.translate("open.error"), JOptionPane.ERROR_MESSAGE); + return OpenFileResult.NOT_FOUND; + } + swfFile = file.getCanonicalPath(); + SWFSourceInfo sourceInfo = new SWFSourceInfo(null, swfFile, fileTitle); + OpenFileResult openResult = openFile(sourceInfo); + return openResult; + } catch (IOException ex) { + View.showMessageDialog(null, AppStrings.translate("open.error.cannotOpen"), AppStrings.translate("open.error"), JOptionPane.ERROR_MESSAGE); + return OpenFileResult.ERROR; + } + } + + public static OpenFileResult openFile(SWFSourceInfo sourceInfo) { + return openFile(new SWFSourceInfo[]{sourceInfo}); + } + + public static OpenFileResult openFile(SWFSourceInfo sourceInfo, Runnable executeAfterOpen) { + return openFile(new SWFSourceInfo[]{sourceInfo}, executeAfterOpen); + } + + public static OpenFileResult openFile(SWFSourceInfo sourceInfo, Runnable executeAfterOpen, int reloadIndex) { + return openFile(new SWFSourceInfo[]{sourceInfo}, executeAfterOpen, new int[]{reloadIndex}); + } + + public static OpenFileResult openFile(SWFSourceInfo[] newSourceInfos) { + return openFile(newSourceInfos, null); + } + + public static OpenFileResult openFile(SWFSourceInfo[] newSourceInfos, Runnable executeAfterOpen) { + return openFile(newSourceInfos, executeAfterOpen, null); + } + + public static OpenFileResult openFile(SWFSourceInfo[] newSourceInfos, Runnable executeAfterOpen, int[] reloadIndices) { + if (mainFrame != null && !Configuration.openMultipleFiles.get()) { + sourceInfos.clear(); + mainFrame.getPanel().closeAll(false); + mainFrame.setVisible(false); + Helper.freeMem(); + reloadIndices = null; + } + + loadingDialog.setVisible(true); + + for (int i = 0; i < sourceInfos.size(); i++) { + SWFSourceInfo si = newSourceInfos[i]; + String fileName = si.getFile(); + if (fileName != null) { + Configuration.addRecentFile(fileName); + } + } + + OpenFileWorker wrk = new OpenFileWorker(newSourceInfos, executeAfterOpen, reloadIndices); + wrk.execute(); + if (reloadIndices == null) { + sourceInfos.addAll(Arrays.asList(newSourceInfos)); + } else { + for (int i = 0; i < reloadIndices.length; i++) { + sourceInfos.set(reloadIndices[i], newSourceInfos[i]); + } + } + return OpenFileResult.OK; + } + + public static void closeFile(SWFList swf) { + sourceInfos.remove(swf.sourceInfo); + mainFrame.getPanel().close(swf); + } + + public static void reloadFile(SWFList swf) { + //mainFrame.getPanel().close(swf); + openFile(swf.sourceInfo, null, sourceInfos.indexOf(swf.sourceInfo)); + } + + public static boolean closeAll() { + boolean closeResult = mainFrame.getPanel().closeAll(true); + if (closeResult) { + sourceInfos.clear(); + } + + return closeResult; + } + + public static boolean saveFileDialog(SWF swf, final SaveFileMode mode) { + JFileChooser fc = new JFileChooser(); + fc.setCurrentDirectory(new File(Configuration.lastSaveDir.get())); + String ext = ".swf"; + switch (mode) { + case SAVE: + case SAVEAS: + if (swf.getFile() != null) { + ext = Path.getExtension(swf.getFile()); + } + break; + case EXE: + ext = ".exe"; + break; + } + + FileFilter swfFilter = new FileFilter() { + @Override + public boolean accept(File f) { + return (f.getName().toLowerCase().endsWith(".swf")) || (f.isDirectory()); + } + + @Override + public String getDescription() { + return AppStrings.translate("filter.swf"); + } + }; + + FileFilter gfxFilter = new FileFilter() { + @Override + public boolean accept(File f) { + return (f.getName().toLowerCase().endsWith(".gfx")) || (f.isDirectory()); + } + + @Override + public String getDescription() { + return AppStrings.translate("filter.gfx"); + } + }; + + ExeExportMode exeExportMode = null; + if (mode == SaveFileMode.EXE) { + exeExportMode = Configuration.exeExportMode.get(); + if (exeExportMode == null) { + exeExportMode = ExeExportMode.WRAPPER; + } + String filterDescription = null; + switch (exeExportMode) { + case WRAPPER: + case PROJECTOR_WIN: + ext = ".exe"; + filterDescription = "filter.exe"; + break; + case PROJECTOR_MAC: + ext = ".dmg"; + filterDescription = "filter.dmg"; + break; + case PROJECTOR_LINUX: + // linux projector is compressed with tar.gz + // todo: decompress + ext = ""; + filterDescription = "filter.linuxExe"; + break; + } + + String fext = ext; + String ffilterDescription = filterDescription; + FileFilter exeFilter = new FileFilter() { + @Override + public boolean accept(File f) { + return (f.getName().toLowerCase().endsWith(fext)) || (f.isDirectory()); + } + + @Override + public String getDescription() { + return AppStrings.translate(ffilterDescription); + } + }; + fc.setFileFilter(exeFilter); + } else if (swf.gfx) { + fc.addChoosableFileFilter(swfFilter); + fc.setFileFilter(gfxFilter); + } else { + fc.setFileFilter(swfFilter); + fc.addChoosableFileFilter(gfxFilter); + } + final String extension = ext; + fc.setAcceptAllFileFilterUsed(false); + JFrame f = new JFrame(); + View.setWindowIcon(f); + if (fc.showSaveDialog(f) == JFileChooser.APPROVE_OPTION) { + File file = Helper.fixDialogFile(fc.getSelectedFile()); + FileFilter selFilter = fc.getFileFilter(); + try { + String fileName = file.getAbsolutePath(); + if (selFilter == swfFilter) { + if (!fileName.toLowerCase().endsWith(extension)) { + fileName += extension; + } + swf.gfx = false; + } + if (selFilter == gfxFilter) { + if (!fileName.toLowerCase().endsWith(".gfx")) { + fileName += ".gfx"; + } + swf.gfx = true; + } + Main.saveFile(swf, fileName, mode, exeExportMode); + Configuration.lastSaveDir.set(file.getParentFile().getAbsolutePath()); + return true; + } catch (IOException ex) { + View.showMessageDialog(null, AppStrings.translate("error.file.write")); + } + } + return false; + } + + public static boolean openFileDialog() { + JFileChooser fc = new JFileChooser(); + if (Configuration.openMultipleFiles.get()) { + fc.setMultiSelectionEnabled(true); + } + fc.setCurrentDirectory(new File(Configuration.lastOpenDir.get())); + FileFilter allSupportedFilter = new FileFilter() { + private final String[] supportedExtensions = new String[]{".swf", ".gfx", ".swc", ".zip"}; + + @Override + public boolean accept(File f) { + String name = f.getName().toLowerCase(); + for (String ext : supportedExtensions) { + if (name.endsWith(ext)) { + return true; + } + } + return f.isDirectory(); + } + + @Override + public String getDescription() { + String exts = Helper.joinStrings(supportedExtensions, "*%s", "; "); + return AppStrings.translate("filter.supported") + " (" + exts + ")"; + } + }; + fc.setFileFilter(allSupportedFilter); + FileFilter swfFilter = new FileFilter() { + @Override + public boolean accept(File f) { + return (f.getName().toLowerCase().endsWith(".swf")) || (f.isDirectory()); + } + + @Override + public String getDescription() { + return AppStrings.translate("filter.swf"); + } + }; + fc.addChoosableFileFilter(swfFilter); + + FileFilter swcFilter = new FileFilter() { + @Override + public boolean accept(File f) { + return (f.getName().toLowerCase().endsWith(".swc")) || (f.isDirectory()); + } + + @Override + public String getDescription() { + return AppStrings.translate("filter.swc"); + } + }; + fc.addChoosableFileFilter(swcFilter); + + FileFilter gfxFilter = new FileFilter() { + @Override + public boolean accept(File f) { + return (f.getName().toLowerCase().endsWith(".gfx")) || (f.isDirectory()); + } + + @Override + public String getDescription() { + return AppStrings.translate("filter.gfx"); + } + }; + fc.addChoosableFileFilter(gfxFilter); + + FileFilter zipFilter = new FileFilter() { + @Override + public boolean accept(File f) { + return (f.getName().toLowerCase().endsWith(".zip")) || (f.isDirectory()); + } + + @Override + public String getDescription() { + return AppStrings.translate("filter.zip"); + } + }; + fc.addChoosableFileFilter(zipFilter); + + FileFilter binaryFilter = new FileFilter() { + @Override + public boolean accept(File f) { + return true; + } + + @Override + public String getDescription() { + return AppStrings.translate("filter.binary"); + } + }; + fc.addChoosableFileFilter(binaryFilter); + + fc.setAcceptAllFileFilterUsed(false); + JFrame f = new JFrame(); + View.setWindowIcon(f); + int returnVal = fc.showOpenDialog(f); + if (returnVal == JFileChooser.APPROVE_OPTION) { + Configuration.lastOpenDir.set(Helper.fixDialogFile(fc.getSelectedFile()).getParentFile().getAbsolutePath()); + File[] selFiles = fc.getSelectedFiles(); + for (File file : selFiles) { + File selfile = Helper.fixDialogFile(file); + Main.openFile(selfile.getAbsolutePath(), null); + } + return true; + } else { + return false; + } + } + + public static void displayErrorFrame() { + ErrorLogFrame.getInstance().setVisible(true); + } + + private static String md5(byte data[]) { + try { + java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5"); + byte[] array = md.digest(data); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < array.length; ++i) { + sb.append(Integer.toHexString((array[i] & 0xFF) | 0x100).substring(1, 3)); + } + return sb.toString(); + } catch (java.security.NoSuchAlgorithmException e) { + } + return null; + } + + private static void initGui() { + if (GraphicsEnvironment.isHeadless()) { + System.err.println("Error: Your system does not support Graphic User Interface"); + exit(); + } + + System.setProperty("sun.java2d.d3d", "false"); + System.setProperty("sun.java2d.noddraw", "true"); + + if (Configuration.hwAcceleratedGraphics.get()) { + System.setProperty("sun.java2d.opengl", Configuration._debugMode.get() ? "True" : "true"); + } else { + System.setProperty("sun.java2d.opengl", "false"); + } + + initUiLang(); + + if (Configuration.useRibbonInterface.get()) { + View.setLookAndFeel(); + } else { + try { + UIManager.put(SubstanceLookAndFeel.COLORIZATION_FACTOR, null); + UIManager.put("Tree.expandedIcon", null); + UIManager.put("Tree.collapsedIcon", null); + UIManager.put("ColorChooserUI", null); + UIManager.put("ColorChooser.swatchesRecentSwatchSize", null); + UIManager.put("ColorChooser.swatchesSwatchSize", null); + UIManager.put("RibbonApplicationMenuPopupPanelUI", null); + UIManager.put("RibbonApplicationMenuButtonUI", null); + UIManager.put("ProgressBarUI", null); + UIManager.put("TextField.background", null); + UIManager.put("FormattedTextField.background", null); + UIManager.put("CommandButtonUI", null); + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { + logger.log(Level.SEVERE, null, ex); + } + } + + View.execInEventDispatch(() -> { + ErrorLogFrame.createNewInstance(); + + autoCheckForUpdates(); + offerAssociation(); + loadingDialog = new LoadingDialog(); + + DebuggerTools.initDebugger().addMessageListener(new DebugListener() { + @Override + public void onMessage(String clientId, String msg) { + } + + @Override + public void onLoaderURL(String clientId, String url) { + } + + @Override + public void onLoaderBytes(String clientId, byte[] data) { + String hash = md5(data); + for (SWFList sl : Main.getMainFrame().getPanel().getSwfs()) { + for (int s = 0; s < sl.size(); s++) { + String t = sl.get(s).getFileTitle(); + if (t == null) { + t = ""; + } + if (t.endsWith(":" + hash)) { //this one is already opened + return; + } + } + } + SWF swf = Main.getMainFrame().getPanel().getCurrentSwf(); + + String title = swf == null ? "?" : swf.getFileTitle(); + title = title + ":" + hash; + String tfile; + try { + tfile = tempFile(title); + Helper.writeFile(tfile, data); + openFile(new SWFSourceInfo(null, tfile, title)); + } catch (IOException ex) { + logger.log(Level.SEVERE, "Cannot create tempfile"); + } + } + + @Override + public void onFinish(String clientId) { + } + }); + + try { + flashDebugger = new Debugger(); + debugHandler = new DebuggerHandler(); + debugHandler.addBreakListener(new DebuggerHandler.BreakListener() { + @Override + public void doContinue() { + mainFrame.getPanel().clearDebuggerColors(); + } + + @Override + public void breakAt(String scriptName, int line, final int classIndex, final int traitIndex, final int methodIndex) { + View.execInEventDispatch(new Runnable() { + @Override + public void run() { + mainFrame.getPanel().gotoScriptLine(getMainFrame().getPanel().getCurrentSwf(), scriptName, line, classIndex, traitIndex, methodIndex); + } + }); + } + }); + debugHandler.addConnectionListener(new DebuggerHandler.ConnectionListener() { + @Override + public void connected() { + Main.mainFrame.getMenu().updateComponents(); + } + + @Override + public void disconnected() { + if (Main.mainFrame != null && Main.mainFrame.getPanel() != null) { + Main.mainFrame.getPanel().refreshBreakPoints(); + } + } + }); + flashDebugger.addConnectionListener(debugHandler); + } catch (IOException ex) { + logger.log(Level.SEVERE, "eeex", ex); + } + }); + } + + public static void startDebugger() { + flashDebugger.startDebugger(); + } + + public static void stopDebugger() { + flashDebugger.stopDebugger(); + } + + public static void showModeFrame() { + ensureMainFrame(); + mainFrame.setVisible(true); + } + + private static void offerAssociation() { + boolean offered = Configuration.offeredAssociation.get(); + if (!offered) { + if (Platform.isWindows()) { + if ((!ContextMenuTools.isAddedToContextMenu()) && View.showConfirmDialog(null, "Do you want to add FFDec to context menu of SWF files?\n(Can be changed later from main menu)", "Context menu", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) { + ContextMenuTools.addToContextMenu(true, false); + } + } + + Configuration.offeredAssociation.set(true); + } + } + + public static void initUiLang() { + if (GraphicsEnvironment.isHeadless()) { //No GUI in OS + return; + } + try { + Class cl = Class.forName("org.pushingpixels.substance.api.SubstanceLookAndFeel"); + Field field = cl.getDeclaredField("LABEL_BUNDLE"); + field.setAccessible(true); + field.set(null, null); + } catch (Throwable ex) { + logger.log(Level.SEVERE, null, ex); + } + + UIManager.put("OptionPane.okButtonText", AppStrings.translate("button.ok")); + UIManager.put("OptionPane.yesButtonText", AppStrings.translate("button.yes")); + UIManager.put("OptionPane.noButtonText", AppStrings.translate("button.no")); + UIManager.put("OptionPane.cancelButtonText", AppStrings.translate("button.cancel")); + UIManager.put("OptionPane.messageDialogTitle", AppStrings.translate("dialog.message.title")); + UIManager.put("OptionPane.titleText", AppStrings.translate("dialog.select.title")); + + UIManager.put("FileChooser.acceptAllFileFilterText", AppStrings.translate("FileChooser.acceptAllFileFilterText")); + UIManager.put("FileChooser.lookInLabelText", AppStrings.translate("FileChooser.lookInLabelText")); + UIManager.put("FileChooser.cancelButtonText", AppStrings.translate("button.cancel")); + UIManager.put("FileChooser.cancelButtonToolTipText", AppStrings.translate("button.cancel")); + UIManager.put("FileChooser.openButtonText", AppStrings.translate("FileChooser.openButtonText")); + UIManager.put("FileChooser.openButtonToolTipText", AppStrings.translate("FileChooser.openButtonToolTipText")); + UIManager.put("FileChooser.filesOfTypeLabelText", AppStrings.translate("FileChooser.filesOfTypeLabelText")); + UIManager.put("FileChooser.fileNameLabelText", AppStrings.translate("FileChooser.fileNameLabelText")); + UIManager.put("FileChooser.listViewButtonToolTipText", AppStrings.translate("FileChooser.listViewButtonToolTipText")); + UIManager.put("FileChooser.listViewButtonAccessibleName", AppStrings.translate("FileChooser.listViewButtonAccessibleName")); + UIManager.put("FileChooser.detailsViewButtonToolTipText", AppStrings.translate("FileChooser.detailsViewButtonToolTipText")); + UIManager.put("FileChooser.detailsViewButtonAccessibleName", AppStrings.translate("FileChooser.detailsViewButtonAccessibleName")); + UIManager.put("FileChooser.upFolderToolTipText", AppStrings.translate("FileChooser.upFolderToolTipText")); + UIManager.put("FileChooser.upFolderAccessibleName", AppStrings.translate("FileChooser.upFolderAccessibleName")); + UIManager.put("FileChooser.homeFolderToolTipText", AppStrings.translate("FileChooser.homeFolderToolTipText")); + UIManager.put("FileChooser.homeFolderAccessibleName", AppStrings.translate("FileChooser.homeFolderAccessibleName")); + UIManager.put("FileChooser.fileNameHeaderText", AppStrings.translate("FileChooser.fileNameHeaderText")); + UIManager.put("FileChooser.fileSizeHeaderText", AppStrings.translate("FileChooser.fileSizeHeaderText")); + UIManager.put("FileChooser.fileTypeHeaderText", AppStrings.translate("FileChooser.fileTypeHeaderText")); + UIManager.put("FileChooser.fileDateHeaderText", AppStrings.translate("FileChooser.fileDateHeaderText")); + UIManager.put("FileChooser.fileAttrHeaderText", AppStrings.translate("FileChooser.fileAttrHeaderText")); + UIManager.put("FileChooser.openDialogTitleText", AppStrings.translate("FileChooser.openDialogTitleText")); + UIManager.put("FileChooser.directoryDescriptionText", AppStrings.translate("FileChooser.directoryDescriptionText")); + UIManager.put("FileChooser.directoryOpenButtonText", AppStrings.translate("FileChooser.directoryOpenButtonText")); + UIManager.put("FileChooser.directoryOpenButtonToolTipText", AppStrings.translate("FileChooser.directoryOpenButtonToolTipText")); + UIManager.put("FileChooser.fileDescriptionText", AppStrings.translate("FileChooser.fileDescriptionText")); + UIManager.put("FileChooser.fileNameLabelText", AppStrings.translate("FileChooser.fileNameLabelText")); + UIManager.put("FileChooser.helpButtonText", AppStrings.translate("FileChooser.helpButtonText")); + UIManager.put("FileChooser.helpButtonToolTipText", AppStrings.translate("FileChooser.helpButtonToolTipText")); + UIManager.put("FileChooser.newFolderAccessibleName", AppStrings.translate("FileChooser.newFolderAccessibleName")); + UIManager.put("FileChooser.newFolderErrorText", AppStrings.translate("FileChooser.newFolderErrorText")); + UIManager.put("FileChooser.newFolderToolTipText", AppStrings.translate("FileChooser.newFolderToolTipText")); + UIManager.put("FileChooser.other.newFolder", AppStrings.translate("FileChooser.other.newFolder")); + UIManager.put("FileChooser.other.newFolder.subsequent", AppStrings.translate("FileChooser.other.newFolder.subsequent")); + UIManager.put("FileChooser.win32.newFolder", AppStrings.translate("FileChooser.win32.newFolder")); + UIManager.put("FileChooser.win32.newFolder.subsequent", AppStrings.translate("FileChooser.win32.newFolder.subsequent")); + UIManager.put("FileChooser.saveButtonText", AppStrings.translate("FileChooser.saveButtonText")); + UIManager.put("FileChooser.saveButtonToolTipText", AppStrings.translate("FileChooser.saveButtonToolTipText")); + UIManager.put("FileChooser.saveDialogTitleText", AppStrings.translate("FileChooser.saveDialogTitleText")); + UIManager.put("FileChooser.saveInLabelText", AppStrings.translate("FileChooser.saveInLabelText")); + UIManager.put("FileChooser.updateButtonText", AppStrings.translate("FileChooser.updateButtonText")); + UIManager.put("FileChooser.updateButtonToolTipText", AppStrings.translate("FileChooser.updateButtonToolTipText")); + + UIManager.put("FileChooser.detailsViewActionLabel.textAndMnemonic", AppStrings.translate("FileChooser.detailsViewActionLabel.textAndMnemonic")); + UIManager.put("FileChooser.detailsViewButtonToolTip.textAndMnemonic", AppStrings.translate("FileChooser.detailsViewButtonToolTip.textAndMnemonic")); + UIManager.put("FileChooser.fileAttrHeader.textAndMnemonic", AppStrings.translate("FileChooser.fileAttrHeader.textAndMnemonic")); + UIManager.put("FileChooser.fileDateHeader.textAndMnemonic", AppStrings.translate("FileChooser.fileDateHeader.textAndMnemonic")); + UIManager.put("FileChooser.fileNameHeader.textAndMnemonic", AppStrings.translate("FileChooser.fileNameHeader.textAndMnemonic")); + UIManager.put("FileChooser.fileNameLabel.textAndMnemonic", AppStrings.translate("FileChooser.fileNameLabel.textAndMnemonic")); + UIManager.put("FileChooser.fileSizeHeader.textAndMnemonic", AppStrings.translate("FileChooser.fileSizeHeader.textAndMnemonic")); + UIManager.put("FileChooser.fileTypeHeader.textAndMnemonic", AppStrings.translate("FileChooser.fileTypeHeader.textAndMnemonic")); + UIManager.put("FileChooser.filesOfTypeLabel.textAndMnemonic", AppStrings.translate("FileChooser.filesOfTypeLabel.textAndMnemonic")); + UIManager.put("FileChooser.folderNameLabel.textAndMnemonic", AppStrings.translate("FileChooser.folderNameLabel.textAndMnemonic")); + UIManager.put("FileChooser.homeFolderToolTip.textAndMnemonic", AppStrings.translate("FileChooser.homeFolderToolTip.textAndMnemonic")); + UIManager.put("FileChooser.listViewActionLabel.textAndMnemonic", AppStrings.translate("FileChooser.listViewActionLabel.textAndMnemonic")); + UIManager.put("FileChooser.listViewButtonToolTip.textAndMnemonic", AppStrings.translate("FileChooser.listViewButtonToolTip.textAndMnemonic")); + UIManager.put("FileChooser.lookInLabel.textAndMnemonic", AppStrings.translate("FileChooser.lookInLabel.textAndMnemonic")); + UIManager.put("FileChooser.newFolderActionLabel.textAndMnemonic", AppStrings.translate("FileChooser.newFolderActionLabel.textAndMnemonic")); + UIManager.put("FileChooser.newFolderToolTip.textAndMnemonic", AppStrings.translate("FileChooser.newFolderToolTip.textAndMnemonic")); + UIManager.put("FileChooser.refreshActionLabel.textAndMnemonic", AppStrings.translate("FileChooser.refreshActionLabel.textAndMnemonic")); + UIManager.put("FileChooser.saveInLabel.textAndMnemonic", AppStrings.translate("FileChooser.saveInLabel.textAndMnemonic")); + UIManager.put("FileChooser.upFolderToolTip.textAndMnemonic", AppStrings.translate("FileChooser.upFolderToolTip.textAndMnemonic")); + UIManager.put("FileChooser.viewMenuButtonAccessibleName", AppStrings.translate("FileChooser.viewMenuButtonAccessibleName")); + UIManager.put("FileChooser.viewMenuButtonToolTipText", AppStrings.translate("FileChooser.viewMenuButtonToolTipText")); + UIManager.put("FileChooser.viewMenuLabel.textAndMnemonic", AppStrings.translate("FileChooser.viewMenuLabel.textAndMnemonic")); + UIManager.put("FileChooser.newFolderActionLabelText", AppStrings.translate("FileChooser.newFolderActionLabelText")); + UIManager.put("FileChooser.listViewActionLabelText", AppStrings.translate("FileChooser.listViewActionLabelText")); + UIManager.put("FileChooser.detailsViewActionLabelText", AppStrings.translate("FileChooser.detailsViewActionLabelText")); + UIManager.put("FileChooser.refreshActionLabelText", AppStrings.translate("FileChooser.refreshActionLabelText")); + UIManager.put("FileChooser.sortMenuLabelText", AppStrings.translate("FileChooser.sortMenuLabelText")); + UIManager.put("FileChooser.viewMenuLabelText", AppStrings.translate("FileChooser.viewMenuLabelText")); + UIManager.put("FileChooser.fileSizeKiloBytes", AppStrings.translate("FileChooser.fileSizeKiloBytes")); + UIManager.put("FileChooser.fileSizeMegaBytes", AppStrings.translate("FileChooser.fileSizeMegaBytes")); + UIManager.put("FileChooser.fileSizeGigaBytes", AppStrings.translate("FileChooser.fileSizeGigaBytes")); + UIManager.put("FileChooser.folderNameLabelText", AppStrings.translate("FileChooser.folderNameLabelText")); + + UIManager.put("ColorChooser.okText", AppStrings.translate("ColorChooser.okText")); + UIManager.put("ColorChooser.cancelText", AppStrings.translate("ColorChooser.cancelText")); + UIManager.put("ColorChooser.resetText", AppStrings.translate("ColorChooser.resetText")); + UIManager.put("ColorChooser.previewText", AppStrings.translate("ColorChooser.previewText")); + UIManager.put("ColorChooser.swatchesNameText", AppStrings.translate("ColorChooser.swatchesNameText")); + UIManager.put("ColorChooser.swatchesRecentText", AppStrings.translate("ColorChooser.swatchesRecentText")); + UIManager.put("ColorChooser.sampleText", AppStrings.translate("ColorChooser.sampleText")); + + } + + public static void initLang() { + if (!Configuration.locale.hasValue()) { + if (Platform.isWindows()) { + //Load from Installer + String uninstKey = "{E618D276-6596-41F4-8A98-447D442A77DB}_is1"; + uninstKey = "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\" + uninstKey; + try { + if (Advapi32Util.registryKeyExists(WinReg.HKEY_LOCAL_MACHINE, uninstKey)) { + if (Advapi32Util.registryValueExists(WinReg.HKEY_LOCAL_MACHINE, uninstKey, "NSIS: Language")) { + String installedLoc = Advapi32Util.registryGetStringValue(WinReg.HKEY_LOCAL_MACHINE, uninstKey, "NSIS: Language"); + int lcid = Integer.parseInt(installedLoc); + char[] buf = new char[9]; + int cnt = Kernel32.INSTANCE.GetLocaleInfo(lcid, Kernel32.LOCALE_SISO639LANGNAME, buf, 9); + String langCode = new String(buf, 0, cnt).trim().toLowerCase(); + + cnt = Kernel32.INSTANCE.GetLocaleInfo(lcid, Kernel32.LOCALE_SISO3166CTRYNAME, buf, 9); + String countryCode = new String(buf, 0, cnt).trim().toLowerCase(); + + List langs = Arrays.asList(SelectLanguageDialog.getAvailableLanguages()); + for (int i = 0; i < langs.size(); i++) { + langs.set(i, langs.get(i).toLowerCase()); + } + + String selectedLang = null; + + if (langs.contains(langCode + "-" + countryCode)) { + selectedLang = SelectLanguageDialog.getAvailableLanguages()[langs.indexOf(langCode + "-" + countryCode)]; + } else if (langs.contains(langCode)) { + selectedLang = SelectLanguageDialog.getAvailableLanguages()[langs.indexOf(langCode)]; + } + if (selectedLang != null) { + Configuration.locale.set(selectedLang); + } + } + } + } catch (Exception ex) { + //ignore + } + } + } + Locale.setDefault(Locale.forLanguageTag(Configuration.locale.get())); + AppStrings.updateLanguage(); + + Helper.decompilationErrorAdd = AppStrings.translate(Configuration.autoDeobfuscate.get() ? "deobfuscation.comment.failed" : "deobfuscation.comment.tryenable"); + } + + /** + * Clear old FFDec/JavactiveX temp files + */ + private static void clearTemp() { + String tempDirPath = System.getProperty("java.io.tmpdir"); + if (tempDirPath == null) { + return; + } + File tempDir = new File(tempDirPath); + if (!tempDir.exists()) { + return; + } + File[] delFiles = tempDir.listFiles(new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + return name.matches("ffdec_cache.*\\.tmp") || name.matches("javactivex_.*\\.exe") || name.matches("temp[0-9]+\\.swf") || name.matches("ffdec_view_.*\\.swf"); + } + }); + + if (delFiles != null) { + for (File f : delFiles) { + try { + f.delete(); + } catch (Exception ex) { + //ignore + } + } + } + } + + /** + * @param args the command line arguments + * @throws IOException On error + */ + public static void main(String[] args) throws IOException { + setSessionLoaded(false); + clearTemp(); + + try { + SWFDecompilerPlugin.loadPlugins(); + } catch (Throwable ex) { + logger.log(Level.SEVERE, "Failed to load plugins", ex); + } + + AppStrings.setResourceClass(MainFrame.class); + initLogging(Configuration._debugMode.get()); + + initLang(); + + if (Configuration.cacheOnDisk.get()) { + Cache.setStorageType(Cache.STORAGE_FILES); + } else { + Cache.setStorageType(Cache.STORAGE_MEMORY); + } + + if (args.length == 0) { + initGui(); + checkLibraryVersion(); + View.execInEventDispatch(() -> { + if (Configuration.allowOnlyOneInstance.get() && FirstInstance.focus()) { //Try to focus first instance + Main.exit(); + } else { + showModeFrame(); + reloadLastSession(); + } + }); + } else { + checkLibraryVersion(); + setSessionLoaded(true); + String[] filesToOpen = CommandLineArgumentParser.parseArguments(args); + if (filesToOpen != null && filesToOpen.length > 0) { + View.execInEventDispatch(() -> { + initGui(); + shouldCloseWhenClosingLoadingDialog = true; + if (Configuration.allowOnlyOneInstance.get() && FirstInstance.openFiles(Arrays.asList(filesToOpen))) { //Try to open in first instance + Main.exit(); + } else { + for (String fileToOpen : filesToOpen) { + openFile(fileToOpen, null); + } + } + }); + } + } + } + + private static void checkLibraryVersion() { + if (!ApplicationInfo.version.equals("unknown") && !ApplicationInfo.libraryVersion.equals("unknown") + && !Objects.equals(ApplicationInfo.version, ApplicationInfo.libraryVersion)) { + logger.log(Level.WARNING, "Application version is different from library version. FFDec may not work properly."); + } + } + + private static void reloadLastSession() { + boolean openingFiles = false; + if (Configuration.saveSessionOnExit.get()) { + String lastSession = Configuration.lastSessionFiles.get(); + if (lastSession != null && lastSession.length() > 0) { + String[] filesToOpen = lastSession.split(File.pathSeparator, -1); + List exfiles = new ArrayList<>(); + List extitles = new ArrayList<>(); + String lastSessionTitles = Configuration.lastSessionFileTitles.get(); + String[] fileTitles = new String[0]; + if (lastSessionTitles != null && !lastSessionTitles.isEmpty()) { + fileTitles = lastSessionTitles.split(File.pathSeparator, -1); + } + for (int i = 0; i < filesToOpen.length; i++) { + if (new File(filesToOpen[i]).exists()) { + exfiles.add(filesToOpen[i]); + if (fileTitles.length > i) { + extitles.add(fileTitles[i]); + } else { + extitles.add(null); + } + } + } + SWFSourceInfo[] sourceInfos = new SWFSourceInfo[exfiles.size()]; + for (int i = 0; i < exfiles.size(); i++) { + String extitle = extitles.get(i); + sourceInfos[i] = new SWFSourceInfo(null, exfiles.get(i), extitle == null || extitle.isEmpty() ? null : extitle); + } + if (sourceInfos.length > 0) { + openingFiles = true; + openFile(sourceInfos, () -> { + mainFrame.getPanel().tagTree.setSelectionPathString(Configuration.lastSessionSelection.get()); + setSessionLoaded(true); + }); + } + } + } + + if (!openingFiles) { + setSessionLoaded(true); + } + } + + public static String tempFile(String url) throws IOException { + File f = new File(Configuration.getFFDecHome() + "saved" + File.separator); + Path.createDirectorySafe(f); + return Configuration.getFFDecHome() + "saved" + File.separator + "asdec_" + Integer.toHexString(url.hashCode()) + ".tmp"; + } + + public static void removeTrayIcon() { + if (SystemTray.isSupported()) { + SystemTray tray = SystemTray.getSystemTray(); + if (trayIcon != null) { + tray.remove(trayIcon); + trayIcon = null; + } + } + } + + public static void switchProxy() { + proxyFrame.switchState(); + if (stopMenuItem != null) { + if (proxyFrame.isRunning()) { + stopMenuItem.setLabel(AppStrings.translate("proxy.stop")); + } else { + stopMenuItem.setLabel(AppStrings.translate("proxy.start")); + } + } + } + + public static void addTrayIcon() { + if (trayIcon != null) { + return; + } + if (SystemTray.isSupported()) { + SystemTray tray = SystemTray.getSystemTray(); + trayIcon = new TrayIcon(View.loadImage("proxy16"), ApplicationInfo.VENDOR + " " + ApplicationInfo.SHORT_APPLICATION_NAME + " " + AppStrings.translate("proxy")); + trayIcon.setImageAutoSize(true); + PopupMenu trayPopup = new PopupMenu(); + + ActionListener trayListener = new ActionListener() { + /** + * Invoked when an action occurs. + */ + @Override + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().equals("EXIT")) { + Main.exit(); + } + if (e.getActionCommand().equals("SHOW")) { + Main.showProxy(); + } + if (e.getActionCommand().equals("SWITCH")) { + Main.switchProxy(); + } + } + }; + + MenuItem showMenuItem = new MenuItem(AppStrings.translate("proxy.show")); + showMenuItem.setActionCommand("SHOW"); + showMenuItem.addActionListener(trayListener); + trayPopup.add(showMenuItem); + stopMenuItem = new MenuItem(AppStrings.translate("proxy.start")); + stopMenuItem.setActionCommand("SWITCH"); + stopMenuItem.addActionListener(trayListener); + trayPopup.add(stopMenuItem); + trayPopup.addSeparator(); + MenuItem exitMenuItem = new MenuItem(AppStrings.translate("exit")); + exitMenuItem.setActionCommand("EXIT"); + exitMenuItem.addActionListener(trayListener); + trayPopup.add(exitMenuItem); + + trayIcon.setPopupMenu(trayPopup); + trayIcon.addMouseListener(new MouseAdapter() { + /** + * {@inheritDoc} + */ + @Override + public void mouseClicked(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON1) { + Main.showProxy(); + } + } + }); + try { + tray.add(trayIcon); + } catch (AWTException ex) { + } + } + } + + public static void exit() { + Configuration.saveConfig(); + if (mainFrame != null && mainFrame.getPanel() != null) { + mainFrame.getPanel().unloadFlashPlayer(); + mainFrame.dispose(); + } + if (fileTxt != null) { + try { + fileTxt.flush(); + fileTxt.close(); + } catch (Exception ex) { + //ignore + } + } + System.exit(0); + } + + public static void about() { + (new AboutDialog()).setVisible(true); + } + + public static void advancedSettings() { + advancedSettings(null); + } + + public static void advancedSettings(String category) { + (new AdvancedSettingsDialog(category)).setVisible(true); + } + + public static void autoCheckForUpdates() { + if (Configuration.checkForUpdatesAuto.get()) { + Calendar lastUpdatesCheckDate = Configuration.lastUpdatesCheckDate.get(); + if ((lastUpdatesCheckDate == null) || (lastUpdatesCheckDate.getTime().getTime() < Calendar.getInstance().getTime().getTime() - Configuration.checkForUpdatesDelay.get())) { + new SwingWorker() { + @Override + protected Object doInBackground() throws Exception { + checkForUpdates(); + return null; + } + }.execute(); + } + } + } + + public static boolean checkForUpdates() { + String currentVersion = ApplicationInfo.version; + if (currentVersion.equals("unknown")) { + // sometimes during development the version information is not available + return false; + } + + List accepted = new ArrayList<>(); + if (Configuration.checkForUpdatesStable.get()) { + accepted.add("stable"); + } + if (Configuration.checkForUpdatesNightly.get()) { + accepted.add("nightly"); + } + + if (accepted.isEmpty()) { + return false; + } + + String acceptVersions = String.join(",", accepted); + try { + String proxyAddress = Configuration.updateProxyAddress.get(); + URL url = new URL(ApplicationInfo.updateCheckUrl); + + URLConnection uc; + if (proxyAddress != null && !proxyAddress.isEmpty()) { + int port = 8080; + if (proxyAddress.contains(":")) { + String[] parts = proxyAddress.split(":"); + port = Integer.parseInt(parts[1]); + proxyAddress = parts[0]; + } + + uc = url.openConnection(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyAddress, port))); + } else { + uc = url.openConnection(); + } + uc.setRequestProperty("X-Accept-Versions", acceptVersions); + uc.setRequestProperty("X-Update-Major", "" + UPDATE_SYSTEM_MAJOR); + uc.setRequestProperty("X-Update-Minor", "" + UPDATE_SYSTEM_MINOR); + uc.setRequestProperty("User-Agent", ApplicationInfo.shortApplicationVerName); + String currentLoc = Configuration.locale.get("en"); + uc.setRequestProperty("Accept-Language", currentLoc + ("en".equals(currentLoc) ? "" : ", en;q=0.8")); + + uc.connect(); + + BufferedReader br = new BufferedReader(new InputStreamReader(uc.getInputStream())); + String s; + final java.util.List versions = new ArrayList<>(); + String header = ""; + Pattern headerPat = Pattern.compile("\\[([a-zA-Z0-9]+)\\]"); + int updateMajor; + int updateMinor; + Version ver = null; + while ((s = br.readLine()) != null) { + + Matcher m = headerPat.matcher(s); + if (m.matches()) { + header = m.group(1); + if (header.equals("version")) { + ver = new Version(); + versions.add(ver); + } + if (header.equals("noversion")) { + break; + } + } else if (s.contains("=")) { + String key = s.substring(0, s.indexOf('=')); + String val = s.substring(s.indexOf('=') + 1); + if ("updateSystem".equals(header)) { + if (key.equals("majorVersion")) { + updateMajor = Integer.parseInt(val); + if (updateMajor > UPDATE_SYSTEM_MAJOR) { + break; + } + } + if (key.equals("minorVersion")) { + updateMinor = Integer.parseInt(val); + } + } + if ("version".equals(header) && (ver != null)) { + if (key.equals("versionId")) { + ver.versionId = Integer.parseInt(val); + } + if (key.equals("versionName")) { + ver.versionName = val; + } + if (key.equals("nightly")) { + ver.nightly = val.equals("true"); + } + if (key.equals("revision")) { + ver.revision = val; + } + if (key.equals("build")) { + ver.build = Integer.parseInt(val); + } + if (key.equals("major")) { + ver.major = Integer.parseInt(val); + } + if (key.equals("minor")) { + ver.minor = Integer.parseInt(val); + } + if (key.equals("release")) { + ver.release = Integer.parseInt(val); + } + if (key.equals("longVersionName")) { + ver.longVersionName = val; + } + if (key.equals("releaseDate")) { + ver.releaseDate = val; + } + if (key.equals("appName")) { + ver.appName = val; + } + if (key.equals("appFullName")) { + ver.appFullName = val; + } + if (key.equals("updateLink")) { + ver.updateLink = val; + } + if (key.equals("change[]")) { + String changeType = val.substring(0, val.indexOf('|')); + String change = val.substring(val.indexOf('|') + 1); + if (!ver.changes.containsKey(changeType)) { + ver.changes.put(changeType, new ArrayList<>()); + } + List chlist = ver.changes.get(changeType); + chlist.add(change); + } + } + } + } + + if (!versions.isEmpty()) { + View.execInEventDispatch(() -> { + NewVersionDialog newVersionDialog = new NewVersionDialog(versions); + newVersionDialog.setVisible(true); + Configuration.lastUpdatesCheckDate.set(Calendar.getInstance()); + }); + + return true; + } + } catch (IOException | NumberFormatException ex) { + return false; + } + Configuration.lastUpdatesCheckDate.set(Calendar.getInstance()); + return false; + } + + private static FileHandler fileTxt; + + public static void clearLogFile() { + Logger logger = Logger.getLogger(""); + + FileHandler oldFileTxt = fileTxt; + fileTxt = null; + if (oldFileTxt != null) { + logger.removeHandler(fileTxt); + oldFileTxt.flush(); + oldFileTxt.close(); + } + + String fileName = null; + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-hh-mm-ss"); + + try { + fileName = Configuration.getFFDecHome() + "logs" + File.separator; + if (Configuration.useDetailedLogging.get()) { + fileName += "log-" + sdf.format(new Date()) + ".txt"; + } else { + fileName += "log.txt"; + } + File f = new File(fileName).getParentFile(); + if (!f.exists()) { + f.mkdir(); + } + fileTxt = new FileHandler(fileName); + } catch (IOException | SecurityException ex) { + //cannot get lock error + if (ex.getMessage().contains("lock for")) { + //remove all old log files and their .lck + for (int i = 0; i <= 100; i++) { + File flog = new File(fileName + (i == 0 ? "" : "." + i)); + File flog_lock = new File(fileName + (i == 0 ? "" : "." + i) + ".lck"); + flog.delete(); + flog_lock.delete(); + } + try { + fileTxt = new FileHandler(fileName); + } catch (IOException | SecurityException ex1) { + logger.log(Level.SEVERE, "Cannot initialize logging", ex); + } + } else { + logger.log(Level.SEVERE, "Cannot initialize logging", ex); + } + } + + Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { + @Override + public void uncaughtException(Thread t, Throwable e) { + logger.log(Level.SEVERE, "Uncaught exception in thread: " + t.getName(), e); + if (e instanceof OutOfMemoryError || !Helper.is64BitJre() && Helper.is64BitOs()) { + View.showMessageDialog(null, AppStrings.translate("message.warning.outOfMemory32BitJre"), AppStrings.translate("message.warning"), JOptionPane.WARNING_MESSAGE); + } + } + }); + + Formatter formatterTxt = new LogFormatter(); + if (fileTxt != null) { + fileTxt.setFormatter(formatterTxt); + logger.addHandler(fileTxt); + } + + if (!GraphicsEnvironment.isHeadless() && ErrorLogFrame.hasInstance()) { + ErrorLogFrame.getInstance().clearErrorState(); + } + + sdf = new SimpleDateFormat("yyyy-MM-dd"); + logger.log(Level.INFO, "Date: {0}", sdf.format(new Date())); + logger.log(Level.INFO, ApplicationInfo.applicationVerName); + logger.log(Level.INFO, "{0} {1} {2}", new Object[]{ + System.getProperty("os.name"), System.getProperty("os.version"), System.getProperty("os.arch")}); + logger.log(Level.INFO, "{0} {1} {2}", new Object[]{ + System.getProperty("java.version"), System.getProperty("java.vendor"), System.getProperty("os.arch")}); + } + + public static void initLogging(boolean debug) { + try { + Logger logger = Logger.getLogger(""); + logger.setLevel(Configuration.logLevel); + + Handler[] handlers = logger.getHandlers(); + for (int i = handlers.length - 1; i >= 0; i--) { + logger.removeHandler(handlers[i]); + } + + ConsoleHandler conHan = new ConsoleHandler(); + conHan.setLevel(debug ? Level.CONFIG : Level.WARNING); + SimpleFormatter formatterTxt = new SimpleFormatter(); + conHan.setFormatter(formatterTxt); + logger.addHandler(conHan); + clearLogFile(); + + } catch (Exception ex) { + throw new RuntimeException("Problems with creating the log files"); + } + } +} diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index 717970b20..c45bc048b 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -1,3681 +1,3681 @@ -/* - * 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.AbortRetryIgnoreHandler; -import com.jpexs.decompiler.flash.ApplicationInfo; -import com.jpexs.decompiler.flash.EventListener; -import com.jpexs.decompiler.flash.ReadOnlyTagList; -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFBundle; -import com.jpexs.decompiler.flash.SWFSourceInfo; -import com.jpexs.decompiler.flash.abc.ABC; -import com.jpexs.decompiler.flash.abc.RenameType; -import com.jpexs.decompiler.flash.abc.ScriptPack; -import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool; -import com.jpexs.decompiler.flash.abc.avm2.deobfuscation.AbcMultiNameCollisionFixer; -import com.jpexs.decompiler.flash.abc.avm2.deobfuscation.DeobfuscationLevel; -import com.jpexs.decompiler.flash.abc.types.traits.Trait; -import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.decompiler.flash.configuration.ConfigurationItem; -import com.jpexs.decompiler.flash.configuration.SwfSpecificConfiguration; -import com.jpexs.decompiler.flash.dumpview.DumpInfo; -import com.jpexs.decompiler.flash.dumpview.DumpInfoSwfNode; -import com.jpexs.decompiler.flash.exporters.BinaryDataExporter; -import com.jpexs.decompiler.flash.exporters.FontExporter; -import com.jpexs.decompiler.flash.exporters.FrameExporter; -import com.jpexs.decompiler.flash.exporters.ImageExporter; -import com.jpexs.decompiler.flash.exporters.MorphShapeExporter; -import com.jpexs.decompiler.flash.exporters.MovieExporter; -import com.jpexs.decompiler.flash.exporters.ShapeExporter; -import com.jpexs.decompiler.flash.exporters.SoundExporter; -import com.jpexs.decompiler.flash.exporters.SymbolClassExporter; -import com.jpexs.decompiler.flash.exporters.TextExporter; -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.exporters.script.AS2ScriptExporter; -import com.jpexs.decompiler.flash.exporters.script.AS3ScriptExporter; -import com.jpexs.decompiler.flash.exporters.settings.BinaryDataExportSettings; -import com.jpexs.decompiler.flash.exporters.settings.ButtonExportSettings; -import com.jpexs.decompiler.flash.exporters.settings.FontExportSettings; -import com.jpexs.decompiler.flash.exporters.settings.FrameExportSettings; -import com.jpexs.decompiler.flash.exporters.settings.ImageExportSettings; -import com.jpexs.decompiler.flash.exporters.settings.MorphShapeExportSettings; -import com.jpexs.decompiler.flash.exporters.settings.MovieExportSettings; -import com.jpexs.decompiler.flash.exporters.settings.ScriptExportSettings; -import com.jpexs.decompiler.flash.exporters.settings.ShapeExportSettings; -import com.jpexs.decompiler.flash.exporters.settings.SoundExportSettings; -import com.jpexs.decompiler.flash.exporters.settings.SpriteExportSettings; -import com.jpexs.decompiler.flash.exporters.settings.TextExportSettings; -import com.jpexs.decompiler.flash.exporters.swf.SwfJavaExporter; -import com.jpexs.decompiler.flash.exporters.swf.SwfXmlExporter; -import com.jpexs.decompiler.flash.flexsdk.MxmlcAs3ScriptReplacer; -import com.jpexs.decompiler.flash.gui.abc.ABCPanel; -import com.jpexs.decompiler.flash.gui.abc.ABCPanelSearchResult; -import com.jpexs.decompiler.flash.gui.abc.ClassesListTreeModel; -import com.jpexs.decompiler.flash.gui.abc.DecompiledEditorPane; -import com.jpexs.decompiler.flash.gui.abc.DeobfuscationDialog; -import com.jpexs.decompiler.flash.gui.action.ActionPanel; -import com.jpexs.decompiler.flash.gui.action.ActionSearchResult; -import com.jpexs.decompiler.flash.gui.controls.JPersistentSplitPane; -import com.jpexs.decompiler.flash.gui.dumpview.DumpTree; -import com.jpexs.decompiler.flash.gui.dumpview.DumpTreeModel; -import com.jpexs.decompiler.flash.gui.dumpview.DumpViewPanel; -import com.jpexs.decompiler.flash.gui.editor.LineMarkedEditorPane; -import com.jpexs.decompiler.flash.gui.helpers.ObservableList; -import com.jpexs.decompiler.flash.gui.player.FlashPlayerPanel; -import com.jpexs.decompiler.flash.gui.tagtree.TagTree; -import com.jpexs.decompiler.flash.gui.tagtree.TagTreeModel; -import com.jpexs.decompiler.flash.gui.timeline.TimelineViewPanel; -import com.jpexs.decompiler.flash.helpers.FileTextWriter; -import com.jpexs.decompiler.flash.helpers.Freed; -import com.jpexs.decompiler.flash.importers.AS2ScriptImporter; -import com.jpexs.decompiler.flash.importers.AS3ScriptImporter; -import com.jpexs.decompiler.flash.importers.As3ScriptReplacerFactory; -import com.jpexs.decompiler.flash.importers.As3ScriptReplacerInterface; -import com.jpexs.decompiler.flash.importers.BinaryDataImporter; -import com.jpexs.decompiler.flash.importers.FFDecAs3ScriptReplacer; -import com.jpexs.decompiler.flash.importers.ImageImporter; -import com.jpexs.decompiler.flash.importers.ShapeImporter; -import com.jpexs.decompiler.flash.importers.SwfXmlImporter; -import com.jpexs.decompiler.flash.importers.SymbolClassImporter; -import com.jpexs.decompiler.flash.importers.TextImporter; -import com.jpexs.decompiler.flash.importers.svg.SvgImporter; -import com.jpexs.decompiler.flash.tags.ABCContainerTag; -import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag; -import com.jpexs.decompiler.flash.tags.DefineBitsJPEG3Tag; -import com.jpexs.decompiler.flash.tags.DefineBitsJPEG4Tag; -import com.jpexs.decompiler.flash.tags.DefineSoundTag; -import com.jpexs.decompiler.flash.tags.DefineSpriteTag; -import com.jpexs.decompiler.flash.tags.DoActionTag; -import com.jpexs.decompiler.flash.tags.DoInitActionTag; -import com.jpexs.decompiler.flash.tags.FileAttributesTag; -import com.jpexs.decompiler.flash.tags.MetadataTag; -import com.jpexs.decompiler.flash.tags.Tag; -import com.jpexs.decompiler.flash.tags.TagInfo; -import com.jpexs.decompiler.flash.tags.base.ASMSource; -import com.jpexs.decompiler.flash.tags.base.BoundedTag; -import com.jpexs.decompiler.flash.tags.base.ButtonTag; -import com.jpexs.decompiler.flash.tags.base.CharacterTag; -import com.jpexs.decompiler.flash.tags.base.DrawableTag; -import com.jpexs.decompiler.flash.tags.base.FontTag; -import com.jpexs.decompiler.flash.tags.base.ImageTag; -import com.jpexs.decompiler.flash.tags.base.MissingCharacterHandler; -import com.jpexs.decompiler.flash.tags.base.MorphShapeTag; -import com.jpexs.decompiler.flash.tags.base.ShapeTag; -import com.jpexs.decompiler.flash.tags.base.SoundStreamHeadTypeTag; -import com.jpexs.decompiler.flash.tags.base.SoundTag; -import com.jpexs.decompiler.flash.tags.base.SymbolClassTypeTag; -import com.jpexs.decompiler.flash.tags.base.TextImportErrorHandler; -import com.jpexs.decompiler.flash.tags.base.TextTag; -import com.jpexs.decompiler.flash.tags.text.TextAlign; -import com.jpexs.decompiler.flash.tags.text.TextParseException; -import com.jpexs.decompiler.flash.timeline.DepthState; -import com.jpexs.decompiler.flash.timeline.Frame; -import com.jpexs.decompiler.flash.timeline.TagScript; -import com.jpexs.decompiler.flash.timeline.Timeline; -import com.jpexs.decompiler.flash.timeline.Timelined; -import com.jpexs.decompiler.flash.treeitems.FolderItem; -import com.jpexs.decompiler.flash.treeitems.HeaderItem; -import com.jpexs.decompiler.flash.treeitems.SWFList; -import com.jpexs.decompiler.flash.treeitems.TreeItem; -import com.jpexs.decompiler.flash.types.MATRIX; -import com.jpexs.decompiler.flash.types.RECT; -import com.jpexs.decompiler.flash.types.sound.SoundFormat; -import com.jpexs.decompiler.flash.xfl.FLAVersion; -import com.jpexs.helpers.CancellableWorker; -import com.jpexs.helpers.Helper; -import com.jpexs.helpers.Path; -import com.jpexs.helpers.ProgressListener; -import com.jpexs.helpers.SerializableImage; -import java.awt.BorderLayout; -import java.awt.CardLayout; -import java.awt.Color; -import java.awt.Component; -import java.awt.Container; -import java.awt.Desktop; -import java.awt.FlowLayout; -import java.awt.Font; -import java.awt.datatransfer.DataFlavor; -import java.awt.datatransfer.Transferable; -import java.awt.datatransfer.UnsupportedFlavorException; -import java.awt.dnd.DnDConstants; -import java.awt.dnd.DragGestureEvent; -import java.awt.dnd.DragGestureListener; -import java.awt.dnd.DragSource; -import java.awt.dnd.DragSourceDragEvent; -import java.awt.dnd.DragSourceDropEvent; -import java.awt.dnd.DragSourceEvent; -import java.awt.dnd.DragSourceListener; -import java.awt.dnd.DropTarget; -import java.awt.dnd.DropTargetDropEvent; -import java.awt.event.ActionEvent; -import java.awt.event.ComponentAdapter; -import java.awt.event.ComponentEvent; -import java.awt.event.KeyAdapter; -import java.awt.event.KeyEvent; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Random; -import java.util.Set; -import java.util.concurrent.CancellationException; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import javax.sound.sampled.LineUnavailableException; -import javax.sound.sampled.UnsupportedAudioFileException; -import javax.swing.Box; -import javax.swing.BoxLayout; -import javax.swing.Icon; -import javax.swing.JColorChooser; -import javax.swing.JFileChooser; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JProgressBar; -import javax.swing.JScrollPane; -import javax.swing.JSplitPane; -import javax.swing.JTabbedPane; -import javax.swing.JTextField; -import javax.swing.SwingConstants; -import javax.swing.UIManager; -import javax.swing.event.DocumentEvent; -import javax.swing.event.DocumentListener; -import javax.swing.event.TreeSelectionEvent; -import javax.swing.event.TreeSelectionListener; -import javax.swing.filechooser.FileFilter; -import javax.swing.plaf.basic.BasicTreeUI; -import javax.swing.tree.DefaultTreeSelectionModel; -import javax.swing.tree.TreePath; -import jsyntaxpane.DefaultSyntaxKit; - -/** - * - * @author JPEXS - */ -public final class MainPanel extends JPanel implements TreeSelectionListener, SearchListener, Freed { - - private final MainFrame mainFrame; - - private final ObservableList swfs; - - private final JPanel welcomePanel; - - private final TimelineViewPanel timelineViewPanel; - - private final MainFrameStatusPanel statusPanel; - - private final MainFrameMenu mainMenu; - - private final JProgressBar progressBar = new JProgressBar(0, 100); - - public TagTree tagTree; - - public DumpTree dumpTree; - - private final FlashPlayerPanel flashPanel; - - private final FlashPlayerPanel flashPanel2; - - private final JPanel contentPanel; - - private final JPanel displayPanel; - - public FolderPreviewPanel folderPreviewPanel; - - private boolean isWelcomeScreen = true; - - private static final String CARDPREVIEWPANEL = "Preview card"; - - private static final String CARDFOLDERPREVIEWPANEL = "Folder preview card"; - - private static final String CARDEMPTYPANEL = "Empty card"; - - private static final String CARDDUMPVIEW = "Dump view"; - - private static final String CARDACTIONSCRIPTPANEL = "ActionScript card"; - - private static final String CARDACTIONSCRIPT3PANEL = "ActionScript3 card"; - - private static final String CARDHEADER = "Header card"; - - private static final String DETAILCARDAS3NAVIGATOR = "Traits list"; - - private static final String DETAILCARDTAGINFO = "Tag information"; - - private static final String DETAILCARDEMPTYPANEL = "Empty card"; - - private static final String SPLIT_PANE1 = "SPLITPANE1"; - - private static final String WELCOME_PANEL = "WELCOMEPANEL"; - - private static final String TIMELINE_PANEL = "TIMELINEPANEL"; - - private static final String RESOURCES_VIEW = "RESOURCES"; - - private static final String DUMP_VIEW = "DUMP"; - - private static final String TIMELINE_VIEW = "TIMELINE"; - - private final JPersistentSplitPane splitPane1; - - private final JPersistentSplitPane splitPane2; - - private JPanel detailPanel; - - private JTextField filterField = new MyTextField(""); - - private JPanel searchPanel; - - private ABCPanel abcPanel; - - private ActionPanel actionPanel; - - private final PreviewPanel previewPanel; - - private final HeaderInfoPanel headerPanel; - - private DumpViewPanel dumpViewPanel; - - private final JPanel treePanel; - - private final PreviewPanel dumpPreviewPanel; - - private final TagInfoPanel tagInfoPanel; - - private TreePanelMode treePanelMode; - - private CancellableWorker setSourceWorker; - - public TreeItem oldItem; - - // play morph shape in 2 second(s) - public static final int MORPH_SHAPE_ANIMATION_LENGTH = 2; - - public static final int MORPH_SHAPE_ANIMATION_FRAME_RATE = 30; - - private static final Logger logger = Logger.getLogger(MainPanel.class.getName()); - - public void setPercent(int percent) { - progressBar.setValue(percent); - progressBar.setVisible(true); - } - - public void hidePercent() { - if (progressBar.isVisible()) { - progressBar.setVisible(false); - } - } - - public MainFrame getMainFrame() { - return mainFrame; - } - - static { - try { - File.createTempFile("temp", ".swf").delete(); //First call to this is slow, so make it first - } catch (IOException ex) { - logger.log(Level.SEVERE, null, ex); - } - } - - public void updateMenu() { - mainMenu.updateComponents(); - } - - private static void addTab(JTabbedPane tabbedPane, Component tab, String title, Icon icon) { - tabbedPane.add(tab); - - JLabel lbl = new JLabel(title); - lbl.setIcon(icon); - lbl.setIconTextGap(5); - lbl.setHorizontalTextPosition(SwingConstants.RIGHT); - - tabbedPane.setTabComponentAt(tabbedPane.getTabCount() - 1, lbl); - } - - public void setStatus(String s) { - statusPanel.setStatus(s); - } - - public void setWorkStatus(String s, CancellableWorker worker) { - statusPanel.setWorkStatus(s, worker); - mainMenu.updateComponents(); - } - - private JPanel createWelcomePanel() { - JPanel welcomePanel = new JPanel(); - welcomePanel.setLayout(new BoxLayout(welcomePanel, BoxLayout.Y_AXIS)); - JLabel welcomeToLabel = new JLabel(translate("startup.welcometo")); - welcomeToLabel.setFont(welcomeToLabel.getFont().deriveFont(40)); - welcomeToLabel.setAlignmentX(0.5f); - JPanel appNamePanel = new JPanel(new FlowLayout()); - JLabel jpLabel = new JLabel("JPEXS "); - jpLabel.setAlignmentX(0.5f); - jpLabel.setForeground(new Color(0, 0, 160)); - jpLabel.setFont(new Font("Tahoma", Font.BOLD, 50)); - jpLabel.setHorizontalAlignment(SwingConstants.CENTER); - appNamePanel.add(jpLabel); - - JLabel ffLabel = new JLabel("Free Flash "); - ffLabel.setAlignmentX(0.5f); - ffLabel.setFont(new Font("Tahoma", Font.BOLD, 50)); - ffLabel.setHorizontalAlignment(SwingConstants.CENTER); - appNamePanel.add(ffLabel); - - JLabel decLabel = new JLabel("Decompiler"); - decLabel.setAlignmentX(0.5f); - decLabel.setForeground(Color.red); - decLabel.setFont(new Font("Tahoma", Font.BOLD, 50)); - decLabel.setHorizontalAlignment(SwingConstants.CENTER); - appNamePanel.add(decLabel); - appNamePanel.setAlignmentX(0.5f); - welcomePanel.add(Box.createGlue()); - welcomePanel.add(welcomeToLabel); - welcomePanel.add(appNamePanel); - JLabel startLabel = new JLabel(translate("startup.selectopen")); - startLabel.setAlignmentX(0.5f); - startLabel.setFont(startLabel.getFont().deriveFont(30)); - welcomePanel.add(startLabel); - welcomePanel.add(Box.createGlue()); - return welcomePanel; - } - - private JPanel createFolderPreviewCard() { - JPanel folderPreviewCard = new JPanel(new BorderLayout()); - folderPreviewPanel = new FolderPreviewPanel(this, new ArrayList<>()); - folderPreviewCard.add(new JScrollPane(folderPreviewPanel), BorderLayout.CENTER); - - return folderPreviewCard; - } - - private JPanel createDumpPreviewCard() { - JPanel dumpViewCard = new JPanel(new BorderLayout()); - dumpViewPanel = new DumpViewPanel(dumpTree); - dumpViewCard.add(new JScrollPane(dumpViewPanel), BorderLayout.CENTER); - - return dumpViewCard; - } - - public String translate(String key) { - return mainFrame.translate(key); - } - - public MainPanel(MainFrame mainFrame, MainFrameMenu mainMenu, FlashPlayerPanel flashPanel, FlashPlayerPanel previewFlashPanel) { - super(); - - this.mainFrame = mainFrame; - this.mainMenu = mainMenu; - this.flashPanel = flashPanel; - this.flashPanel2 = previewFlashPanel; - - mainFrame.setTitle(ApplicationInfo.applicationVerName); - - setLayout(new BorderLayout()); - swfs = new ObservableList<>(); - - detailPanel = new JPanel(); - detailPanel.setLayout(new CardLayout()); - - JPanel whitePanel = new JPanel(); - whitePanel.setBackground(Color.white); - detailPanel.add(whitePanel, DETAILCARDEMPTYPANEL); - - tagInfoPanel = new TagInfoPanel(this); - detailPanel.add(tagInfoPanel, DETAILCARDTAGINFO); - - UIManager.getDefaults().put("TreeUI", BasicTreeUI.class.getName()); - tagTree = new TagTree(null, this); - tagTree.addTreeSelectionListener(this); - tagTree.setSelectionModel(new DefaultTreeSelectionModel() { - private boolean isModified() { - if (abcPanel != null && abcPanel.isEditing()) { - abcPanel.tryAutoSave(); - } - - if (actionPanel != null && actionPanel.isEditing()) { - actionPanel.tryAutoSave(); - } - - if (previewPanel.isEditing()) { - previewPanel.tryAutoSave(); - } - - if (headerPanel.isEditing()) { - headerPanel.tryAutoSave(); - } - - return (abcPanel != null && abcPanel.isEditing()) - || (actionPanel != null && actionPanel.isEditing()) - || previewPanel.isEditing() || headerPanel.isEditing(); - } - - @Override - public void addSelectionPath(TreePath path) { - if (isModified()) { - return; - } - - super.addSelectionPath(path); - } - - @Override - public void addSelectionPaths(TreePath[] paths) { - if (isModified()) { - return; - } - - super.addSelectionPaths(paths); - } - - @Override - public void setSelectionPath(TreePath path) { - if (isModified()) { - return; - } - - super.setSelectionPath(path); - } - - @Override - public void setSelectionPaths(TreePath[] pPaths) { - if (isModified()) { - return; - } - - super.setSelectionPaths(pPaths); - } - - @Override - public void clearSelection() { - if (isModified()) { - return; - } - - super.clearSelection(); - } - - public void setSelection(TreePath[] selection) { - if (isModified()) { - return; - } - - this.selection = selection; - } - - @Override - public void removeSelectionPath(TreePath path) { - if (isModified()) { - return; - } - - super.removeSelectionPath(path); - } - - @Override - public void removeSelectionPaths(TreePath[] paths) { - if (isModified()) { - return; - } - - super.removeSelectionPaths(paths); - } - }); - - DragSource dragSource = DragSource.getDefaultDragSource(); - dragSource.createDefaultDragGestureRecognizer(tagTree, DnDConstants.ACTION_COPY_OR_MOVE, new DragGestureListener() { - @Override - public void dragGestureRecognized(DragGestureEvent dge) { - dge.startDrag(DragSource.DefaultCopyDrop, new Transferable() { - @Override - public DataFlavor[] getTransferDataFlavors() { - return new DataFlavor[]{DataFlavor.javaFileListFlavor}; - } - - @Override - public boolean isDataFlavorSupported(DataFlavor flavor) { - return flavor.equals(DataFlavor.javaFileListFlavor); - } - - @Override - public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException { - if (flavor.equals(DataFlavor.javaFileListFlavor)) { - List files; - String tempDir = System.getProperty("java.io.tmpdir"); - if (!tempDir.endsWith(File.separator)) { - tempDir += File.separator; - } - Random rnd = new Random(); - tempDir += "ffdec" + File.separator + "export" + File.separator + System.currentTimeMillis() + "_" + rnd.nextInt(1000); - File fTempDir = new File(tempDir); - Path.createDirectorySafe(fTempDir); - - File ftemp = new File(tempDir); - ExportDialog exd = new ExportDialog(null); - try { - files = exportSelection(new GuiAbortRetryIgnoreHandler(), tempDir, exd); - } catch (InterruptedException ex) { - logger.log(Level.SEVERE, null, ex); - return null; - } - - files.clear(); - - File[] fs = ftemp.listFiles(); - files.addAll(Arrays.asList(fs)); - - Main.stopWork(); - - for (File f : files) { - f.deleteOnExit(); - } - new File(tempDir).deleteOnExit(); - return files; - - } - return null; - } - }, new DragSourceListener() { - @Override - public void dragEnter(DragSourceDragEvent dsde) { - enableDrop(false); - } - - @Override - public void dragOver(DragSourceDragEvent dsde) { - } - - @Override - public void dropActionChanged(DragSourceDragEvent dsde) { - } - - @Override - public void dragExit(DragSourceEvent dse) { - } - - @Override - public void dragDropEnd(DragSourceDropEvent dsde) { - enableDrop(true); - } - }); - } - }); - - tagTree.createContextMenu(); - - dumpTree = new DumpTree(null, this); - dumpTree.addTreeSelectionListener(this); - dumpTree.createContextMenu(); - - statusPanel = new MainFrameStatusPanel(this); - add(statusPanel, BorderLayout.SOUTH); - - displayPanel = new JPanel(new CardLayout()); - - DefaultSyntaxKit.initKit(); - previewPanel = new PreviewPanel(this, flashPanel); - - dumpPreviewPanel = new PreviewPanel(this, previewFlashPanel); - dumpPreviewPanel.setReadOnly(true); - - displayPanel.add(previewPanel, CARDPREVIEWPANEL); - displayPanel.add(createFolderPreviewCard(), CARDFOLDERPREVIEWPANEL); - displayPanel.add(createDumpPreviewCard(), CARDDUMPVIEW); - - headerPanel = new HeaderInfoPanel(); - displayPanel.add(headerPanel, CARDHEADER); - - displayPanel.add(new JPanel(), CARDEMPTYPANEL); - showCard(CARDEMPTYPANEL); - - searchPanel = new JPanel(); - searchPanel.setLayout(new BorderLayout()); - searchPanel.add(filterField, BorderLayout.CENTER); - searchPanel.add(new JLabel(View.getIcon("search16")), BorderLayout.WEST); - JLabel closeSearchButton = new JLabel(View.getIcon("cancel16")); - closeSearchButton.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - closeTagTreeSearch(); - } - }); - searchPanel.add(closeSearchButton, BorderLayout.EAST); - searchPanel.setVisible(false); - treePanel = new JPanel(new CardLayout()); - treePanel.add(createResourcesViewCard(), RESOURCES_VIEW); - treePanel.add(createDumpViewCard(), DUMP_VIEW); - //treePanel.add(searchPanel, BorderLayout.SOUTH); - //searchPanel.setVisible(false); - filterField.getDocument().addDocumentListener(new DocumentListener() { - @Override - public void changedUpdate(DocumentEvent e) { - warn(); - } - - @Override - public void removeUpdate(DocumentEvent e) { - warn(); - } - - @Override - public void insertUpdate(DocumentEvent e) { - warn(); - } - - public void warn() { - doFilter(); - } - }); - - //displayPanel.setBorder(BorderFactory.createLineBorder(Color.black)); - splitPane2 = new JPersistentSplitPane(JSplitPane.VERTICAL_SPLIT, treePanel, detailPanel, Configuration.guiSplitPane2DividerLocationPercent); - splitPane1 = new JPersistentSplitPane(JSplitPane.HORIZONTAL_SPLIT, splitPane2, displayPanel, Configuration.guiSplitPane1DividerLocationPercent); - - welcomePanel = createWelcomePanel(); - add(welcomePanel, BorderLayout.CENTER); - - timelineViewPanel = new TimelineViewPanel(); - - CardLayout cl3 = new CardLayout(); - contentPanel = new JPanel(cl3); - contentPanel.add(welcomePanel, WELCOME_PANEL); - contentPanel.add(splitPane1, SPLIT_PANE1); - contentPanel.add(timelineViewPanel, TIMELINE_PANEL); - add(contentPanel); - cl3.show(contentPanel, WELCOME_PANEL); - - tagTree.addKeyListener(new KeyAdapter() { - @Override - public void keyPressed(KeyEvent e) { - if ((e.getKeyCode() == 'F') && (e.isControlDown())) { - searchPanel.setVisible(true); - filterField.requestFocusInWindow(); - } - } - }); - detailPanel.setVisible(false); - - updateUi(); - - this.swfs.addCollectionChangedListener((e) -> { - TagTreeModel ttm = tagTree.getModel(); - if (ttm != null) { - if (getCurrentSwf() == null) { - tagTree.setSelectionPath(ttm.getTreePath(ttm.getRoot())); - } - ttm.updateSwfs(e); - tagTree.expandRoot(); - tagTree.expandFirstLevelNodes(); - } - - DumpTreeModel dtm = dumpTree.getModel(); - if (dtm != null) { - List> expandedNodes = View.getExpandedNodes(dumpTree); - dtm.updateSwfs(); - View.expandTreeNodes(dumpTree, expandedNodes); - dumpTree.expandRoot(); - dumpTree.expandFirstLevelNodes(); - } - - if (swfs.isEmpty()) { - tagTree.setUI(new BasicTreeUI() { - { - setHashColor(Color.gray); - } - }); - dumpTree.setUI(new BasicTreeUI() { - { - setHashColor(Color.gray); - } - }); - } - }); - - //Opening files with drag&drop to main window - enableDrop(true); - } - - public void closeTagTreeSearch() { - filterField.setText(""); - doFilter(); - searchPanel.setVisible(false); - } - - public void loadSwfAtPos(SWFList newSwfs, int index) { - previewPanel.clear(); - swfs.set(index, newSwfs); - SWF swf = newSwfs.size() > 0 ? newSwfs.get(0) : null; - if (swf != null) { - updateUi(swf); - } - - doFilter(); - reload(false); - } - - public void load(SWFList newSwfs, boolean first) { - - previewPanel.clear(); - - swfs.add(newSwfs); - SWF swf = newSwfs.size() > 0 ? newSwfs.get(0) : null; - if (swf != null) { - updateUi(swf); - } - - doFilter(); - reload(false); - } - - private ABCPanel getABCPanel() { - if (abcPanel == null) { - abcPanel = new ABCPanel(this); - displayPanel.add(abcPanel, CARDACTIONSCRIPT3PANEL); - detailPanel.add(abcPanel.tabbedPane, DETAILCARDAS3NAVIGATOR); - } - - return abcPanel; - } - - private ActionPanel getActionPanel() { - if (actionPanel == null) { - actionPanel = new ActionPanel(MainPanel.this); - displayPanel.add(actionPanel, CARDACTIONSCRIPTPANEL); - } - - return actionPanel; - } - - private void updateUi(final SWF swf) { - - mainFrame.setTitle(ApplicationInfo.applicationVerName + (Configuration.displayFileName.get() ? " - " + swf.getFileTitle() : "")); - - List abcList = swf.getAbcList(); - - boolean hasAbc = !abcList.isEmpty(); - - if (hasAbc) { - getABCPanel().setAbc(abcList.get(0).getABC()); - } - - if (isWelcomeScreen) { - CardLayout cl = (CardLayout) (contentPanel.getLayout()); - cl.show(contentPanel, SPLIT_PANE1); - isWelcomeScreen = false; - } - - mainMenu.updateComponents(swf); - } - - private void updateUi() { - if (!isWelcomeScreen && swfs.isEmpty()) { - CardLayout cl = (CardLayout) (contentPanel.getLayout()); - cl.show(contentPanel, WELCOME_PANEL); - isWelcomeScreen = true; - closeTagTreeSearch(); - } - - mainFrame.setTitle(ApplicationInfo.applicationVerName); - mainMenu.updateComponents(null); - - showView(getCurrentView()); - } - - private boolean closeConfirmation(SWFList swfList) { - String message = swfList == null - ? translate("message.confirm.closeAll") - : translate("message.confirm.close").replace("{swfName}", swfList.toString()); - - return View.showConfirmDialog(this, message, translate("message.warning"), JOptionPane.OK_CANCEL_OPTION, Configuration.showCloseConfirmation, JOptionPane.OK_OPTION) == JOptionPane.OK_OPTION; - } - - public boolean isModified() { - for (SWFList swfList : swfs) { - for (SWF swf : swfList) { - if (swf.isModified()) { - return true; - } - } - } - - return false; - } - - public boolean closeAll(boolean showCloseConfirmation) { - if (showCloseConfirmation && isModified()) { - boolean closeConfirmResult = closeConfirmation(swfs.size() == 1 ? swfs.get(0) : null); - if (!closeConfirmResult) { - return false; - } - } - - List swfsLists = new ArrayList<>(swfs); - swfs.clear(); - oldItem = null; - clear(); - updateUi(); - - for (SWFList swfList : swfsLists) { - List swfs2 = new ArrayList<>(swfList); - for (SWF swf : swfs2) { - swf.clearTagSwfs(); - } - } - - return true; - } - - public boolean close(SWFList swfList) { - boolean modified = false; - for (SWF swf : swfList) { - if (swf.isModified()) { - modified = true; - } - } - - if (modified) { - boolean closeConfirmResult = closeConfirmation(swfList); - if (!closeConfirmResult) { - return false; - } - } - - swfs.remove(swfList); - oldItem = null; - clear(); - updateUi(); - - List swfs2 = new ArrayList<>(swfList); - for (SWF swf : swfs2) { - swf.clearTagSwfs(); - } - - return true; - } - - public void enableDrop(boolean value) { - if (value) { - setDropTarget(new DropTarget() { - @Override - public synchronized void drop(DropTargetDropEvent dtde) { - try { - dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE); - @SuppressWarnings("unchecked") - List droppedFiles = (List) dtde.getTransferable().getTransferData(DataFlavor.javaFileListFlavor); - if (!droppedFiles.isEmpty()) { - SWFSourceInfo[] sourceInfos = new SWFSourceInfo[droppedFiles.size()]; - for (int i = 0; i < droppedFiles.size(); i++) { - sourceInfos[i] = new SWFSourceInfo(null, droppedFiles.get(i).getAbsolutePath(), null); - } - Main.openFile(sourceInfos, null); - } - } catch (UnsupportedFlavorException | IOException ex) { - } - } - }); - } else { - setDropTarget(null); - } - } - - public void updateClassesList() { - List nodes = getASTreeNodes(tagTree); - boolean updateNeeded = false; - for (TreeItem n : nodes) { - if (n instanceof ClassesListTreeModel) { - ((ClassesListTreeModel) n).update(); - updateNeeded = true; - } - } - - refreshTree(); - - if (updateNeeded) { - tagTree.updateUI(); - } - } - - public void doFilter() { - List nodes = getASTreeNodes(tagTree); - for (TreeItem n : nodes) { - if (n instanceof ClassesListTreeModel) { - String filterText = filterField.getText(); - ((ClassesListTreeModel) n).setFilter(filterText); - TagTreeModel tm = tagTree.getModel(); - TreePath path = tm.getTreePath(n); - tm.updateNode(path); - if (!filterText.isEmpty()) { - View.expandTreeNodes(tagTree, path, true); - } - } - } - } - - public void renameIdentifier(SWF swf, String identifier) throws InterruptedException { - String oldName = identifier; - String newName = View.showInputDialog(translate("rename.enternew"), oldName); - if (newName != null) { - if (!oldName.equals(newName)) { - swf.renameAS2Identifier(oldName, newName); - View.showMessageDialog(null, translate("rename.finished.identifier")); - updateClassesList(); - reload(true); - } - } - } - - public void renameMultiname(List abcList, int multiNameIndex) { - String oldName = ""; - AVM2ConstantPool constants = getABCPanel().abc.constants; - if (constants.getMultiname(multiNameIndex).name_index > 0) { - oldName = constants.getString(constants.getMultiname(multiNameIndex).name_index); - } - - String newName = View.showInputDialog(translate("rename.enternew"), oldName); - if (newName != null) { - if (!oldName.equals(newName)) { - int mulCount = 0; - for (ABCContainerTag cnt : abcList) { - ABC abc = cnt.getABC(); - for (int m = 1; m < abc.constants.getMultinameCount(); m++) { - int ni = abc.constants.getMultiname(m).name_index; - String n = ""; - if (ni > 0) { - n = abc.constants.getString(ni); - } - if (n.equals(oldName)) { - abc.renameMultiname(m, newName); - mulCount++; - } - } - } - - View.showMessageDialog(null, translate("rename.finished.multiname").replace("%count%", Integer.toString(mulCount))); - if (abcPanel != null) { - abcPanel.reload(); - } - - updateClassesList(); - reload(true); - ABCPanel abcPanel = getABCPanel(); - abcPanel.hilightScript(abcPanel.getSwf(), abcPanel.decompiledTextArea.getScriptLeaf().getClassPath().toRawString()); - } - } - } - - public List getASTreeNodes(TagTree tree) { - List result = new ArrayList<>(); - TagTreeModel tm = (TagTreeModel) tree.getModel(); - if (tm == null) { - return result; - } - TreeItem root = tm.getRoot(); - for (int i = 0; i < tm.getChildCount(root); i++) { - // first level node can be SWF and SWFBundle - TreeItem node = tm.getChild(root, i); - if (node instanceof SWFBundle) { - for (int j = 0; j < tm.getChildCount(node); j++) { - // child of SWFBundle should be SWF - SWF swfNode = (SWF) tm.getChild(node, j); - result.add(tm.getScriptsNode(swfNode)); - } - } else if (node instanceof SWF) { - SWF swfNode = (SWF) tm.getChild(root, i); - result.add(tm.getScriptsNode(swfNode)); - } - } - return result; - } - - public boolean confirmExperimental() { - return View.showConfirmDialog(null, translate("message.confirm.experimental"), translate("message.warning"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.OK_OPTION; - } - - public List exportSelection(AbortRetryIgnoreHandler handler, String selFile, ExportDialog export) throws IOException, InterruptedException { - - List ret = new ArrayList<>(); - List sel = folderPreviewPanel.selectedItems.isEmpty() ? tagTree.getAllSelected() : new ArrayList<>(folderPreviewPanel.selectedItems.values()); - - Set usedSwfs = new HashSet<>(); - for (TreeItem d : sel) { - SWF selectedNodeSwf = d.getSwf(); - if (!usedSwfs.contains(selectedNodeSwf)) { - usedSwfs.add(selectedNodeSwf); - } - } - - Map usedSwfsIds = new HashMap<>(); - for (SWF swf : usedSwfs) { - List as3scripts = new ArrayList<>(); - List images = new ArrayList<>(); - List shapes = new ArrayList<>(); - List morphshapes = new ArrayList<>(); - List buttons = new ArrayList<>(); - List movies = new ArrayList<>(); - List sounds = new ArrayList<>(); - List texts = new ArrayList<>(); - List as12scripts = new ArrayList<>(); - List binaryData = new ArrayList<>(); - Map> frames = new HashMap<>(); - List fonts = new ArrayList<>(); - List symbolNames = new ArrayList<>(); - - for (TreeItem d : sel) { - SWF selectedNodeSwf = d.getSwf(); - - if (selectedNodeSwf != swf) { - continue; - } - - if (d instanceof TagScript) { - Tag tag = ((TagScript) d).getTag(); - if (tag instanceof DoActionTag || tag instanceof DoInitActionTag) { - as12scripts.add(d); - } - } - - if (d instanceof Tag || d instanceof ASMSource) { - TreeNodeType nodeType = TagTree.getTreeNodeType(d); - if (nodeType == TreeNodeType.IMAGE) { - images.add((Tag) d); - } - if (nodeType == TreeNodeType.SHAPE) { - shapes.add((Tag) d); - } - if (nodeType == TreeNodeType.BUTTON) { - buttons.add((Tag) d); - } - if (nodeType == TreeNodeType.MORPH_SHAPE) { - morphshapes.add((Tag) d); - } - if (nodeType == TreeNodeType.AS) { - as12scripts.add(d); - } - if (nodeType == TreeNodeType.MOVIE) { - movies.add((Tag) d); - } - if (nodeType == TreeNodeType.SOUND) { - sounds.add((Tag) d); - } - if (nodeType == TreeNodeType.BINARY_DATA) { - binaryData.add((Tag) d); - } - if (nodeType == TreeNodeType.TEXT) { - texts.add((Tag) d); - } - if (nodeType == TreeNodeType.FONT) { - fonts.add((Tag) d); - } - if (nodeType == TreeNodeType.OTHER_TAG) { - if (d instanceof SymbolClassTypeTag) { - symbolNames.add((Tag) d); - } - } - } - - if (d instanceof Frame) { - Frame fn = (Frame) d; - Timelined parent = fn.timeline.timelined; - int frame = fn.frame; - int parentId = 0; - if (parent instanceof CharacterTag) { - parentId = ((CharacterTag) parent).getCharacterId(); - } - if (!frames.containsKey(parentId)) { - frames.put(parentId, new ArrayList<>()); - } - frames.get(parentId).add(frame); - } - if (d instanceof ScriptPack) { - as3scripts.add((ScriptPack) d); - } - } - - String selFile2; - if (usedSwfs.size() > 1) { - selFile2 = selFile + File.separator + Helper.getNextId(swf.getShortFileName(), usedSwfsIds); - } else { - selFile2 = selFile; - } - - EventListener evl = swf.getExportEventListener(); - - if (export.isOptionEnabled(ImageExportMode.class)) { - ret.addAll(new ImageExporter().exportImages(handler, selFile2 + File.separator + ImageExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(images), - new ImageExportSettings(export.getValue(ImageExportMode.class)), evl)); - } - - if (export.isOptionEnabled(ShapeExportMode.class)) { - ret.addAll(new ShapeExporter().exportShapes(handler, selFile2 + File.separator + ShapeExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(shapes), - new ShapeExportSettings(export.getValue(ShapeExportMode.class), export.getZoom()), evl)); - } - - if (export.isOptionEnabled(MorphShapeExportMode.class)) { - ret.addAll(new MorphShapeExporter().exportMorphShapes(handler, selFile2 + File.separator + MorphShapeExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(morphshapes), - new MorphShapeExportSettings(export.getValue(MorphShapeExportMode.class), export.getZoom()), evl)); - } - - if (export.isOptionEnabled(TextExportMode.class)) { - ret.addAll(new TextExporter().exportTexts(handler, selFile2 + File.separator + TextExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(texts), - new TextExportSettings(export.getValue(TextExportMode.class), Configuration.textExportSingleFile.get(), export.getZoom()), evl)); - } - - if (export.isOptionEnabled(MovieExportMode.class)) { - ret.addAll(new MovieExporter().exportMovies(handler, selFile2 + File.separator + MovieExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(movies), - new MovieExportSettings(export.getValue(MovieExportMode.class)), evl)); - } - - if (export.isOptionEnabled(SoundExportMode.class)) { - ret.addAll(new SoundExporter().exportSounds(handler, selFile2 + File.separator + SoundExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(sounds), - new SoundExportSettings(export.getValue(SoundExportMode.class)), evl)); - } - - if (export.isOptionEnabled(BinaryDataExportMode.class)) { - ret.addAll(new BinaryDataExporter().exportBinaryData(handler, selFile2 + File.separator + BinaryDataExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(binaryData), - new BinaryDataExportSettings(export.getValue(BinaryDataExportMode.class)), evl)); - } - - if (export.isOptionEnabled(FontExportMode.class)) { - ret.addAll(new FontExporter().exportFonts(handler, selFile2 + File.separator + FontExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(fonts), - new FontExportSettings(export.getValue(FontExportMode.class)), evl)); - } - - if (export.isOptionEnabled(SymbolClassExportMode.class)) { - ret.addAll(new SymbolClassExporter().exportNames(selFile2, new ReadOnlyTagList(symbolNames), evl)); - } - - FrameExporter frameExporter = new FrameExporter(); - - if (export.isOptionEnabled(FrameExportMode.class)) { - FrameExportSettings fes = new FrameExportSettings(export.getValue(FrameExportMode.class), export.getZoom()); - for (Entry> entry : frames.entrySet()) { - int containerId = entry.getKey(); - if (containerId == 0) { - String subFolder = FrameExportSettings.EXPORT_FOLDER_NAME; - ret.addAll(frameExporter.exportFrames(handler, selFile2 + File.separator + subFolder, swf, containerId, entry.getValue(), fes, evl)); - } - } - } - - if (export.isOptionEnabled(SpriteExportMode.class)) { - SpriteExportSettings ses = new SpriteExportSettings(export.getValue(SpriteExportMode.class), export.getZoom()); - for (Entry> entry : frames.entrySet()) { - int containerId = entry.getKey(); - if (containerId != 0) { - String subFolder = SpriteExportSettings.EXPORT_FOLDER_NAME; - ret.addAll(frameExporter.exportFrames(handler, selFile2 + File.separator + subFolder, swf, containerId, entry.getValue(), ses, evl)); - } - } - } - - if (export.isOptionEnabled(ButtonExportMode.class)) { - ButtonExportSettings bes = new ButtonExportSettings(export.getValue(ButtonExportMode.class), export.getZoom()); - for (Tag tag : buttons) { - ButtonTag button = (ButtonTag) tag; - String subFolder = ButtonExportSettings.EXPORT_FOLDER_NAME; - List frameNums = new ArrayList<>(); - frameNums.add(0); // todo: export all frames - ret.addAll(frameExporter.exportFrames(handler, selFile2 + File.separator + subFolder, swf, button.getCharacterId(), frameNums, bes, evl)); - } - } - - if (export.isOptionEnabled(ScriptExportMode.class)) { - if (as3scripts.size() > 0 || as12scripts.size() > 0) { - boolean parallel = Configuration.parallelSpeedUp.get(); - String scriptsFolder = Path.combine(selFile2, ScriptExportSettings.EXPORT_FOLDER_NAME); - Path.createDirectorySafe(new File(scriptsFolder)); - boolean singleScriptFile = Configuration.scriptExportSingleFile.get(); - if (parallel && singleScriptFile) { - logger.log(Level.WARNING, AppStrings.translate("export.script.singleFilePallelModeWarning")); - singleScriptFile = false; - } - - ScriptExportSettings scriptExportSettings = new ScriptExportSettings(export.getValue(ScriptExportMode.class), singleScriptFile); - String singleFileName = Path.combine(scriptsFolder, swf.getShortFileName() + scriptExportSettings.getFileExtension()); - try (FileTextWriter writer = scriptExportSettings.singleFile ? new FileTextWriter(Configuration.getCodeFormatting(), new FileOutputStream(singleFileName)) : null) { - scriptExportSettings.singleFileWriter = writer; - if (swf.isAS3()) { - ret.addAll(new AS3ScriptExporter().exportActionScript3(swf, handler, scriptsFolder, as3scripts, scriptExportSettings, parallel, evl)); - } else { - Map asmsToExport = swf.getASMs(true, as12scripts, false); - ret.addAll(new AS2ScriptExporter().exportAS2Scripts(handler, scriptsFolder, asmsToExport, scriptExportSettings, parallel, evl)); - } - } - } - } - } - - return ret; - } - - public void exportAll(SWF swf, AbortRetryIgnoreHandler handler, String selFile, ExportDialog export) throws IOException, InterruptedException { - boolean exportAll = false; - if (exportAll) { - exportAllDebug(swf, handler, selFile, export); - return; - } - - EventListener evl = swf.getExportEventListener(); - - if (export.isOptionEnabled(ImageExportMode.class)) { - new ImageExporter().exportImages(handler, Path.combine(selFile, ImageExportSettings.EXPORT_FOLDER_NAME), swf.getTags(), - new ImageExportSettings(export.getValue(ImageExportMode.class)), evl); - } - - if (export.isOptionEnabled(ShapeExportMode.class)) { - new ShapeExporter().exportShapes(handler, Path.combine(selFile, ShapeExportSettings.EXPORT_FOLDER_NAME), swf.getTags(), - new ShapeExportSettings(export.getValue(ShapeExportMode.class), export.getZoom()), evl); - } - - if (export.isOptionEnabled(MorphShapeExportMode.class)) { - new MorphShapeExporter().exportMorphShapes(handler, Path.combine(selFile, MorphShapeExportSettings.EXPORT_FOLDER_NAME), swf.getTags(), - new MorphShapeExportSettings(export.getValue(MorphShapeExportMode.class), export.getZoom()), evl); - } - - if (export.isOptionEnabled(TextExportMode.class)) { - new TextExporter().exportTexts(handler, Path.combine(selFile, TextExportSettings.EXPORT_FOLDER_NAME), swf.getTags(), - new TextExportSettings(export.getValue(TextExportMode.class), Configuration.textExportSingleFile.get(), export.getZoom()), evl); - } - - if (export.isOptionEnabled(MovieExportMode.class)) { - new MovieExporter().exportMovies(handler, Path.combine(selFile, MovieExportSettings.EXPORT_FOLDER_NAME), swf.getTags(), - new MovieExportSettings(export.getValue(MovieExportMode.class)), evl); - } - - if (export.isOptionEnabled(SoundExportMode.class)) { - new SoundExporter().exportSounds(handler, Path.combine(selFile, SoundExportSettings.EXPORT_FOLDER_NAME), swf.getTags(), - new SoundExportSettings(export.getValue(SoundExportMode.class)), evl); - } - - if (export.isOptionEnabled(BinaryDataExportMode.class)) { - new BinaryDataExporter().exportBinaryData(handler, Path.combine(selFile, BinaryDataExportSettings.EXPORT_FOLDER_NAME), swf.getTags(), - new BinaryDataExportSettings(export.getValue(BinaryDataExportMode.class)), evl); - } - - if (export.isOptionEnabled(FontExportMode.class)) { - new FontExporter().exportFonts(handler, Path.combine(selFile, FontExportSettings.EXPORT_FOLDER_NAME), swf.getTags(), - new FontExportSettings(export.getValue(FontExportMode.class)), evl); - } - - if (export.isOptionEnabled(SymbolClassExportMode.class)) { - new SymbolClassExporter().exportNames(selFile, swf.getTags(), evl); - } - - FrameExporter frameExporter = new FrameExporter(); - - if (export.isOptionEnabled(FrameExportMode.class)) { - FrameExportSettings fes = new FrameExportSettings(export.getValue(FrameExportMode.class), export.getZoom()); - frameExporter.exportFrames(handler, Path.combine(selFile, FrameExportSettings.EXPORT_FOLDER_NAME), swf, 0, null, fes, evl); - } - - if (export.isOptionEnabled(SpriteExportMode.class)) { - SpriteExportSettings ses = new SpriteExportSettings(export.getValue(SpriteExportMode.class), export.getZoom()); - for (CharacterTag c : swf.getCharacters().values()) { - if (c instanceof DefineSpriteTag) { - frameExporter.exportFrames(handler, Path.combine(selFile, SpriteExportSettings.EXPORT_FOLDER_NAME), swf, c.getCharacterId(), null, ses, evl); - } - } - } - - if (export.isOptionEnabled(ButtonExportMode.class)) { - ButtonExportSettings bes = new ButtonExportSettings(export.getValue(ButtonExportMode.class), export.getZoom()); - for (CharacterTag c : swf.getCharacters().values()) { - if (c instanceof ButtonTag) { - List frameNums = new ArrayList<>(); - frameNums.add(0); // todo: export all frames - frameExporter.exportFrames(handler, Path.combine(selFile, ButtonExportSettings.EXPORT_FOLDER_NAME), swf, c.getCharacterId(), frameNums, bes, evl); - } - } - } - - if (export.isOptionEnabled(ScriptExportMode.class)) { - boolean parallel = Configuration.parallelSpeedUp.get(); - String scriptsFolder = Path.combine(selFile, ScriptExportSettings.EXPORT_FOLDER_NAME); - Path.createDirectorySafe(new File(scriptsFolder)); - boolean singleScriptFile = Configuration.scriptExportSingleFile.get(); - if (parallel && singleScriptFile) { - logger.log(Level.WARNING, AppStrings.translate("export.script.singleFilePallelModeWarning")); - singleScriptFile = false; - } - - ScriptExportSettings scriptExportSettings = new ScriptExportSettings(export.getValue(ScriptExportMode.class), singleScriptFile); - String singleFileName = Path.combine(scriptsFolder, swf.getShortFileName() + scriptExportSettings.getFileExtension()); - try (FileTextWriter writer = scriptExportSettings.singleFile ? new FileTextWriter(Configuration.getCodeFormatting(), new FileOutputStream(singleFileName)) : null) { - scriptExportSettings.singleFileWriter = writer; - swf.exportActionScript(handler, scriptsFolder, scriptExportSettings, parallel, evl); - } - } - } - - public void exportAllDebug(SWF swf, AbortRetryIgnoreHandler handler, String selFile, ExportDialog export) throws IOException, InterruptedException { - EventListener evl = swf.getExportEventListener(); - - if (export.isOptionEnabled(ImageExportMode.class)) { - for (ImageExportMode exportMode : ImageExportMode.values()) { - new ImageExporter().exportImages(handler, Path.combine(selFile, ImageExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.getTags(), - new ImageExportSettings(exportMode), evl); - } - } - - if (export.isOptionEnabled(ShapeExportMode.class)) { - for (ShapeExportMode exportMode : ShapeExportMode.values()) { - new ShapeExporter().exportShapes(handler, Path.combine(selFile, ShapeExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.getTags(), - new ShapeExportSettings(exportMode, export.getZoom()), evl); - } - } - - if (export.isOptionEnabled(MorphShapeExportMode.class)) { - for (MorphShapeExportMode exportMode : MorphShapeExportMode.values()) { - new MorphShapeExporter().exportMorphShapes(handler, Path.combine(selFile, MorphShapeExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.getTags(), - new MorphShapeExportSettings(exportMode, export.getZoom()), evl); - } - } - - if (export.isOptionEnabled(TextExportMode.class)) { - for (TextExportMode exportMode : TextExportMode.values()) { - new TextExporter().exportTexts(handler, Path.combine(selFile, TextExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.getTags(), - new TextExportSettings(exportMode, Configuration.textExportSingleFile.get(), export.getZoom()), evl); - } - } - - if (export.isOptionEnabled(MovieExportMode.class)) { - for (MovieExportMode exportMode : MovieExportMode.values()) { - new MovieExporter().exportMovies(handler, Path.combine(selFile, MovieExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.getTags(), - new MovieExportSettings(exportMode), evl); - } - } - - if (export.isOptionEnabled(SoundExportMode.class)) { - for (SoundExportMode exportMode : SoundExportMode.values()) { - new SoundExporter().exportSounds(handler, Path.combine(selFile, SoundExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.getTags(), - new SoundExportSettings(exportMode), evl); - } - } - - if (export.isOptionEnabled(BinaryDataExportMode.class)) { - for (BinaryDataExportMode exportMode : BinaryDataExportMode.values()) { - new BinaryDataExporter().exportBinaryData(handler, Path.combine(selFile, BinaryDataExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.getTags(), - new BinaryDataExportSettings(exportMode), evl); - } - } - - if (export.isOptionEnabled(FontExportMode.class)) { - for (FontExportMode exportMode : FontExportMode.values()) { - new FontExporter().exportFonts(handler, Path.combine(selFile, FontExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.getTags(), - new FontExportSettings(exportMode), evl); - } - } - - if (export.isOptionEnabled(SymbolClassExportMode.class)) { - for (SymbolClassExportMode exportMode : SymbolClassExportMode.values()) { - new SymbolClassExporter().exportNames(selFile, swf.getTags(), evl); - } - } - - FrameExporter frameExporter = new FrameExporter(); - - if (export.isOptionEnabled(FrameExportMode.class)) { - for (FrameExportMode exportMode : FrameExportMode.values()) { - FrameExportSettings fes = new FrameExportSettings(exportMode, export.getZoom()); - frameExporter.exportFrames(handler, Path.combine(selFile, FrameExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf, 0, null, fes, evl); - } - } - - if (export.isOptionEnabled(SpriteExportMode.class)) { - for (SpriteExportMode exportMode : SpriteExportMode.values()) { - SpriteExportSettings ses = new SpriteExportSettings(exportMode, export.getZoom()); - for (CharacterTag c : swf.getCharacters().values()) { - if (c instanceof DefineSpriteTag) { - frameExporter.exportFrames(handler, Path.combine(selFile, SpriteExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf, c.getCharacterId(), null, ses, evl); - } - } - } - } - - if (export.isOptionEnabled(ButtonExportMode.class)) { - for (ButtonExportMode exportMode : ButtonExportMode.values()) { - ButtonExportSettings bes = new ButtonExportSettings(exportMode, export.getZoom()); - for (CharacterTag c : swf.getCharacters().values()) { - if (c instanceof ButtonTag) { - List frameNums = new ArrayList<>(); - frameNums.add(0); // todo: export all frames - frameExporter.exportFrames(handler, Path.combine(selFile, ButtonExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf, c.getCharacterId(), frameNums, bes, evl); - } - } - } - } - - if (export.isOptionEnabled(ScriptExportMode.class)) { - boolean parallel = Configuration.parallelSpeedUp.get(); - for (ScriptExportMode exportMode : ScriptExportMode.values()) { - String scriptsFolder = Path.combine(selFile, ScriptExportSettings.EXPORT_FOLDER_NAME, exportMode.name()); - Path.createDirectorySafe(new File(scriptsFolder)); - boolean singleScriptFile = Configuration.scriptExportSingleFile.get(); - if (parallel && singleScriptFile) { - logger.log(Level.WARNING, AppStrings.translate("export.script.singleFilePallelModeWarning")); - singleScriptFile = false; - } - - ScriptExportSettings scriptExportSettings = new ScriptExportSettings(exportMode, singleScriptFile); - String singleFileName = Path.combine(scriptsFolder, swf.getShortFileName() + scriptExportSettings.getFileExtension()); - try (FileTextWriter writer = scriptExportSettings.singleFile ? new FileTextWriter(Configuration.getCodeFormatting(), new FileOutputStream(singleFileName)) : null) { - scriptExportSettings.singleFileWriter = writer; - swf.exportActionScript(handler, scriptsFolder, scriptExportSettings, parallel, evl); - } - } - } - } - - public List getSwfs() { - return swfs; - } - - public SWFList getCurrentSwfList() { - SWF swf = getCurrentSwf(); - if (swf == null) { - return null; - } - - return swf.swfList; - } - - public SWF getCurrentSwf() { - if (swfs == null || swfs.isEmpty()) { - return null; - } - - if (treePanelMode == TreePanelMode.TAG_TREE) { - TreeItem treeNode = (TreeItem) tagTree.getLastSelectedPathComponent(); - if (treeNode == null || treeNode instanceof SWFList) { - return null; - } - - return treeNode.getSwf(); - } else if (treePanelMode == TreePanelMode.DUMP_TREE) { - DumpInfo dumpInfo = (DumpInfo) dumpTree.getLastSelectedPathComponent(); - - if (dumpInfo == null) { - return null; - } - - return DumpInfoSwfNode.getSwfNode(dumpInfo).getSwf(); - } - - return null; - } - - public void gotoFrame(int frame) { - TreeItem treeItem = (TreeItem) tagTree.getLastSelectedPathComponent(); - if (treeItem == null) { - return; - } - if (treeItem instanceof Timelined) { - Timelined t = (Timelined) treeItem; - Frame f = tagTree.getModel().getFrame(treeItem.getSwf(), t, frame); - if (f != null) { - setTagTreeSelectedNode(f); - } - } - } - - public void gotoScriptLine(SWF swf, String scriptName, int line, int classIndex, int traitIndex, int methodIndex) { - gotoScriptName(swf, scriptName); - if (abcPanel != null) { - if (Main.isDebugPCode()) { - if (classIndex != -1) { - boolean classChanged = false; - if (abcPanel.decompiledTextArea.getClassIndex() != classIndex) { - abcPanel.decompiledTextArea.setClassIndex(classIndex); - classChanged = true; - } - if (traitIndex != -10 && (classChanged || abcPanel.decompiledTextArea.lastTraitIndex != traitIndex)) { - abcPanel.decompiledTextArea.gotoTrait(traitIndex); - } - } - abcPanel.detailPanel.methodTraitPanel.methodCodePanel.gotoInstrLine(line); - } else { - abcPanel.decompiledTextArea.gotoLine(line); - } - } else if (actionPanel != null) { - if (Main.isDebugPCode()) { - actionPanel.editor.gotoLine(line); - } else { - actionPanel.decompiledEditor.gotoLine(line); - } - } - refreshBreakPoints(); - - } - - public void refreshBreakPoints() { - if (abcPanel != null) { - abcPanel.decompiledTextArea.refreshMarkers(); - abcPanel.detailPanel.methodTraitPanel.methodCodePanel.refreshMarkers(); - } - if (actionPanel != null) { - actionPanel.decompiledEditor.refreshMarkers(); - actionPanel.editor.refreshMarkers(); - } - } - - /* - public void debuggerBreakAt(SWF swf, String cls, int line) { - View.execInEventDispatchLater(new Runnable() { - - @Override - public void run() { - gotoClassLine(swf, cls, line); - if (abcPanel != null) { - abcPanel.decompiledTextArea.addColorMarker(line, DecompiledEditorPane.FG_IP_COLOR, DecompiledEditorPane.BG_IP_COLOR, DecompiledEditorPane.PRIORITY_IP); - } - } - }); - - }*/ - public void gotoScriptName(SWF swf, String scriptName) { - if (swf == null) { - return; - } - if (swf.isAS3()) { - String rawScriptName = scriptName; - if (rawScriptName.startsWith("#PCODE ")) { - rawScriptName = rawScriptName.substring(rawScriptName.indexOf(';') + 1); - } - - List abcList = swf.getAbcList(); - if (!abcList.isEmpty()) { - ABCPanel abcPanel = getABCPanel(); - abcPanel.setAbc(abcList.get(0).getABC()); - abcPanel.hilightScript(swf, rawScriptName); - } - } else { - String rawScriptName = scriptName; - if (rawScriptName.startsWith("#PCODE ")) { - rawScriptName = rawScriptName.substring("#PCODE ".length()); - } - Map asms = swf.getASMs(true); - if (actionPanel != null && asms.containsKey(rawScriptName)) { - actionPanel.setSource(asms.get(rawScriptName), true); - } - } - } - - public void gotoDocumentClass(SWF swf) { - if (swf == null) { - return; - } - - String documentClass = swf.getDocumentClass(); - if (documentClass != null && !Configuration.dumpView.get()) { - List abcList = swf.getAbcList(); - if (!abcList.isEmpty()) { - ABCPanel abcPanel = getABCPanel(); - for (ABCContainerTag c : abcList) { - if (c.getABC().findClassByName(documentClass) > -1) { - abcPanel.setAbc(c.getABC()); - abcPanel.hilightScript(swf, documentClass); - break; - } - } - } - } - } - - public void disableDecompilationChanged() { - clearAllScriptCache(); - - if (abcPanel != null) { - abcPanel.reload(); - } - - updateClassesList(); - } - - private void clearAllScriptCache() { - for (SWFList swfList : swfs) { - for (SWF swf : swfList) { - swf.clearScriptCache(); - } - } - } - - public void searchInActionScriptOrText(Boolean searchInText, SWF swf) { - SearchDialog searchDialog = new SearchDialog(getMainFrame().getWindow(), false); - if (searchInText != null) { - if (searchInText) { - searchDialog.searchInTextsRadioButton.setSelected(true); - } else { - searchDialog.searchInASRadioButton.setSelected(true); - } - } - - if (searchDialog.showDialog() == AppDialog.OK_OPTION) { - final String txt = searchDialog.searchField.getText(); - if (!txt.isEmpty()) { - if (swf.isAS3()) { - getABCPanel(); - } else { - getActionPanel(); - } - - boolean ignoreCase = searchDialog.ignoreCaseCheckBox.isSelected(); - boolean regexp = searchDialog.regexpCheckBox.isSelected(); - - if (searchDialog.searchInASRadioButton.isSelected()) { - new CancellableWorker() { - @Override - protected Void doInBackground() throws Exception { - List abcResult = null; - List actionResult = null; - if (swf.isAS3()) { - abcResult = getABCPanel().search(swf, txt, ignoreCase, regexp, this); - } else { - actionResult = getActionPanel().search(swf, txt, ignoreCase, regexp, this); - } - - List fAbcResult = abcResult; - List fActionResult = actionResult; - View.execInEventDispatch(() -> { - boolean found = false; - if (fAbcResult != null) { - found = true; - getABCPanel().searchPanel.setSearchText(txt); - SearchResultsDialog sr = new SearchResultsDialog<>(getMainFrame().getWindow(), txt, getABCPanel()); - sr.setResults(fAbcResult); - sr.setVisible(true); - } else if (fActionResult != null) { - found = true; - getActionPanel().searchPanel.setSearchText(txt); - - SearchResultsDialog sr = new SearchResultsDialog<>(getMainFrame().getWindow(), txt, getActionPanel()); - sr.setResults(fActionResult); - sr.setVisible(true); - } - - if (!found) { - View.showMessageDialog(null, translate("message.search.notfound").replace("%searchtext%", txt), translate("message.search.notfound.title"), JOptionPane.INFORMATION_MESSAGE); - } - - Main.stopWork(); - }); - - return null; - } - - @Override - protected void done() { - View.execInEventDispatch(() -> { - Main.stopWork(); - }); - - } - }.execute(); - } else if (searchDialog.searchInTextsRadioButton.isSelected()) { - new CancellableWorker() { - @Override - protected Void doInBackground() throws Exception { - List textResult; - SearchPanel textSearchPanel = previewPanel.getTextPanel().getSearchPanel(); - textSearchPanel.setOptions(ignoreCase, regexp); - textResult = searchText(txt, ignoreCase, regexp, swf); - - List fTextResult = textResult; - View.execInEventDispatch(() -> { - textSearchPanel.setSearchText(txt); - boolean found = textSearchPanel.setResults(fTextResult); - if (!found) { - View.showMessageDialog(null, translate("message.search.notfound").replace("%searchtext%", txt), translate("message.search.notfound.title"), JOptionPane.INFORMATION_MESSAGE); - } - - Main.stopWork(); - }); - - return null; - } - - @Override - protected void done() { - View.execInEventDispatch(() -> { - Main.stopWork(); - }); - - } - }.execute(); - } - } - } - } - - public void replaceText() { - SearchDialog replaceDialog = new SearchDialog(getMainFrame().getWindow(), true); - if (replaceDialog.showDialog() == AppDialog.OK_OPTION) { - final String txt = replaceDialog.searchField.getText(); - if (!txt.isEmpty()) { - final SWF swf = getCurrentSwf(); - - new CancellableWorker() { - @Override - protected Void doInBackground() throws Exception { - int findCount = 0; - boolean ignoreCase = replaceDialog.ignoreCaseCheckBox.isSelected(); - boolean regexp = replaceDialog.regexpCheckBox.isSelected(); - String replacement = replaceDialog.replaceField.getText(); - if (!regexp) { - replacement = Matcher.quoteReplacement(replacement); - } - Pattern pat; - if (regexp) { - pat = Pattern.compile(txt, ignoreCase ? (Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE) : 0); - } else { - pat = Pattern.compile(Pattern.quote(txt), ignoreCase ? (Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE) : 0); - } - List textTags = new ArrayList<>(); - for (Tag tag : swf.getTags()) { - if (tag instanceof TextTag) { - textTags.add((TextTag) tag); - } - } - for (TextTag textTag : textTags) { - if (!replaceDialog.replaceInParametersCheckBox.isSelected()) { - List texts = textTag.getTexts(); - boolean found = false; - for (int i = 0; i < texts.size(); i++) { - String text = texts.get(i); - if (pat.matcher(text).find()) { - texts.set(i, text.replaceAll(txt, replacement)); - found = true; - findCount++; - } - } - if (found) { - String[] textArray = texts.toArray(new String[texts.size()]); - textTag.setFormattedText(getMissingCharacterHandler(), textTag.getFormattedText(false).text, textArray); - } - } else { - String text = textTag.getFormattedText(false).text; - if (pat.matcher(text).find()) { - textTag.setFormattedText(getMissingCharacterHandler(), text.replaceAll(txt, replacement), null); - findCount++; - } - } - } - - if (findCount > 0) { - swf.clearImageCache(); - repaintTree(); - } - - return null; - } - }.execute(); - } - } - } - - private List searchText(String txt, boolean ignoreCase, boolean regexp, SWF swf) { - if (txt != null && !txt.isEmpty()) { - List found = new ArrayList<>(); - Pattern pat; - if (regexp) { - pat = Pattern.compile(txt, ignoreCase ? (Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE) : 0); - } else { - pat = Pattern.compile(Pattern.quote(txt), ignoreCase ? (Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE) : 0); - } - for (Tag tag : swf.getTags()) { - if (tag instanceof TextTag) { - TextTag textTag = (TextTag) tag; - if (pat.matcher(textTag.getFormattedText(false).text).find()) { - found.add(textTag); - } - } - } - - return found; - } - - return null; - } - - @Override - public void updateSearchPos(TextTag item) { - setTagTreeSelectedNode(item); - previewPanel.getTextPanel().updateSearchPos(); - } - - private void setDumpTreeSelectedNode(DumpInfo dumpInfo) { - DumpTreeModel dtm = (DumpTreeModel) dumpTree.getModel(); - TreePath tp = dtm.getDumpInfoPath(dumpInfo); - if (tp != null) { - dumpTree.setSelectionPath(tp); - dumpTree.scrollPathToVisible(tp); - } else { - showCard(CARDEMPTYPANEL); - } - } - - public void setTagTreeSelectedNode(TreeItem treeItem) { - TagTreeModel ttm = tagTree.getModel(); - TreePath tp = ttm.getTreePath(treeItem); - if (tp != null) { - tagTree.setSelectionPath(tp); - tagTree.scrollPathToVisible(tp); - } else { - showCard(CARDEMPTYPANEL); - } - } - - public void autoDeobfuscateChanged() { - Helper.decompilationErrorAdd = AppStrings.translate(Configuration.autoDeobfuscate.get() ? "deobfuscation.comment.failed" : "deobfuscation.comment.tryenable"); - clearAllScriptCache(); - if (abcPanel != null) { - abcPanel.reload(); - } - reload(true); - updateClassesList(); - } - - public void renameColliding(final SWF swf) { - if (swf == null) { - return; - } - if (confirmExperimental()) { - new CancellableWorker() { - @Override - protected Integer doInBackground() throws Exception { - AbcMultiNameCollisionFixer fixer = new AbcMultiNameCollisionFixer(); - return fixer.fixCollisions(swf); - } - - @Override - protected void onStart() { - Main.startWork(translate("work.renaming.identifiers") + "...", this); - } - - @Override - protected void done() { - View.execInEventDispatch(() -> { - try { - int cnt = get(); - Main.stopWork(); - View.showMessageDialog(null, translate("message.rename.renamed").replace("%count%", Integer.toString(cnt))); - swf.assignClassesToSymbols(); - swf.clearScriptCache(); - if (abcPanel != null) { - abcPanel.reload(); - } - updateClassesList(); - reload(true); - } catch (Exception ex) { - logger.log(Level.SEVERE, "Error during renaming identifiers", ex); - Main.stopWork(); - View.showMessageDialog(null, translate("error.occured").replace("%error%", ex.getClass().getSimpleName())); - } - }); - } - }.execute(); - } - } - - public void renameOneIdentifier(final SWF swf) { - if (swf == null) { - return; - } - - FileAttributesTag fileAttributes = swf.getFileAttributes(); - if (fileAttributes != null && fileAttributes.actionScript3) { - final int multiName = getABCPanel().decompiledTextArea.getMultinameUnderCaret(); - final List abcList = swf.getAbcList(); - if (multiName > 0) { - new CancellableWorker() { - @Override - public Void doInBackground() throws Exception { - renameMultiname(abcList, multiName); - return null; - } - - @Override - protected void onStart() { - Main.startWork(translate("work.renaming") + "...", this); - } - - @Override - protected void done() { - Main.stopWork(); - } - }.execute(); - - } else { - View.showMessageDialog(null, translate("message.rename.notfound.multiname"), translate("message.rename.notfound.title"), JOptionPane.INFORMATION_MESSAGE); - } - } else { - final String identifier = getActionPanel().getStringUnderCursor(); - if (identifier != null) { - new CancellableWorker() { - @Override - public Void doInBackground() throws Exception { - try { - renameIdentifier(swf, identifier); - } catch (InterruptedException ex) { - logger.log(Level.SEVERE, null, ex); - } - return null; - } - - @Override - protected void onStart() { - Main.startWork(translate("work.renaming") + "...", this); - } - - @Override - protected void done() { - Main.stopWork(); - } - }.execute(); - } else { - View.showMessageDialog(null, translate("message.rename.notfound.identifier"), translate("message.rename.notfound.title"), JOptionPane.INFORMATION_MESSAGE); - } - } - } - - public void exportFla(final SWF swf) { - if (swf == null) { - return; - } - JFileChooser fc = new JFileChooser(); - String selDir = Configuration.lastOpenDir.get(); - fc.setCurrentDirectory(new File(selDir)); - if (!selDir.endsWith(File.separator)) { - selDir += File.separator; - } - String fileName = new File(swf.getFile()).getName(); - fileName = fileName.substring(0, fileName.length() - 4) + ".fla"; - fc.setSelectedFile(new File(selDir + fileName)); - List flaFilters = new ArrayList<>(); - List xflFilters = new ArrayList<>(); - List versions = new ArrayList<>(); - boolean isAS3 = swf.isAS3(); - for (int i = FLAVersion.values().length - 1; i >= 0; i--) { - final FLAVersion v = FLAVersion.values()[i]; - if (!isAS3 && v.minASVersion() > 2) { - // This version does not support AS1/2 - } else { - versions.add(v); - FileFilter f = new FileFilter() { - @Override - public boolean accept(File f) { - return f.isDirectory() || (f.getName().toLowerCase().endsWith(".fla")); - } - - @Override - public String getDescription() { - return translate("filter.fla").replace("%version%", v.applicationName()); - } - }; - if (v == FLAVersion.CS6) { - fc.setFileFilter(f); - } else { - fc.addChoosableFileFilter(f); - } - flaFilters.add(f); - f = new FileFilter() { - @Override - public boolean accept(File f) { - return f.isDirectory() || (f.getName().toLowerCase().endsWith(".xfl")); - } - - @Override - public String getDescription() { - return translate("filter.xfl").replace("%version%", v.applicationName()); - } - }; - fc.addChoosableFileFilter(f); - xflFilters.add(f); - } - } - - fc.setAcceptAllFileFilterUsed(false); - JFrame f = new JFrame(); - View.setWindowIcon(f); - if (fc.showSaveDialog(f) == JFileChooser.APPROVE_OPTION) { - Configuration.lastOpenDir.set(Helper.fixDialogFile(fc.getSelectedFile()).getParentFile().getAbsolutePath()); - File sf = Helper.fixDialogFile(fc.getSelectedFile()); - - FileFilter selectedFilter = fc.getFileFilter(); - final boolean compressed = flaFilters.contains(selectedFilter); - String path = sf.getAbsolutePath(); - if (path.endsWith(".fla") || path.endsWith(".xfl")) { - path = path.substring(0, path.length() - 4); - } - path += compressed ? ".fla" : ".xfl"; - final FLAVersion selectedVersion = versions.get(compressed ? flaFilters.indexOf(selectedFilter) : xflFilters.indexOf(selectedFilter)); - final File selfile = new File(path); - new CancellableWorker() { - @Override - protected Void doInBackground() throws Exception { - Helper.freeMem(); - try { - AbortRetryIgnoreHandler errorHandler = new GuiAbortRetryIgnoreHandler(); - if (compressed) { - swf.exportFla(errorHandler, selfile.getAbsolutePath(), new File(swf.getFile()).getName(), ApplicationInfo.APPLICATION_NAME, ApplicationInfo.applicationVerName, ApplicationInfo.version, Configuration.parallelSpeedUp.get(), selectedVersion); - } else { - swf.exportXfl(errorHandler, selfile.getAbsolutePath(), new File(swf.getFile()).getName(), ApplicationInfo.APPLICATION_NAME, ApplicationInfo.applicationVerName, ApplicationInfo.version, Configuration.parallelSpeedUp.get(), selectedVersion); - } - } catch (Exception ex) { - logger.log(Level.SEVERE, "FLA export error", ex); - View.showMessageDialog(null, translate("error.export") + ": " + ex.getClass().getName() + " " + ex.getLocalizedMessage(), translate("error"), JOptionPane.ERROR_MESSAGE); - } - Helper.freeMem(); - return null; - } - - @Override - protected void onStart() { - Main.startWork(translate("work.exporting.fla") + "...", this); - } - - @Override - protected void done() { - if (Configuration.openFolderAfterFlaExport.get()) { - try { - Desktop.getDesktop().open(selfile.getAbsoluteFile().getParentFile()); - } catch (IOException ex) { - logger.log(Level.SEVERE, null, ex); - } - } - - Main.stopWork(); - } - }.execute(); - } - } - - public void importText(final SWF swf) { - JFileChooser chooser = new JFileChooser(); - chooser.setCurrentDirectory(new File(Configuration.lastExportDir.get())); - chooser.setDialogTitle(translate("import.select.directory")); - chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); - chooser.setAcceptAllFileFilterUsed(false); - if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { - String selFile = Helper.fixDialogFile(chooser.getSelectedFile()).getAbsolutePath(); - File textsFile = new File(Path.combine(selFile, TextExportSettings.EXPORT_FOLDER_NAME, TextExporter.TEXT_EXPORT_FILENAME_FORMATTED)); - TextImporter textImporter = new TextImporter(getMissingCharacterHandler(), new TextImportErrorHandler() { - // "configuration items" for the current replace only - private final ConfigurationItem showAgainImportError = new ConfigurationItem<>("showAgainImportError", true, true); - - private final ConfigurationItem showAgainInvalidText = new ConfigurationItem<>("showAgainInvalidText", true, true); - - private String getTextTagInfo(TextTag textTag) { - StringBuilder ret = new StringBuilder(); - if (textTag != null) { - ret.append(" TextId: ").append(textTag.getCharacterId()).append(" (").append(String.join(", ", textTag.getTexts())).append(")"); - } - - return ret.toString(); - } - - @Override - public boolean handle(TextTag textTag) { - String msg = translate("error.text.import"); - logger.log(Level.SEVERE, msg + getTextTagInfo(textTag)); - return View.showConfirmDialog(MainPanel.this, msg, translate("error"), JOptionPane.OK_CANCEL_OPTION, showAgainImportError, JOptionPane.OK_OPTION) != JOptionPane.OK_OPTION; - } - - @Override - public boolean handle(TextTag textTag, String message, long line) { - String msg = translate("error.text.invalid.continue").replace("%text%", message).replace("%line%", Long.toString(line)); - logger.log(Level.SEVERE, msg + getTextTagInfo(textTag)); - return View.showConfirmDialog(MainPanel.this, msg, translate("error"), JOptionPane.OK_CANCEL_OPTION, showAgainInvalidText, JOptionPane.OK_OPTION) != JOptionPane.OK_OPTION; - } - }); - - // try to import formatted texts - if (textsFile.exists()) { - textImporter.importTextsSingleFileFormatted(textsFile, swf); - } else { - textsFile = new File(Path.combine(selFile, TextExportSettings.EXPORT_FOLDER_NAME, TextExporter.TEXT_EXPORT_FILENAME_PLAIN)); - // try to import plain texts - if (textsFile.exists()) { - textImporter.importTextsSingleFile(textsFile, swf); - } else { - textImporter.importTextsMultipleFiles(selFile, swf); - } - } - - swf.clearImageCache(); - reload(true); - } - } - - public As3ScriptReplacerInterface getAs3ScriptReplacer() { - As3ScriptReplacerInterface r = As3ScriptReplacerFactory.createByConfig(); - if (!r.isAvailable()) { - if (r instanceof MxmlcAs3ScriptReplacer) { - if (View.showConfirmDialog(null, AppStrings.translate("message.flexpath.notset"), AppStrings.translate("error"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.OK_OPTION) { - Main.advancedSettings("paths"); - } - } else if (r instanceof FFDecAs3ScriptReplacer) { - if (View.showConfirmDialog(this, AppStrings.translate("message.playerpath.lib.notset"), AppStrings.translate("message.action.playerglobal.title"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.OK_OPTION) { - Main.advancedSettings("paths"); - } - } else { - //Not translated yet - just in case there are more Script replacers in the future. Unused now. - View.showConfirmDialog(this, "Current script replacer is not available", "Script replacer not available", JOptionPane.OK_OPTION, JOptionPane.ERROR_MESSAGE); - } - return null; - } - return r; - } - - public void importScript(final SWF swf) { - As3ScriptReplacerInterface as3ScriptReplacer = getAs3ScriptReplacer(); - if (as3ScriptReplacer == null) { - return; - } - String flexLocation = Configuration.flexSdkLocation.get(); - JFileChooser chooser = new JFileChooser(); - chooser.setCurrentDirectory(new File(Configuration.lastExportDir.get())); - chooser.setDialogTitle(translate("import.select.directory")); - chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); - chooser.setAcceptAllFileFilterUsed(false); - if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { - String selFile = Helper.fixDialogFile(chooser.getSelectedFile()).getAbsolutePath(); - String scriptsFolder = Path.combine(selFile, ScriptExportSettings.EXPORT_FOLDER_NAME); - - int countAs2 = new AS2ScriptImporter().importScripts(scriptsFolder, swf.getASMs(true)); - int countAs3 = new AS3ScriptImporter().importScripts(as3ScriptReplacer, scriptsFolder, swf.getAS3Packs()); - - if (countAs3 > 0) { - updateClassesList(); - } - - View.showMessageDialog(this, translate("import.script.result").replace("%count%", Integer.toString(countAs2 + countAs3))); - if (countAs2 != 0 || countAs3 != 0) { - reload(true); - } - } - } - - public void importSymbolClass(final SWF swf) { - JFileChooser chooser = new JFileChooser(); - chooser.setCurrentDirectory(new File(Configuration.lastExportDir.get())); - chooser.setDialogTitle(translate("import.select.directory")); - chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); - chooser.setAcceptAllFileFilterUsed(false); - if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { - String selFile = Helper.fixDialogFile(chooser.getSelectedFile()).getAbsolutePath(); - File importFile = new File(Path.combine(selFile, SymbolClassExporter.SYMBOL_CLASS_EXPORT_FILENAME)); - SymbolClassImporter importer = new SymbolClassImporter(); - - if (importFile.exists()) { - importer.importSymbolClasses(importFile, swf); - } - } - } - - private String selectExportDir() { - JFileChooser chooser = new JFileChooser(); - chooser.setCurrentDirectory(new File(Configuration.lastExportDir.get())); - chooser.setDialogTitle(translate("export.select.directory")); - chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); - chooser.setAcceptAllFileFilterUsed(false); - if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { - final String selFile = Helper.fixDialogFile(chooser.getSelectedFile()).getAbsolutePath(); - Configuration.lastExportDir.set(Helper.fixDialogFile(chooser.getSelectedFile()).getAbsolutePath()); - return selFile; - } - return null; - } - - public void export(final boolean onlySel) { - - final SWF swf = getCurrentSwf(); - List sel = tagTree.getAllSelected(); - if (!onlySel) { - sel = null; - } else if (sel.isEmpty()) { - return; - } - final ExportDialog export = new ExportDialog(sel); - if (export.showExportDialog() == AppDialog.OK_OPTION) { - final String selFile = selectExportDir(); - if (selFile != null) { - final long timeBefore = System.currentTimeMillis(); - - new CancellableWorker() { - @Override - public Void doInBackground() throws Exception { - try { - AbortRetryIgnoreHandler errorHandler = new GuiAbortRetryIgnoreHandler(); - if (onlySel) { - exportSelection(errorHandler, selFile, export); - } else { - exportAll(swf, errorHandler, selFile, export); - } - } catch (Exception ex) { - logger.log(Level.SEVERE, "Error during export", ex); - View.showMessageDialog(null, translate("error.export") + ": " + ex.getClass().getName() + " " + ex.getLocalizedMessage()); - } - return null; - } - - @Override - protected void onStart() { - Main.startWork(translate("work.exporting") + "...", this); - } - - @Override - protected void done() { - Main.stopWork(); - long timeAfter = System.currentTimeMillis(); - final long timeMs = timeAfter - timeBefore; - - View.execInEventDispatchLater(() -> { - setStatus(translate("export.finishedin").replace("%time%", Helper.formatTimeSec(timeMs))); - }); - } - }.execute(); - - } - } - } - - public void exportJavaSource() { - List sel = tagTree.getSelected(); - for (TreeItem item : sel) { - if (item instanceof SWF) { - SWF swf = (SWF) item; - final String selFile = selectExportDir(); - if (selFile != null) { - Main.startWork(translate("work.exporting") + "...", null); - - try { - new SwfJavaExporter().exportJavaCode(swf, selFile); - Main.stopWork(); - } catch (IOException ex) { - logger.log(Level.SEVERE, null, ex); - } - } - } - } - } - - public void exportSwfXml() { - List sel = tagTree.getSelected(); - Set swfs = new HashSet<>(); - - for (TreeItem item : sel) { - swfs.add(item.getSwf()); - } - - for (SWF swf : swfs) { - final String selFile = selectExportDir(); - if (selFile != null) { - Main.startWork(translate("work.exporting") + "...", null); - - try { - File outFile = new File(selFile + File.separator + Helper.makeFileName("swf.xml")); - new SwfXmlExporter().exportXml(swf, outFile); - Main.stopWork(); - } catch (IOException ex) { - logger.log(Level.SEVERE, null, ex); - } - } - } - } - - public void importSwfXml() { - List sel = tagTree.getSelected(); - Set swfs = new HashSet<>(); - for (TreeItem item : sel) { - swfs.add(item.getSwf()); - } - if (swfs.size() > 1) { - return; - } - - for (SWF swf : swfs) { - File selectedFile = showImportFileChooser("filter.xml|*.xml"); - if (selectedFile != null) { - File selfile = Helper.fixDialogFile(selectedFile); - String xml = Helper.readTextFile(selfile.getPath()); - try { - new SwfXmlImporter().importSwf(swf, xml); - swf.clearAllCache(); - swf.assignExportNamesToSymbols(); - swf.assignClassesToSymbols(); - refreshTree(swf); - } catch (IOException ex) { - logger.log(Level.SEVERE, null, ex); - } - } - } - } - - public void renameIdentifiers(final SWF swf) { - if (swf == null) { - return; - } - if (confirmExperimental()) { - RenameDialog renameDialog = new RenameDialog(); - if (renameDialog.showRenameDialog() == AppDialog.OK_OPTION) { - final RenameType renameType = renameDialog.getRenameType(); - new CancellableWorker() { - @Override - protected Integer doInBackground() throws Exception { - int cnt = swf.deobfuscateIdentifiers(renameType); - return cnt; - } - - @Override - protected void onStart() { - Main.startWork(translate("work.renaming.identifiers") + "...", this); - } - - @Override - protected void done() { - View.execInEventDispatch(() -> { - try { - int cnt = get(); - Main.stopWork(); - View.showMessageDialog(null, translate("message.rename.renamed").replace("%count%", Integer.toString(cnt))); - swf.assignClassesToSymbols(); - swf.clearScriptCache(); - if (abcPanel != null) { - abcPanel.reload(); - } - updateClassesList(); - reload(true); - } catch (Exception ex) { - logger.log(Level.SEVERE, "Error during renaming identifiers", ex); - Main.stopWork(); - View.showMessageDialog(null, translate("error.occured").replace("%error%", ex.getClass().getSimpleName())); - } - }); - } - }.execute(); - } - } - } - - public void deobfuscate() { - DeobfuscationDialog deobfuscationDialog = new DeobfuscationDialog(); - if (deobfuscationDialog.showDialog() == AppDialog.OK_OPTION) { - DeobfuscationLevel level = DeobfuscationLevel.getByLevel(deobfuscationDialog.codeProcessingLevel.getValue()); - new CancellableWorker() { - @Override - protected Void doInBackground() throws Exception { - try { - ABCPanel abcPanel = getABCPanel(); - if (deobfuscationDialog.processAllCheckbox.isSelected()) { - SWF swf = abcPanel.getSwf(); - swf.deobfuscate(level); - } else { - int bi = abcPanel.detailPanel.methodTraitPanel.methodCodePanel.getBodyIndex(); - DecompiledEditorPane decompiledTextArea = abcPanel.decompiledTextArea; - Trait t = abcPanel.decompiledTextArea.getCurrentTrait(); - ABC abc = abcPanel.abc; - if (bi != -1) { - int scriptIndex = decompiledTextArea.getScriptLeaf().scriptIndex; - int classIndex = decompiledTextArea.getClassIndex(); - boolean isStatic = decompiledTextArea.getIsStatic(); - abc.bodies.get(bi).deobfuscate(level, t, scriptIndex, classIndex, isStatic, ""/*FIXME*/); - } - abcPanel.detailPanel.methodTraitPanel.methodCodePanel.setBodyIndex(decompiledTextArea.getScriptLeaf().getPathScriptName(), bi, abc, t, abcPanel.detailPanel.methodTraitPanel.methodCodePanel.getScriptIndex()); - } - } catch (Exception ex) { - logger.log(Level.SEVERE, "Deobfuscation error", ex); - } - - return null; - } - - @Override - protected void onStart() { - Main.startWork(translate("work.deobfuscating") + "...", this); - } - - @Override - protected void done() { - View.execInEventDispatch(() -> { - Main.stopWork(); - View.showMessageDialog(null, translate("work.deobfuscating.complete")); - - clearAllScriptCache(); - getABCPanel().reload(); - updateClassesList(); - }); - } - }.execute(); - } - } - - public void removeNonScripts(SWF swf) { - if (swf == null) { - return; - } - - List tags = swf.getTags().toArrayList(); - List toRemove = new ArrayList<>(); - for (Tag tag : tags) { - System.out.println(tag.getClass()); - if (!(tag instanceof ABCContainerTag || tag instanceof ASMSource)) { - toRemove.add(tag); - } - } - - swf.removeTags(toRemove, true); - refreshTree(swf); - } - - public void removeExceptSelected(SWF swf) { - if (swf == null) { - return; - } - - List sel = tagTree.getAllSelected(); - Set needed = new HashSet<>(); - for (TreeItem item : sel) { - if (item instanceof CharacterTag) { - CharacterTag characterTag = (CharacterTag) item; - characterTag.getNeededCharactersDeep(needed); - needed.add(characterTag.getCharacterId()); - } - } - - List tagsToRemove = new ArrayList<>(); - for (Tag tag : swf.getTags()) { - if (tag instanceof CharacterTag) { - CharacterTag characterTag = (CharacterTag) tag; - if (!needed.contains(characterTag.getCharacterId())) { - tagsToRemove.add(tag); - } - } - } - - swf.removeTags(tagsToRemove, true); - refreshTree(swf); - } - - private void clear() { - dumpViewPanel.clear(); - previewPanel.clear(); - headerPanel.clear(); - folderPreviewPanel.clear(); - if (abcPanel != null) { - abcPanel.clearSwf(); - } - if (actionPanel != null) { - actionPanel.clearSource(); - } - } - - public void refreshTree() { - refreshTree(new SWF[0]); - } - - public void refreshTree(SWF swf) { - refreshTree(new SWF[]{swf}); - } - - public void refreshTree(SWF[] swfs) { - clear(); - showCard(CARDEMPTYPANEL); - TreeItem treeItem = tagTree.getCurrentTreeItem(); - - tagTree.updateSwfs(swfs); - - if (treeItem != null) { - SWF treeItemSwf = treeItem.getSwf().getRootSwf(); - if (this.swfs.contains(treeItemSwf.swfList)) { - setTagTreeSelectedNode(treeItem); - } - } - - reload(true); - } - - public void refreshDecompiled() { - clearAllScriptCache(); - if (abcPanel != null) { - abcPanel.reload(); - } - - reload(true); - updateClassesList(); - } - - private MissingCharacterHandler getMissingCharacterHandler() { - return new MissingCharacterHandler() { - // "configuration items" for the current replace only - private final ConfigurationItem showAgainIgnoreMissingCharacters = new ConfigurationItem<>("showAgainIgnoreMissingCharacters", true, true); - - private boolean ignoreMissingCharacters = false; - - @Override - public boolean getIgnoreMissingCharacters() { - return ignoreMissingCharacters; - } - - @Override - public boolean handle(TextTag textTag, final FontTag font, final char character) { - String fontName = font.getSwf().sourceFontNamesMap.get(font.getFontId()); - if (fontName == null) { - fontName = font.getFontName(); - } - final Font f = FontTag.installedFontsByName.get(fontName); - if (f == null || !f.canDisplay(character)) { - String msg = translate("error.font.nocharacter").replace("%char%", "" + character); - logger.log(Level.SEVERE, "{0} FontId: {1} TextId: {2}", new Object[]{msg, font.getCharacterId(), textTag.getCharacterId()}); - ignoreMissingCharacters = View.showConfirmDialog(null, msg, translate("error"), - JOptionPane.OK_CANCEL_OPTION, JOptionPane.ERROR_MESSAGE, - showAgainIgnoreMissingCharacters, - ignoreMissingCharacters ? JOptionPane.OK_OPTION : JOptionPane.CANCEL_OPTION) == JOptionPane.OK_OPTION; - return false; - } - - font.addCharacter(character, f); - - return true; - } - }; - } - - public boolean saveText(TextTag textTag, String formattedText, String[] texts, LineMarkedEditorPane editor) { - try { - if (textTag.setFormattedText(getMissingCharacterHandler(), formattedText, texts)) { - return true; - } - } catch (TextParseException ex) { - if (editor != null) { - editor.gotoLine((int) ex.line); - editor.markError(); - } - - View.showMessageDialog(null, translate("error.text.invalid").replace("%text%", ex.text).replace("%line%", Long.toString(ex.line)), translate("error"), JOptionPane.ERROR_MESSAGE); - } - - return false; - } - - public boolean alignText(TextTag textTag, TextAlign textAlign) { - return (textTag.alignText(textAlign)); - } - - public boolean translateText(TextTag textTag, int diff) { - return textTag.translateText(diff); - } - - public boolean previousTag() { - if (getCurrentView() == VIEW_RESOURCES) { - if (tagTree.getSelectionRows().length > 0) { - int row = tagTree.getSelectionRows()[0]; - if (row > 0) { - tagTree.setSelectionRow(row - 1); - tagTree.scrollRowToVisible(row - 1); - previewPanel.focusTextPanel(); - } - } - return true; - } - return false; - } - - public boolean nextTag() { - if (getCurrentView() == VIEW_RESOURCES) { - if (tagTree.getSelectionRows().length > 0) { - int row = tagTree.getSelectionRows()[0]; - if (row < tagTree.getRowCount() - 1) { - tagTree.setSelectionRow(row + 1); - tagTree.scrollRowToVisible(row + 1); - previewPanel.focusTextPanel(); - } - } - return true; - } - return false; - } - - public void selectBkColorButtonActionPerformed(ActionEvent evt) { - Color newColor = JColorChooser.showDialog(null, AppStrings.translate("dialog.selectbkcolor.title"), View.getSwfBackgroundColor()); - if (newColor != null) { - View.setSwfBackgroundColor(newColor); - reload(true); - } - } - - public void replaceButtonActionPerformed(ActionEvent evt) { - TreeItem item = tagTree.getCurrentTreeItem(); - if (item == null) { - return; - } - - if (item instanceof DefineSoundTag) { - File selectedFile = showImportFileChooser("filter.sounds|*.mp3;*.wav|filter.sounds.mp3|*.mp3|filter.sounds.wav|*.wav"); - if (selectedFile != null) { - File selfile = Helper.fixDialogFile(selectedFile); - DefineSoundTag ds = (DefineSoundTag) item; - int soundFormat = SoundFormat.FORMAT_UNCOMPRESSED_LITTLE_ENDIAN; - if (selfile.getName().toLowerCase().endsWith(".mp3")) { - soundFormat = SoundFormat.FORMAT_MP3; - } - - boolean ok = false; - try { - ok = ds.setSound(new FileInputStream(selfile), soundFormat); - ds.getSwf().clearSoundCache(); - } catch (IOException ex) { - //ignore - } - - if (!ok) { - View.showMessageDialog(null, translate("error.sound.invalid"), translate("error"), JOptionPane.ERROR_MESSAGE); - } else { - reload(true); - } - } - } - if (item instanceof ImageTag) { - ImageTag it = (ImageTag) item; - if (it.importSupported()) { - File selectedFile = showImportFileChooser("filter.images|*.jpg;*.jpeg;*.gif;*.png;*.bmp"); - if (selectedFile != null) { - File selfile = Helper.fixDialogFile(selectedFile); - byte[] data = Helper.readFile(selfile.getAbsolutePath()); - try { - Tag newTag = new ImageImporter().importImage(it, data); - SWF swf = it.getSwf(); - if (newTag != null) { - refreshTree(swf); - setTagTreeSelectedNode(newTag); - } - swf.clearImageCache(); - } catch (IOException ex) { - logger.log(Level.SEVERE, "Invalid image", ex); - View.showMessageDialog(null, translate("error.image.invalid"), translate("error"), JOptionPane.ERROR_MESSAGE); - } - - reload(true); - } - } - } - if (item instanceof ShapeTag) { - ShapeTag st = (ShapeTag) item; - String filter = "filter.images|*.jpg;*.jpeg;*.gif;*.png;*.bmp;*.svg"; - File selectedFile = showImportFileChooser(filter); - if (selectedFile != null) { - File selfile = Helper.fixDialogFile(selectedFile); - byte[] data = null; - String svgText = null; - if (".svg".equals(Path.getExtension(selfile))) { - svgText = Helper.readTextFile(selfile.getAbsolutePath()); - showSvgImportWarning(); - } else { - data = Helper.readFile(selfile.getAbsolutePath()); - } - try { - Tag newTag = svgText != null ? new SvgImporter().importSvg(st, svgText) : new ShapeImporter().importImage(st, data); - SWF swf = st.getSwf(); - if (newTag != null) { - refreshTree(swf); - setTagTreeSelectedNode(newTag); - } - - swf.clearImageCache(); - } catch (IOException ex) { - logger.log(Level.SEVERE, "Invalid image", ex); - View.showMessageDialog(null, translate("error.image.invalid"), translate("error"), JOptionPane.ERROR_MESSAGE); - } - reload(true); - } - } - if (item instanceof DefineBinaryDataTag) { - DefineBinaryDataTag bt = (DefineBinaryDataTag) item; - File selectedFile = showImportFileChooser(""); - if (selectedFile != null) { - File selfile = Helper.fixDialogFile(selectedFile); - byte[] data = Helper.readFile(selfile.getAbsolutePath()); - new BinaryDataImporter().importData(bt, data); - refreshTree(bt.getSwf()); - reload(true); - } - } - } - - public void replaceNoFillButtonActionPerformed(ActionEvent evt) { - TreeItem item = tagTree.getCurrentTreeItem(); - if (item == null) { - return; - } - - if (item instanceof ShapeTag) { - ShapeTag st = (ShapeTag) item; - String filter = "filter.images|*.jpg;*.jpeg;*.gif;*.png;*.bmp;*.svg"; - File selectedFile = showImportFileChooser(filter); - if (selectedFile != null) { - File selfile = Helper.fixDialogFile(selectedFile); - byte[] data = null; - String svgText = null; - if (".svg".equals(Path.getExtension(selfile))) { - svgText = Helper.readTextFile(selfile.getAbsolutePath()); - showSvgImportWarning(); - } else { - data = Helper.readFile(selfile.getAbsolutePath()); - } - try { - Tag newTag = svgText != null ? new SvgImporter().importSvg(st, svgText, false) : new ShapeImporter().importImage(st, data, 0, false); - SWF swf = st.getSwf(); - if (newTag != null) { - refreshTree(swf); - setTagTreeSelectedNode(newTag); - } - - swf.clearImageCache(); - } catch (IOException ex) { - logger.log(Level.SEVERE, "Invalid image", ex); - View.showMessageDialog(null, translate("error.image.invalid"), translate("error"), JOptionPane.ERROR_MESSAGE); - } - reload(true); - } - } - } - - private void showSvgImportWarning() { - View.showMessageDialog(null, AppStrings.translate("message.warning.svgImportExperimental"), AppStrings.translate("message.warning"), JOptionPane.WARNING_MESSAGE, Configuration.warningSvgImport); - } - - public void replaceAlphaButtonActionPerformed(ActionEvent evt) { - TreeItem item = tagTree.getCurrentTreeItem(); - if (item == null) { - return; - } - - if (item instanceof DefineBitsJPEG3Tag || item instanceof DefineBitsJPEG4Tag) { - ImageTag it = (ImageTag) item; - if (it.importSupported()) { - File selectedFile = showImportFileChooser(""); - if (selectedFile != null) { - File selfile = Helper.fixDialogFile(selectedFile); - byte[] data = Helper.readFile(selfile.getAbsolutePath()); - try { - new ImageImporter().importImageAlpha(it, data); - SWF swf = it.getSwf(); - swf.clearImageCache(); - } catch (IOException ex) { - logger.log(Level.SEVERE, "Invalid alpha channel data", ex); - View.showMessageDialog(null, translate("error.image.alpha.invalid"), translate("error"), JOptionPane.ERROR_MESSAGE); - } - - reload(true); - } - } - } - } - - public void exportJavaSourceActionPerformed(ActionEvent evt) { - if (Main.isWorking()) { - return; - } - - exportJavaSource(); - } - - public void exportSwfXmlActionPerformed(ActionEvent evt) { - if (Main.isWorking()) { - return; - } - - exportSwfXml(); - } - - public void importSwfXmlActionPerformed(ActionEvent evt) { - if (Main.isWorking()) { - return; - } - - importSwfXml(); - } - - public void exportSelectionActionPerformed(ActionEvent evt) { - if (Main.isWorking()) { - return; - } - - export(true); - } - - public File showImportFileChooser(String filter) { - String[] filterArray = filter.length() > 0 ? filter.split("\\|") : new String[0]; - - JFileChooser fc = new JFileChooser(); - fc.setCurrentDirectory(new File(Configuration.lastOpenDir.get())); - boolean first = true; - for (int i = 0; i < filterArray.length; i += 2) { - final String filterName = filterArray[i]; - final String[] extensions = filterArray[i + 1].split(";"); - for (int j = 0; j < extensions.length; j++) { - if (extensions[j].startsWith("*.")) { - extensions[j] = extensions[j].substring(1); - } - } - FileFilter ff = new FileFilter() { - @Override - public boolean accept(File f) { - if (f.isDirectory()) { - return true; - } - String fileName = f.getName().toLowerCase(); - for (String ext : extensions) { - if (fileName.endsWith(ext)) { - return true; - } - } - return false; - } - - @Override - public String getDescription() { - StringBuilder extStr = new StringBuilder(); - boolean first = true; - for (String ext : extensions) { - if (first) { - first = false; - } else { - extStr.append(","); - } - - extStr.append("*").append(ext); - } - - return translate(filterName).replace("%extensions%", extStr); - } - }; - if (first) { - fc.setFileFilter(ff); - } else { - fc.addChoosableFileFilter(ff); - } - first = false; - } - - JFrame f = new JFrame(); - View.setWindowIcon(f); - if (fc.showOpenDialog(f) == JFileChooser.APPROVE_OPTION) { - File result = fc.getSelectedFile(); - Configuration.lastOpenDir.set(Helper.fixDialogFile(result).getParentFile().getAbsolutePath()); - return result; - } - - return null; - } - - private void showDetail(String card) { - CardLayout cl = (CardLayout) (detailPanel.getLayout()); - cl.show(detailPanel, card); - if (card.equals(DETAILCARDEMPTYPANEL)) { - if (detailPanel.isVisible()) { - detailPanel.setVisible(false); - } - } else if (!detailPanel.isVisible()) { - detailPanel.setVisible(true); - } - } - - private void showCard(String card) { - CardLayout cl = (CardLayout) (displayPanel.getLayout()); - cl.show(displayPanel, card); - } - - @Override - public void valueChanged(TreeSelectionEvent e) { - Object source = e.getSource(); - TreeItem treeItem = (TreeItem) e.getPath().getLastPathComponent(); - - if (!(treeItem instanceof SWFList)) { - SWF swf = treeItem.getSwf(); - if (swfs.isEmpty()) { - // show welcome panel after closing swfs - updateUi(); - } else { - if (swf == null) { - swf = swfs.get(0).get(0); - } - - updateUi(swf); - } - } else { - updateUi(); - } - - reload(false); - - if (source == dumpTree) { - Tag t = null; - if (treeItem instanceof DumpInfo) { - DumpInfo di = (DumpInfo) treeItem; - t = di.getTag(); - } - - showPreview(t, dumpPreviewPanel); - } - } - - public void unloadFlashPlayer() { - if (flashPanel != null) { - try { - flashPanel.close(); - } catch (IOException ex) { - // ignore - } - } - if (flashPanel2 != null) { - try { - flashPanel2.close(); - } catch (IOException ex) { - // ignore - } - } - } - - public void clearDebuggerColors() { - if (abcPanel != null) { - abcPanel.decompiledTextArea.removeColorMarkerOnAllLines(DecompiledEditorPane.IP_MARKER); - abcPanel.detailPanel.methodTraitPanel.methodCodePanel.clearDebuggerColors(); - } - if (actionPanel != null) { - actionPanel.decompiledEditor.removeColorMarkerOnAllLines(DecompiledEditorPane.IP_MARKER); - actionPanel.editor.removeColorMarkerOnAllLines(DecompiledEditorPane.IP_MARKER); - } - } - - private void stopFlashPlayer() { - if (flashPanel != null) { - if (!flashPanel.isStopped()) { - flashPanel.stopSWF(); - } - } - if (flashPanel2 != null) { - if (!flashPanel2.isStopped()) { - flashPanel2.stopSWF(); - } - } - } - - public boolean isInternalFlashViewerSelected() { - return mainMenu.isInternalFlashViewerSelected(); - } - - public static final int VIEW_RESOURCES = 0; - - public static final int VIEW_DUMP = 1; - - public static final int VIEW_TIMELINE = 2; - - private int getCurrentView() { - return Configuration.dumpView.get() ? VIEW_DUMP : VIEW_RESOURCES; - } - - public void setTreeModel(int view) { - switch (view) { - case VIEW_DUMP: - if (dumpTree.getModel() == null) { - DumpTreeModel dtm = new DumpTreeModel(swfs); - dumpTree.setModel(dtm); - dumpTree.expandFirstLevelNodes(); - } - break; - case VIEW_RESOURCES: - if (tagTree.getModel() == null) { - TagTreeModel ttm = new TagTreeModel(swfs, Configuration.tagTreeShowEmptyFolders.get()); - tagTree.setModel(ttm); - tagTree.expandFirstLevelNodes(); - } - break; - } - } - - private JPanel createDumpViewCard() { - JPanel r = new JPanel(new BorderLayout()); - r.add(new JPersistentSplitPane(JSplitPane.VERTICAL_SPLIT, new JScrollPane(dumpTree), dumpPreviewPanel, Configuration.guiDumpSplitPaneDividerLocationPercent), BorderLayout.CENTER); - return r; - } - - private JPanel createResourcesViewCard() { - JPanel r = new JPanel(new BorderLayout()); - r.add(new JScrollPane(tagTree), BorderLayout.CENTER); - r.add(searchPanel, BorderLayout.SOUTH); - return r; - } - - public boolean showView(int view) { - - CardLayout cl = (CardLayout) (contentPanel.getLayout()); - CardLayout cl2 = (CardLayout) (treePanel.getLayout()); - - setTreeModel(view); - switch (view) { - case VIEW_DUMP: - if (!isWelcomeScreen) { - cl.show(contentPanel, SPLIT_PANE1); - } - cl2.show(treePanel, DUMP_VIEW); - treePanelMode = TreePanelMode.DUMP_TREE; - showDetail(DETAILCARDEMPTYPANEL); - reload(true); - return true; - case VIEW_RESOURCES: - if (!isWelcomeScreen) { - cl.show(contentPanel, SPLIT_PANE1); - } - cl2.show(treePanel, RESOURCES_VIEW); - - treePanelMode = TreePanelMode.TAG_TREE; - - treePanel.addComponentListener(new ComponentAdapter() { - @Override - public void componentResized(ComponentEvent e) { - tagTree.scrollPathToVisible(tagTree.getSelectionPath()); - } - }); - - reload(true); - return true; - case VIEW_TIMELINE: - final SWF swf = getCurrentSwf(); - if (swf != null) { - TreeItem item = tagTree.getCurrentTreeItem(); - if (item instanceof TagScript) { - item = ((TagScript) item).getTag(); - } - if (item instanceof Timelined) { - timelineViewPanel.setTimelined((Timelined) item); - } else if (item instanceof Frame) { - timelineViewPanel.setTimelined(((Frame) item).timeline.timelined); - } else { - timelineViewPanel.setTimelined(swf); - } - cl.show(contentPanel, TIMELINE_PANEL); - return true; - } - return false; - } - return false; - - } - - private void dumpViewReload(boolean forceReload) { - showDetail(DETAILCARDEMPTYPANEL); - - DumpInfo dumpInfo = (DumpInfo) dumpTree.getLastSelectedPathComponent(); - if (dumpInfo == null) { - showCard(CARDEMPTYPANEL); - return; - } - - dumpViewPanel.revalidate(); - dumpViewPanel.setSelectedNode(dumpInfo); - showCard(CARDDUMPVIEW); - } - - public void loadFromBinaryTag(final DefineBinaryDataTag binaryDataTag) { - loadFromBinaryTag(Arrays.asList(binaryDataTag)); - } - - public void loadFromBinaryTag(final List binaryDataTags) { - - Main.loadingDialog.setVisible(true); - new CancellableWorker() { - @Override - protected Void doInBackground() throws Exception { - try { - for (DefineBinaryDataTag binaryDataTag : binaryDataTags) { - try { - InputStream is = new ByteArrayInputStream(binaryDataTag.binaryData.getRangeData()); - SWF bswf = new SWF(is, null, "(SWF Data)", new ProgressListener() { - @Override - public void progress(int p) { - Main.loadingDialog.setPercent(p); - } - }, Configuration.parallelSpeedUp.get()); - binaryDataTag.innerSwf = bswf; - bswf.binaryData = binaryDataTag; - } catch (IOException ex) { - //ignore - } - } - } catch (InterruptedException ex) { - //ignore - } - - return null; - } - - @Override - protected void onStart() { - Main.startWork(AppStrings.translate("work.reading.swf") + "...", this); - } - - @Override - protected void done() { - View.execInEventDispatch(() -> { - Main.loadingDialog.setVisible(false); - Main.stopWork(); - }); - } - }.execute(); - } - - private void closeTag() { - previewPanel.closeTag(); - } - - public void showPreview(TreeItem treeItem, PreviewPanel previewPanel) { - previewPanel.clear(); - if (treeItem == null) { - previewPanel.showEmpty(); - return; - } - boolean internalViewer = isInternalFlashViewerSelected(); - if (treeItem instanceof SWF) { - SWF swf = (SWF) treeItem; - if (internalViewer) { - previewPanel.showImagePanel(swf, swf, -1); - } else { - previewPanel.setParametersPanelVisible(false); - if (flashPanel != null) { //same for flashPanel2 - previewPanel.showFlashViewerPanel(); - previewPanel.showSwf(swf); - } - } - } else if (treeItem instanceof MetadataTag) { - MetadataTag metadataTag = (MetadataTag) treeItem; - previewPanel.showMetaDataPanel(metadataTag); - } else if (treeItem instanceof DefineBinaryDataTag) { - DefineBinaryDataTag binaryTag = (DefineBinaryDataTag) treeItem; - previewPanel.showBinaryPanel(binaryTag); - } else if (treeItem instanceof ImageTag) { - ImageTag imageTag = (ImageTag) treeItem; - previewPanel.setImageReplaceButtonVisible(!((Tag) imageTag).isReadOnly() && imageTag.importSupported(), imageTag instanceof DefineBitsJPEG3Tag || imageTag instanceof DefineBitsJPEG4Tag); - previewPanel.showImagePanel(imageTag.getImageCached()); - - } else if ((treeItem instanceof DrawableTag) && (!(treeItem instanceof TextTag)) && (!(treeItem instanceof FontTag)) && internalViewer) { - final Tag tag = (Tag) treeItem; - DrawableTag d = (DrawableTag) tag; - Timelined timelined; - if (treeItem instanceof Timelined && !(treeItem instanceof ButtonTag)) { - timelined = (Timelined) tag; - } else { - timelined = makeTimelined(tag); - } - - previewPanel.setParametersPanelVisible(false); - previewPanel.showImagePanel(timelined, tag.getSwf(), -1); - } else if (treeItem instanceof Frame && internalViewer) { - Frame fn = (Frame) treeItem; - SWF swf = fn.getSwf(); - previewPanel.showImagePanel(fn.timeline.timelined, swf, fn.frame); - } else if ((treeItem instanceof SoundTag)) { //&& isInternalFlashViewerSelected() && (Arrays.asList("mp3", "wav").contains(((SoundTag) tagObj).getExportFormat())))) { - previewPanel.showImagePanel(new SerializableImage(View.loadImage("sound32"))); - previewPanel.setImageReplaceButtonVisible(((Tag) treeItem).isReadOnly() && (treeItem instanceof DefineSoundTag), false); - try { - SoundTagPlayer soundThread = new SoundTagPlayer((SoundTag) treeItem, Configuration.loopMedia.get() ? Integer.MAX_VALUE : 1, true); - previewPanel.setMedia(soundThread); - } catch (LineUnavailableException | IOException | UnsupportedAudioFileException ex) { - logger.log(Level.SEVERE, null, ex); - } - - } else if ((treeItem instanceof FontTag) && internalViewer) { - previewPanel.showFontPanel((FontTag) treeItem); - } else if ((treeItem instanceof TextTag) && internalViewer) { - previewPanel.showTextPanel((TextTag) treeItem); - } else if ((treeItem instanceof Frame) || (treeItem instanceof CharacterTag) || (treeItem instanceof FontTag) || (treeItem instanceof SoundStreamHeadTypeTag)) { - previewPanel.createAndShowTempSwf(treeItem); - - if (treeItem instanceof TextTag) { - previewPanel.showTextPanel((TextTag) treeItem); - } else if (treeItem instanceof FontTag) { - previewPanel.showFontPanel((FontTag) treeItem); - } else { - previewPanel.setParametersPanelVisible(false); - } - } else { - previewPanel.showEmpty(); - } - } - - public void reload(boolean forceReload) { - tagTree.scrollPathToVisible(tagTree.getSelectionPath()); - if (Configuration.dumpView.get()) { - dumpViewReload(forceReload); - return; - } - - TreeItem treeItem = null; - TreePath treePath = tagTree.getSelectionPath(); - if (treePath != null && tagTree.getModel().treePathExists(treePath)) { - treeItem = (TreeItem) treePath.getLastPathComponent(); - } - - // save last selected node to config - if (treeItem != null) { - SWF swf = treeItem.getSwf(); - if (swf != null) { - swf = swf.getRootSwf(); - } - - if (swf != null) { - SwfSpecificConfiguration swfConf = Configuration.getOrCreateSwfSpecificConfiguration(swf.getShortFileName()); - swfConf.lastSelectedPath = tagTree.getSelectionPathString(); - } - } - - if (!forceReload && (treeItem == oldItem)) { - return; - } - - if (oldItem != treeItem) { - closeTag(); - } - - oldItem = treeItem; - - // show the preview of the tag when the user clicks to the tagname inside the scripts node, too - // this is a little bit inconsistent, beacuse the frames (FrameScript) are not shown - boolean preferScript = false; - if (treeItem instanceof TagScript) { - treeItem = ((TagScript) treeItem).getTag(); - preferScript = true; - } - - folderPreviewPanel.clear(); - previewPanel.clear(); - stopFlashPlayer(); - - previewPanel.setImageReplaceButtonVisible(false, false); - - boolean internalViewer = isInternalFlashViewerSelected(); - - if (treeItem instanceof ScriptPack) { - final ScriptPack scriptLeaf = (ScriptPack) treeItem; - if (setSourceWorker != null) { - setSourceWorker.cancel(true); - setSourceWorker = null; - } - if (!Main.isInited() || !Main.isWorking() || Main.isDebugging()) { - ABCPanel abcPanel = getABCPanel(); - CancellableWorker worker = new CancellableWorker() { - @Override - protected Void doInBackground() throws Exception { - abcPanel.detailPanel.methodTraitPanel.methodCodePanel.clear(); - abcPanel.setAbc(scriptLeaf.abc); - abcPanel.decompiledTextArea.setScript(scriptLeaf, true); - abcPanel.decompiledTextArea.setNoTrait(); - return null; - } - - @Override - protected void onStart() { - Main.startWork(translate("work.decompiling") + "...", this); - } - - @Override - protected void done() { - View.execInEventDispatch(() -> { - setSourceWorker = null; - try { - get(); - } catch (CancellationException ex) { - abcPanel.decompiledTextArea.setText("// " + AppStrings.translate("work.canceled")); - } catch (Exception ex) { - logger.log(Level.SEVERE, "Error", ex); - getABCPanel().decompiledTextArea.setText("// " + AppStrings.translate("decompilationError") + ": " + ex); - } - - Main.stopWork(); - }); - } - }; - - worker.execute(); - setSourceWorker = worker; - } - - showDetail(DETAILCARDAS3NAVIGATOR); - showCard(CARDACTIONSCRIPT3PANEL); - return; - } - - if (treeItem instanceof Tag) { - Tag tag = (Tag) treeItem; - TagInfo tagInfo = new TagInfo(); - tag.getTagInfo(tagInfo); - if (!tagInfo.isEmpty()) { - tagInfoPanel.setTagInfos(tagInfo); - showDetail(DETAILCARDTAGINFO); - } else { - showDetail(DETAILCARDEMPTYPANEL); - } - } else { - showDetail(DETAILCARDEMPTYPANEL); - } - - if (treeItem instanceof HeaderItem) { - headerPanel.load(((HeaderItem) treeItem).getSwf()); - showCard(CARDHEADER); - } else if (treeItem instanceof FolderItem) { - showFolderPreview((FolderItem) treeItem); - } else if (treeItem instanceof SWF) { - showPreview(treeItem, previewPanel); - showCard(CARDPREVIEWPANEL); - } else if (treeItem instanceof MetadataTag) { - showPreview(treeItem, previewPanel); - showCard(CARDPREVIEWPANEL); - } else if (treeItem instanceof DefineBinaryDataTag) { - showPreview(treeItem, previewPanel); - showCard(CARDPREVIEWPANEL); - } else if (treeItem instanceof ASMSource && (!(treeItem instanceof DrawableTag) || preferScript)) { - getActionPanel().setSource((ASMSource) treeItem, !forceReload); - showCard(CARDACTIONSCRIPTPANEL); - } else if (treeItem instanceof ImageTag) { - showPreview(treeItem, previewPanel); - showCard(CARDPREVIEWPANEL); - } else if ((treeItem instanceof DrawableTag) && (!(treeItem instanceof TextTag)) && (!(treeItem instanceof FontTag)) && internalViewer) { - showPreview(treeItem, previewPanel); - showCard(CARDPREVIEWPANEL); - } else if ((treeItem instanceof FontTag) && internalViewer) { - showPreview(treeItem, previewPanel); - showCard(CARDPREVIEWPANEL); - } else if ((treeItem instanceof TextTag) && internalViewer) { - showPreview(treeItem, previewPanel); - showCard(CARDPREVIEWPANEL); - } else if (treeItem instanceof Frame && internalViewer) { - showPreview(treeItem, previewPanel); - showCard(CARDPREVIEWPANEL); - } else if ((treeItem instanceof SoundTag)) { //&& isInternalFlashViewerSelected() && (Arrays.asList("mp3", "wav").contains(((SoundTag) tagObj).getExportFormat())))) { - showPreview(treeItem, previewPanel); - showCard(CARDPREVIEWPANEL); - } else if ((treeItem instanceof Frame) || (treeItem instanceof CharacterTag) || (treeItem instanceof FontTag) || (treeItem instanceof SoundStreamHeadTypeTag)) { - showPreview(treeItem, previewPanel); - - showCard(CARDPREVIEWPANEL); - } else if (treeItem instanceof Tag) { - showGenericTag((Tag) treeItem); - } else { - showCard(CARDEMPTYPANEL); - } - } - - public void repaintTree() { - tagTree.repaint(); - reload(true); - } - - public void showGenericTag(Tag tag) { - previewPanel.showGenericTagPanel(tag); - showCard(CARDPREVIEWPANEL); - } - - public void showTextTagWithNewValue(TextTag textTag, TextTag newTextTag) { - - previewPanel.showTextComparePanel(textTag, newTextTag); - } - - private void showFolderPreview(FolderItem item) { - List folderPreviewItems = new ArrayList<>(); - String folderName = item.getName(); - SWF swf = item.swf; - switch (folderName) { - case TagTreeModel.FOLDER_SHAPES: - for (Tag tag : swf.getTags()) { - if (tag instanceof ShapeTag) { - folderPreviewItems.add(tag); - } - } - break; - case TagTreeModel.FOLDER_MORPHSHAPES: - for (Tag tag : swf.getTags()) { - if (tag instanceof MorphShapeTag) { - folderPreviewItems.add(tag); - } - } - break; - case TagTreeModel.FOLDER_SPRITES: - for (Tag tag : swf.getTags()) { - if (tag instanceof DefineSpriteTag) { - folderPreviewItems.add(tag); - } - } - break; - case TagTreeModel.FOLDER_BUTTONS: - for (Tag tag : swf.getTags()) { - if (tag instanceof ButtonTag) { - folderPreviewItems.add(tag); - } - } - break; - case TagTreeModel.FOLDER_FONTS: - for (Tag tag : swf.getTags()) { - if (tag instanceof FontTag) { - folderPreviewItems.add(tag); - } - } - break; - case TagTreeModel.FOLDER_FRAMES: - for (Frame frame : swf.getTimeline().getFrames()) { - folderPreviewItems.add(frame); - } - break; - case TagTreeModel.FOLDER_IMAGES: - for (Tag tag : swf.getTags()) { - if (tag instanceof ImageTag) { - folderPreviewItems.add(tag); - } - } - break; - case TagTreeModel.FOLDER_TEXTS: - for (Tag tag : swf.getTags()) { - if (tag instanceof TextTag) { - folderPreviewItems.add(tag); - } - } - break; - } - - folderPreviewPanel.setItems(folderPreviewItems); - showCard(CARDFOLDERPREVIEWPANEL); - } - - private boolean isFreeing; - - @Override - public boolean isFreeing() { - return isFreeing; - } - - @Override - public void free() { - isFreeing = true; - } - - public void setErrorState(ErrorState errorState) { - statusPanel.setErrorState(errorState); - } - - public static Timelined makeTimelined(final Tag tag) { - return makeTimelined(tag, -1); - } - - public static Timelined makeTimelined(final Tag tag, final int fontFrameNum) { - - return new Timelined() { - private Timeline tim; - - @Override - public Timeline getTimeline() { - if (tim == null) { - Timeline timeline = new Timeline(tag.getSwf(), this, ((CharacterTag) tag).getCharacterId(), getRect()); - initTimeline(timeline); - tim = timeline; - } - - return tim; - } - - @Override - public void resetTimeline() { - if (tim != null) { - tim.reset(tag.getSwf(), this, ((CharacterTag) tag).getCharacterId(), getRect()); - initTimeline(tim); - } - } - - private void initTimeline(Timeline timeline) { - if (tag instanceof MorphShapeTag) { - timeline.frameRate = MORPH_SHAPE_ANIMATION_FRAME_RATE; - int framesCnt = (int) (timeline.frameRate * MORPH_SHAPE_ANIMATION_LENGTH); - for (int i = 0; i < framesCnt; i++) { - Frame f = new Frame(timeline, i); - DepthState ds = new DepthState(tag.getSwf(), f); - ds.characterId = ((CharacterTag) tag).getCharacterId(); - ds.matrix = new MATRIX(); - ds.ratio = i * 65535 / framesCnt; - f.layers.put(1, ds); - f.layersChanged = true; - timeline.addFrame(f); - } - } else if (tag instanceof FontTag) { - int pageCount = PreviewPanel.getFontPageCount((FontTag) tag); - int frame = fontFrameNum; - if (frame < 0 || frame >= pageCount) { - frame = 0; - } - - Frame f = new Frame(timeline, 0); - DepthState ds = new DepthState(tag.getSwf(), f); - ds.characterId = ((CharacterTag) tag).getCharacterId(); - ds.matrix = new MATRIX(); - f.layers.put(1, ds); - f.layersChanged = true; - timeline.addFrame(f); - timeline.fontFrameNum = frame; - } else { - Frame f = new Frame(timeline, 0); - DepthState ds = new DepthState(tag.getSwf(), f); - ds.characterId = ((CharacterTag) tag).getCharacterId(); - ds.matrix = new MATRIX(); - f.layers.put(1, ds); - timeline.addFrame(f); - } - timeline.displayRect = getRect(); - } - - @Override - public RECT getRect() { - return getRect(new HashSet<>()); - } - - @Override - public RECT getRect(Set added) { - BoundedTag bt = (BoundedTag) tag; - if (!added.contains(bt)) { - return bt.getRect(added); - } - return new RECT(Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE); - } - - @Override - public int hashCode() { - return tag.hashCode(); - } - - @Override - public void setModified(boolean value) { - } - - @Override - public ReadOnlyTagList getTags() { - return ReadOnlyTagList.EMPTY; - } - - @Override - public void removeTag(int index) { - } - - @Override - public void removeTag(Tag tag) { - } - - @Override - public void addTag(Tag tag) { - } - - @Override - public void addTag(int index, Tag tag) { - } - - @Override - public void replaceTag(int index, Tag newTag) { - } - }; - } - - private void disposeInner(Container container) { - for (Component c : container.getComponents()) { - if (c instanceof Container) { - Container c2 = (Container) c; - disposeInner(c2); - } - } - - container.removeAll(); - container.setLayout(null); - if (container instanceof TagEditorPanel) { - Helper.emptyObject(container); - } - } - - public void dispose() { - setDropTarget(null); - disposeInner(this); - Helper.emptyObject(this); - } -} +/* + * 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.AbortRetryIgnoreHandler; +import com.jpexs.decompiler.flash.ApplicationInfo; +import com.jpexs.decompiler.flash.EventListener; +import com.jpexs.decompiler.flash.ReadOnlyTagList; +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFBundle; +import com.jpexs.decompiler.flash.SWFSourceInfo; +import com.jpexs.decompiler.flash.abc.ABC; +import com.jpexs.decompiler.flash.abc.RenameType; +import com.jpexs.decompiler.flash.abc.ScriptPack; +import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool; +import com.jpexs.decompiler.flash.abc.avm2.deobfuscation.AbcMultiNameCollisionFixer; +import com.jpexs.decompiler.flash.abc.avm2.deobfuscation.DeobfuscationLevel; +import com.jpexs.decompiler.flash.abc.types.traits.Trait; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.configuration.ConfigurationItem; +import com.jpexs.decompiler.flash.configuration.SwfSpecificConfiguration; +import com.jpexs.decompiler.flash.dumpview.DumpInfo; +import com.jpexs.decompiler.flash.dumpview.DumpInfoSwfNode; +import com.jpexs.decompiler.flash.exporters.BinaryDataExporter; +import com.jpexs.decompiler.flash.exporters.FontExporter; +import com.jpexs.decompiler.flash.exporters.FrameExporter; +import com.jpexs.decompiler.flash.exporters.ImageExporter; +import com.jpexs.decompiler.flash.exporters.MorphShapeExporter; +import com.jpexs.decompiler.flash.exporters.MovieExporter; +import com.jpexs.decompiler.flash.exporters.ShapeExporter; +import com.jpexs.decompiler.flash.exporters.SoundExporter; +import com.jpexs.decompiler.flash.exporters.SymbolClassExporter; +import com.jpexs.decompiler.flash.exporters.TextExporter; +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.exporters.script.AS2ScriptExporter; +import com.jpexs.decompiler.flash.exporters.script.AS3ScriptExporter; +import com.jpexs.decompiler.flash.exporters.settings.BinaryDataExportSettings; +import com.jpexs.decompiler.flash.exporters.settings.ButtonExportSettings; +import com.jpexs.decompiler.flash.exporters.settings.FontExportSettings; +import com.jpexs.decompiler.flash.exporters.settings.FrameExportSettings; +import com.jpexs.decompiler.flash.exporters.settings.ImageExportSettings; +import com.jpexs.decompiler.flash.exporters.settings.MorphShapeExportSettings; +import com.jpexs.decompiler.flash.exporters.settings.MovieExportSettings; +import com.jpexs.decompiler.flash.exporters.settings.ScriptExportSettings; +import com.jpexs.decompiler.flash.exporters.settings.ShapeExportSettings; +import com.jpexs.decompiler.flash.exporters.settings.SoundExportSettings; +import com.jpexs.decompiler.flash.exporters.settings.SpriteExportSettings; +import com.jpexs.decompiler.flash.exporters.settings.TextExportSettings; +import com.jpexs.decompiler.flash.exporters.swf.SwfJavaExporter; +import com.jpexs.decompiler.flash.exporters.swf.SwfXmlExporter; +import com.jpexs.decompiler.flash.flexsdk.MxmlcAs3ScriptReplacer; +import com.jpexs.decompiler.flash.gui.abc.ABCPanel; +import com.jpexs.decompiler.flash.gui.abc.ABCPanelSearchResult; +import com.jpexs.decompiler.flash.gui.abc.ClassesListTreeModel; +import com.jpexs.decompiler.flash.gui.abc.DecompiledEditorPane; +import com.jpexs.decompiler.flash.gui.abc.DeobfuscationDialog; +import com.jpexs.decompiler.flash.gui.action.ActionPanel; +import com.jpexs.decompiler.flash.gui.action.ActionSearchResult; +import com.jpexs.decompiler.flash.gui.controls.JPersistentSplitPane; +import com.jpexs.decompiler.flash.gui.dumpview.DumpTree; +import com.jpexs.decompiler.flash.gui.dumpview.DumpTreeModel; +import com.jpexs.decompiler.flash.gui.dumpview.DumpViewPanel; +import com.jpexs.decompiler.flash.gui.editor.LineMarkedEditorPane; +import com.jpexs.decompiler.flash.gui.helpers.ObservableList; +import com.jpexs.decompiler.flash.gui.player.FlashPlayerPanel; +import com.jpexs.decompiler.flash.gui.tagtree.TagTree; +import com.jpexs.decompiler.flash.gui.tagtree.TagTreeModel; +import com.jpexs.decompiler.flash.gui.timeline.TimelineViewPanel; +import com.jpexs.decompiler.flash.helpers.FileTextWriter; +import com.jpexs.decompiler.flash.helpers.Freed; +import com.jpexs.decompiler.flash.importers.AS2ScriptImporter; +import com.jpexs.decompiler.flash.importers.AS3ScriptImporter; +import com.jpexs.decompiler.flash.importers.As3ScriptReplacerFactory; +import com.jpexs.decompiler.flash.importers.As3ScriptReplacerInterface; +import com.jpexs.decompiler.flash.importers.BinaryDataImporter; +import com.jpexs.decompiler.flash.importers.FFDecAs3ScriptReplacer; +import com.jpexs.decompiler.flash.importers.ImageImporter; +import com.jpexs.decompiler.flash.importers.ShapeImporter; +import com.jpexs.decompiler.flash.importers.SwfXmlImporter; +import com.jpexs.decompiler.flash.importers.SymbolClassImporter; +import com.jpexs.decompiler.flash.importers.TextImporter; +import com.jpexs.decompiler.flash.importers.svg.SvgImporter; +import com.jpexs.decompiler.flash.tags.ABCContainerTag; +import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag; +import com.jpexs.decompiler.flash.tags.DefineBitsJPEG3Tag; +import com.jpexs.decompiler.flash.tags.DefineBitsJPEG4Tag; +import com.jpexs.decompiler.flash.tags.DefineSoundTag; +import com.jpexs.decompiler.flash.tags.DefineSpriteTag; +import com.jpexs.decompiler.flash.tags.DoActionTag; +import com.jpexs.decompiler.flash.tags.DoInitActionTag; +import com.jpexs.decompiler.flash.tags.FileAttributesTag; +import com.jpexs.decompiler.flash.tags.MetadataTag; +import com.jpexs.decompiler.flash.tags.Tag; +import com.jpexs.decompiler.flash.tags.TagInfo; +import com.jpexs.decompiler.flash.tags.base.ASMSource; +import com.jpexs.decompiler.flash.tags.base.BoundedTag; +import com.jpexs.decompiler.flash.tags.base.ButtonTag; +import com.jpexs.decompiler.flash.tags.base.CharacterTag; +import com.jpexs.decompiler.flash.tags.base.DrawableTag; +import com.jpexs.decompiler.flash.tags.base.FontTag; +import com.jpexs.decompiler.flash.tags.base.ImageTag; +import com.jpexs.decompiler.flash.tags.base.MissingCharacterHandler; +import com.jpexs.decompiler.flash.tags.base.MorphShapeTag; +import com.jpexs.decompiler.flash.tags.base.ShapeTag; +import com.jpexs.decompiler.flash.tags.base.SoundStreamHeadTypeTag; +import com.jpexs.decompiler.flash.tags.base.SoundTag; +import com.jpexs.decompiler.flash.tags.base.SymbolClassTypeTag; +import com.jpexs.decompiler.flash.tags.base.TextImportErrorHandler; +import com.jpexs.decompiler.flash.tags.base.TextTag; +import com.jpexs.decompiler.flash.tags.text.TextAlign; +import com.jpexs.decompiler.flash.tags.text.TextParseException; +import com.jpexs.decompiler.flash.timeline.DepthState; +import com.jpexs.decompiler.flash.timeline.Frame; +import com.jpexs.decompiler.flash.timeline.TagScript; +import com.jpexs.decompiler.flash.timeline.Timeline; +import com.jpexs.decompiler.flash.timeline.Timelined; +import com.jpexs.decompiler.flash.treeitems.FolderItem; +import com.jpexs.decompiler.flash.treeitems.HeaderItem; +import com.jpexs.decompiler.flash.treeitems.SWFList; +import com.jpexs.decompiler.flash.treeitems.TreeItem; +import com.jpexs.decompiler.flash.types.MATRIX; +import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.decompiler.flash.types.sound.SoundFormat; +import com.jpexs.decompiler.flash.xfl.FLAVersion; +import com.jpexs.helpers.CancellableWorker; +import com.jpexs.helpers.Helper; +import com.jpexs.helpers.Path; +import com.jpexs.helpers.ProgressListener; +import com.jpexs.helpers.SerializableImage; +import java.awt.BorderLayout; +import java.awt.CardLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Desktop; +import java.awt.FlowLayout; +import java.awt.Font; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.dnd.DragSourceDragEvent; +import java.awt.dnd.DragSourceDropEvent; +import java.awt.dnd.DragSourceEvent; +import java.awt.dnd.DragSourceListener; +import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetDropEvent; +import java.awt.event.ActionEvent; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Random; +import java.util.Set; +import java.util.concurrent.CancellationException; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.UnsupportedAudioFileException; +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.Icon; +import javax.swing.JColorChooser; +import javax.swing.JFileChooser; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JProgressBar; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; +import javax.swing.JTabbedPane; +import javax.swing.JTextField; +import javax.swing.SwingConstants; +import javax.swing.UIManager; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; +import javax.swing.filechooser.FileFilter; +import javax.swing.plaf.basic.BasicTreeUI; +import javax.swing.tree.DefaultTreeSelectionModel; +import javax.swing.tree.TreePath; +import jsyntaxpane.DefaultSyntaxKit; + +/** + * + * @author JPEXS + */ +public final class MainPanel extends JPanel implements TreeSelectionListener, SearchListener, Freed { + + private final MainFrame mainFrame; + + private final ObservableList swfs; + + private final JPanel welcomePanel; + + private final TimelineViewPanel timelineViewPanel; + + private final MainFrameStatusPanel statusPanel; + + private final MainFrameMenu mainMenu; + + private final JProgressBar progressBar = new JProgressBar(0, 100); + + public TagTree tagTree; + + public DumpTree dumpTree; + + private final FlashPlayerPanel flashPanel; + + private final FlashPlayerPanel flashPanel2; + + private final JPanel contentPanel; + + private final JPanel displayPanel; + + public FolderPreviewPanel folderPreviewPanel; + + private boolean isWelcomeScreen = true; + + private static final String CARDPREVIEWPANEL = "Preview card"; + + private static final String CARDFOLDERPREVIEWPANEL = "Folder preview card"; + + private static final String CARDEMPTYPANEL = "Empty card"; + + private static final String CARDDUMPVIEW = "Dump view"; + + private static final String CARDACTIONSCRIPTPANEL = "ActionScript card"; + + private static final String CARDACTIONSCRIPT3PANEL = "ActionScript3 card"; + + private static final String CARDHEADER = "Header card"; + + private static final String DETAILCARDAS3NAVIGATOR = "Traits list"; + + private static final String DETAILCARDTAGINFO = "Tag information"; + + private static final String DETAILCARDEMPTYPANEL = "Empty card"; + + private static final String SPLIT_PANE1 = "SPLITPANE1"; + + private static final String WELCOME_PANEL = "WELCOMEPANEL"; + + private static final String TIMELINE_PANEL = "TIMELINEPANEL"; + + private static final String RESOURCES_VIEW = "RESOURCES"; + + private static final String DUMP_VIEW = "DUMP"; + + private static final String TIMELINE_VIEW = "TIMELINE"; + + private final JPersistentSplitPane splitPane1; + + private final JPersistentSplitPane splitPane2; + + private JPanel detailPanel; + + private JTextField filterField = new MyTextField(""); + + private JPanel searchPanel; + + private ABCPanel abcPanel; + + private ActionPanel actionPanel; + + private final PreviewPanel previewPanel; + + private final HeaderInfoPanel headerPanel; + + private DumpViewPanel dumpViewPanel; + + private final JPanel treePanel; + + private final PreviewPanel dumpPreviewPanel; + + private final TagInfoPanel tagInfoPanel; + + private TreePanelMode treePanelMode; + + private CancellableWorker setSourceWorker; + + public TreeItem oldItem; + + // play morph shape in 2 second(s) + public static final int MORPH_SHAPE_ANIMATION_LENGTH = 2; + + public static final int MORPH_SHAPE_ANIMATION_FRAME_RATE = 30; + + private static final Logger logger = Logger.getLogger(MainPanel.class.getName()); + + public void setPercent(int percent) { + progressBar.setValue(percent); + progressBar.setVisible(true); + } + + public void hidePercent() { + if (progressBar.isVisible()) { + progressBar.setVisible(false); + } + } + + public MainFrame getMainFrame() { + return mainFrame; + } + + static { + try { + File.createTempFile("temp", ".swf").delete(); //First call to this is slow, so make it first + } catch (IOException ex) { + logger.log(Level.SEVERE, null, ex); + } + } + + public void updateMenu() { + mainMenu.updateComponents(); + } + + private static void addTab(JTabbedPane tabbedPane, Component tab, String title, Icon icon) { + tabbedPane.add(tab); + + JLabel lbl = new JLabel(title); + lbl.setIcon(icon); + lbl.setIconTextGap(5); + lbl.setHorizontalTextPosition(SwingConstants.RIGHT); + + tabbedPane.setTabComponentAt(tabbedPane.getTabCount() - 1, lbl); + } + + public void setStatus(String s) { + statusPanel.setStatus(s); + } + + public void setWorkStatus(String s, CancellableWorker worker) { + statusPanel.setWorkStatus(s, worker); + mainMenu.updateComponents(); + } + + private JPanel createWelcomePanel() { + JPanel welcomePanel = new JPanel(); + welcomePanel.setLayout(new BoxLayout(welcomePanel, BoxLayout.Y_AXIS)); + JLabel welcomeToLabel = new JLabel(translate("startup.welcometo")); + welcomeToLabel.setFont(welcomeToLabel.getFont().deriveFont(40)); + welcomeToLabel.setAlignmentX(0.5f); + JPanel appNamePanel = new JPanel(new FlowLayout()); + JLabel jpLabel = new JLabel("JPEXS "); + jpLabel.setAlignmentX(0.5f); + jpLabel.setForeground(new Color(0, 0, 160)); + jpLabel.setFont(new Font("Tahoma", Font.BOLD, 50)); + jpLabel.setHorizontalAlignment(SwingConstants.CENTER); + appNamePanel.add(jpLabel); + + JLabel ffLabel = new JLabel("Free Flash "); + ffLabel.setAlignmentX(0.5f); + ffLabel.setFont(new Font("Tahoma", Font.BOLD, 50)); + ffLabel.setHorizontalAlignment(SwingConstants.CENTER); + appNamePanel.add(ffLabel); + + JLabel decLabel = new JLabel("Decompiler"); + decLabel.setAlignmentX(0.5f); + decLabel.setForeground(Color.red); + decLabel.setFont(new Font("Tahoma", Font.BOLD, 50)); + decLabel.setHorizontalAlignment(SwingConstants.CENTER); + appNamePanel.add(decLabel); + appNamePanel.setAlignmentX(0.5f); + welcomePanel.add(Box.createGlue()); + welcomePanel.add(welcomeToLabel); + welcomePanel.add(appNamePanel); + JLabel startLabel = new JLabel(translate("startup.selectopen")); + startLabel.setAlignmentX(0.5f); + startLabel.setFont(startLabel.getFont().deriveFont(30)); + welcomePanel.add(startLabel); + welcomePanel.add(Box.createGlue()); + return welcomePanel; + } + + private JPanel createFolderPreviewCard() { + JPanel folderPreviewCard = new JPanel(new BorderLayout()); + folderPreviewPanel = new FolderPreviewPanel(this, new ArrayList<>()); + folderPreviewCard.add(new JScrollPane(folderPreviewPanel), BorderLayout.CENTER); + + return folderPreviewCard; + } + + private JPanel createDumpPreviewCard() { + JPanel dumpViewCard = new JPanel(new BorderLayout()); + dumpViewPanel = new DumpViewPanel(dumpTree); + dumpViewCard.add(new JScrollPane(dumpViewPanel), BorderLayout.CENTER); + + return dumpViewCard; + } + + public String translate(String key) { + return mainFrame.translate(key); + } + + public MainPanel(MainFrame mainFrame, MainFrameMenu mainMenu, FlashPlayerPanel flashPanel, FlashPlayerPanel previewFlashPanel) { + super(); + + this.mainFrame = mainFrame; + this.mainMenu = mainMenu; + this.flashPanel = flashPanel; + this.flashPanel2 = previewFlashPanel; + + mainFrame.setTitle(ApplicationInfo.applicationVerName); + + setLayout(new BorderLayout()); + swfs = new ObservableList<>(); + + detailPanel = new JPanel(); + detailPanel.setLayout(new CardLayout()); + + JPanel whitePanel = new JPanel(); + whitePanel.setBackground(Color.white); + detailPanel.add(whitePanel, DETAILCARDEMPTYPANEL); + + tagInfoPanel = new TagInfoPanel(this); + detailPanel.add(tagInfoPanel, DETAILCARDTAGINFO); + + UIManager.getDefaults().put("TreeUI", BasicTreeUI.class.getName()); + tagTree = new TagTree(null, this); + tagTree.addTreeSelectionListener(this); + tagTree.setSelectionModel(new DefaultTreeSelectionModel() { + private boolean isModified() { + if (abcPanel != null && abcPanel.isEditing()) { + abcPanel.tryAutoSave(); + } + + if (actionPanel != null && actionPanel.isEditing()) { + actionPanel.tryAutoSave(); + } + + if (previewPanel.isEditing()) { + previewPanel.tryAutoSave(); + } + + if (headerPanel.isEditing()) { + headerPanel.tryAutoSave(); + } + + return (abcPanel != null && abcPanel.isEditing()) + || (actionPanel != null && actionPanel.isEditing()) + || previewPanel.isEditing() || headerPanel.isEditing(); + } + + @Override + public void addSelectionPath(TreePath path) { + if (isModified()) { + return; + } + + super.addSelectionPath(path); + } + + @Override + public void addSelectionPaths(TreePath[] paths) { + if (isModified()) { + return; + } + + super.addSelectionPaths(paths); + } + + @Override + public void setSelectionPath(TreePath path) { + if (isModified()) { + return; + } + + super.setSelectionPath(path); + } + + @Override + public void setSelectionPaths(TreePath[] pPaths) { + if (isModified()) { + return; + } + + super.setSelectionPaths(pPaths); + } + + @Override + public void clearSelection() { + if (isModified()) { + return; + } + + super.clearSelection(); + } + + public void setSelection(TreePath[] selection) { + if (isModified()) { + return; + } + + this.selection = selection; + } + + @Override + public void removeSelectionPath(TreePath path) { + if (isModified()) { + return; + } + + super.removeSelectionPath(path); + } + + @Override + public void removeSelectionPaths(TreePath[] paths) { + if (isModified()) { + return; + } + + super.removeSelectionPaths(paths); + } + }); + + DragSource dragSource = DragSource.getDefaultDragSource(); + dragSource.createDefaultDragGestureRecognizer(tagTree, DnDConstants.ACTION_COPY_OR_MOVE, new DragGestureListener() { + @Override + public void dragGestureRecognized(DragGestureEvent dge) { + dge.startDrag(DragSource.DefaultCopyDrop, new Transferable() { + @Override + public DataFlavor[] getTransferDataFlavors() { + return new DataFlavor[]{DataFlavor.javaFileListFlavor}; + } + + @Override + public boolean isDataFlavorSupported(DataFlavor flavor) { + return flavor.equals(DataFlavor.javaFileListFlavor); + } + + @Override + public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException { + if (flavor.equals(DataFlavor.javaFileListFlavor)) { + List files; + String tempDir = System.getProperty("java.io.tmpdir"); + if (!tempDir.endsWith(File.separator)) { + tempDir += File.separator; + } + Random rnd = new Random(); + tempDir += "ffdec" + File.separator + "export" + File.separator + System.currentTimeMillis() + "_" + rnd.nextInt(1000); + File fTempDir = new File(tempDir); + Path.createDirectorySafe(fTempDir); + + File ftemp = new File(tempDir); + ExportDialog exd = new ExportDialog(null); + try { + files = exportSelection(new GuiAbortRetryIgnoreHandler(), tempDir, exd); + } catch (InterruptedException ex) { + logger.log(Level.SEVERE, null, ex); + return null; + } + + files.clear(); + + File[] fs = ftemp.listFiles(); + files.addAll(Arrays.asList(fs)); + + Main.stopWork(); + + for (File f : files) { + f.deleteOnExit(); + } + new File(tempDir).deleteOnExit(); + return files; + + } + return null; + } + }, new DragSourceListener() { + @Override + public void dragEnter(DragSourceDragEvent dsde) { + enableDrop(false); + } + + @Override + public void dragOver(DragSourceDragEvent dsde) { + } + + @Override + public void dropActionChanged(DragSourceDragEvent dsde) { + } + + @Override + public void dragExit(DragSourceEvent dse) { + } + + @Override + public void dragDropEnd(DragSourceDropEvent dsde) { + enableDrop(true); + } + }); + } + }); + + tagTree.createContextMenu(); + + dumpTree = new DumpTree(null, this); + dumpTree.addTreeSelectionListener(this); + dumpTree.createContextMenu(); + + statusPanel = new MainFrameStatusPanel(this); + add(statusPanel, BorderLayout.SOUTH); + + displayPanel = new JPanel(new CardLayout()); + + DefaultSyntaxKit.initKit(); + previewPanel = new PreviewPanel(this, flashPanel); + + dumpPreviewPanel = new PreviewPanel(this, previewFlashPanel); + dumpPreviewPanel.setReadOnly(true); + + displayPanel.add(previewPanel, CARDPREVIEWPANEL); + displayPanel.add(createFolderPreviewCard(), CARDFOLDERPREVIEWPANEL); + displayPanel.add(createDumpPreviewCard(), CARDDUMPVIEW); + + headerPanel = new HeaderInfoPanel(); + displayPanel.add(headerPanel, CARDHEADER); + + displayPanel.add(new JPanel(), CARDEMPTYPANEL); + showCard(CARDEMPTYPANEL); + + searchPanel = new JPanel(); + searchPanel.setLayout(new BorderLayout()); + searchPanel.add(filterField, BorderLayout.CENTER); + searchPanel.add(new JLabel(View.getIcon("search16")), BorderLayout.WEST); + JLabel closeSearchButton = new JLabel(View.getIcon("cancel16")); + closeSearchButton.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + closeTagTreeSearch(); + } + }); + searchPanel.add(closeSearchButton, BorderLayout.EAST); + searchPanel.setVisible(false); + treePanel = new JPanel(new CardLayout()); + treePanel.add(createResourcesViewCard(), RESOURCES_VIEW); + treePanel.add(createDumpViewCard(), DUMP_VIEW); + //treePanel.add(searchPanel, BorderLayout.SOUTH); + //searchPanel.setVisible(false); + filterField.getDocument().addDocumentListener(new DocumentListener() { + @Override + public void changedUpdate(DocumentEvent e) { + warn(); + } + + @Override + public void removeUpdate(DocumentEvent e) { + warn(); + } + + @Override + public void insertUpdate(DocumentEvent e) { + warn(); + } + + public void warn() { + doFilter(); + } + }); + + //displayPanel.setBorder(BorderFactory.createLineBorder(Color.black)); + splitPane2 = new JPersistentSplitPane(JSplitPane.VERTICAL_SPLIT, treePanel, detailPanel, Configuration.guiSplitPane2DividerLocationPercent); + splitPane1 = new JPersistentSplitPane(JSplitPane.HORIZONTAL_SPLIT, splitPane2, displayPanel, Configuration.guiSplitPane1DividerLocationPercent); + + welcomePanel = createWelcomePanel(); + add(welcomePanel, BorderLayout.CENTER); + + timelineViewPanel = new TimelineViewPanel(); + + CardLayout cl3 = new CardLayout(); + contentPanel = new JPanel(cl3); + contentPanel.add(welcomePanel, WELCOME_PANEL); + contentPanel.add(splitPane1, SPLIT_PANE1); + contentPanel.add(timelineViewPanel, TIMELINE_PANEL); + add(contentPanel); + cl3.show(contentPanel, WELCOME_PANEL); + + tagTree.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + if ((e.getKeyCode() == 'F') && (e.isControlDown())) { + searchPanel.setVisible(true); + filterField.requestFocusInWindow(); + } + } + }); + detailPanel.setVisible(false); + + updateUi(); + + this.swfs.addCollectionChangedListener((e) -> { + TagTreeModel ttm = tagTree.getModel(); + if (ttm != null) { + if (getCurrentSwf() == null) { + tagTree.setSelectionPath(ttm.getTreePath(ttm.getRoot())); + } + ttm.updateSwfs(e); + tagTree.expandRoot(); + tagTree.expandFirstLevelNodes(); + } + + DumpTreeModel dtm = dumpTree.getModel(); + if (dtm != null) { + List> expandedNodes = View.getExpandedNodes(dumpTree); + dtm.updateSwfs(); + View.expandTreeNodes(dumpTree, expandedNodes); + dumpTree.expandRoot(); + dumpTree.expandFirstLevelNodes(); + } + + if (swfs.isEmpty()) { + tagTree.setUI(new BasicTreeUI() { + { + setHashColor(Color.gray); + } + }); + dumpTree.setUI(new BasicTreeUI() { + { + setHashColor(Color.gray); + } + }); + } + }); + + //Opening files with drag&drop to main window + enableDrop(true); + } + + public void closeTagTreeSearch() { + filterField.setText(""); + doFilter(); + searchPanel.setVisible(false); + } + + public void loadSwfAtPos(SWFList newSwfs, int index) { + previewPanel.clear(); + swfs.set(index, newSwfs); + SWF swf = newSwfs.size() > 0 ? newSwfs.get(0) : null; + if (swf != null) { + updateUi(swf); + } + + doFilter(); + reload(false); + } + + public void load(SWFList newSwfs, boolean first) { + + previewPanel.clear(); + + swfs.add(newSwfs); + SWF swf = newSwfs.size() > 0 ? newSwfs.get(0) : null; + if (swf != null) { + updateUi(swf); + } + + doFilter(); + reload(false); + } + + private ABCPanel getABCPanel() { + if (abcPanel == null) { + abcPanel = new ABCPanel(this); + displayPanel.add(abcPanel, CARDACTIONSCRIPT3PANEL); + detailPanel.add(abcPanel.tabbedPane, DETAILCARDAS3NAVIGATOR); + } + + return abcPanel; + } + + private ActionPanel getActionPanel() { + if (actionPanel == null) { + actionPanel = new ActionPanel(MainPanel.this); + displayPanel.add(actionPanel, CARDACTIONSCRIPTPANEL); + } + + return actionPanel; + } + + private void updateUi(final SWF swf) { + + mainFrame.setTitle(ApplicationInfo.applicationVerName + (Configuration.displayFileName.get() ? " - " + swf.getFileTitle() : "")); + + List abcList = swf.getAbcList(); + + boolean hasAbc = !abcList.isEmpty(); + + if (hasAbc) { + getABCPanel().setAbc(abcList.get(0).getABC()); + } + + if (isWelcomeScreen) { + CardLayout cl = (CardLayout) (contentPanel.getLayout()); + cl.show(contentPanel, SPLIT_PANE1); + isWelcomeScreen = false; + } + + mainMenu.updateComponents(swf); + } + + private void updateUi() { + if (!isWelcomeScreen && swfs.isEmpty()) { + CardLayout cl = (CardLayout) (contentPanel.getLayout()); + cl.show(contentPanel, WELCOME_PANEL); + isWelcomeScreen = true; + closeTagTreeSearch(); + } + + mainFrame.setTitle(ApplicationInfo.applicationVerName); + mainMenu.updateComponents(null); + + showView(getCurrentView()); + } + + private boolean closeConfirmation(SWFList swfList) { + String message = swfList == null + ? translate("message.confirm.closeAll") + : translate("message.confirm.close").replace("{swfName}", swfList.toString()); + + return View.showConfirmDialog(this, message, translate("message.warning"), JOptionPane.OK_CANCEL_OPTION, Configuration.showCloseConfirmation, JOptionPane.OK_OPTION) == JOptionPane.OK_OPTION; + } + + public boolean isModified() { + for (SWFList swfList : swfs) { + for (SWF swf : swfList) { + if (swf.isModified()) { + return true; + } + } + } + + return false; + } + + public boolean closeAll(boolean showCloseConfirmation) { + if (showCloseConfirmation && isModified()) { + boolean closeConfirmResult = closeConfirmation(swfs.size() == 1 ? swfs.get(0) : null); + if (!closeConfirmResult) { + return false; + } + } + + List swfsLists = new ArrayList<>(swfs); + swfs.clear(); + oldItem = null; + clear(); + updateUi(); + + for (SWFList swfList : swfsLists) { + List swfs2 = new ArrayList<>(swfList); + for (SWF swf : swfs2) { + swf.clearTagSwfs(); + } + } + + return true; + } + + public boolean close(SWFList swfList) { + boolean modified = false; + for (SWF swf : swfList) { + if (swf.isModified()) { + modified = true; + } + } + + if (modified) { + boolean closeConfirmResult = closeConfirmation(swfList); + if (!closeConfirmResult) { + return false; + } + } + + swfs.remove(swfList); + oldItem = null; + clear(); + updateUi(); + + List swfs2 = new ArrayList<>(swfList); + for (SWF swf : swfs2) { + swf.clearTagSwfs(); + } + + return true; + } + + public void enableDrop(boolean value) { + if (value) { + setDropTarget(new DropTarget() { + @Override + public synchronized void drop(DropTargetDropEvent dtde) { + try { + dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE); + @SuppressWarnings("unchecked") + List droppedFiles = (List) dtde.getTransferable().getTransferData(DataFlavor.javaFileListFlavor); + if (!droppedFiles.isEmpty()) { + SWFSourceInfo[] sourceInfos = new SWFSourceInfo[droppedFiles.size()]; + for (int i = 0; i < droppedFiles.size(); i++) { + sourceInfos[i] = new SWFSourceInfo(null, droppedFiles.get(i).getAbsolutePath(), null); + } + Main.openFile(sourceInfos, null); + } + } catch (UnsupportedFlavorException | IOException ex) { + } + } + }); + } else { + setDropTarget(null); + } + } + + public void updateClassesList() { + List nodes = getASTreeNodes(tagTree); + boolean updateNeeded = false; + for (TreeItem n : nodes) { + if (n instanceof ClassesListTreeModel) { + ((ClassesListTreeModel) n).update(); + updateNeeded = true; + } + } + + refreshTree(); + + if (updateNeeded) { + tagTree.updateUI(); + } + } + + public void doFilter() { + List nodes = getASTreeNodes(tagTree); + for (TreeItem n : nodes) { + if (n instanceof ClassesListTreeModel) { + String filterText = filterField.getText(); + ((ClassesListTreeModel) n).setFilter(filterText); + TagTreeModel tm = tagTree.getModel(); + TreePath path = tm.getTreePath(n); + tm.updateNode(path); + if (!filterText.isEmpty()) { + View.expandTreeNodes(tagTree, path, true); + } + } + } + } + + public void renameIdentifier(SWF swf, String identifier) throws InterruptedException { + String oldName = identifier; + String newName = View.showInputDialog(translate("rename.enternew"), oldName); + if (newName != null) { + if (!oldName.equals(newName)) { + swf.renameAS2Identifier(oldName, newName); + View.showMessageDialog(null, translate("rename.finished.identifier")); + updateClassesList(); + reload(true); + } + } + } + + public void renameMultiname(List abcList, int multiNameIndex) { + String oldName = ""; + AVM2ConstantPool constants = getABCPanel().abc.constants; + if (constants.getMultiname(multiNameIndex).name_index > 0) { + oldName = constants.getString(constants.getMultiname(multiNameIndex).name_index); + } + + String newName = View.showInputDialog(translate("rename.enternew"), oldName); + if (newName != null) { + if (!oldName.equals(newName)) { + int mulCount = 0; + for (ABCContainerTag cnt : abcList) { + ABC abc = cnt.getABC(); + for (int m = 1; m < abc.constants.getMultinameCount(); m++) { + int ni = abc.constants.getMultiname(m).name_index; + String n = ""; + if (ni > 0) { + n = abc.constants.getString(ni); + } + if (n.equals(oldName)) { + abc.renameMultiname(m, newName); + mulCount++; + } + } + } + + View.showMessageDialog(null, translate("rename.finished.multiname").replace("%count%", Integer.toString(mulCount))); + if (abcPanel != null) { + abcPanel.reload(); + } + + updateClassesList(); + reload(true); + ABCPanel abcPanel = getABCPanel(); + abcPanel.hilightScript(abcPanel.getSwf(), abcPanel.decompiledTextArea.getScriptLeaf().getClassPath().toRawString()); + } + } + } + + public List getASTreeNodes(TagTree tree) { + List result = new ArrayList<>(); + TagTreeModel tm = (TagTreeModel) tree.getModel(); + if (tm == null) { + return result; + } + TreeItem root = tm.getRoot(); + for (int i = 0; i < tm.getChildCount(root); i++) { + // first level node can be SWF and SWFBundle + TreeItem node = tm.getChild(root, i); + if (node instanceof SWFBundle) { + for (int j = 0; j < tm.getChildCount(node); j++) { + // child of SWFBundle should be SWF + SWF swfNode = (SWF) tm.getChild(node, j); + result.add(tm.getScriptsNode(swfNode)); + } + } else if (node instanceof SWF) { + SWF swfNode = (SWF) tm.getChild(root, i); + result.add(tm.getScriptsNode(swfNode)); + } + } + return result; + } + + public boolean confirmExperimental() { + return View.showConfirmDialog(null, translate("message.confirm.experimental"), translate("message.warning"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.OK_OPTION; + } + + public List exportSelection(AbortRetryIgnoreHandler handler, String selFile, ExportDialog export) throws IOException, InterruptedException { + + List ret = new ArrayList<>(); + List sel = folderPreviewPanel.selectedItems.isEmpty() ? tagTree.getAllSelected() : new ArrayList<>(folderPreviewPanel.selectedItems.values()); + + Set usedSwfs = new HashSet<>(); + for (TreeItem d : sel) { + SWF selectedNodeSwf = d.getSwf(); + if (!usedSwfs.contains(selectedNodeSwf)) { + usedSwfs.add(selectedNodeSwf); + } + } + + Map usedSwfsIds = new HashMap<>(); + for (SWF swf : usedSwfs) { + List as3scripts = new ArrayList<>(); + List images = new ArrayList<>(); + List shapes = new ArrayList<>(); + List morphshapes = new ArrayList<>(); + List buttons = new ArrayList<>(); + List movies = new ArrayList<>(); + List sounds = new ArrayList<>(); + List texts = new ArrayList<>(); + List as12scripts = new ArrayList<>(); + List binaryData = new ArrayList<>(); + Map> frames = new HashMap<>(); + List fonts = new ArrayList<>(); + List symbolNames = new ArrayList<>(); + + for (TreeItem d : sel) { + SWF selectedNodeSwf = d.getSwf(); + + if (selectedNodeSwf != swf) { + continue; + } + + if (d instanceof TagScript) { + Tag tag = ((TagScript) d).getTag(); + if (tag instanceof DoActionTag || tag instanceof DoInitActionTag) { + as12scripts.add(d); + } + } + + if (d instanceof Tag || d instanceof ASMSource) { + TreeNodeType nodeType = TagTree.getTreeNodeType(d); + if (nodeType == TreeNodeType.IMAGE) { + images.add((Tag) d); + } + if (nodeType == TreeNodeType.SHAPE) { + shapes.add((Tag) d); + } + if (nodeType == TreeNodeType.BUTTON) { + buttons.add((Tag) d); + } + if (nodeType == TreeNodeType.MORPH_SHAPE) { + morphshapes.add((Tag) d); + } + if (nodeType == TreeNodeType.AS) { + as12scripts.add(d); + } + if (nodeType == TreeNodeType.MOVIE) { + movies.add((Tag) d); + } + if (nodeType == TreeNodeType.SOUND) { + sounds.add((Tag) d); + } + if (nodeType == TreeNodeType.BINARY_DATA) { + binaryData.add((Tag) d); + } + if (nodeType == TreeNodeType.TEXT) { + texts.add((Tag) d); + } + if (nodeType == TreeNodeType.FONT) { + fonts.add((Tag) d); + } + if (nodeType == TreeNodeType.OTHER_TAG) { + if (d instanceof SymbolClassTypeTag) { + symbolNames.add((Tag) d); + } + } + } + + if (d instanceof Frame) { + Frame fn = (Frame) d; + Timelined parent = fn.timeline.timelined; + int frame = fn.frame; + int parentId = 0; + if (parent instanceof CharacterTag) { + parentId = ((CharacterTag) parent).getCharacterId(); + } + if (!frames.containsKey(parentId)) { + frames.put(parentId, new ArrayList<>()); + } + frames.get(parentId).add(frame); + } + if (d instanceof ScriptPack) { + as3scripts.add((ScriptPack) d); + } + } + + String selFile2; + if (usedSwfs.size() > 1) { + selFile2 = selFile + File.separator + Helper.getNextId(swf.getShortFileName(), usedSwfsIds); + } else { + selFile2 = selFile; + } + + EventListener evl = swf.getExportEventListener(); + + if (export.isOptionEnabled(ImageExportMode.class)) { + ret.addAll(new ImageExporter().exportImages(handler, selFile2 + File.separator + ImageExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(images), + new ImageExportSettings(export.getValue(ImageExportMode.class)), evl)); + } + + if (export.isOptionEnabled(ShapeExportMode.class)) { + ret.addAll(new ShapeExporter().exportShapes(handler, selFile2 + File.separator + ShapeExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(shapes), + new ShapeExportSettings(export.getValue(ShapeExportMode.class), export.getZoom()), evl)); + } + + if (export.isOptionEnabled(MorphShapeExportMode.class)) { + ret.addAll(new MorphShapeExporter().exportMorphShapes(handler, selFile2 + File.separator + MorphShapeExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(morphshapes), + new MorphShapeExportSettings(export.getValue(MorphShapeExportMode.class), export.getZoom()), evl)); + } + + if (export.isOptionEnabled(TextExportMode.class)) { + ret.addAll(new TextExporter().exportTexts(handler, selFile2 + File.separator + TextExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(texts), + new TextExportSettings(export.getValue(TextExportMode.class), Configuration.textExportSingleFile.get(), export.getZoom()), evl)); + } + + if (export.isOptionEnabled(MovieExportMode.class)) { + ret.addAll(new MovieExporter().exportMovies(handler, selFile2 + File.separator + MovieExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(movies), + new MovieExportSettings(export.getValue(MovieExportMode.class)), evl)); + } + + if (export.isOptionEnabled(SoundExportMode.class)) { + ret.addAll(new SoundExporter().exportSounds(handler, selFile2 + File.separator + SoundExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(sounds), + new SoundExportSettings(export.getValue(SoundExportMode.class)), evl)); + } + + if (export.isOptionEnabled(BinaryDataExportMode.class)) { + ret.addAll(new BinaryDataExporter().exportBinaryData(handler, selFile2 + File.separator + BinaryDataExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(binaryData), + new BinaryDataExportSettings(export.getValue(BinaryDataExportMode.class)), evl)); + } + + if (export.isOptionEnabled(FontExportMode.class)) { + ret.addAll(new FontExporter().exportFonts(handler, selFile2 + File.separator + FontExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(fonts), + new FontExportSettings(export.getValue(FontExportMode.class)), evl)); + } + + if (export.isOptionEnabled(SymbolClassExportMode.class)) { + ret.addAll(new SymbolClassExporter().exportNames(selFile2, new ReadOnlyTagList(symbolNames), evl)); + } + + FrameExporter frameExporter = new FrameExporter(); + + if (export.isOptionEnabled(FrameExportMode.class)) { + FrameExportSettings fes = new FrameExportSettings(export.getValue(FrameExportMode.class), export.getZoom()); + for (Entry> entry : frames.entrySet()) { + int containerId = entry.getKey(); + if (containerId == 0) { + String subFolder = FrameExportSettings.EXPORT_FOLDER_NAME; + ret.addAll(frameExporter.exportFrames(handler, selFile2 + File.separator + subFolder, swf, containerId, entry.getValue(), fes, evl)); + } + } + } + + if (export.isOptionEnabled(SpriteExportMode.class)) { + SpriteExportSettings ses = new SpriteExportSettings(export.getValue(SpriteExportMode.class), export.getZoom()); + for (Entry> entry : frames.entrySet()) { + int containerId = entry.getKey(); + if (containerId != 0) { + String subFolder = SpriteExportSettings.EXPORT_FOLDER_NAME; + ret.addAll(frameExporter.exportFrames(handler, selFile2 + File.separator + subFolder, swf, containerId, entry.getValue(), ses, evl)); + } + } + } + + if (export.isOptionEnabled(ButtonExportMode.class)) { + ButtonExportSettings bes = new ButtonExportSettings(export.getValue(ButtonExportMode.class), export.getZoom()); + for (Tag tag : buttons) { + ButtonTag button = (ButtonTag) tag; + String subFolder = ButtonExportSettings.EXPORT_FOLDER_NAME; + List frameNums = new ArrayList<>(); + frameNums.add(0); // todo: export all frames + ret.addAll(frameExporter.exportFrames(handler, selFile2 + File.separator + subFolder, swf, button.getCharacterId(), frameNums, bes, evl)); + } + } + + if (export.isOptionEnabled(ScriptExportMode.class)) { + if (as3scripts.size() > 0 || as12scripts.size() > 0) { + boolean parallel = Configuration.parallelSpeedUp.get(); + String scriptsFolder = Path.combine(selFile2, ScriptExportSettings.EXPORT_FOLDER_NAME); + Path.createDirectorySafe(new File(scriptsFolder)); + boolean singleScriptFile = Configuration.scriptExportSingleFile.get(); + if (parallel && singleScriptFile) { + logger.log(Level.WARNING, AppStrings.translate("export.script.singleFilePallelModeWarning")); + singleScriptFile = false; + } + + ScriptExportSettings scriptExportSettings = new ScriptExportSettings(export.getValue(ScriptExportMode.class), singleScriptFile); + String singleFileName = Path.combine(scriptsFolder, swf.getShortFileName() + scriptExportSettings.getFileExtension()); + try (FileTextWriter writer = scriptExportSettings.singleFile ? new FileTextWriter(Configuration.getCodeFormatting(), new FileOutputStream(singleFileName)) : null) { + scriptExportSettings.singleFileWriter = writer; + if (swf.isAS3()) { + ret.addAll(new AS3ScriptExporter().exportActionScript3(swf, handler, scriptsFolder, as3scripts, scriptExportSettings, parallel, evl)); + } else { + Map asmsToExport = swf.getASMs(true, as12scripts, false); + ret.addAll(new AS2ScriptExporter().exportAS2Scripts(handler, scriptsFolder, asmsToExport, scriptExportSettings, parallel, evl)); + } + } + } + } + } + + return ret; + } + + public void exportAll(SWF swf, AbortRetryIgnoreHandler handler, String selFile, ExportDialog export) throws IOException, InterruptedException { + boolean exportAll = false; + if (exportAll) { + exportAllDebug(swf, handler, selFile, export); + return; + } + + EventListener evl = swf.getExportEventListener(); + + if (export.isOptionEnabled(ImageExportMode.class)) { + new ImageExporter().exportImages(handler, Path.combine(selFile, ImageExportSettings.EXPORT_FOLDER_NAME), swf.getTags(), + new ImageExportSettings(export.getValue(ImageExportMode.class)), evl); + } + + if (export.isOptionEnabled(ShapeExportMode.class)) { + new ShapeExporter().exportShapes(handler, Path.combine(selFile, ShapeExportSettings.EXPORT_FOLDER_NAME), swf.getTags(), + new ShapeExportSettings(export.getValue(ShapeExportMode.class), export.getZoom()), evl); + } + + if (export.isOptionEnabled(MorphShapeExportMode.class)) { + new MorphShapeExporter().exportMorphShapes(handler, Path.combine(selFile, MorphShapeExportSettings.EXPORT_FOLDER_NAME), swf.getTags(), + new MorphShapeExportSettings(export.getValue(MorphShapeExportMode.class), export.getZoom()), evl); + } + + if (export.isOptionEnabled(TextExportMode.class)) { + new TextExporter().exportTexts(handler, Path.combine(selFile, TextExportSettings.EXPORT_FOLDER_NAME), swf.getTags(), + new TextExportSettings(export.getValue(TextExportMode.class), Configuration.textExportSingleFile.get(), export.getZoom()), evl); + } + + if (export.isOptionEnabled(MovieExportMode.class)) { + new MovieExporter().exportMovies(handler, Path.combine(selFile, MovieExportSettings.EXPORT_FOLDER_NAME), swf.getTags(), + new MovieExportSettings(export.getValue(MovieExportMode.class)), evl); + } + + if (export.isOptionEnabled(SoundExportMode.class)) { + new SoundExporter().exportSounds(handler, Path.combine(selFile, SoundExportSettings.EXPORT_FOLDER_NAME), swf.getTags(), + new SoundExportSettings(export.getValue(SoundExportMode.class)), evl); + } + + if (export.isOptionEnabled(BinaryDataExportMode.class)) { + new BinaryDataExporter().exportBinaryData(handler, Path.combine(selFile, BinaryDataExportSettings.EXPORT_FOLDER_NAME), swf.getTags(), + new BinaryDataExportSettings(export.getValue(BinaryDataExportMode.class)), evl); + } + + if (export.isOptionEnabled(FontExportMode.class)) { + new FontExporter().exportFonts(handler, Path.combine(selFile, FontExportSettings.EXPORT_FOLDER_NAME), swf.getTags(), + new FontExportSettings(export.getValue(FontExportMode.class)), evl); + } + + if (export.isOptionEnabled(SymbolClassExportMode.class)) { + new SymbolClassExporter().exportNames(selFile, swf.getTags(), evl); + } + + FrameExporter frameExporter = new FrameExporter(); + + if (export.isOptionEnabled(FrameExportMode.class)) { + FrameExportSettings fes = new FrameExportSettings(export.getValue(FrameExportMode.class), export.getZoom()); + frameExporter.exportFrames(handler, Path.combine(selFile, FrameExportSettings.EXPORT_FOLDER_NAME), swf, 0, null, fes, evl); + } + + if (export.isOptionEnabled(SpriteExportMode.class)) { + SpriteExportSettings ses = new SpriteExportSettings(export.getValue(SpriteExportMode.class), export.getZoom()); + for (CharacterTag c : swf.getCharacters().values()) { + if (c instanceof DefineSpriteTag) { + frameExporter.exportFrames(handler, Path.combine(selFile, SpriteExportSettings.EXPORT_FOLDER_NAME), swf, c.getCharacterId(), null, ses, evl); + } + } + } + + if (export.isOptionEnabled(ButtonExportMode.class)) { + ButtonExportSettings bes = new ButtonExportSettings(export.getValue(ButtonExportMode.class), export.getZoom()); + for (CharacterTag c : swf.getCharacters().values()) { + if (c instanceof ButtonTag) { + List frameNums = new ArrayList<>(); + frameNums.add(0); // todo: export all frames + frameExporter.exportFrames(handler, Path.combine(selFile, ButtonExportSettings.EXPORT_FOLDER_NAME), swf, c.getCharacterId(), frameNums, bes, evl); + } + } + } + + if (export.isOptionEnabled(ScriptExportMode.class)) { + boolean parallel = Configuration.parallelSpeedUp.get(); + String scriptsFolder = Path.combine(selFile, ScriptExportSettings.EXPORT_FOLDER_NAME); + Path.createDirectorySafe(new File(scriptsFolder)); + boolean singleScriptFile = Configuration.scriptExportSingleFile.get(); + if (parallel && singleScriptFile) { + logger.log(Level.WARNING, AppStrings.translate("export.script.singleFilePallelModeWarning")); + singleScriptFile = false; + } + + ScriptExportSettings scriptExportSettings = new ScriptExportSettings(export.getValue(ScriptExportMode.class), singleScriptFile); + String singleFileName = Path.combine(scriptsFolder, swf.getShortFileName() + scriptExportSettings.getFileExtension()); + try (FileTextWriter writer = scriptExportSettings.singleFile ? new FileTextWriter(Configuration.getCodeFormatting(), new FileOutputStream(singleFileName)) : null) { + scriptExportSettings.singleFileWriter = writer; + swf.exportActionScript(handler, scriptsFolder, scriptExportSettings, parallel, evl); + } + } + } + + public void exportAllDebug(SWF swf, AbortRetryIgnoreHandler handler, String selFile, ExportDialog export) throws IOException, InterruptedException { + EventListener evl = swf.getExportEventListener(); + + if (export.isOptionEnabled(ImageExportMode.class)) { + for (ImageExportMode exportMode : ImageExportMode.values()) { + new ImageExporter().exportImages(handler, Path.combine(selFile, ImageExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.getTags(), + new ImageExportSettings(exportMode), evl); + } + } + + if (export.isOptionEnabled(ShapeExportMode.class)) { + for (ShapeExportMode exportMode : ShapeExportMode.values()) { + new ShapeExporter().exportShapes(handler, Path.combine(selFile, ShapeExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.getTags(), + new ShapeExportSettings(exportMode, export.getZoom()), evl); + } + } + + if (export.isOptionEnabled(MorphShapeExportMode.class)) { + for (MorphShapeExportMode exportMode : MorphShapeExportMode.values()) { + new MorphShapeExporter().exportMorphShapes(handler, Path.combine(selFile, MorphShapeExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.getTags(), + new MorphShapeExportSettings(exportMode, export.getZoom()), evl); + } + } + + if (export.isOptionEnabled(TextExportMode.class)) { + for (TextExportMode exportMode : TextExportMode.values()) { + new TextExporter().exportTexts(handler, Path.combine(selFile, TextExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.getTags(), + new TextExportSettings(exportMode, Configuration.textExportSingleFile.get(), export.getZoom()), evl); + } + } + + if (export.isOptionEnabled(MovieExportMode.class)) { + for (MovieExportMode exportMode : MovieExportMode.values()) { + new MovieExporter().exportMovies(handler, Path.combine(selFile, MovieExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.getTags(), + new MovieExportSettings(exportMode), evl); + } + } + + if (export.isOptionEnabled(SoundExportMode.class)) { + for (SoundExportMode exportMode : SoundExportMode.values()) { + new SoundExporter().exportSounds(handler, Path.combine(selFile, SoundExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.getTags(), + new SoundExportSettings(exportMode), evl); + } + } + + if (export.isOptionEnabled(BinaryDataExportMode.class)) { + for (BinaryDataExportMode exportMode : BinaryDataExportMode.values()) { + new BinaryDataExporter().exportBinaryData(handler, Path.combine(selFile, BinaryDataExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.getTags(), + new BinaryDataExportSettings(exportMode), evl); + } + } + + if (export.isOptionEnabled(FontExportMode.class)) { + for (FontExportMode exportMode : FontExportMode.values()) { + new FontExporter().exportFonts(handler, Path.combine(selFile, FontExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.getTags(), + new FontExportSettings(exportMode), evl); + } + } + + if (export.isOptionEnabled(SymbolClassExportMode.class)) { + for (SymbolClassExportMode exportMode : SymbolClassExportMode.values()) { + new SymbolClassExporter().exportNames(selFile, swf.getTags(), evl); + } + } + + FrameExporter frameExporter = new FrameExporter(); + + if (export.isOptionEnabled(FrameExportMode.class)) { + for (FrameExportMode exportMode : FrameExportMode.values()) { + FrameExportSettings fes = new FrameExportSettings(exportMode, export.getZoom()); + frameExporter.exportFrames(handler, Path.combine(selFile, FrameExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf, 0, null, fes, evl); + } + } + + if (export.isOptionEnabled(SpriteExportMode.class)) { + for (SpriteExportMode exportMode : SpriteExportMode.values()) { + SpriteExportSettings ses = new SpriteExportSettings(exportMode, export.getZoom()); + for (CharacterTag c : swf.getCharacters().values()) { + if (c instanceof DefineSpriteTag) { + frameExporter.exportFrames(handler, Path.combine(selFile, SpriteExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf, c.getCharacterId(), null, ses, evl); + } + } + } + } + + if (export.isOptionEnabled(ButtonExportMode.class)) { + for (ButtonExportMode exportMode : ButtonExportMode.values()) { + ButtonExportSettings bes = new ButtonExportSettings(exportMode, export.getZoom()); + for (CharacterTag c : swf.getCharacters().values()) { + if (c instanceof ButtonTag) { + List frameNums = new ArrayList<>(); + frameNums.add(0); // todo: export all frames + frameExporter.exportFrames(handler, Path.combine(selFile, ButtonExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf, c.getCharacterId(), frameNums, bes, evl); + } + } + } + } + + if (export.isOptionEnabled(ScriptExportMode.class)) { + boolean parallel = Configuration.parallelSpeedUp.get(); + for (ScriptExportMode exportMode : ScriptExportMode.values()) { + String scriptsFolder = Path.combine(selFile, ScriptExportSettings.EXPORT_FOLDER_NAME, exportMode.name()); + Path.createDirectorySafe(new File(scriptsFolder)); + boolean singleScriptFile = Configuration.scriptExportSingleFile.get(); + if (parallel && singleScriptFile) { + logger.log(Level.WARNING, AppStrings.translate("export.script.singleFilePallelModeWarning")); + singleScriptFile = false; + } + + ScriptExportSettings scriptExportSettings = new ScriptExportSettings(exportMode, singleScriptFile); + String singleFileName = Path.combine(scriptsFolder, swf.getShortFileName() + scriptExportSettings.getFileExtension()); + try (FileTextWriter writer = scriptExportSettings.singleFile ? new FileTextWriter(Configuration.getCodeFormatting(), new FileOutputStream(singleFileName)) : null) { + scriptExportSettings.singleFileWriter = writer; + swf.exportActionScript(handler, scriptsFolder, scriptExportSettings, parallel, evl); + } + } + } + } + + public List getSwfs() { + return swfs; + } + + public SWFList getCurrentSwfList() { + SWF swf = getCurrentSwf(); + if (swf == null) { + return null; + } + + return swf.swfList; + } + + public SWF getCurrentSwf() { + if (swfs == null || swfs.isEmpty()) { + return null; + } + + if (treePanelMode == TreePanelMode.TAG_TREE) { + TreeItem treeNode = (TreeItem) tagTree.getLastSelectedPathComponent(); + if (treeNode == null || treeNode instanceof SWFList) { + return null; + } + + return treeNode.getSwf(); + } else if (treePanelMode == TreePanelMode.DUMP_TREE) { + DumpInfo dumpInfo = (DumpInfo) dumpTree.getLastSelectedPathComponent(); + + if (dumpInfo == null) { + return null; + } + + return DumpInfoSwfNode.getSwfNode(dumpInfo).getSwf(); + } + + return null; + } + + public void gotoFrame(int frame) { + TreeItem treeItem = (TreeItem) tagTree.getLastSelectedPathComponent(); + if (treeItem == null) { + return; + } + if (treeItem instanceof Timelined) { + Timelined t = (Timelined) treeItem; + Frame f = tagTree.getModel().getFrame(treeItem.getSwf(), t, frame); + if (f != null) { + setTagTreeSelectedNode(f); + } + } + } + + public void gotoScriptLine(SWF swf, String scriptName, int line, int classIndex, int traitIndex, int methodIndex) { + gotoScriptName(swf, scriptName); + if (abcPanel != null) { + if (Main.isDebugPCode()) { + if (classIndex != -1) { + boolean classChanged = false; + if (abcPanel.decompiledTextArea.getClassIndex() != classIndex) { + abcPanel.decompiledTextArea.setClassIndex(classIndex); + classChanged = true; + } + if (traitIndex != -10 && (classChanged || abcPanel.decompiledTextArea.lastTraitIndex != traitIndex)) { + abcPanel.decompiledTextArea.gotoTrait(traitIndex); + } + } + abcPanel.detailPanel.methodTraitPanel.methodCodePanel.gotoInstrLine(line); + } else { + abcPanel.decompiledTextArea.gotoLine(line); + } + } else if (actionPanel != null) { + if (Main.isDebugPCode()) { + actionPanel.editor.gotoLine(line); + } else { + actionPanel.decompiledEditor.gotoLine(line); + } + } + refreshBreakPoints(); + + } + + public void refreshBreakPoints() { + if (abcPanel != null) { + abcPanel.decompiledTextArea.refreshMarkers(); + abcPanel.detailPanel.methodTraitPanel.methodCodePanel.refreshMarkers(); + } + if (actionPanel != null) { + actionPanel.decompiledEditor.refreshMarkers(); + actionPanel.editor.refreshMarkers(); + } + } + + /* + public void debuggerBreakAt(SWF swf, String cls, int line) { + View.execInEventDispatchLater(new Runnable() { + + @Override + public void run() { + gotoClassLine(swf, cls, line); + if (abcPanel != null) { + abcPanel.decompiledTextArea.addColorMarker(line, DecompiledEditorPane.FG_IP_COLOR, DecompiledEditorPane.BG_IP_COLOR, DecompiledEditorPane.PRIORITY_IP); + } + } + }); + + }*/ + public void gotoScriptName(SWF swf, String scriptName) { + if (swf == null) { + return; + } + if (swf.isAS3()) { + String rawScriptName = scriptName; + if (rawScriptName.startsWith("#PCODE ")) { + rawScriptName = rawScriptName.substring(rawScriptName.indexOf(';') + 1); + } + + List abcList = swf.getAbcList(); + if (!abcList.isEmpty()) { + ABCPanel abcPanel = getABCPanel(); + abcPanel.setAbc(abcList.get(0).getABC()); + abcPanel.hilightScript(swf, rawScriptName); + } + } else { + String rawScriptName = scriptName; + if (rawScriptName.startsWith("#PCODE ")) { + rawScriptName = rawScriptName.substring("#PCODE ".length()); + } + Map asms = swf.getASMs(true); + if (actionPanel != null && asms.containsKey(rawScriptName)) { + actionPanel.setSource(asms.get(rawScriptName), true); + } + } + } + + public void gotoDocumentClass(SWF swf) { + if (swf == null) { + return; + } + + String documentClass = swf.getDocumentClass(); + if (documentClass != null && !Configuration.dumpView.get()) { + List abcList = swf.getAbcList(); + if (!abcList.isEmpty()) { + ABCPanel abcPanel = getABCPanel(); + for (ABCContainerTag c : abcList) { + if (c.getABC().findClassByName(documentClass) > -1) { + abcPanel.setAbc(c.getABC()); + abcPanel.hilightScript(swf, documentClass); + break; + } + } + } + } + } + + public void disableDecompilationChanged() { + clearAllScriptCache(); + + if (abcPanel != null) { + abcPanel.reload(); + } + + updateClassesList(); + } + + private void clearAllScriptCache() { + for (SWFList swfList : swfs) { + for (SWF swf : swfList) { + swf.clearScriptCache(); + } + } + } + + public void searchInActionScriptOrText(Boolean searchInText, SWF swf) { + SearchDialog searchDialog = new SearchDialog(getMainFrame().getWindow(), false); + if (searchInText != null) { + if (searchInText) { + searchDialog.searchInTextsRadioButton.setSelected(true); + } else { + searchDialog.searchInASRadioButton.setSelected(true); + } + } + + if (searchDialog.showDialog() == AppDialog.OK_OPTION) { + final String txt = searchDialog.searchField.getText(); + if (!txt.isEmpty()) { + if (swf.isAS3()) { + getABCPanel(); + } else { + getActionPanel(); + } + + boolean ignoreCase = searchDialog.ignoreCaseCheckBox.isSelected(); + boolean regexp = searchDialog.regexpCheckBox.isSelected(); + + if (searchDialog.searchInASRadioButton.isSelected()) { + new CancellableWorker() { + @Override + protected Void doInBackground() throws Exception { + List abcResult = null; + List actionResult = null; + if (swf.isAS3()) { + abcResult = getABCPanel().search(swf, txt, ignoreCase, regexp, this); + } else { + actionResult = getActionPanel().search(swf, txt, ignoreCase, regexp, this); + } + + List fAbcResult = abcResult; + List fActionResult = actionResult; + View.execInEventDispatch(() -> { + boolean found = false; + if (fAbcResult != null) { + found = true; + getABCPanel().searchPanel.setSearchText(txt); + SearchResultsDialog sr = new SearchResultsDialog<>(getMainFrame().getWindow(), txt, getABCPanel()); + sr.setResults(fAbcResult); + sr.setVisible(true); + } else if (fActionResult != null) { + found = true; + getActionPanel().searchPanel.setSearchText(txt); + + SearchResultsDialog sr = new SearchResultsDialog<>(getMainFrame().getWindow(), txt, getActionPanel()); + sr.setResults(fActionResult); + sr.setVisible(true); + } + + if (!found) { + View.showMessageDialog(null, translate("message.search.notfound").replace("%searchtext%", txt), translate("message.search.notfound.title"), JOptionPane.INFORMATION_MESSAGE); + } + + Main.stopWork(); + }); + + return null; + } + + @Override + protected void done() { + View.execInEventDispatch(() -> { + Main.stopWork(); + }); + + } + }.execute(); + } else if (searchDialog.searchInTextsRadioButton.isSelected()) { + new CancellableWorker() { + @Override + protected Void doInBackground() throws Exception { + List textResult; + SearchPanel textSearchPanel = previewPanel.getTextPanel().getSearchPanel(); + textSearchPanel.setOptions(ignoreCase, regexp); + textResult = searchText(txt, ignoreCase, regexp, swf); + + List fTextResult = textResult; + View.execInEventDispatch(() -> { + textSearchPanel.setSearchText(txt); + boolean found = textSearchPanel.setResults(fTextResult); + if (!found) { + View.showMessageDialog(null, translate("message.search.notfound").replace("%searchtext%", txt), translate("message.search.notfound.title"), JOptionPane.INFORMATION_MESSAGE); + } + + Main.stopWork(); + }); + + return null; + } + + @Override + protected void done() { + View.execInEventDispatch(() -> { + Main.stopWork(); + }); + + } + }.execute(); + } + } + } + } + + public void replaceText() { + SearchDialog replaceDialog = new SearchDialog(getMainFrame().getWindow(), true); + if (replaceDialog.showDialog() == AppDialog.OK_OPTION) { + final String txt = replaceDialog.searchField.getText(); + if (!txt.isEmpty()) { + final SWF swf = getCurrentSwf(); + + new CancellableWorker() { + @Override + protected Void doInBackground() throws Exception { + int findCount = 0; + boolean ignoreCase = replaceDialog.ignoreCaseCheckBox.isSelected(); + boolean regexp = replaceDialog.regexpCheckBox.isSelected(); + String replacement = replaceDialog.replaceField.getText(); + if (!regexp) { + replacement = Matcher.quoteReplacement(replacement); + } + Pattern pat; + if (regexp) { + pat = Pattern.compile(txt, ignoreCase ? (Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE) : 0); + } else { + pat = Pattern.compile(Pattern.quote(txt), ignoreCase ? (Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE) : 0); + } + List textTags = new ArrayList<>(); + for (Tag tag : swf.getTags()) { + if (tag instanceof TextTag) { + textTags.add((TextTag) tag); + } + } + for (TextTag textTag : textTags) { + if (!replaceDialog.replaceInParametersCheckBox.isSelected()) { + List texts = textTag.getTexts(); + boolean found = false; + for (int i = 0; i < texts.size(); i++) { + String text = texts.get(i); + if (pat.matcher(text).find()) { + texts.set(i, text.replaceAll(txt, replacement)); + found = true; + findCount++; + } + } + if (found) { + String[] textArray = texts.toArray(new String[texts.size()]); + textTag.setFormattedText(getMissingCharacterHandler(), textTag.getFormattedText(false).text, textArray); + } + } else { + String text = textTag.getFormattedText(false).text; + if (pat.matcher(text).find()) { + textTag.setFormattedText(getMissingCharacterHandler(), text.replaceAll(txt, replacement), null); + findCount++; + } + } + } + + if (findCount > 0) { + swf.clearImageCache(); + repaintTree(); + } + + return null; + } + }.execute(); + } + } + } + + private List searchText(String txt, boolean ignoreCase, boolean regexp, SWF swf) { + if (txt != null && !txt.isEmpty()) { + List found = new ArrayList<>(); + Pattern pat; + if (regexp) { + pat = Pattern.compile(txt, ignoreCase ? (Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE) : 0); + } else { + pat = Pattern.compile(Pattern.quote(txt), ignoreCase ? (Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE) : 0); + } + for (Tag tag : swf.getTags()) { + if (tag instanceof TextTag) { + TextTag textTag = (TextTag) tag; + if (pat.matcher(textTag.getFormattedText(false).text).find()) { + found.add(textTag); + } + } + } + + return found; + } + + return null; + } + + @Override + public void updateSearchPos(TextTag item) { + setTagTreeSelectedNode(item); + previewPanel.getTextPanel().updateSearchPos(); + } + + private void setDumpTreeSelectedNode(DumpInfo dumpInfo) { + DumpTreeModel dtm = (DumpTreeModel) dumpTree.getModel(); + TreePath tp = dtm.getDumpInfoPath(dumpInfo); + if (tp != null) { + dumpTree.setSelectionPath(tp); + dumpTree.scrollPathToVisible(tp); + } else { + showCard(CARDEMPTYPANEL); + } + } + + public void setTagTreeSelectedNode(TreeItem treeItem) { + TagTreeModel ttm = tagTree.getModel(); + TreePath tp = ttm.getTreePath(treeItem); + if (tp != null) { + tagTree.setSelectionPath(tp); + tagTree.scrollPathToVisible(tp); + } else { + showCard(CARDEMPTYPANEL); + } + } + + public void autoDeobfuscateChanged() { + Helper.decompilationErrorAdd = AppStrings.translate(Configuration.autoDeobfuscate.get() ? "deobfuscation.comment.failed" : "deobfuscation.comment.tryenable"); + clearAllScriptCache(); + if (abcPanel != null) { + abcPanel.reload(); + } + reload(true); + updateClassesList(); + } + + public void renameColliding(final SWF swf) { + if (swf == null) { + return; + } + if (confirmExperimental()) { + new CancellableWorker() { + @Override + protected Integer doInBackground() throws Exception { + AbcMultiNameCollisionFixer fixer = new AbcMultiNameCollisionFixer(); + return fixer.fixCollisions(swf); + } + + @Override + protected void onStart() { + Main.startWork(translate("work.renaming.identifiers") + "...", this); + } + + @Override + protected void done() { + View.execInEventDispatch(() -> { + try { + int cnt = get(); + Main.stopWork(); + View.showMessageDialog(null, translate("message.rename.renamed").replace("%count%", Integer.toString(cnt))); + swf.assignClassesToSymbols(); + swf.clearScriptCache(); + if (abcPanel != null) { + abcPanel.reload(); + } + updateClassesList(); + reload(true); + } catch (Exception ex) { + logger.log(Level.SEVERE, "Error during renaming identifiers", ex); + Main.stopWork(); + View.showMessageDialog(null, translate("error.occured").replace("%error%", ex.getClass().getSimpleName())); + } + }); + } + }.execute(); + } + } + + public void renameOneIdentifier(final SWF swf) { + if (swf == null) { + return; + } + + FileAttributesTag fileAttributes = swf.getFileAttributes(); + if (fileAttributes != null && fileAttributes.actionScript3) { + final int multiName = getABCPanel().decompiledTextArea.getMultinameUnderCaret(); + final List abcList = swf.getAbcList(); + if (multiName > 0) { + new CancellableWorker() { + @Override + public Void doInBackground() throws Exception { + renameMultiname(abcList, multiName); + return null; + } + + @Override + protected void onStart() { + Main.startWork(translate("work.renaming") + "...", this); + } + + @Override + protected void done() { + Main.stopWork(); + } + }.execute(); + + } else { + View.showMessageDialog(null, translate("message.rename.notfound.multiname"), translate("message.rename.notfound.title"), JOptionPane.INFORMATION_MESSAGE); + } + } else { + final String identifier = getActionPanel().getStringUnderCursor(); + if (identifier != null) { + new CancellableWorker() { + @Override + public Void doInBackground() throws Exception { + try { + renameIdentifier(swf, identifier); + } catch (InterruptedException ex) { + logger.log(Level.SEVERE, null, ex); + } + return null; + } + + @Override + protected void onStart() { + Main.startWork(translate("work.renaming") + "...", this); + } + + @Override + protected void done() { + Main.stopWork(); + } + }.execute(); + } else { + View.showMessageDialog(null, translate("message.rename.notfound.identifier"), translate("message.rename.notfound.title"), JOptionPane.INFORMATION_MESSAGE); + } + } + } + + public void exportFla(final SWF swf) { + if (swf == null) { + return; + } + JFileChooser fc = new JFileChooser(); + String selDir = Configuration.lastOpenDir.get(); + fc.setCurrentDirectory(new File(selDir)); + if (!selDir.endsWith(File.separator)) { + selDir += File.separator; + } + String fileName = new File(swf.getFile()).getName(); + fileName = fileName.substring(0, fileName.length() - 4) + ".fla"; + fc.setSelectedFile(new File(selDir + fileName)); + List flaFilters = new ArrayList<>(); + List xflFilters = new ArrayList<>(); + List versions = new ArrayList<>(); + boolean isAS3 = swf.isAS3(); + for (int i = FLAVersion.values().length - 1; i >= 0; i--) { + final FLAVersion v = FLAVersion.values()[i]; + if (!isAS3 && v.minASVersion() > 2) { + // This version does not support AS1/2 + } else { + versions.add(v); + FileFilter f = new FileFilter() { + @Override + public boolean accept(File f) { + return f.isDirectory() || (f.getName().toLowerCase().endsWith(".fla")); + } + + @Override + public String getDescription() { + return translate("filter.fla").replace("%version%", v.applicationName()); + } + }; + if (v == FLAVersion.CS6) { + fc.setFileFilter(f); + } else { + fc.addChoosableFileFilter(f); + } + flaFilters.add(f); + f = new FileFilter() { + @Override + public boolean accept(File f) { + return f.isDirectory() || (f.getName().toLowerCase().endsWith(".xfl")); + } + + @Override + public String getDescription() { + return translate("filter.xfl").replace("%version%", v.applicationName()); + } + }; + fc.addChoosableFileFilter(f); + xflFilters.add(f); + } + } + + fc.setAcceptAllFileFilterUsed(false); + JFrame f = new JFrame(); + View.setWindowIcon(f); + if (fc.showSaveDialog(f) == JFileChooser.APPROVE_OPTION) { + Configuration.lastOpenDir.set(Helper.fixDialogFile(fc.getSelectedFile()).getParentFile().getAbsolutePath()); + File sf = Helper.fixDialogFile(fc.getSelectedFile()); + + FileFilter selectedFilter = fc.getFileFilter(); + final boolean compressed = flaFilters.contains(selectedFilter); + String path = sf.getAbsolutePath(); + if (path.endsWith(".fla") || path.endsWith(".xfl")) { + path = path.substring(0, path.length() - 4); + } + path += compressed ? ".fla" : ".xfl"; + final FLAVersion selectedVersion = versions.get(compressed ? flaFilters.indexOf(selectedFilter) : xflFilters.indexOf(selectedFilter)); + final File selfile = new File(path); + new CancellableWorker() { + @Override + protected Void doInBackground() throws Exception { + Helper.freeMem(); + try { + AbortRetryIgnoreHandler errorHandler = new GuiAbortRetryIgnoreHandler(); + if (compressed) { + swf.exportFla(errorHandler, selfile.getAbsolutePath(), new File(swf.getFile()).getName(), ApplicationInfo.APPLICATION_NAME, ApplicationInfo.applicationVerName, ApplicationInfo.version, Configuration.parallelSpeedUp.get(), selectedVersion); + } else { + swf.exportXfl(errorHandler, selfile.getAbsolutePath(), new File(swf.getFile()).getName(), ApplicationInfo.APPLICATION_NAME, ApplicationInfo.applicationVerName, ApplicationInfo.version, Configuration.parallelSpeedUp.get(), selectedVersion); + } + } catch (Exception ex) { + logger.log(Level.SEVERE, "FLA export error", ex); + View.showMessageDialog(null, translate("error.export") + ": " + ex.getClass().getName() + " " + ex.getLocalizedMessage(), translate("error"), JOptionPane.ERROR_MESSAGE); + } + Helper.freeMem(); + return null; + } + + @Override + protected void onStart() { + Main.startWork(translate("work.exporting.fla") + "...", this); + } + + @Override + protected void done() { + if (Configuration.openFolderAfterFlaExport.get()) { + try { + Desktop.getDesktop().open(selfile.getAbsoluteFile().getParentFile()); + } catch (IOException ex) { + logger.log(Level.SEVERE, null, ex); + } + } + + Main.stopWork(); + } + }.execute(); + } + } + + public void importText(final SWF swf) { + JFileChooser chooser = new JFileChooser(); + chooser.setCurrentDirectory(new File(Configuration.lastExportDir.get())); + chooser.setDialogTitle(translate("import.select.directory")); + chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + chooser.setAcceptAllFileFilterUsed(false); + if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { + String selFile = Helper.fixDialogFile(chooser.getSelectedFile()).getAbsolutePath(); + File textsFile = new File(Path.combine(selFile, TextExportSettings.EXPORT_FOLDER_NAME, TextExporter.TEXT_EXPORT_FILENAME_FORMATTED)); + TextImporter textImporter = new TextImporter(getMissingCharacterHandler(), new TextImportErrorHandler() { + // "configuration items" for the current replace only + private final ConfigurationItem showAgainImportError = new ConfigurationItem<>("showAgainImportError", true, true); + + private final ConfigurationItem showAgainInvalidText = new ConfigurationItem<>("showAgainInvalidText", true, true); + + private String getTextTagInfo(TextTag textTag) { + StringBuilder ret = new StringBuilder(); + if (textTag != null) { + ret.append(" TextId: ").append(textTag.getCharacterId()).append(" (").append(String.join(", ", textTag.getTexts())).append(")"); + } + + return ret.toString(); + } + + @Override + public boolean handle(TextTag textTag) { + String msg = translate("error.text.import"); + logger.log(Level.SEVERE, msg + getTextTagInfo(textTag)); + return View.showConfirmDialog(MainPanel.this, msg, translate("error"), JOptionPane.OK_CANCEL_OPTION, showAgainImportError, JOptionPane.OK_OPTION) != JOptionPane.OK_OPTION; + } + + @Override + public boolean handle(TextTag textTag, String message, long line) { + String msg = translate("error.text.invalid.continue").replace("%text%", message).replace("%line%", Long.toString(line)); + logger.log(Level.SEVERE, msg + getTextTagInfo(textTag)); + return View.showConfirmDialog(MainPanel.this, msg, translate("error"), JOptionPane.OK_CANCEL_OPTION, showAgainInvalidText, JOptionPane.OK_OPTION) != JOptionPane.OK_OPTION; + } + }); + + // try to import formatted texts + if (textsFile.exists()) { + textImporter.importTextsSingleFileFormatted(textsFile, swf); + } else { + textsFile = new File(Path.combine(selFile, TextExportSettings.EXPORT_FOLDER_NAME, TextExporter.TEXT_EXPORT_FILENAME_PLAIN)); + // try to import plain texts + if (textsFile.exists()) { + textImporter.importTextsSingleFile(textsFile, swf); + } else { + textImporter.importTextsMultipleFiles(selFile, swf); + } + } + + swf.clearImageCache(); + reload(true); + } + } + + public As3ScriptReplacerInterface getAs3ScriptReplacer() { + As3ScriptReplacerInterface r = As3ScriptReplacerFactory.createByConfig(); + if (!r.isAvailable()) { + if (r instanceof MxmlcAs3ScriptReplacer) { + if (View.showConfirmDialog(null, AppStrings.translate("message.flexpath.notset"), AppStrings.translate("error"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.OK_OPTION) { + Main.advancedSettings("paths"); + } + } else if (r instanceof FFDecAs3ScriptReplacer) { + if (View.showConfirmDialog(this, AppStrings.translate("message.playerpath.lib.notset"), AppStrings.translate("message.action.playerglobal.title"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.OK_OPTION) { + Main.advancedSettings("paths"); + } + } else { + //Not translated yet - just in case there are more Script replacers in the future. Unused now. + View.showConfirmDialog(this, "Current script replacer is not available", "Script replacer not available", JOptionPane.OK_OPTION, JOptionPane.ERROR_MESSAGE); + } + return null; + } + return r; + } + + public void importScript(final SWF swf) { + As3ScriptReplacerInterface as3ScriptReplacer = getAs3ScriptReplacer(); + if (as3ScriptReplacer == null) { + return; + } + String flexLocation = Configuration.flexSdkLocation.get(); + JFileChooser chooser = new JFileChooser(); + chooser.setCurrentDirectory(new File(Configuration.lastExportDir.get())); + chooser.setDialogTitle(translate("import.select.directory")); + chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + chooser.setAcceptAllFileFilterUsed(false); + if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { + String selFile = Helper.fixDialogFile(chooser.getSelectedFile()).getAbsolutePath(); + String scriptsFolder = Path.combine(selFile, ScriptExportSettings.EXPORT_FOLDER_NAME); + + int countAs2 = new AS2ScriptImporter().importScripts(scriptsFolder, swf.getASMs(true)); + int countAs3 = new AS3ScriptImporter().importScripts(as3ScriptReplacer, scriptsFolder, swf.getAS3Packs()); + + if (countAs3 > 0) { + updateClassesList(); + } + + View.showMessageDialog(this, translate("import.script.result").replace("%count%", Integer.toString(countAs2 + countAs3))); + if (countAs2 != 0 || countAs3 != 0) { + reload(true); + } + } + } + + public void importSymbolClass(final SWF swf) { + JFileChooser chooser = new JFileChooser(); + chooser.setCurrentDirectory(new File(Configuration.lastExportDir.get())); + chooser.setDialogTitle(translate("import.select.directory")); + chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + chooser.setAcceptAllFileFilterUsed(false); + if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { + String selFile = Helper.fixDialogFile(chooser.getSelectedFile()).getAbsolutePath(); + File importFile = new File(Path.combine(selFile, SymbolClassExporter.SYMBOL_CLASS_EXPORT_FILENAME)); + SymbolClassImporter importer = new SymbolClassImporter(); + + if (importFile.exists()) { + importer.importSymbolClasses(importFile, swf); + } + } + } + + private String selectExportDir() { + JFileChooser chooser = new JFileChooser(); + chooser.setCurrentDirectory(new File(Configuration.lastExportDir.get())); + chooser.setDialogTitle(translate("export.select.directory")); + chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + chooser.setAcceptAllFileFilterUsed(false); + if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { + final String selFile = Helper.fixDialogFile(chooser.getSelectedFile()).getAbsolutePath(); + Configuration.lastExportDir.set(Helper.fixDialogFile(chooser.getSelectedFile()).getAbsolutePath()); + return selFile; + } + return null; + } + + public void export(final boolean onlySel) { + + final SWF swf = getCurrentSwf(); + List sel = tagTree.getAllSelected(); + if (!onlySel) { + sel = null; + } else if (sel.isEmpty()) { + return; + } + final ExportDialog export = new ExportDialog(sel); + if (export.showExportDialog() == AppDialog.OK_OPTION) { + final String selFile = selectExportDir(); + if (selFile != null) { + final long timeBefore = System.currentTimeMillis(); + + new CancellableWorker() { + @Override + public Void doInBackground() throws Exception { + try { + AbortRetryIgnoreHandler errorHandler = new GuiAbortRetryIgnoreHandler(); + if (onlySel) { + exportSelection(errorHandler, selFile, export); + } else { + exportAll(swf, errorHandler, selFile, export); + } + } catch (Exception ex) { + logger.log(Level.SEVERE, "Error during export", ex); + View.showMessageDialog(null, translate("error.export") + ": " + ex.getClass().getName() + " " + ex.getLocalizedMessage()); + } + return null; + } + + @Override + protected void onStart() { + Main.startWork(translate("work.exporting") + "...", this); + } + + @Override + protected void done() { + Main.stopWork(); + long timeAfter = System.currentTimeMillis(); + final long timeMs = timeAfter - timeBefore; + + View.execInEventDispatchLater(() -> { + setStatus(translate("export.finishedin").replace("%time%", Helper.formatTimeSec(timeMs))); + }); + } + }.execute(); + + } + } + } + + public void exportJavaSource() { + List sel = tagTree.getSelected(); + for (TreeItem item : sel) { + if (item instanceof SWF) { + SWF swf = (SWF) item; + final String selFile = selectExportDir(); + if (selFile != null) { + Main.startWork(translate("work.exporting") + "...", null); + + try { + new SwfJavaExporter().exportJavaCode(swf, selFile); + Main.stopWork(); + } catch (IOException ex) { + logger.log(Level.SEVERE, null, ex); + } + } + } + } + } + + public void exportSwfXml() { + List sel = tagTree.getSelected(); + Set swfs = new HashSet<>(); + + for (TreeItem item : sel) { + swfs.add(item.getSwf()); + } + + for (SWF swf : swfs) { + final String selFile = selectExportDir(); + if (selFile != null) { + Main.startWork(translate("work.exporting") + "...", null); + + try { + File outFile = new File(selFile + File.separator + Helper.makeFileName("swf.xml")); + new SwfXmlExporter().exportXml(swf, outFile); + Main.stopWork(); + } catch (IOException ex) { + logger.log(Level.SEVERE, null, ex); + } + } + } + } + + public void importSwfXml() { + List sel = tagTree.getSelected(); + Set swfs = new HashSet<>(); + for (TreeItem item : sel) { + swfs.add(item.getSwf()); + } + if (swfs.size() > 1) { + return; + } + + for (SWF swf : swfs) { + File selectedFile = showImportFileChooser("filter.xml|*.xml"); + if (selectedFile != null) { + File selfile = Helper.fixDialogFile(selectedFile); + String xml = Helper.readTextFile(selfile.getPath()); + try { + new SwfXmlImporter().importSwf(swf, xml); + swf.clearAllCache(); + swf.assignExportNamesToSymbols(); + swf.assignClassesToSymbols(); + refreshTree(swf); + } catch (IOException ex) { + logger.log(Level.SEVERE, null, ex); + } + } + } + } + + public void renameIdentifiers(final SWF swf) { + if (swf == null) { + return; + } + if (confirmExperimental()) { + RenameDialog renameDialog = new RenameDialog(); + if (renameDialog.showRenameDialog() == AppDialog.OK_OPTION) { + final RenameType renameType = renameDialog.getRenameType(); + new CancellableWorker() { + @Override + protected Integer doInBackground() throws Exception { + int cnt = swf.deobfuscateIdentifiers(renameType); + return cnt; + } + + @Override + protected void onStart() { + Main.startWork(translate("work.renaming.identifiers") + "...", this); + } + + @Override + protected void done() { + View.execInEventDispatch(() -> { + try { + int cnt = get(); + Main.stopWork(); + View.showMessageDialog(null, translate("message.rename.renamed").replace("%count%", Integer.toString(cnt))); + swf.assignClassesToSymbols(); + swf.clearScriptCache(); + if (abcPanel != null) { + abcPanel.reload(); + } + updateClassesList(); + reload(true); + } catch (Exception ex) { + logger.log(Level.SEVERE, "Error during renaming identifiers", ex); + Main.stopWork(); + View.showMessageDialog(null, translate("error.occured").replace("%error%", ex.getClass().getSimpleName())); + } + }); + } + }.execute(); + } + } + } + + public void deobfuscate() { + DeobfuscationDialog deobfuscationDialog = new DeobfuscationDialog(); + if (deobfuscationDialog.showDialog() == AppDialog.OK_OPTION) { + DeobfuscationLevel level = DeobfuscationLevel.getByLevel(deobfuscationDialog.codeProcessingLevel.getValue()); + new CancellableWorker() { + @Override + protected Void doInBackground() throws Exception { + try { + ABCPanel abcPanel = getABCPanel(); + if (deobfuscationDialog.processAllCheckbox.isSelected()) { + SWF swf = abcPanel.getSwf(); + swf.deobfuscate(level); + } else { + int bi = abcPanel.detailPanel.methodTraitPanel.methodCodePanel.getBodyIndex(); + DecompiledEditorPane decompiledTextArea = abcPanel.decompiledTextArea; + Trait t = abcPanel.decompiledTextArea.getCurrentTrait(); + ABC abc = abcPanel.abc; + if (bi != -1) { + int scriptIndex = decompiledTextArea.getScriptLeaf().scriptIndex; + int classIndex = decompiledTextArea.getClassIndex(); + boolean isStatic = decompiledTextArea.getIsStatic(); + abc.bodies.get(bi).deobfuscate(level, t, scriptIndex, classIndex, isStatic, ""/*FIXME*/); + } + abcPanel.detailPanel.methodTraitPanel.methodCodePanel.setBodyIndex(decompiledTextArea.getScriptLeaf().getPathScriptName(), bi, abc, t, abcPanel.detailPanel.methodTraitPanel.methodCodePanel.getScriptIndex()); + } + } catch (Exception ex) { + logger.log(Level.SEVERE, "Deobfuscation error", ex); + } + + return null; + } + + @Override + protected void onStart() { + Main.startWork(translate("work.deobfuscating") + "...", this); + } + + @Override + protected void done() { + View.execInEventDispatch(() -> { + Main.stopWork(); + View.showMessageDialog(null, translate("work.deobfuscating.complete")); + + clearAllScriptCache(); + getABCPanel().reload(); + updateClassesList(); + }); + } + }.execute(); + } + } + + public void removeNonScripts(SWF swf) { + if (swf == null) { + return; + } + + List tags = swf.getTags().toArrayList(); + List toRemove = new ArrayList<>(); + for (Tag tag : tags) { + System.out.println(tag.getClass()); + if (!(tag instanceof ABCContainerTag || tag instanceof ASMSource)) { + toRemove.add(tag); + } + } + + swf.removeTags(toRemove, true); + refreshTree(swf); + } + + public void removeExceptSelected(SWF swf) { + if (swf == null) { + return; + } + + List sel = tagTree.getAllSelected(); + Set needed = new HashSet<>(); + for (TreeItem item : sel) { + if (item instanceof CharacterTag) { + CharacterTag characterTag = (CharacterTag) item; + characterTag.getNeededCharactersDeep(needed); + needed.add(characterTag.getCharacterId()); + } + } + + List tagsToRemove = new ArrayList<>(); + for (Tag tag : swf.getTags()) { + if (tag instanceof CharacterTag) { + CharacterTag characterTag = (CharacterTag) tag; + if (!needed.contains(characterTag.getCharacterId())) { + tagsToRemove.add(tag); + } + } + } + + swf.removeTags(tagsToRemove, true); + refreshTree(swf); + } + + private void clear() { + dumpViewPanel.clear(); + previewPanel.clear(); + headerPanel.clear(); + folderPreviewPanel.clear(); + if (abcPanel != null) { + abcPanel.clearSwf(); + } + if (actionPanel != null) { + actionPanel.clearSource(); + } + } + + public void refreshTree() { + refreshTree(new SWF[0]); + } + + public void refreshTree(SWF swf) { + refreshTree(new SWF[]{swf}); + } + + public void refreshTree(SWF[] swfs) { + clear(); + showCard(CARDEMPTYPANEL); + TreeItem treeItem = tagTree.getCurrentTreeItem(); + + tagTree.updateSwfs(swfs); + + if (treeItem != null) { + SWF treeItemSwf = treeItem.getSwf().getRootSwf(); + if (this.swfs.contains(treeItemSwf.swfList)) { + setTagTreeSelectedNode(treeItem); + } + } + + reload(true); + } + + public void refreshDecompiled() { + clearAllScriptCache(); + if (abcPanel != null) { + abcPanel.reload(); + } + + reload(true); + updateClassesList(); + } + + private MissingCharacterHandler getMissingCharacterHandler() { + return new MissingCharacterHandler() { + // "configuration items" for the current replace only + private final ConfigurationItem showAgainIgnoreMissingCharacters = new ConfigurationItem<>("showAgainIgnoreMissingCharacters", true, true); + + private boolean ignoreMissingCharacters = false; + + @Override + public boolean getIgnoreMissingCharacters() { + return ignoreMissingCharacters; + } + + @Override + public boolean handle(TextTag textTag, final FontTag font, final char character) { + String fontName = font.getSwf().sourceFontNamesMap.get(font.getFontId()); + if (fontName == null) { + fontName = font.getFontName(); + } + final Font f = FontTag.installedFontsByName.get(fontName); + if (f == null || !f.canDisplay(character)) { + String msg = translate("error.font.nocharacter").replace("%char%", "" + character); + logger.log(Level.SEVERE, "{0} FontId: {1} TextId: {2}", new Object[]{msg, font.getCharacterId(), textTag.getCharacterId()}); + ignoreMissingCharacters = View.showConfirmDialog(null, msg, translate("error"), + JOptionPane.OK_CANCEL_OPTION, JOptionPane.ERROR_MESSAGE, + showAgainIgnoreMissingCharacters, + ignoreMissingCharacters ? JOptionPane.OK_OPTION : JOptionPane.CANCEL_OPTION) == JOptionPane.OK_OPTION; + return false; + } + + font.addCharacter(character, f); + + return true; + } + }; + } + + public boolean saveText(TextTag textTag, String formattedText, String[] texts, LineMarkedEditorPane editor) { + try { + if (textTag.setFormattedText(getMissingCharacterHandler(), formattedText, texts)) { + return true; + } + } catch (TextParseException ex) { + if (editor != null) { + editor.gotoLine((int) ex.line); + editor.markError(); + } + + View.showMessageDialog(null, translate("error.text.invalid").replace("%text%", ex.text).replace("%line%", Long.toString(ex.line)), translate("error"), JOptionPane.ERROR_MESSAGE); + } + + return false; + } + + public boolean alignText(TextTag textTag, TextAlign textAlign) { + return (textTag.alignText(textAlign)); + } + + public boolean translateText(TextTag textTag, int diff) { + return textTag.translateText(diff); + } + + public boolean previousTag() { + if (getCurrentView() == VIEW_RESOURCES) { + if (tagTree.getSelectionRows().length > 0) { + int row = tagTree.getSelectionRows()[0]; + if (row > 0) { + tagTree.setSelectionRow(row - 1); + tagTree.scrollRowToVisible(row - 1); + previewPanel.focusTextPanel(); + } + } + return true; + } + return false; + } + + public boolean nextTag() { + if (getCurrentView() == VIEW_RESOURCES) { + if (tagTree.getSelectionRows().length > 0) { + int row = tagTree.getSelectionRows()[0]; + if (row < tagTree.getRowCount() - 1) { + tagTree.setSelectionRow(row + 1); + tagTree.scrollRowToVisible(row + 1); + previewPanel.focusTextPanel(); + } + } + return true; + } + return false; + } + + public void selectBkColorButtonActionPerformed(ActionEvent evt) { + Color newColor = JColorChooser.showDialog(null, AppStrings.translate("dialog.selectbkcolor.title"), View.getSwfBackgroundColor()); + if (newColor != null) { + View.setSwfBackgroundColor(newColor); + reload(true); + } + } + + public void replaceButtonActionPerformed(ActionEvent evt) { + TreeItem item = tagTree.getCurrentTreeItem(); + if (item == null) { + return; + } + + if (item instanceof DefineSoundTag) { + File selectedFile = showImportFileChooser("filter.sounds|*.mp3;*.wav|filter.sounds.mp3|*.mp3|filter.sounds.wav|*.wav"); + if (selectedFile != null) { + File selfile = Helper.fixDialogFile(selectedFile); + DefineSoundTag ds = (DefineSoundTag) item; + int soundFormat = SoundFormat.FORMAT_UNCOMPRESSED_LITTLE_ENDIAN; + if (selfile.getName().toLowerCase().endsWith(".mp3")) { + soundFormat = SoundFormat.FORMAT_MP3; + } + + boolean ok = false; + try { + ok = ds.setSound(new FileInputStream(selfile), soundFormat); + ds.getSwf().clearSoundCache(); + } catch (IOException ex) { + //ignore + } + + if (!ok) { + View.showMessageDialog(null, translate("error.sound.invalid"), translate("error"), JOptionPane.ERROR_MESSAGE); + } else { + reload(true); + } + } + } + if (item instanceof ImageTag) { + ImageTag it = (ImageTag) item; + if (it.importSupported()) { + File selectedFile = showImportFileChooser("filter.images|*.jpg;*.jpeg;*.gif;*.png;*.bmp"); + if (selectedFile != null) { + File selfile = Helper.fixDialogFile(selectedFile); + byte[] data = Helper.readFile(selfile.getAbsolutePath()); + try { + Tag newTag = new ImageImporter().importImage(it, data); + SWF swf = it.getSwf(); + if (newTag != null) { + refreshTree(swf); + setTagTreeSelectedNode(newTag); + } + swf.clearImageCache(); + } catch (IOException ex) { + logger.log(Level.SEVERE, "Invalid image", ex); + View.showMessageDialog(null, translate("error.image.invalid"), translate("error"), JOptionPane.ERROR_MESSAGE); + } + + reload(true); + } + } + } + if (item instanceof ShapeTag) { + ShapeTag st = (ShapeTag) item; + String filter = "filter.images|*.jpg;*.jpeg;*.gif;*.png;*.bmp;*.svg"; + File selectedFile = showImportFileChooser(filter); + if (selectedFile != null) { + File selfile = Helper.fixDialogFile(selectedFile); + byte[] data = null; + String svgText = null; + if (".svg".equals(Path.getExtension(selfile))) { + svgText = Helper.readTextFile(selfile.getAbsolutePath()); + showSvgImportWarning(); + } else { + data = Helper.readFile(selfile.getAbsolutePath()); + } + try { + Tag newTag = svgText != null ? new SvgImporter().importSvg(st, svgText) : new ShapeImporter().importImage(st, data); + SWF swf = st.getSwf(); + if (newTag != null) { + refreshTree(swf); + setTagTreeSelectedNode(newTag); + } + + swf.clearImageCache(); + } catch (IOException ex) { + logger.log(Level.SEVERE, "Invalid image", ex); + View.showMessageDialog(null, translate("error.image.invalid"), translate("error"), JOptionPane.ERROR_MESSAGE); + } + reload(true); + } + } + if (item instanceof DefineBinaryDataTag) { + DefineBinaryDataTag bt = (DefineBinaryDataTag) item; + File selectedFile = showImportFileChooser(""); + if (selectedFile != null) { + File selfile = Helper.fixDialogFile(selectedFile); + byte[] data = Helper.readFile(selfile.getAbsolutePath()); + new BinaryDataImporter().importData(bt, data); + refreshTree(bt.getSwf()); + reload(true); + } + } + } + + public void replaceNoFillButtonActionPerformed(ActionEvent evt) { + TreeItem item = tagTree.getCurrentTreeItem(); + if (item == null) { + return; + } + + if (item instanceof ShapeTag) { + ShapeTag st = (ShapeTag) item; + String filter = "filter.images|*.jpg;*.jpeg;*.gif;*.png;*.bmp;*.svg"; + File selectedFile = showImportFileChooser(filter); + if (selectedFile != null) { + File selfile = Helper.fixDialogFile(selectedFile); + byte[] data = null; + String svgText = null; + if (".svg".equals(Path.getExtension(selfile))) { + svgText = Helper.readTextFile(selfile.getAbsolutePath()); + showSvgImportWarning(); + } else { + data = Helper.readFile(selfile.getAbsolutePath()); + } + try { + Tag newTag = svgText != null ? new SvgImporter().importSvg(st, svgText, false) : new ShapeImporter().importImage(st, data, 0, false); + SWF swf = st.getSwf(); + if (newTag != null) { + refreshTree(swf); + setTagTreeSelectedNode(newTag); + } + + swf.clearImageCache(); + } catch (IOException ex) { + logger.log(Level.SEVERE, "Invalid image", ex); + View.showMessageDialog(null, translate("error.image.invalid"), translate("error"), JOptionPane.ERROR_MESSAGE); + } + reload(true); + } + } + } + + private void showSvgImportWarning() { + View.showMessageDialog(null, AppStrings.translate("message.warning.svgImportExperimental"), AppStrings.translate("message.warning"), JOptionPane.WARNING_MESSAGE, Configuration.warningSvgImport); + } + + public void replaceAlphaButtonActionPerformed(ActionEvent evt) { + TreeItem item = tagTree.getCurrentTreeItem(); + if (item == null) { + return; + } + + if (item instanceof DefineBitsJPEG3Tag || item instanceof DefineBitsJPEG4Tag) { + ImageTag it = (ImageTag) item; + if (it.importSupported()) { + File selectedFile = showImportFileChooser(""); + if (selectedFile != null) { + File selfile = Helper.fixDialogFile(selectedFile); + byte[] data = Helper.readFile(selfile.getAbsolutePath()); + try { + new ImageImporter().importImageAlpha(it, data); + SWF swf = it.getSwf(); + swf.clearImageCache(); + } catch (IOException ex) { + logger.log(Level.SEVERE, "Invalid alpha channel data", ex); + View.showMessageDialog(null, translate("error.image.alpha.invalid"), translate("error"), JOptionPane.ERROR_MESSAGE); + } + + reload(true); + } + } + } + } + + public void exportJavaSourceActionPerformed(ActionEvent evt) { + if (Main.isWorking()) { + return; + } + + exportJavaSource(); + } + + public void exportSwfXmlActionPerformed(ActionEvent evt) { + if (Main.isWorking()) { + return; + } + + exportSwfXml(); + } + + public void importSwfXmlActionPerformed(ActionEvent evt) { + if (Main.isWorking()) { + return; + } + + importSwfXml(); + } + + public void exportSelectionActionPerformed(ActionEvent evt) { + if (Main.isWorking()) { + return; + } + + export(true); + } + + public File showImportFileChooser(String filter) { + String[] filterArray = filter.length() > 0 ? filter.split("\\|") : new String[0]; + + JFileChooser fc = new JFileChooser(); + fc.setCurrentDirectory(new File(Configuration.lastOpenDir.get())); + boolean first = true; + for (int i = 0; i < filterArray.length; i += 2) { + final String filterName = filterArray[i]; + final String[] extensions = filterArray[i + 1].split(";"); + for (int j = 0; j < extensions.length; j++) { + if (extensions[j].startsWith("*.")) { + extensions[j] = extensions[j].substring(1); + } + } + FileFilter ff = new FileFilter() { + @Override + public boolean accept(File f) { + if (f.isDirectory()) { + return true; + } + String fileName = f.getName().toLowerCase(); + for (String ext : extensions) { + if (fileName.endsWith(ext)) { + return true; + } + } + return false; + } + + @Override + public String getDescription() { + StringBuilder extStr = new StringBuilder(); + boolean first = true; + for (String ext : extensions) { + if (first) { + first = false; + } else { + extStr.append(","); + } + + extStr.append("*").append(ext); + } + + return translate(filterName).replace("%extensions%", extStr); + } + }; + if (first) { + fc.setFileFilter(ff); + } else { + fc.addChoosableFileFilter(ff); + } + first = false; + } + + JFrame f = new JFrame(); + View.setWindowIcon(f); + if (fc.showOpenDialog(f) == JFileChooser.APPROVE_OPTION) { + File result = fc.getSelectedFile(); + Configuration.lastOpenDir.set(Helper.fixDialogFile(result).getParentFile().getAbsolutePath()); + return result; + } + + return null; + } + + private void showDetail(String card) { + CardLayout cl = (CardLayout) (detailPanel.getLayout()); + cl.show(detailPanel, card); + if (card.equals(DETAILCARDEMPTYPANEL)) { + if (detailPanel.isVisible()) { + detailPanel.setVisible(false); + } + } else if (!detailPanel.isVisible()) { + detailPanel.setVisible(true); + } + } + + private void showCard(String card) { + CardLayout cl = (CardLayout) (displayPanel.getLayout()); + cl.show(displayPanel, card); + } + + @Override + public void valueChanged(TreeSelectionEvent e) { + Object source = e.getSource(); + TreeItem treeItem = (TreeItem) e.getPath().getLastPathComponent(); + + if (!(treeItem instanceof SWFList)) { + SWF swf = treeItem.getSwf(); + if (swfs.isEmpty()) { + // show welcome panel after closing swfs + updateUi(); + } else { + if (swf == null) { + swf = swfs.get(0).get(0); + } + + updateUi(swf); + } + } else { + updateUi(); + } + + reload(false); + + if (source == dumpTree) { + Tag t = null; + if (treeItem instanceof DumpInfo) { + DumpInfo di = (DumpInfo) treeItem; + t = di.getTag(); + } + + showPreview(t, dumpPreviewPanel); + } + } + + public void unloadFlashPlayer() { + if (flashPanel != null) { + try { + flashPanel.close(); + } catch (IOException ex) { + // ignore + } + } + if (flashPanel2 != null) { + try { + flashPanel2.close(); + } catch (IOException ex) { + // ignore + } + } + } + + public void clearDebuggerColors() { + if (abcPanel != null) { + abcPanel.decompiledTextArea.removeColorMarkerOnAllLines(DecompiledEditorPane.IP_MARKER); + abcPanel.detailPanel.methodTraitPanel.methodCodePanel.clearDebuggerColors(); + } + if (actionPanel != null) { + actionPanel.decompiledEditor.removeColorMarkerOnAllLines(DecompiledEditorPane.IP_MARKER); + actionPanel.editor.removeColorMarkerOnAllLines(DecompiledEditorPane.IP_MARKER); + } + } + + private void stopFlashPlayer() { + if (flashPanel != null) { + if (!flashPanel.isStopped()) { + flashPanel.stopSWF(); + } + } + if (flashPanel2 != null) { + if (!flashPanel2.isStopped()) { + flashPanel2.stopSWF(); + } + } + } + + public boolean isInternalFlashViewerSelected() { + return mainMenu.isInternalFlashViewerSelected(); + } + + public static final int VIEW_RESOURCES = 0; + + public static final int VIEW_DUMP = 1; + + public static final int VIEW_TIMELINE = 2; + + private int getCurrentView() { + return Configuration.dumpView.get() ? VIEW_DUMP : VIEW_RESOURCES; + } + + public void setTreeModel(int view) { + switch (view) { + case VIEW_DUMP: + if (dumpTree.getModel() == null) { + DumpTreeModel dtm = new DumpTreeModel(swfs); + dumpTree.setModel(dtm); + dumpTree.expandFirstLevelNodes(); + } + break; + case VIEW_RESOURCES: + if (tagTree.getModel() == null) { + TagTreeModel ttm = new TagTreeModel(swfs, Configuration.tagTreeShowEmptyFolders.get()); + tagTree.setModel(ttm); + tagTree.expandFirstLevelNodes(); + } + break; + } + } + + private JPanel createDumpViewCard() { + JPanel r = new JPanel(new BorderLayout()); + r.add(new JPersistentSplitPane(JSplitPane.VERTICAL_SPLIT, new JScrollPane(dumpTree), dumpPreviewPanel, Configuration.guiDumpSplitPaneDividerLocationPercent), BorderLayout.CENTER); + return r; + } + + private JPanel createResourcesViewCard() { + JPanel r = new JPanel(new BorderLayout()); + r.add(new JScrollPane(tagTree), BorderLayout.CENTER); + r.add(searchPanel, BorderLayout.SOUTH); + return r; + } + + public boolean showView(int view) { + + CardLayout cl = (CardLayout) (contentPanel.getLayout()); + CardLayout cl2 = (CardLayout) (treePanel.getLayout()); + + setTreeModel(view); + switch (view) { + case VIEW_DUMP: + if (!isWelcomeScreen) { + cl.show(contentPanel, SPLIT_PANE1); + } + cl2.show(treePanel, DUMP_VIEW); + treePanelMode = TreePanelMode.DUMP_TREE; + showDetail(DETAILCARDEMPTYPANEL); + reload(true); + return true; + case VIEW_RESOURCES: + if (!isWelcomeScreen) { + cl.show(contentPanel, SPLIT_PANE1); + } + cl2.show(treePanel, RESOURCES_VIEW); + + treePanelMode = TreePanelMode.TAG_TREE; + + treePanel.addComponentListener(new ComponentAdapter() { + @Override + public void componentResized(ComponentEvent e) { + tagTree.scrollPathToVisible(tagTree.getSelectionPath()); + } + }); + + reload(true); + return true; + case VIEW_TIMELINE: + final SWF swf = getCurrentSwf(); + if (swf != null) { + TreeItem item = tagTree.getCurrentTreeItem(); + if (item instanceof TagScript) { + item = ((TagScript) item).getTag(); + } + if (item instanceof Timelined) { + timelineViewPanel.setTimelined((Timelined) item); + } else if (item instanceof Frame) { + timelineViewPanel.setTimelined(((Frame) item).timeline.timelined); + } else { + timelineViewPanel.setTimelined(swf); + } + cl.show(contentPanel, TIMELINE_PANEL); + return true; + } + return false; + } + return false; + + } + + private void dumpViewReload(boolean forceReload) { + showDetail(DETAILCARDEMPTYPANEL); + + DumpInfo dumpInfo = (DumpInfo) dumpTree.getLastSelectedPathComponent(); + if (dumpInfo == null) { + showCard(CARDEMPTYPANEL); + return; + } + + dumpViewPanel.revalidate(); + dumpViewPanel.setSelectedNode(dumpInfo); + showCard(CARDDUMPVIEW); + } + + public void loadFromBinaryTag(final DefineBinaryDataTag binaryDataTag) { + loadFromBinaryTag(Arrays.asList(binaryDataTag)); + } + + public void loadFromBinaryTag(final List binaryDataTags) { + + Main.loadingDialog.setVisible(true); + new CancellableWorker() { + @Override + protected Void doInBackground() throws Exception { + try { + for (DefineBinaryDataTag binaryDataTag : binaryDataTags) { + try { + InputStream is = new ByteArrayInputStream(binaryDataTag.binaryData.getRangeData()); + SWF bswf = new SWF(is, null, "(SWF Data)", new ProgressListener() { + @Override + public void progress(int p) { + Main.loadingDialog.setPercent(p); + } + }, Configuration.parallelSpeedUp.get()); + binaryDataTag.innerSwf = bswf; + bswf.binaryData = binaryDataTag; + } catch (IOException ex) { + //ignore + } + } + } catch (InterruptedException ex) { + //ignore + } + + return null; + } + + @Override + protected void onStart() { + Main.startWork(AppStrings.translate("work.reading.swf") + "...", this); + } + + @Override + protected void done() { + View.execInEventDispatch(() -> { + Main.loadingDialog.setVisible(false); + Main.stopWork(); + }); + } + }.execute(); + } + + private void closeTag() { + previewPanel.closeTag(); + } + + public void showPreview(TreeItem treeItem, PreviewPanel previewPanel) { + previewPanel.clear(); + if (treeItem == null) { + previewPanel.showEmpty(); + return; + } + boolean internalViewer = isInternalFlashViewerSelected(); + if (treeItem instanceof SWF) { + SWF swf = (SWF) treeItem; + if (internalViewer) { + previewPanel.showImagePanel(swf, swf, -1); + } else { + previewPanel.setParametersPanelVisible(false); + if (flashPanel != null) { //same for flashPanel2 + previewPanel.showFlashViewerPanel(); + previewPanel.showSwf(swf); + } + } + } else if (treeItem instanceof MetadataTag) { + MetadataTag metadataTag = (MetadataTag) treeItem; + previewPanel.showMetaDataPanel(metadataTag); + } else if (treeItem instanceof DefineBinaryDataTag) { + DefineBinaryDataTag binaryTag = (DefineBinaryDataTag) treeItem; + previewPanel.showBinaryPanel(binaryTag); + } else if (treeItem instanceof ImageTag) { + ImageTag imageTag = (ImageTag) treeItem; + previewPanel.setImageReplaceButtonVisible(!((Tag) imageTag).isReadOnly() && imageTag.importSupported(), imageTag instanceof DefineBitsJPEG3Tag || imageTag instanceof DefineBitsJPEG4Tag); + previewPanel.showImagePanel(imageTag.getImageCached()); + + } else if ((treeItem instanceof DrawableTag) && (!(treeItem instanceof TextTag)) && (!(treeItem instanceof FontTag)) && internalViewer) { + final Tag tag = (Tag) treeItem; + DrawableTag d = (DrawableTag) tag; + Timelined timelined; + if (treeItem instanceof Timelined && !(treeItem instanceof ButtonTag)) { + timelined = (Timelined) tag; + } else { + timelined = makeTimelined(tag); + } + + previewPanel.setParametersPanelVisible(false); + previewPanel.showImagePanel(timelined, tag.getSwf(), -1); + } else if (treeItem instanceof Frame && internalViewer) { + Frame fn = (Frame) treeItem; + SWF swf = fn.getSwf(); + previewPanel.showImagePanel(fn.timeline.timelined, swf, fn.frame); + } else if ((treeItem instanceof SoundTag)) { //&& isInternalFlashViewerSelected() && (Arrays.asList("mp3", "wav").contains(((SoundTag) tagObj).getExportFormat())))) { + previewPanel.showImagePanel(new SerializableImage(View.loadImage("sound32"))); + previewPanel.setImageReplaceButtonVisible(((Tag) treeItem).isReadOnly() && (treeItem instanceof DefineSoundTag), false); + try { + SoundTagPlayer soundThread = new SoundTagPlayer((SoundTag) treeItem, Configuration.loopMedia.get() ? Integer.MAX_VALUE : 1, true); + previewPanel.setMedia(soundThread); + } catch (LineUnavailableException | IOException | UnsupportedAudioFileException ex) { + logger.log(Level.SEVERE, null, ex); + } + + } else if ((treeItem instanceof FontTag) && internalViewer) { + previewPanel.showFontPanel((FontTag) treeItem); + } else if ((treeItem instanceof TextTag) && internalViewer) { + previewPanel.showTextPanel((TextTag) treeItem); + } else if ((treeItem instanceof Frame) || (treeItem instanceof CharacterTag) || (treeItem instanceof FontTag) || (treeItem instanceof SoundStreamHeadTypeTag)) { + previewPanel.createAndShowTempSwf(treeItem); + + if (treeItem instanceof TextTag) { + previewPanel.showTextPanel((TextTag) treeItem); + } else if (treeItem instanceof FontTag) { + previewPanel.showFontPanel((FontTag) treeItem); + } else { + previewPanel.setParametersPanelVisible(false); + } + } else { + previewPanel.showEmpty(); + } + } + + public void reload(boolean forceReload) { + tagTree.scrollPathToVisible(tagTree.getSelectionPath()); + if (Configuration.dumpView.get()) { + dumpViewReload(forceReload); + return; + } + + TreeItem treeItem = null; + TreePath treePath = tagTree.getSelectionPath(); + if (treePath != null && tagTree.getModel().treePathExists(treePath)) { + treeItem = (TreeItem) treePath.getLastPathComponent(); + } + + // save last selected node to config + if (treeItem != null) { + SWF swf = treeItem.getSwf(); + if (swf != null) { + swf = swf.getRootSwf(); + } + + if (swf != null) { + SwfSpecificConfiguration swfConf = Configuration.getOrCreateSwfSpecificConfiguration(swf.getShortFileName()); + swfConf.lastSelectedPath = tagTree.getSelectionPathString(); + } + } + + if (!forceReload && (treeItem == oldItem)) { + return; + } + + if (oldItem != treeItem) { + closeTag(); + } + + oldItem = treeItem; + + // show the preview of the tag when the user clicks to the tagname inside the scripts node, too + // this is a little bit inconsistent, beacuse the frames (FrameScript) are not shown + boolean preferScript = false; + if (treeItem instanceof TagScript) { + treeItem = ((TagScript) treeItem).getTag(); + preferScript = true; + } + + folderPreviewPanel.clear(); + previewPanel.clear(); + stopFlashPlayer(); + + previewPanel.setImageReplaceButtonVisible(false, false); + + boolean internalViewer = isInternalFlashViewerSelected(); + + if (treeItem instanceof ScriptPack) { + final ScriptPack scriptLeaf = (ScriptPack) treeItem; + if (setSourceWorker != null) { + setSourceWorker.cancel(true); + setSourceWorker = null; + } + if (!Main.isInited() || !Main.isWorking() || Main.isDebugging()) { + ABCPanel abcPanel = getABCPanel(); + CancellableWorker worker = new CancellableWorker() { + @Override + protected Void doInBackground() throws Exception { + abcPanel.detailPanel.methodTraitPanel.methodCodePanel.clear(); + abcPanel.setAbc(scriptLeaf.abc); + abcPanel.decompiledTextArea.setScript(scriptLeaf, true); + abcPanel.decompiledTextArea.setNoTrait(); + return null; + } + + @Override + protected void onStart() { + Main.startWork(translate("work.decompiling") + "...", this); + } + + @Override + protected void done() { + View.execInEventDispatch(() -> { + setSourceWorker = null; + try { + get(); + } catch (CancellationException ex) { + abcPanel.decompiledTextArea.setText("// " + AppStrings.translate("work.canceled")); + } catch (Exception ex) { + logger.log(Level.SEVERE, "Error", ex); + getABCPanel().decompiledTextArea.setText("// " + AppStrings.translate("decompilationError") + ": " + ex); + } + + Main.stopWork(); + }); + } + }; + + worker.execute(); + setSourceWorker = worker; + } + + showDetail(DETAILCARDAS3NAVIGATOR); + showCard(CARDACTIONSCRIPT3PANEL); + return; + } + + if (treeItem instanceof Tag) { + Tag tag = (Tag) treeItem; + TagInfo tagInfo = new TagInfo(); + tag.getTagInfo(tagInfo); + if (!tagInfo.isEmpty()) { + tagInfoPanel.setTagInfos(tagInfo); + showDetail(DETAILCARDTAGINFO); + } else { + showDetail(DETAILCARDEMPTYPANEL); + } + } else { + showDetail(DETAILCARDEMPTYPANEL); + } + + if (treeItem instanceof HeaderItem) { + headerPanel.load(((HeaderItem) treeItem).getSwf()); + showCard(CARDHEADER); + } else if (treeItem instanceof FolderItem) { + showFolderPreview((FolderItem) treeItem); + } else if (treeItem instanceof SWF) { + showPreview(treeItem, previewPanel); + showCard(CARDPREVIEWPANEL); + } else if (treeItem instanceof MetadataTag) { + showPreview(treeItem, previewPanel); + showCard(CARDPREVIEWPANEL); + } else if (treeItem instanceof DefineBinaryDataTag) { + showPreview(treeItem, previewPanel); + showCard(CARDPREVIEWPANEL); + } else if (treeItem instanceof ASMSource && (!(treeItem instanceof DrawableTag) || preferScript)) { + getActionPanel().setSource((ASMSource) treeItem, !forceReload); + showCard(CARDACTIONSCRIPTPANEL); + } else if (treeItem instanceof ImageTag) { + showPreview(treeItem, previewPanel); + showCard(CARDPREVIEWPANEL); + } else if ((treeItem instanceof DrawableTag) && (!(treeItem instanceof TextTag)) && (!(treeItem instanceof FontTag)) && internalViewer) { + showPreview(treeItem, previewPanel); + showCard(CARDPREVIEWPANEL); + } else if ((treeItem instanceof FontTag) && internalViewer) { + showPreview(treeItem, previewPanel); + showCard(CARDPREVIEWPANEL); + } else if ((treeItem instanceof TextTag) && internalViewer) { + showPreview(treeItem, previewPanel); + showCard(CARDPREVIEWPANEL); + } else if (treeItem instanceof Frame && internalViewer) { + showPreview(treeItem, previewPanel); + showCard(CARDPREVIEWPANEL); + } else if ((treeItem instanceof SoundTag)) { //&& isInternalFlashViewerSelected() && (Arrays.asList("mp3", "wav").contains(((SoundTag) tagObj).getExportFormat())))) { + showPreview(treeItem, previewPanel); + showCard(CARDPREVIEWPANEL); + } else if ((treeItem instanceof Frame) || (treeItem instanceof CharacterTag) || (treeItem instanceof FontTag) || (treeItem instanceof SoundStreamHeadTypeTag)) { + showPreview(treeItem, previewPanel); + + showCard(CARDPREVIEWPANEL); + } else if (treeItem instanceof Tag) { + showGenericTag((Tag) treeItem); + } else { + showCard(CARDEMPTYPANEL); + } + } + + public void repaintTree() { + tagTree.repaint(); + reload(true); + } + + public void showGenericTag(Tag tag) { + previewPanel.showGenericTagPanel(tag); + showCard(CARDPREVIEWPANEL); + } + + public void showTextTagWithNewValue(TextTag textTag, TextTag newTextTag) { + + previewPanel.showTextComparePanel(textTag, newTextTag); + } + + private void showFolderPreview(FolderItem item) { + List folderPreviewItems = new ArrayList<>(); + String folderName = item.getName(); + SWF swf = item.swf; + switch (folderName) { + case TagTreeModel.FOLDER_SHAPES: + for (Tag tag : swf.getTags()) { + if (tag instanceof ShapeTag) { + folderPreviewItems.add(tag); + } + } + break; + case TagTreeModel.FOLDER_MORPHSHAPES: + for (Tag tag : swf.getTags()) { + if (tag instanceof MorphShapeTag) { + folderPreviewItems.add(tag); + } + } + break; + case TagTreeModel.FOLDER_SPRITES: + for (Tag tag : swf.getTags()) { + if (tag instanceof DefineSpriteTag) { + folderPreviewItems.add(tag); + } + } + break; + case TagTreeModel.FOLDER_BUTTONS: + for (Tag tag : swf.getTags()) { + if (tag instanceof ButtonTag) { + folderPreviewItems.add(tag); + } + } + break; + case TagTreeModel.FOLDER_FONTS: + for (Tag tag : swf.getTags()) { + if (tag instanceof FontTag) { + folderPreviewItems.add(tag); + } + } + break; + case TagTreeModel.FOLDER_FRAMES: + for (Frame frame : swf.getTimeline().getFrames()) { + folderPreviewItems.add(frame); + } + break; + case TagTreeModel.FOLDER_IMAGES: + for (Tag tag : swf.getTags()) { + if (tag instanceof ImageTag) { + folderPreviewItems.add(tag); + } + } + break; + case TagTreeModel.FOLDER_TEXTS: + for (Tag tag : swf.getTags()) { + if (tag instanceof TextTag) { + folderPreviewItems.add(tag); + } + } + break; + } + + folderPreviewPanel.setItems(folderPreviewItems); + showCard(CARDFOLDERPREVIEWPANEL); + } + + private boolean isFreeing; + + @Override + public boolean isFreeing() { + return isFreeing; + } + + @Override + public void free() { + isFreeing = true; + } + + public void setErrorState(ErrorState errorState) { + statusPanel.setErrorState(errorState); + } + + public static Timelined makeTimelined(final Tag tag) { + return makeTimelined(tag, -1); + } + + public static Timelined makeTimelined(final Tag tag, final int fontFrameNum) { + + return new Timelined() { + private Timeline tim; + + @Override + public Timeline getTimeline() { + if (tim == null) { + Timeline timeline = new Timeline(tag.getSwf(), this, ((CharacterTag) tag).getCharacterId(), getRect()); + initTimeline(timeline); + tim = timeline; + } + + return tim; + } + + @Override + public void resetTimeline() { + if (tim != null) { + tim.reset(tag.getSwf(), this, ((CharacterTag) tag).getCharacterId(), getRect()); + initTimeline(tim); + } + } + + private void initTimeline(Timeline timeline) { + if (tag instanceof MorphShapeTag) { + timeline.frameRate = MORPH_SHAPE_ANIMATION_FRAME_RATE; + int framesCnt = (int) (timeline.frameRate * MORPH_SHAPE_ANIMATION_LENGTH); + for (int i = 0; i < framesCnt; i++) { + Frame f = new Frame(timeline, i); + DepthState ds = new DepthState(tag.getSwf(), f); + ds.characterId = ((CharacterTag) tag).getCharacterId(); + ds.matrix = new MATRIX(); + ds.ratio = i * 65535 / framesCnt; + f.layers.put(1, ds); + f.layersChanged = true; + timeline.addFrame(f); + } + } else if (tag instanceof FontTag) { + int pageCount = PreviewPanel.getFontPageCount((FontTag) tag); + int frame = fontFrameNum; + if (frame < 0 || frame >= pageCount) { + frame = 0; + } + + Frame f = new Frame(timeline, 0); + DepthState ds = new DepthState(tag.getSwf(), f); + ds.characterId = ((CharacterTag) tag).getCharacterId(); + ds.matrix = new MATRIX(); + f.layers.put(1, ds); + f.layersChanged = true; + timeline.addFrame(f); + timeline.fontFrameNum = frame; + } else { + Frame f = new Frame(timeline, 0); + DepthState ds = new DepthState(tag.getSwf(), f); + ds.characterId = ((CharacterTag) tag).getCharacterId(); + ds.matrix = new MATRIX(); + f.layers.put(1, ds); + timeline.addFrame(f); + } + timeline.displayRect = getRect(); + } + + @Override + public RECT getRect() { + return getRect(new HashSet<>()); + } + + @Override + public RECT getRect(Set added) { + BoundedTag bt = (BoundedTag) tag; + if (!added.contains(bt)) { + return bt.getRect(added); + } + return new RECT(Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE); + } + + @Override + public int hashCode() { + return tag.hashCode(); + } + + @Override + public void setModified(boolean value) { + } + + @Override + public ReadOnlyTagList getTags() { + return ReadOnlyTagList.EMPTY; + } + + @Override + public void removeTag(int index) { + } + + @Override + public void removeTag(Tag tag) { + } + + @Override + public void addTag(Tag tag) { + } + + @Override + public void addTag(int index, Tag tag) { + } + + @Override + public void replaceTag(int index, Tag newTag) { + } + }; + } + + private void disposeInner(Container container) { + for (Component c : container.getComponents()) { + if (c instanceof Container) { + Container c2 = (Container) c; + disposeInner(c2); + } + } + + container.removeAll(); + container.setLayout(null); + if (container instanceof TagEditorPanel) { + Helper.emptyObject(container); + } + } + + public void dispose() { + setDropTarget(null); + disposeInner(this); + Helper.emptyObject(this); + } +}