From a74ba0e9ff8f92c9bbd002d83d2cdf785d7e0889 Mon Sep 17 00:00:00 2001 From: Honfika Date: Tue, 20 Aug 2013 18:56:39 +0200 Subject: [PATCH 01/11] Issue #338: Errors log expand (+) icon fixed --- .../decompiler/flash/gui/ErrorLogFrame.java | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/ErrorLogFrame.java b/trunk/src/com/jpexs/decompiler/flash/gui/ErrorLogFrame.java index 0c8b7ff6b..ee1e78ba5 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/ErrorLogFrame.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/ErrorLogFrame.java @@ -36,6 +36,7 @@ import java.util.logging.Level; import java.util.logging.LogRecord; import javax.swing.BorderFactory; import javax.swing.BoxLayout; +import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel; @@ -52,7 +53,10 @@ import javax.swing.SwingUtilities; public class ErrorLogFrame extends AppFrame { private JPanel logView = new JPanel(); + private JPanel logViewInner = new JPanel(); private Handler handler; + private ImageIcon expandIcon; + private ImageIcon collapseIcon; public Handler getHandler() { return handler; @@ -68,10 +72,16 @@ public class ErrorLogFrame extends AppFrame { Container cnt = getContentPane(); cnt.setLayout(new BorderLayout()); logView.setBackground(Color.white); - logView.setLayout(new BoxLayout(logView, BoxLayout.Y_AXIS)); + logView.setLayout(new BorderLayout()); cnt.setBackground(Color.white); + + logViewInner.setLayout(new BoxLayout(logViewInner, BoxLayout.Y_AXIS)); + logView.add(logViewInner, BorderLayout.NORTH); - cnt.add(new JScrollPane(logView), BorderLayout.NORTH); + expandIcon = View.getIcon("expand16"); + collapseIcon = View.getIcon("collapse16"); + + cnt.add(new JScrollPane(logView), BorderLayout.CENTER); handler = new Handler() { @Override public void publish(LogRecord record) { @@ -132,7 +142,7 @@ public class ErrorLogFrame extends AppFrame { } }); - final JToggleButton expandButton = new JToggleButton(View.getIcon("collapse16")); + final JToggleButton expandButton = new JToggleButton(collapseIcon); expandButton.setFocusPainted(false); expandButton.setBorderPainted(false); expandButton.setFocusable(false); @@ -145,8 +155,6 @@ public class ErrorLogFrame extends AppFrame { if (detailComponent != null) { scrollPane = new JScrollPane(detailComponent); scrollPane.setAlignmentX(0f); - scrollPane.setMinimumSize(new Dimension(getWidth(), 500)); - scrollPane.setPreferredSize(new Dimension(getWidth(), 500)); } else { scrollPane = null; } @@ -156,12 +164,8 @@ public class ErrorLogFrame extends AppFrame { expandButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - if (expandButton.isSelected()) { - expandButton.setIcon(View.getIcon("expand16")); - } + expandButton.setIcon(expandButton.isSelected() ? expandIcon : collapseIcon); scrollPane.setVisible(expandButton.isSelected()); - scrollPane.setMinimumSize(new Dimension(getWidth(), 500)); - scrollPane.setSize(new Dimension(getWidth(), 500)); revalidate(); repaint(); } @@ -199,7 +203,7 @@ public class ErrorLogFrame extends AppFrame { scrollPane.setVisible(false); } pan.setAlignmentX(0f); - logView.add(pan); + logViewInner.add(pan); revalidate(); repaint(); } From 018fab22bdc7271e633aa31fa1debd6c97c4537a Mon Sep 17 00:00:00 2001 From: Honfika Date: Tue, 20 Aug 2013 19:11:00 +0200 Subject: [PATCH 02/11] Issue #336: Graph window is too small --- .../decompiler/flash/gui/GraphFrame.java | 49 +++++++++++++++---- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/GraphFrame.java b/trunk/src/com/jpexs/decompiler/flash/gui/GraphFrame.java index 748a7f640..dfd4ef8ed 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/GraphFrame.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/GraphFrame.java @@ -234,15 +234,30 @@ public class GraphFrame extends AppFrame { return w; } } + GraphPanel gp; - + int scrollBarWidth; + int scrollBarHeight; + int frameWidthDiff; + int frameHeightDiff; + public GraphFrame(Graph graph, String name) { setSize(500, 500); Container cnt = getContentPane(); cnt.setLayout(new BorderLayout()); gp = new GraphPanel(graph); setTitle(translate("graph") + " " + name); - cnt.add(new JScrollPane(gp)); + JScrollPane scrollPane = new JScrollPane(gp); + scrollBarWidth = scrollPane.getVerticalScrollBar().getPreferredSize().width; + scrollBarHeight = scrollPane.getHorizontalScrollBar().getPreferredSize().height; + cnt.add(scrollPane, BorderLayout.CENTER); + pack(); + + Dimension size = getSize(); + Dimension innerSize = getContentPane().getSize(); + + frameWidthDiff = size.width - innerSize.width; + frameHeightDiff = size.height - innerSize.height; View.setWindowIcon(this); @@ -255,24 +270,40 @@ public class GraphFrame extends AppFrame { Dimension screen = getToolkit().getScreenSize(); Dimension dim = new Dimension(0, 0); Dimension panDim = gp.getPreferredSize(); - if (panDim.width < screen.width) { - dim.width = panDim.width + 10; + // add some magic constants + panDim = new Dimension(panDim.width + 3, panDim.height + 2); + + boolean tooHigh = false; + boolean tooWide = false; + + if (panDim.width + frameWidthDiff < screen.width) { + dim.width = panDim.width; } else { dim.width = screen.width; + tooWide = true; } - if (panDim.height < screen.height) { - dim.height = panDim.height + 10; + if (panDim.height + frameHeightDiff < screen.height) { + dim.height = panDim.height; } else { dim.height = screen.height; + tooHigh = true; } + + if (tooWide) { + dim.height += scrollBarHeight; + dim.height = Math.min(dim.height, screen.height); + } + if (tooHigh) { + dim.width += scrollBarWidth; + dim.width = Math.min(dim.width, screen.width); + } + setVisibleSize(dim); View.centerScreen(this); } private void setVisibleSize(Dimension dim) { - Insets insets = this.getInsets(); - setSize(new Dimension(insets.left + insets.right + dim.width, - insets.top + insets.bottom + dim.height)); + setSize(new Dimension(dim.width + frameWidthDiff, dim.height + frameHeightDiff)); } private void drawArrow(Graphics g, int x1, int y1, int x2, int y2) { From 64807210072a7fd62946adafd2a5cef68da395da Mon Sep 17 00:00:00 2001 From: Honfika Date: Tue, 20 Aug 2013 19:12:20 +0200 Subject: [PATCH 03/11] Issue #330: protection against adding the same multiple cyrillic characters doesn't work --- trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java | 1 + 1 file changed, 1 insertion(+) diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java b/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java index 00a6d54a4..d6535ae6b 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java @@ -2192,6 +2192,7 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel char c = newchars.charAt(i); if (oldchars.indexOf((int) c) == -1) { f.addCharacter(swf.tags, c, fontSelection.getSelectedItem().toString()); + oldchars += c; } } fontAddCharactersField.setText(""); From 0ef3a7dea1550ea743d20b5d29b21d8648dee9f9 Mon Sep 17 00:00:00 2001 From: Honfika Date: Tue, 20 Aug 2013 19:18:01 +0200 Subject: [PATCH 04/11] decompilation timeouts --- .../jpexs/decompiler/flash/Configuration.java | 10 ++- trunk/src/com/jpexs/decompiler/flash/SWF.java | 4 +- .../flash/abc/types/MethodBody.java | 63 ++++++++++++------- .../jpexs/decompiler/flash/action/Action.java | 30 ++++++--- .../jpexs/decompiler/flash/gui/MainFrame.java | 6 ++ .../flash/gui/action/ActionPanel.java | 6 +- .../decompiler/flash/helpers/Helper.java | 42 +++++++++++++ 7 files changed, 129 insertions(+), 32 deletions(-) diff --git a/trunk/src/com/jpexs/decompiler/flash/Configuration.java b/trunk/src/com/jpexs/decompiler/flash/Configuration.java index 767ea9e8a..443a128b5 100644 --- a/trunk/src/com/jpexs/decompiler/flash/Configuration.java +++ b/trunk/src/com/jpexs/decompiler/flash/Configuration.java @@ -53,7 +53,15 @@ public class Configuration { * Limit of code subs (for obfuscated code) */ public static final int SUBLIMITER = 500; - //using parameter names in decompiling may cause problems because oficial programs like Flash CS 5.5 inserts wrong parameter names indices + /** + * Decompilation timeout in seconds + */ + public static final int DECOMPILATION_TIMEOUT = 30 * 60; + /** + * Decompilation timeout for a single method in AS3 or single action in AS1/2 in seconds + */ + public static final int DECOMPILATION_TIMEOUT_SINGLE_METHOD = 5; + //using parameter names in decompiling may cause problems because official programs like Flash CS 5.5 inserts wrong parameter names indices public static final boolean PARAM_NAMES_ENABLE = false; private static HashMap config = new HashMap<>(); /** diff --git a/trunk/src/com/jpexs/decompiler/flash/SWF.java b/trunk/src/com/jpexs/decompiler/flash/SWF.java index 94ceb8d73..f959a2c8d 100644 --- a/trunk/src/com/jpexs/decompiler/flash/SWF.java +++ b/trunk/src/com/jpexs/decompiler/flash/SWF.java @@ -622,9 +622,9 @@ public class SWF { try { executor.shutdown(); - executor.awaitTermination(30, TimeUnit.MINUTES); + executor.awaitTermination(Configuration.DECOMPILATION_TIMEOUT, TimeUnit.SECONDS); } catch (InterruptedException ex) { - Logger.getLogger(ABC.class.getName()).log(Level.SEVERE, "30 minutes ActionScript export limit reached", ex); + Logger.getLogger(ABC.class.getName()).log(Level.SEVERE, Helper.formatTimeToText(Configuration.DECOMPILATION_TIMEOUT) + " ActionScript export limit reached", ex); } return ret; } diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java b/trunk/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java index 45bcdd748..698e165b6 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java @@ -22,6 +22,7 @@ import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; import com.jpexs.decompiler.flash.abc.avm2.CodeStats; import com.jpexs.decompiler.flash.abc.avm2.ConstantPool; import com.jpexs.decompiler.flash.abc.types.traits.Traits; +import com.jpexs.decompiler.flash.action.Action; import com.jpexs.decompiler.flash.helpers.Helper; import com.jpexs.decompiler.flash.helpers.Highlighting; import com.jpexs.decompiler.graph.Graph; @@ -31,6 +32,10 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Stack; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.logging.Level; import java.util.logging.Logger; @@ -103,7 +108,7 @@ public class MethodBody implements Cloneable, Serializable { return ret; } - public String toString(String path, boolean pcode, boolean isStatic, int scriptIndex, int classIndex, ABC abc, ConstantPool constants, MethodInfo method_info[], Stack scopeStack, boolean isStaticInitializer, boolean hilight, List fullyQualifiedNames, Traits initTraits) { + public String toString(final String path, boolean pcode, final boolean isStatic, final int scriptIndex, final int classIndex, final ABC abc, final ConstantPool constants, final MethodInfo method_info[], final Stack scopeStack, final boolean isStaticInitializer, final boolean hilight, final List fullyQualifiedNames, final Traits initTraits) { if (debugMode) { System.err.println("Decompiling " + path); } @@ -118,30 +123,46 @@ public class MethodBody implements Cloneable, Serializable { if (pcode) { s += code.toASMSource(constants, this, false); } else { - AVM2Code deobfuscated = null; - MethodBody b = (MethodBody) Helper.deepCopy(this); - deobfuscated = b.code; - deobfuscated.markMappedOffsets(); - if ((Boolean) Configuration.getConfig("autoDeobfuscate", true)) { - try { - deobfuscated.removeTraps(constants, b, abc, scriptIndex, classIndex, isStatic, path); - } catch (Exception | StackOverflowError ex) { - Logger.getLogger(MethodBody.class.getName()).log(Level.SEVERE, "Error during remove traps in " + path, ex); - } - } - //deobfuscated.restoreControlFlow(constants, b); - //try { - s += deobfuscated.toSource(path, isStatic, scriptIndex, classIndex, abc, constants, method_info, b, hilight, getLocalRegNames(abc), scopeStack, isStaticInitializer, fullyQualifiedNames, initTraits, Graph.SOP_USE_STATIC, new HashMap(), deobfuscated.visitCode(b)); - s = s.trim(); - if (s.equals("")) { - s = " "; - } - if (hilight) { - s = Highlighting.hilighMethod(s, this.method_info); + try { + s += Helper.timedCall(new Callable() { + @Override + public String call() throws Exception { + return toSource(path, isStatic, scriptIndex, classIndex, abc, constants, method_info, scopeStack, isStaticInitializer, hilight, fullyQualifiedNames, initTraits); + } + }, Configuration.DECOMPILATION_TIMEOUT_SINGLE_METHOD, TimeUnit.SECONDS); + } catch (InterruptedException | ExecutionException | TimeoutException ex) { + Logger.getLogger(Action.class.getName()).log(Level.SEVERE, "Decompilation error", ex); + s += "/*\r\n * Decompilation error\r\n * Timeout (" + Helper.formatTimeToText(Configuration.DECOMPILATION_TIMEOUT_SINGLE_METHOD) + ") was reached\r\n */"; } } return s; } + + public String toSource(String path, boolean isStatic, int scriptIndex, int classIndex, ABC abc, ConstantPool constants, MethodInfo method_info[], Stack scopeStack, boolean isStaticInitializer, boolean hilight, List fullyQualifiedNames, Traits initTraits) { + AVM2Code deobfuscated = null; + MethodBody b = (MethodBody) Helper.deepCopy(this); + deobfuscated = b.code; + deobfuscated.markMappedOffsets(); + if ((Boolean) Configuration.getConfig("autoDeobfuscate", true)) { + try { + deobfuscated.removeTraps(constants, b, abc, scriptIndex, classIndex, isStatic, path); + } catch (Exception | StackOverflowError ex) { + Logger.getLogger(MethodBody.class.getName()).log(Level.SEVERE, "Error during remove traps in " + path, ex); + } + } + //deobfuscated.restoreControlFlow(constants, b); + //try { + String s = deobfuscated.toSource(path, isStatic, scriptIndex, classIndex, abc, constants, method_info, b, hilight, getLocalRegNames(abc), scopeStack, isStaticInitializer, fullyQualifiedNames, initTraits, Graph.SOP_USE_STATIC, new HashMap(), deobfuscated.visitCode(b)); + s = s.trim(); + if (s.equals("")) { + s = " "; + } + if (hilight) { + s = Highlighting.hilighMethod(s, this.method_info); + } + + return s; + } @Override public Object clone() throws CloneNotSupportedException { diff --git a/trunk/src/com/jpexs/decompiler/flash/action/Action.java b/trunk/src/com/jpexs/decompiler/flash/action/Action.java index a823ec23b..97f1d4661 100644 --- a/trunk/src/com/jpexs/decompiler/flash/action/Action.java +++ b/trunk/src/com/jpexs/decompiler/flash/action/Action.java @@ -16,6 +16,7 @@ */ package com.jpexs.decompiler.flash.action; +import com.jpexs.decompiler.flash.Configuration; import com.jpexs.decompiler.flash.DisassemblyListener; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; @@ -49,6 +50,7 @@ import com.jpexs.decompiler.flash.ecma.Null; import com.jpexs.decompiler.flash.helpers.Helper; import com.jpexs.decompiler.flash.helpers.Highlighting; import com.jpexs.decompiler.flash.helpers.collections.MyEntry; +import com.jpexs.decompiler.flash.tags.base.ASMSource; import com.jpexs.decompiler.graph.Graph; import com.jpexs.decompiler.graph.GraphSource; import com.jpexs.decompiler.graph.GraphSourceItem; @@ -62,6 +64,9 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.StringReader; import java.util.*; +import java.util.concurrent.Callable; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.logging.Level; import java.util.logging.Logger; @@ -408,7 +413,7 @@ public class Action implements GraphSourceItem { * @param path * @return ASM source as String */ - public static String actionsToString(List listeners, long address, List list, List importantOffsets, List constantPool, int version, boolean hex, long swfPos, String path) { + private static String actionsToString(List listeners, long address, List list, List importantOffsets, List constantPool, int version, boolean hex, long swfPos, String path) { long offset; if (importantOffsets == null) { //setActionsAddresses(list, 0, version); @@ -434,6 +439,10 @@ public class Action implements GraphSourceItem { } pos++; if (hex) { + if (lastPush) { + ret.append("\r\n"); + lastPush = false; + } ret.append("");/* +"0x"+Helper.formatAddress(a.getFileAddress())+": "+*/; ret.append(Helper.bytesToHexString(a.getBytes(version))); ret.append("\r\n"); @@ -707,15 +716,22 @@ public class Action implements GraphSourceItem { * @param path * @return String with Source code */ - public static String actionsToSource(List actions, int version, String path) { + public static String actionsToSource(final List actions, final int version, final String path) { try { - //List tree = actionsToTree(new HashMap(), actions, version); - int staticOperation = Graph.SOP_USE_STATIC; //(Boolean) Configuration.getConfig("autoDeobfuscate", true) ? Graph.SOP_SKIP_STATIC : Graph.SOP_USE_STATIC; + return Helper.timedCall(new Callable() { + @Override + public String call() throws Exception { + //List tree = actionsToTree(new HashMap(), actions, version); + int staticOperation = Graph.SOP_USE_STATIC; //(Boolean) Configuration.getConfig("autoDeobfuscate", true) ? Graph.SOP_SKIP_STATIC : Graph.SOP_USE_STATIC; - List tree = actionsToTree(new HashMap(), new HashMap(), new HashMap(), actions, version, staticOperation, path); + List tree = actionsToTree(new HashMap(), new HashMap(), new HashMap(), actions, version, staticOperation, path); - - return Graph.graphToString(tree); + return Graph.graphToString(tree); + } + }, Configuration.DECOMPILATION_TIMEOUT_SINGLE_METHOD, TimeUnit.SECONDS); + } catch (TimeoutException ex) { + Logger.getLogger(Action.class.getName()).log(Level.SEVERE, "Decompilation error", ex); + return "/*\r\n * Decompilation error\r\n * Timeout (" + Helper.formatTimeToText(Configuration.DECOMPILATION_TIMEOUT_SINGLE_METHOD) + ") was reached\r\n */"; } catch (Exception | OutOfMemoryError | StackOverflowError ex2) { Logger.getLogger(Action.class.getName()).log(Level.SEVERE, "Decompilation error", ex2); if (ex2 instanceof OutOfMemoryError) { diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java b/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java index d6535ae6b..0e96799ad 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java @@ -1404,6 +1404,12 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel @Override public void run() { if (record.getLevel() == Level.SEVERE) { + if (errorNotificationButton == null) { + // todo: honfika + // why null? + return; + } + errorNotificationButton.setIcon(View.getIcon("error16")); errorNotificationButton.setToolTipText(translate("errors.present")); if (timer != null) { diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/action/ActionPanel.java b/trunk/src/com/jpexs/decompiler/flash/gui/action/ActionPanel.java index a313c381e..c59f3ead4 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/action/ActionPanel.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/action/ActionPanel.java @@ -168,7 +168,7 @@ public class ActionPanel extends JPanel implements ActionListener { private void cacheScript(ASMSource src) { if (!cache.contains(src)) { List as = src.getActions(SWF.DEFAULT_VERSION); - String s = com.jpexs.decompiler.flash.action.Action.actionsToSource(as, SWF.DEFAULT_VERSION, src.toString()/*FIXME?*/); + String s = Action.actionsToSource(as, SWF.DEFAULT_VERSION, src.toString()/*FIXME?*/); List hilights = Highlighting.getInstrHighlights(s); String srcNoHex = Highlighting.stripHilights(s); cache.put(src, new CachedScript(srcNoHex, hilights)); @@ -567,6 +567,10 @@ public class ActionPanel extends JPanel implements ActionListener { } public void setDecompiledEditMode(boolean val) { + if (lastASM == null) { + return; + } + String pref = lastASM.getActionSourcePrefix(); int lastPos = decompiledEditor.getCaretPosition(); int lastLine = decompiledEditor.getLine(); diff --git a/trunk/src/com/jpexs/decompiler/flash/helpers/Helper.java b/trunk/src/com/jpexs/decompiler/flash/helpers/Helper.java index 8d42a55b1..12d1a1a36 100644 --- a/trunk/src/com/jpexs/decompiler/flash/helpers/Helper.java +++ b/trunk/src/com/jpexs/decompiler/flash/helpers/Helper.java @@ -34,6 +34,13 @@ import java.util.BitSet; import java.util.Collection; import java.util.List; import java.util.Stack; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.FutureTask; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; @@ -46,6 +53,8 @@ import java.util.regex.Pattern; */ public class Helper { + private static final ExecutorService THREAD_POOL = Executors.newCachedThreadPool(); + /** * Converts array of int values to string * @@ -504,4 +513,37 @@ public class Helper { timeStr += Helper.padZeros(timeS, 2) + "." + Helper.padZeros(timeMs, 3); return timeStr; } + + public static String formatTimeToText(int timeS) { + long timeM = timeS / 60; + timeS = timeS % 60; + long timeH = timeM / 60; + timeM = timeM % 60; + + String timeStr = ""; + if (timeH > 0) { + timeStr += timeH + (timeH > 1 ? " hours" : " hour"); + } + if (timeM > 0) { + if (timeStr.length() > 0) { + timeStr += " and "; + } + timeStr += timeM + (timeM > 1 ? " minutes" : " minute"); + } + if (timeS > 0) { + if (timeStr.length() > 0) { + timeStr += " and "; + } + timeStr += timeS + (timeS > 1 ? " seconds" : " second"); + } + + // (currently) used only in log, so no localization is required + return timeStr; + } + + public static T timedCall(Callable c, long timeout, TimeUnit timeUnit) throws InterruptedException, ExecutionException, TimeoutException { + FutureTask task = new FutureTask(c); + THREAD_POOL.execute(task); + return task.get(timeout, timeUnit); + } } From da6d520e968a0c84869ce964f415be3817f09770 Mon Sep 17 00:00:00 2001 From: Honfika Date: Tue, 20 Aug 2013 19:20:21 +0200 Subject: [PATCH 05/11] removed some unused static import --- .../flash/abc/avm2/model/operations/TypeOfAVM2Item.java | 6 ------ .../flash/action/model/PrintAsBitmapActionItem.java | 1 - 2 files changed, 7 deletions(-) diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/model/operations/TypeOfAVM2Item.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/model/operations/TypeOfAVM2Item.java index 07687c50b..bff5b8fb7 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/model/operations/TypeOfAVM2Item.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/model/operations/TypeOfAVM2Item.java @@ -19,12 +19,6 @@ package com.jpexs.decompiler.flash.abc.avm2.model.operations; import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; import com.jpexs.decompiler.flash.ecma.EcmaScript; import com.jpexs.decompiler.flash.ecma.EcmaType; -import static com.jpexs.decompiler.flash.ecma.EcmaType.BOOLEAN; -import static com.jpexs.decompiler.flash.ecma.EcmaType.NULL; -import static com.jpexs.decompiler.flash.ecma.EcmaType.NUMBER; -import static com.jpexs.decompiler.flash.ecma.EcmaType.OBJECT; -import static com.jpexs.decompiler.flash.ecma.EcmaType.STRING; -import static com.jpexs.decompiler.flash.ecma.EcmaType.UNDEFINED; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.model.UnaryOpItem; diff --git a/trunk/src/com/jpexs/decompiler/flash/action/model/PrintAsBitmapActionItem.java b/trunk/src/com/jpexs/decompiler/flash/action/model/PrintAsBitmapActionItem.java index e4212c6f5..15ea46c19 100644 --- a/trunk/src/com/jpexs/decompiler/flash/action/model/PrintAsBitmapActionItem.java +++ b/trunk/src/com/jpexs/decompiler/flash/action/model/PrintAsBitmapActionItem.java @@ -21,7 +21,6 @@ import com.jpexs.decompiler.flash.action.parser.script.ActionSourceGenerator; import com.jpexs.decompiler.flash.action.swf4.ActionGetURL2; import com.jpexs.decompiler.graph.GraphSourceItem; import com.jpexs.decompiler.graph.GraphTargetItem; -import static com.jpexs.decompiler.graph.GraphTargetItem.PRECEDENCE_PRIMARY; import com.jpexs.decompiler.graph.SourceGenerator; import java.util.ArrayList; import java.util.List; From 33d63cfa9580c2ef5fd07056f1b69669d9176040 Mon Sep 17 00:00:00 2001 From: Honfika Date: Tue, 20 Aug 2013 19:22:27 +0200 Subject: [PATCH 06/11] Issue #332: show exporting execution times for AS2 --- trunk/src/com/jpexs/decompiler/flash/SWF.java | 4 +- .../com/jpexs/decompiler/flash/TagNode.java | 41 ++++++++++++++++--- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/trunk/src/com/jpexs/decompiler/flash/SWF.java b/trunk/src/com/jpexs/decompiler/flash/SWF.java index f959a2c8d..13f44e363 100644 --- a/trunk/src/com/jpexs/decompiler/flash/SWF.java +++ b/trunk/src/com/jpexs/decompiler/flash/SWF.java @@ -591,7 +591,9 @@ public class SWF { outdir += File.separator; } outdir += "scripts" + File.separator; - ret.addAll(TagNode.exportNodeAS(tags, handler, list, outdir, isPcode, evl)); + AtomicInteger cnt = new AtomicInteger(1); + int totalCount = TagNode.getTagCountRecursive(list); + ret.addAll(TagNode.exportNodeAS(tags, handler, list, outdir, isPcode, cnt, totalCount, evl)); return ret; } diff --git a/trunk/src/com/jpexs/decompiler/flash/TagNode.java b/trunk/src/com/jpexs/decompiler/flash/TagNode.java index 003e98134..a3983db01 100644 --- a/trunk/src/com/jpexs/decompiler/flash/TagNode.java +++ b/trunk/src/com/jpexs/decompiler/flash/TagNode.java @@ -53,6 +53,9 @@ import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.logging.Level; +import java.util.logging.Logger; public class TagNode { @@ -231,11 +234,30 @@ public class TagNode { } } + public static int getTagCountRecursive(List nodeList) { + int count = 0; + + for (TagNode node : nodeList) { + if (node.subItems.isEmpty()) { + if ((node.tag instanceof ASMSource) && (node.export)) { + count += 1; + } + } else { + count += getTagCountRecursive(node.subItems); + } + + } + + return count; + } + public static List exportNodeAS(List allTags, AbortRetryIgnoreHandler handler, List nodeList, String outdir, boolean isPcode) throws IOException { - return exportNodeAS(allTags, handler, nodeList, outdir, isPcode, null); + AtomicInteger cnt = new AtomicInteger(1); + int totalCount = TagNode.getTagCountRecursive(nodeList); + return exportNodeAS(allTags, handler, nodeList, outdir, isPcode, cnt, totalCount, null); } - public static List exportNodeAS(List allTags, AbortRetryIgnoreHandler handler, List nodeList, String outdir, boolean isPcode, EventListener ev) throws IOException { + public static List exportNodeAS(List allTags, AbortRetryIgnoreHandler handler, List nodeList, String outdir, boolean isPcode, AtomicInteger index, int count, EventListener ev) throws IOException { File dir = new File(outdir); List ret = new ArrayList<>(); if (!outdir.endsWith(File.separator)) { @@ -269,11 +291,10 @@ public class TagNode { do { retry = false; try { + long startTime = System.currentTimeMillis(); + String f = outdir + name + ".as"; File file = new File(f); - if (ev != null) { - ev.handleEvent("export", "Exporting " + f + " ..."); - } String res; ASMSource asm = ((ASMSource) node.tag); if (isPcode) { @@ -286,6 +307,14 @@ public class TagNode { try (FileOutputStream fos = new FileOutputStream(f)) { fos.write(res.getBytes("utf-8")); } + + long stopTime = System.currentTimeMillis(); + + if (ev != null) { + long time = stopTime - startTime; + ev.handleEvent("export", "Exported " + index.getAndIncrement() + "/" + count + " " + f + ", " + Helper.formatTimeSec(time)); + } + ret.add(file); } catch (Exception ex) { if (handler != null) { @@ -305,7 +334,7 @@ public class TagNode { } while (retry); } } else { - ret.addAll(exportNodeAS(allTags, handler, node.subItems, outdir + name, isPcode, ev)); + ret.addAll(exportNodeAS(allTags, handler, node.subItems, outdir + name, isPcode, index, count, ev)); } } From b86ddefdcb423a29f5a05d8391abf7bae94cc0c9 Mon Sep 17 00:00:00 2001 From: Honfika Date: Tue, 20 Aug 2013 19:23:08 +0200 Subject: [PATCH 07/11] Issue #327: AS1/2 disassembly error (readActionList) stops whole application fixed --- trunk/src/com/jpexs/decompiler/flash/TagNode.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/trunk/src/com/jpexs/decompiler/flash/TagNode.java b/trunk/src/com/jpexs/decompiler/flash/TagNode.java index a3983db01..be9bf28c2 100644 --- a/trunk/src/com/jpexs/decompiler/flash/TagNode.java +++ b/trunk/src/com/jpexs/decompiler/flash/TagNode.java @@ -316,7 +316,8 @@ public class TagNode { } ret.add(file); - } catch (Exception ex) { + } catch (Exception | OutOfMemoryError | StackOverflowError ex) { + Logger.getLogger(TagNode.class.getName()).log(Level.SEVERE, "Decompilation error", ex); if (handler != null) { int action = handler.handle(ex); switch (action) { From c38756868568c9ced517ba2d6f8b12fc5d5ddefe Mon Sep 17 00:00:00 2001 From: Honfika Date: Tue, 20 Aug 2013 19:25:01 +0200 Subject: [PATCH 08/11] Issue #313: command line parameter for ignore all errors --- .../flash/ConsoleAbortRetryIgnoreHandler.java | 70 ++++++++ .../com/jpexs/decompiler/flash/TagNode.java | 2 +- .../com/jpexs/decompiler/flash/gui/Main.java | 151 ++++++++++-------- .../jpexs/decompiler/flash/gui/MainFrame.java | 7 + 4 files changed, 166 insertions(+), 64 deletions(-) create mode 100644 trunk/src/com/jpexs/decompiler/flash/ConsoleAbortRetryIgnoreHandler.java diff --git a/trunk/src/com/jpexs/decompiler/flash/ConsoleAbortRetryIgnoreHandler.java b/trunk/src/com/jpexs/decompiler/flash/ConsoleAbortRetryIgnoreHandler.java new file mode 100644 index 000000000..f95dd8c91 --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/ConsoleAbortRetryIgnoreHandler.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2013 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; + +import java.util.Scanner; + +/** + * + * @author JPEXS + */ +public class ConsoleAbortRetryIgnoreHandler implements AbortRetryIgnoreHandler { + int errorCount = 0; + int errorMode; + int retryCount; + + public ConsoleAbortRetryIgnoreHandler(int errorMode, int retryCount) { + this.errorMode = errorMode; + this.retryCount = retryCount; + } + + @Override + public int handle(Throwable thrown) { + if (errorMode != AbortRetryIgnoreHandler.UNDEFINED){ + int result = errorMode; + + if (errorMode == AbortRetryIgnoreHandler.RETRY && errorCount < retryCount) { + errorCount++; + } + else { + result = AbortRetryIgnoreHandler.IGNORE; + } + + return result; + } + Scanner sc = new Scanner(System.in); + System.out.println("Error occured: " + thrown.getLocalizedMessage()); + String n = null; + do { + System.out.print("Select action: (A)bort, (R)Retry, (I)Ignore:"); + n = sc.nextLine(); + switch (n.toLowerCase()) { + case "a": + return AbortRetryIgnoreHandler.ABORT; + case "r": + return AbortRetryIgnoreHandler.RETRY; + case "i": + return AbortRetryIgnoreHandler.IGNORE; + } + } while (true); + } + + @Override + public AbortRetryIgnoreHandler getNewInstance() { + return new ConsoleAbortRetryIgnoreHandler(errorMode, retryCount); + } +} diff --git a/trunk/src/com/jpexs/decompiler/flash/TagNode.java b/trunk/src/com/jpexs/decompiler/flash/TagNode.java index be9bf28c2..b59e97c22 100644 --- a/trunk/src/com/jpexs/decompiler/flash/TagNode.java +++ b/trunk/src/com/jpexs/decompiler/flash/TagNode.java @@ -319,7 +319,7 @@ public class TagNode { } catch (Exception | OutOfMemoryError | StackOverflowError ex) { Logger.getLogger(TagNode.class.getName()).log(Level.SEVERE, "Decompilation error", ex); if (handler != null) { - int action = handler.handle(ex); + int action = handler.getNewInstance().handle(ex); switch (action) { case AbortRetryIgnoreHandler.ABORT: throw ex; diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/Main.java b/trunk/src/com/jpexs/decompiler/flash/gui/Main.java index 17650b1a4..0898262f4 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/Main.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/Main.java @@ -18,6 +18,7 @@ package com.jpexs.decompiler.flash.gui; import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler; import com.jpexs.decompiler.flash.Configuration; +import com.jpexs.decompiler.flash.ConsoleAbortRetryIgnoreHandler; import com.jpexs.decompiler.flash.EventListener; import com.jpexs.decompiler.flash.PercentListener; import com.jpexs.decompiler.flash.SWF; @@ -529,6 +530,8 @@ public class Main { System.out.println(" Values are boolean, you can use 0/1, true/false or yes/no."); System.out.println(" If no other parameters passed, configuration is saved. Otherwise it is used only once."); System.out.println(" DO NOT PUT space between comma (,) and next value."); + System.out.println(" 9) -onerror (abort|retryN|ignore)"); + System.out.println(" ...error handling mode. \"abort\" stops the exporting, \"retry\" tries the exporting N times, \"ignore\" ignores the current file"); System.out.println(); System.out.println("Examples:"); System.out.println("java -jar ffdec.jar myfile.swf"); @@ -540,6 +543,8 @@ public class Main { System.out.println("java -jar ffdec.jar -dumpSWF myfile.swf"); System.out.println("java -jar ffdec.jar -compress myfile.swf myfiledec.swf"); System.out.println("java -jar ffdec.jar -decompress myfiledec.swf myfile.swf"); + System.out.println("java -jar ffdec.jar -onerror ignore -export as \"C:\\decompiled\\\" myfile.swf"); + System.out.println("java -jar ffdec.jar -onerror retry 5 -export as \"C:\\decompiled\\\" myfile.swf"); System.out.println("java -jar ffdec.jar -config autoDeobfuscate=1,parallelSpeedUp=0 -export as \"C:\\decompiled\\\" myfile.swf"); System.out.println(""); System.out.println("Instead of \"java -jar ffdec.jar\" you can use ffdec.bat on Windows, ffdec.sh on Linux/MacOs"); @@ -671,61 +676,100 @@ public class Main { } else { Cache.setStorageType(Cache.STORAGE_MEMORY); } + + int errorMode = AbortRetryIgnoreHandler.UNDEFINED; + int retryCount = 0; if (args.length < pos + 1) { autoCheckForUpdates(); offerAssociation(); showModeFrame(); } else { - if (args[pos].equals("-config")) { - pos++; - if (args.length <= pos) { - System.err.println("Config values expected"); - badArguments(); - } - String cfgStr = args[pos]; - String cfgs[]; - if (cfgStr.contains(",")) { - cfgs = cfgStr.split(","); - } else { - cfgs = new String[]{cfgStr}; - } - - - - for (String c : cfgs) { - String cp[]; - if (c.contains("=")) { - cp = c.split("="); + boolean parameterProcessed = true; + while (parameterProcessed) { + parameterProcessed = false; + if (args[pos].equals("-config")) { + parameterProcessed = true; + pos++; + if (args.length <= pos) { + System.err.println("Config values expected"); + badArguments(); + } + String cfgStr = args[pos]; + String cfgs[]; + if (cfgStr.contains(",")) { + cfgs = cfgStr.split(","); } else { - cp = new String[]{c, "1"}; + cfgs = new String[]{cfgStr}; } - String key = cp[0]; - String value = cp[1]; - if (key.toLowerCase().equals("paralelSpeedUp".toLowerCase())) { - key = "parallelSpeedUp"; - } - for (String bk : commandlineConfigBoolean) { - if (key.toLowerCase().equals(bk.toLowerCase())) { - Boolean bValue = null; - if (value.equals("0") || value.toLowerCase().equals("false") || value.toLowerCase().equals("no") || value.toLowerCase().equals("off")) { - bValue = false; - } - if (value.equals("1") || value.toLowerCase().equals("true") || value.toLowerCase().equals("yes") || value.toLowerCase().equals("on")) { - bValue = true; - } - if (bValue != null) { - System.out.println("Config " + bk + " set to " + bValue); - Configuration.setConfig(bk, bValue); + + for (String c : cfgs) { + String cp[]; + if (c.contains("=")) { + cp = c.split("="); + } else { + cp = new String[]{c, "1"}; + } + String key = cp[0]; + String value = cp[1]; + if (key.toLowerCase().equals("paralelSpeedUp".toLowerCase())) { + key = "parallelSpeedUp"; + } + for (String bk : commandlineConfigBoolean) { + if (key.toLowerCase().equals(bk.toLowerCase())) { + Boolean bValue = null; + if (value.equals("0") || value.toLowerCase().equals("false") || value.toLowerCase().equals("no") || value.toLowerCase().equals("off")) { + bValue = false; + } + if (value.equals("1") || value.toLowerCase().equals("true") || value.toLowerCase().equals("yes") || value.toLowerCase().equals("on")) { + bValue = true; + } + if (bValue != null) { + System.out.println("Config " + bk + " set to " + bValue); + Configuration.setConfig(bk, bValue); + } } } } + pos++; + if (args.length <= pos) { + saveConfig(); + System.out.println("Configuration saved"); + return; + } } - pos++; - if (args.length <= pos) { - saveConfig(); - System.out.println("Configuration saved"); - return; + if (args[pos].equals("-onerror")) { + parameterProcessed = true; + pos++; + if (args.length <= pos) { + System.err.println("onerror parameter expected"); + badArguments(); + } + String errorModeParameter = args[pos]; + switch (errorModeParameter) { + case "abort": + errorMode = AbortRetryIgnoreHandler.ABORT; + break; + case "retry": + errorMode = AbortRetryIgnoreHandler.RETRY; + pos++; + if (args.length <= pos) { + System.err.println("onerror retry count parameter expected"); + badArguments(); + } + + try { + retryCount = Integer.parseInt(args[pos]); + } catch (NumberFormatException nex) { + System.err.println("Bad retry count number"); + } + break; + case "ignore": + errorMode = AbortRetryIgnoreHandler.IGNORE; + break; + } + + pos++; } } if (args[pos].equals("-removefromcontextmenu")) { @@ -774,26 +818,7 @@ public class Main { "xfl" }; - AbortRetryIgnoreHandler handler = new AbortRetryIgnoreHandler() { - @Override - public int handle(Throwable thrown) { - Scanner sc = new Scanner(System.in); - System.out.println("Error occured: " + thrown.getLocalizedMessage()); - String n = null; - do { - System.out.print("Select action: (A)bort, (R)Retry, (I)Ignore:"); - n = sc.nextLine(); - switch (n.toLowerCase()) { - case "a": - return AbortRetryIgnoreHandler.ABORT; - case "r": - return AbortRetryIgnoreHandler.RETRY; - case "i": - return AbortRetryIgnoreHandler.IGNORE; - } - } while (true); - } - }; + AbortRetryIgnoreHandler handler = new ConsoleAbortRetryIgnoreHandler(errorMode, retryCount); String exportFormat = args[pos + 1].toLowerCase(); if (!Arrays.asList(validExportFormats).contains(exportFormat)) { System.err.println("Invalid export format:" + exportFormat); diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java b/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java index 0e96799ad..8cb729200 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java @@ -18,6 +18,7 @@ package com.jpexs.decompiler.flash.gui; import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler; import com.jpexs.decompiler.flash.Configuration; +import com.jpexs.decompiler.flash.ConsoleAbortRetryIgnoreHandler; import com.jpexs.decompiler.flash.FrameNode; import com.jpexs.decompiler.flash.PackageNode; import com.jpexs.decompiler.flash.SWF; @@ -288,6 +289,12 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel return View.showOptionDialog(null, translate("error.occured").replace("%error%", thrown.getLocalizedMessage()), translate("error"), JOptionPane.YES_NO_OPTION, JOptionPane.ERROR_MESSAGE, null, options, ""); } } + + @Override + public AbortRetryIgnoreHandler getNewInstance() { + // there are no non-static field in this class, so return the original instance + return this; + } }; public void setPercent(int percent) { From 7ef99dc3c7ec531916c07fda44575ba313281500 Mon Sep 17 00:00:00 2001 From: Honfika Date: Tue, 20 Aug 2013 19:25:27 +0200 Subject: [PATCH 09/11] Issue #313: command line parameter for ignore all errors (missing file) --- .../com/jpexs/decompiler/flash/AbortRetryIgnoreHandler.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/trunk/src/com/jpexs/decompiler/flash/AbortRetryIgnoreHandler.java b/trunk/src/com/jpexs/decompiler/flash/AbortRetryIgnoreHandler.java index 2526b1f27..4d73742c7 100644 --- a/trunk/src/com/jpexs/decompiler/flash/AbortRetryIgnoreHandler.java +++ b/trunk/src/com/jpexs/decompiler/flash/AbortRetryIgnoreHandler.java @@ -22,9 +22,12 @@ package com.jpexs.decompiler.flash; */ public interface AbortRetryIgnoreHandler { + public static int UNDEFINED = -1; public static int ABORT = 0; public static int RETRY = 1; public static int IGNORE = 2; public int handle(Throwable thrown); + + public AbortRetryIgnoreHandler getNewInstance(); } From 2f559601363ce2b279b30d7f53434c3f396c61bf Mon Sep 17 00:00:00 2001 From: Honfika Date: Tue, 20 Aug 2013 19:26:34 +0200 Subject: [PATCH 10/11] Issue #313: command line parameter for ignore all errors --- trunk/src/com/jpexs/decompiler/flash/SWF.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trunk/src/com/jpexs/decompiler/flash/SWF.java b/trunk/src/com/jpexs/decompiler/flash/SWF.java index 13f44e363..f05d115e3 100644 --- a/trunk/src/com/jpexs/decompiler/flash/SWF.java +++ b/trunk/src/com/jpexs/decompiler/flash/SWF.java @@ -598,7 +598,7 @@ public class SWF { } public List exportActionScript3(AbortRetryIgnoreHandler handler, String outdir, boolean isPcode, boolean parallel) { - ExecutorService executor = Executors.newFixedThreadPool(20); + ExecutorService executor = Executors.newFixedThreadPool(parallel ? 20 : 1); List> futureResults = new ArrayList<>(); AtomicInteger cnt = new AtomicInteger(1); List abcTags = new ArrayList<>(); From 7d6ca221efb5a273308aed35daa0460e9fcb0870 Mon Sep 17 00:00:00 2001 From: Honfika Date: Tue, 20 Aug 2013 19:33:10 +0200 Subject: [PATCH 11/11] source level is 1.7 --- trunk/nbproject/project.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/trunk/nbproject/project.xml b/trunk/nbproject/project.xml index 8210e203e..8b48fa3aa 100644 --- a/trunk/nbproject/project.xml +++ b/trunk/nbproject/project.xml @@ -126,14 +126,14 @@ src lib/LZMA.jar;lib/jna-3.5.1.jar;lib/jpproxy.jar;lib/jsyntaxpane-0.9.5.jar build/classes - 1.6 + 1.7 test lib/LZMA.jar;lib/jna-3.5.1.jar;lib/jpproxy.jar;lib/jsyntaxpane-0.9.5.jar;src;testlib/emma.jar;testlib/emma_ant.jar;testlib/junit-4.8.2.jar;testlib/testng-6.8.jar build/test - 1.6 + 1.7