diff --git a/trunk/src/com/jpexs/decompiler/flash/Configuration.java b/trunk/src/com/jpexs/decompiler/flash/Configuration.java index 5de9939b9..767ea9e8a 100644 --- a/trunk/src/com/jpexs/decompiler/flash/Configuration.java +++ b/trunk/src/com/jpexs/decompiler/flash/Configuration.java @@ -119,13 +119,13 @@ public class Configuration { } public static Object setConfig(String cfg, Object value) { - if(cfg.equals("paralelSpeedUp")){ + if (cfg.equals("paralelSpeedUp")) { cfg = "parallelSpeedUp"; } return config.put(cfg, value); } - - public static void unsetConfig(String cfg){ + + public static void unsetConfig(String cfg) { config.remove(cfg); } @@ -146,7 +146,7 @@ public class Configuration { if (replacementsFile != null) { loadReplacements(replacementsFile); } - if(containsConfig("paralelSpeedUp")){ + if (containsConfig("paralelSpeedUp")) { setConfig("parallelSpeedUp", getConfig("paralelSpeedUp")); unsetConfig("paralelSpeedUp"); } diff --git a/trunk/src/com/jpexs/decompiler/flash/SWFInputStream.java b/trunk/src/com/jpexs/decompiler/flash/SWFInputStream.java index 37d548adc..301cbf427 100644 --- a/trunk/src/com/jpexs/decompiler/flash/SWFInputStream.java +++ b/trunk/src/com/jpexs/decompiler/flash/SWFInputStream.java @@ -16,8 +16,10 @@ */ package com.jpexs.decompiler.flash; +import com.jpexs.decompiler.flash.abc.avm2.model.NotCompileTimeAVM2Item; import com.jpexs.decompiler.flash.action.Action; import com.jpexs.decompiler.flash.action.ActionGraphSource; +import com.jpexs.decompiler.flash.action.StoreTypeAction; import com.jpexs.decompiler.flash.action.model.ConstantPool; import com.jpexs.decompiler.flash.action.model.DirectValueActionItem; import com.jpexs.decompiler.flash.action.special.ActionEnd; @@ -738,7 +740,7 @@ public class SWFInputStream extends InputStream { method = 2; goesPrev = readActionListAtPos(true, localData, stack, cpool, sis, rri, ip, retdups, ip); }*/ - goesPrev = readActionListAtPos(listeners, new ArrayList(), new HashMap>(), address, containerSWFOffset, localData, stack, cpool, sis, rri, ip, retdups, ip, endip, path, new HashMap()); + goesPrev = readActionListAtPos(listeners, new ArrayList(), new HashMap>(), address, containerSWFOffset, localData, stack, cpool, sis, rri, ip, retdups, ip, endip, path, new HashMap(), false, new HashMap>()); if (goesPrev) { } else { @@ -797,7 +799,7 @@ public class SWFInputStream extends InputStream { } @SuppressWarnings("unchecked") - private static boolean readActionListAtPos(List listeners, List output, HashMap> containers, long address, long containerSWFOffset, List localData, Stack stack, ConstantPool cpool, SWFInputStream sis, ReReadableInputStream rri, int ip, List ret, int startIp, int endip, String path, Map visited) throws IOException { + private static boolean readActionListAtPos(List listeners, List output, HashMap> containers, long address, long containerSWFOffset, List localData, Stack stack, ConstantPool cpool, SWFInputStream sis, ReReadableInputStream rri, int ip, List ret, int startIp, int endip, String path, Map visited, boolean indeterminate, Map> decisionStates) throws IOException { boolean debugMode = false; boolean decideBranch = false; @@ -907,6 +909,12 @@ public class SWFInputStream extends InputStream { ActionIf aif = null; boolean goaif = false; if (!a.isIgnored()) { + String varname = null; + if (a instanceof StoreTypeAction) { + StoreTypeAction sta = (StoreTypeAction) a; + varname = sta.getVariableName(stack, cpool); + } + try { if (a instanceof ActionIf) { aif = (ActionIf) a; @@ -983,6 +991,14 @@ public class SWFInputStream extends InputStream { log.log(Level.SEVERE, "Disassembly exception", ex); break; } + + HashMap vars = (HashMap) localData.get(1); + if (varname != null) { + GraphTargetItem varval = vars.get(varname); + if (varval != null && varval.isCompileTime() && indeterminate) { + vars.put(varname, new NotCompileTimeAVM2Item(null, varval)); + } + } } int nopos = -1; for (int i = 0; i < actionLen; i++) { @@ -1023,7 +1039,7 @@ public class SWFInputStream extends InputStream { } else { localData2 = localData; } - readActionListAtPos(listeners, output2, containers, address, containerSWFOffset, localData2, new Stack(), cpool, sis, rri, (int) endAddr, ret, startIp, (int) (endAddr + size), path + (cntName == null ? "" : "/" + cntName), visited); + readActionListAtPos(listeners, output2, containers, address, containerSWFOffset, localData2, new Stack(), cpool, sis, rri, (int) endAddr, ret, startIp, (int) (endAddr + size), path + (cntName == null ? "" : "/" + cntName), visited, indeterminate, decisionStates); output2s.add(output2); endAddr += size; } @@ -1050,13 +1066,34 @@ public class SWFInputStream extends InputStream { rri.setPos(ip); filePos = rri.getPos(); if (goaif) { - if (aif.ignoreUsed && aif.jumpUsed) { - break; - } aif.ignoreUsed = true; aif.jumpUsed = true; + indeterminate = true; - if (curVisited > 1) { + HashMap vars = (HashMap) localData.get(1); + boolean stateChanged = false; + if (decisionStates.containsKey(ip)) { + HashMap oldstate = decisionStates.get(ip); + if (oldstate.size() != vars.size()) { + stateChanged = true; + } else { + for (String k : vars.keySet()) { + if (!oldstate.containsKey(k)) { + stateChanged = true; + break; + } + if (!vars.get(k).isCompileTime() && oldstate.get(k).isCompileTime()) { + stateChanged = true; + break; + } + } + } + } + HashMap curstate = new HashMap(); + curstate.putAll(vars); + decisionStates.put(ip, curstate); + + if ((!stateChanged) && curVisited > 1) { List branches = new ArrayList<>(); branches.add(rri.getPos() + aif.getJumpOffset()); branches.add(rri.getPos()); @@ -1078,7 +1115,7 @@ public class SWFInputStream extends InputStream { int oldPos = rri.getPos(); @SuppressWarnings("unchecked") Stack substack = (Stack) stack.clone(); - if (readActionListAtPos(listeners, output, containers, address, containerSWFOffset, prepareLocalBranch(localData), substack, cpool, sis, rri, rri.getPos() + aif.getJumpOffset(), ret, startIp, endip, path, visited)) { + if (readActionListAtPos(listeners, output, containers, address, containerSWFOffset, prepareLocalBranch(localData), substack, cpool, sis, rri, rri.getPos() + aif.getJumpOffset(), ret, startIp, endip, path, visited, indeterminate, decisionStates)) { retv = true; } rri.setPos(oldPos); @@ -1197,7 +1234,7 @@ public class SWFInputStream extends InputStream { if (tag == null) { break; } - if(!parallel){ + if (!parallel) { tags.add(tag); } if (Configuration.dump_tags && level == 0) { diff --git a/trunk/src/com/jpexs/decompiler/flash/SWFOutputStream.java b/trunk/src/com/jpexs/decompiler/flash/SWFOutputStream.java index c6d938757..3073d43e9 100644 --- a/trunk/src/com/jpexs/decompiler/flash/SWFOutputStream.java +++ b/trunk/src/com/jpexs/decompiler/flash/SWFOutputStream.java @@ -456,7 +456,7 @@ public class SWFOutputStream extends OutputStream { } return nBits; } - + public static int getNeededBitsU(int first, int... params) { int nBits = 0; nBits = enlargeBitCountU(nBits, first); @@ -507,7 +507,7 @@ public class SWFOutputStream extends OutputStream { } return currentBitCount; } - + public static int enlargeBitCountU(int currentBitCount, int value) { int neededNew = getNeededBitsU(value); if (neededNew > currentBitCount) { diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java index 1aa30874c..8a8b747aa 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java @@ -2061,6 +2061,7 @@ public class AVM2Code implements Serializable { public boolean jumpUsed = false; public boolean skipUsed = false; public Set casesUsed = new HashSet<>(); + HashMap registers = new HashMap<>(); } private static int getMostCommonIp(AVM2GraphSource code, List branches) { @@ -2208,13 +2209,13 @@ public class AVM2Code implements Serializable { } @SuppressWarnings("unchecked") - private static int removeTraps(HashMap> refs, boolean secondPass, boolean useVisited, List localData, Stack stack, List output, AVM2GraphSource code, int ip, HashMap visited, HashMap> visitedStates, HashMap decisions, String path) { + private static int removeTraps(HashMap> refs, boolean secondPass, boolean indeterminate, List localData, Stack stack, List output, AVM2GraphSource code, int ip, HashMap visited, HashMap> visitedStates, HashMap decisions, String path) { boolean debugMode = false; int ret = 0; iploop: while ((ip > -1) && ip < code.size()) { - if (useVisited) { + if (false) { //useVisited) { if (visited.containsKey(ip)) { break; } @@ -2275,8 +2276,9 @@ public class AVM2Code implements Serializable { ip++; continue; } + if (debugMode) { - System.out.println((useVisited ? "useV " : "") + (secondPass ? "secondPass " : "") + "Visit " + ip + ": " + ins + " stack:" + Highlighting.stripHilights(stack.toString())); + System.out.println((indeterminate ? "useV " : "") + (secondPass ? "secondPass " : "") + "Visit " + ip + ": " + ins + " stack:" + Highlighting.stripHilights(stack.toString())); HashMap registers = (HashMap) localData.get(2); System.out.print("Registers:"); for (int reg : registers.keySet()) { @@ -2316,6 +2318,20 @@ public class AVM2Code implements Serializable { } + if (ins instanceof AVM2Instruction) { + AVM2Instruction ains = (AVM2Instruction) ins; + if (ains.definition instanceof SetLocalTypeIns) { + SetLocalTypeIns slt = (SetLocalTypeIns) ains.definition; + int regId = slt.getRegisterId(ains); + if (indeterminate) { + HashMap registers = (HashMap) localData.get(2); + GraphTargetItem regVal = registers.get(regId); + if (regVal.isCompileTime()) { + registers.put(regId, new NotCompileTimeAVM2Item(null, regVal)); + } + } + } + } if (ins.isExit()) { break; @@ -2389,10 +2405,29 @@ public class AVM2Code implements Serializable { } else { decisions.put(ins, dec); } + HashMap registers = (HashMap) localData.get(2); + boolean regChanged = false; + if (!dec.registers.isEmpty()) { + if (dec.registers.size() != registers.size()) { + regChanged = true; + } else { + for (int reg : registers.keySet()) { + if (!dec.registers.containsKey(reg)) { + regChanged = true; + break; + } + if (!registers.get(reg).isCompileTime() && dec.registers.get(reg).isCompileTime()) { + regChanged = true; + break; + } + } + } + } + dec.registers.putAll(registers); dec.jumpUsed = true; dec.skipUsed = true; - if ((!(top instanceof HasNextAVM2Item) && curVisited > 1) || (curVisited > 2)) { + if (!regChanged && ((!(top instanceof HasNextAVM2Item) && curVisited > 1) || (curVisited > 2))) { for (int b : branches) { int visc = 0; if (visited.containsKey(b)) { @@ -2405,12 +2440,13 @@ public class AVM2Code implements Serializable { } break; } + indeterminate = true; } for (int b : branches) { Stack brStack = (Stack) stack.clone(); if (b >= 0) { //useVisited || (!ins.isJump()) - ret += removeTraps(refs, secondPass, false, prepareBranchLocalData(localData), brStack, output, code, b, visited, visitedStates, decisions, path); + ret += removeTraps(refs, secondPass, indeterminate, prepareBranchLocalData(localData), brStack, output, code, b, visited, visitedStates, decisions, path); } else { if (debugMode) { System.out.println("Negative branch:" + b); diff --git a/trunk/src/com/jpexs/decompiler/flash/action/StoreTypeAction.java b/trunk/src/com/jpexs/decompiler/flash/action/StoreTypeAction.java new file mode 100644 index 000000000..1fe98c0d6 --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/action/StoreTypeAction.java @@ -0,0 +1,30 @@ +/* + * 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.action; + +import com.jpexs.decompiler.flash.action.model.ConstantPool; +import com.jpexs.decompiler.graph.GraphTargetItem; +import java.util.Stack; + +/** + * + * @author JPEXS + */ +public interface StoreTypeAction { + + public String getVariableName(Stack stack, ConstantPool cpool); +} diff --git a/trunk/src/com/jpexs/decompiler/flash/action/swf4/ActionSetVariable.java b/trunk/src/com/jpexs/decompiler/flash/action/swf4/ActionSetVariable.java index 6eaa5b153..7ebf95753 100644 --- a/trunk/src/com/jpexs/decompiler/flash/action/swf4/ActionSetVariable.java +++ b/trunk/src/com/jpexs/decompiler/flash/action/swf4/ActionSetVariable.java @@ -17,6 +17,7 @@ package com.jpexs.decompiler.flash.action.swf4; import com.jpexs.decompiler.flash.action.Action; +import com.jpexs.decompiler.flash.action.StoreTypeAction; import com.jpexs.decompiler.flash.action.model.ConstantPool; import com.jpexs.decompiler.flash.action.model.DecrementActionItem; import com.jpexs.decompiler.flash.action.model.GetVariableActionItem; @@ -34,7 +35,7 @@ import java.util.HashMap; import java.util.List; import java.util.Stack; -public class ActionSetVariable extends Action { +public class ActionSetVariable extends Action implements StoreTypeAction { public ActionSetVariable() { super(0x1D, 0); @@ -119,4 +120,12 @@ public class ActionSetVariable extends Action { output.add(ret); } + + @Override + public String getVariableName(Stack stack, ConstantPool cpool) { + if (stack.size() < 2) { + return null; + } + return Highlighting.stripHilights(stack.get(stack.size() - 2).toStringNoQuotes(cpool)); + } } diff --git a/trunk/src/com/jpexs/decompiler/flash/action/swf5/ActionStoreRegister.java b/trunk/src/com/jpexs/decompiler/flash/action/swf5/ActionStoreRegister.java index dc15c2392..0e85812b2 100644 --- a/trunk/src/com/jpexs/decompiler/flash/action/swf5/ActionStoreRegister.java +++ b/trunk/src/com/jpexs/decompiler/flash/action/swf5/ActionStoreRegister.java @@ -19,6 +19,8 @@ package com.jpexs.decompiler.flash.action.swf5; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; import com.jpexs.decompiler.flash.action.Action; +import com.jpexs.decompiler.flash.action.StoreTypeAction; +import com.jpexs.decompiler.flash.action.model.ConstantPool; import com.jpexs.decompiler.flash.action.model.DecrementActionItem; import com.jpexs.decompiler.flash.action.model.DirectValueActionItem; import com.jpexs.decompiler.flash.action.model.IncrementActionItem; @@ -37,7 +39,7 @@ import java.util.HashMap; import java.util.List; import java.util.Stack; -public class ActionStoreRegister extends Action { +public class ActionStoreRegister extends Action implements StoreTypeAction { public int registerNumber; @@ -130,4 +132,9 @@ public class ActionStoreRegister extends Action { } stack.push(new StoreRegisterActionItem(this, rn, value, define)); } + + @Override + public String getVariableName(Stack stack, ConstantPool cpool) { + return "__register" + registerNumber; + } } diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/AppDialog.java b/trunk/src/com/jpexs/decompiler/flash/gui/AppDialog.java index aa2095f4b..2f039e20f 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/AppDialog.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/AppDialog.java @@ -36,8 +36,8 @@ public abstract class AppDialog extends JDialog { public String translate(String key) { return resourceBundle.getString(key); } - - public void updateLanguage(){ + + public void updateLanguage() { resourceBundle = ResourceBundle.getBundle(AppStrings.getResourcePath(getClass())); } } diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/AppFrame.java b/trunk/src/com/jpexs/decompiler/flash/gui/AppFrame.java index 0b3b13a51..6f8fa3cb6 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/AppFrame.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/AppFrame.java @@ -33,8 +33,8 @@ public abstract class AppFrame extends JFrame { public String translate(String key) { return resourceBundle.getString(key); } - - public void updateLanguage(){ + + public void updateLanguage() { resourceBundle = ResourceBundle.getBundle(AppStrings.getResourcePath(getClass())); } } diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/AppStrings.java b/trunk/src/com/jpexs/decompiler/flash/gui/AppStrings.java index eba0d9fff..716c8f8b9 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/AppStrings.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/AppStrings.java @@ -43,8 +43,8 @@ public class AppStrings { ResourceBundle b = ResourceBundle.getBundle(bundle); return b.getString(key); } - - public static void updateLanguage(){ + + public static void updateLanguage() { resourceBundle = ResourceBundle.getBundle(getResourcePath(MainFrame.class)); } } diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java b/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java index 19d4ef3d2..96c6aa602 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java @@ -2268,7 +2268,6 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel @Override public void run() { View.execInEventDispatch(new Runnable() { - @Override public void run() { if (abcPanel.search(txt, searchDialog.ignoreCaseCheckBox.isSelected(), searchDialog.regexpCheckBox.isSelected())) { @@ -2279,7 +2278,7 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel } } }); - + } }).start(); } else { diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/SelectLanguageDialog.java b/trunk/src/com/jpexs/decompiler/flash/gui/SelectLanguageDialog.java index 480a3e527..f3c0da485 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/SelectLanguageDialog.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/SelectLanguageDialog.java @@ -53,7 +53,7 @@ public class SelectLanguageDialog extends AppDialog implements ActionListener { boolean found = false; int enIndex = 0; for (String code : languages) { - String name = ResourceBundle.getBundle(AppStrings.getResourcePath(getClass()), Locale.forLanguageTag(code.equals("en")?"":code)).getString("language"); + String name = ResourceBundle.getBundle(AppStrings.getResourcePath(getClass()), Locale.forLanguageTag(code.equals("en") ? "" : code)).getString("language"); if (name.length() > 1) { name = name.substring(0, 1).toUpperCase() + name.substring(1); } @@ -111,7 +111,7 @@ public class SelectLanguageDialog extends AppDialog implements ActionListener { Locale.setDefault(Locale.forLanguageTag(newLanguage)); updateLanguage(); setVisible(false); - AppStrings.updateLanguage(); + AppStrings.updateLanguage(); Main.reloadApp(); } break; diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/abc/SlotConstTraitDetailPanel.java b/trunk/src/com/jpexs/decompiler/flash/gui/abc/SlotConstTraitDetailPanel.java index d707fe888..3a8669093 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/abc/SlotConstTraitDetailPanel.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/abc/SlotConstTraitDetailPanel.java @@ -38,23 +38,23 @@ public class SlotConstTraitDetailPanel extends JPanel implements TraitDetail { public JEditorPane slotConstEditor; private ABC abc; private TraitSlotConst trait; - private boolean showWarning=false; - + private boolean showWarning = false; + public SlotConstTraitDetailPanel() { slotConstEditor = new JEditorPane(); setLayout(new BorderLayout()); add(new JLabel(translate("abc.detail.slotconst.typevalue")), BorderLayout.NORTH); add(new JScrollPane(slotConstEditor), BorderLayout.CENTER); /*StyledDocument doc = warnLabel.getStyledDocument(); - SimpleAttributeSet center = new SimpleAttributeSet(); - StyleConstants.setAlignment(center, StyleConstants.ALIGN_CENTER); - doc.setParagraphAttributes(0, doc.getLength(), center, false); - warnLabel.setOpaque(false); - warnLabel.setFocusable(false); - //warnLabel.setWrapStyleWord(true); - //warnLabel.setLineWrap(true); - warnLabel.setFont(new JLabel().getFont().deriveFont(Font.BOLD)); - add(warnLabel, BorderLayout.SOUTH);*/ + SimpleAttributeSet center = new SimpleAttributeSet(); + StyleConstants.setAlignment(center, StyleConstants.ALIGN_CENTER); + doc.setParagraphAttributes(0, doc.getLength(), center, false); + warnLabel.setOpaque(false); + warnLabel.setFocusable(false); + //warnLabel.setWrapStyleWord(true); + //warnLabel.setLineWrap(true); + warnLabel.setFont(new JLabel().getFont().deriveFont(Font.BOLD)); + add(warnLabel, BorderLayout.SOUTH);*/ slotConstEditor.setContentType("text/flasm3_methodinfo"); Flasm3MethodInfoSyntaxKit sk = (Flasm3MethodInfoSyntaxKit) slotConstEditor.getEditorKit(); sk.deinstallComponent(slotConstEditor, "jsyntaxpane.components.LineNumbersRuler"); @@ -77,7 +77,7 @@ public class SlotConstTraitDetailPanel extends JPanel implements TraitDetail { s = typeStr + valueStr; - showWarning = trait.isConst()||isStatic; + showWarning = trait.isConst() || isStatic; //warnLabel.setVisible(trait.isConst() || isStatic); slotConstEditor.setText(s); } @@ -97,7 +97,7 @@ public class SlotConstTraitDetailPanel extends JPanel implements TraitDetail { @Override public void setEditMode(boolean val) { - if(val){ + if (val) { JOptionPane.showMessageDialog(null, translate("warning.initializers"), translate("message.warning"), JOptionPane.WARNING_MESSAGE); } slotConstEditor.setEditable(val); diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/PlaceObject3Tag.java b/trunk/src/com/jpexs/decompiler/flash/tags/PlaceObject3Tag.java index 8d28d0900..2549dfbea 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/PlaceObject3Tag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/PlaceObject3Tag.java @@ -274,7 +274,7 @@ public class PlaceObject3Tag extends CharacterIdTag implements Container, PlaceO /** * Constructor * - * @param swf + * @param swf * @param data Data bytes * @param version SWF version * @param pos