diff --git a/trunk/src/com/jpexs/decompiler/flash/DisassemblyListener.java b/trunk/src/com/jpexs/decompiler/flash/DisassemblyListener.java new file mode 100644 index 000000000..0a13b4ddf --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/DisassemblyListener.java @@ -0,0 +1,26 @@ +/* + * 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; + +/** + * + * @author JPEXS + */ +public interface DisassemblyListener { + + public void progress(String phase, long pos, long total); +} diff --git a/trunk/src/com/jpexs/decompiler/flash/ReReadableInputStream.java b/trunk/src/com/jpexs/decompiler/flash/ReReadableInputStream.java index f59c4c248..8d87b5cf6 100644 --- a/trunk/src/com/jpexs/decompiler/flash/ReReadableInputStream.java +++ b/trunk/src/com/jpexs/decompiler/flash/ReReadableInputStream.java @@ -81,4 +81,8 @@ public class ReReadableInputStream extends InputStream { public int available() throws IOException { return (count + is.available()) - pos; } + + public long length() throws IOException { + return count + is.available(); + } } diff --git a/trunk/src/com/jpexs/decompiler/flash/SWFInputStream.java b/trunk/src/com/jpexs/decompiler/flash/SWFInputStream.java index 228b37d8c..88766cce5 100644 --- a/trunk/src/com/jpexs/decompiler/flash/SWFInputStream.java +++ b/trunk/src/com/jpexs/decompiler/flash/SWFInputStream.java @@ -502,22 +502,25 @@ public class SWFInputStream extends InputStream { return ret; } - public List readActionList(long address, long containerSWFOffset) throws IOException { + public List readActionList(List listeners, long address, long containerSWFOffset) throws IOException { ReReadableInputStream rri = new ReReadableInputStream(this); - return readActionList(address, containerSWFOffset, rri, version, 0, -1); + return readActionList(listeners, address, containerSWFOffset, rri, version, 0, -1); } - public List readActionList(long address, long containerSWFOffset, ReReadableInputStream rri, int maxlen) throws IOException { - return readActionList(address, containerSWFOffset, rri, version, rri.getPos(), rri.getPos() + maxlen); + public List readActionList(List listeners, long address, long containerSWFOffset, ReReadableInputStream rri, int maxlen) throws IOException { + return readActionList(listeners, address, containerSWFOffset, rri, version, rri.getPos(), rri.getPos() + maxlen); } - private static void getConstantPool(ConstantPool cpool, List localData, Stack stack, List output, ActionGraphSource code, int ip, int lastIp, List constantPools, List visited, int version, int endIp) { + private static void getConstantPool(List listeners, ConstantPool cpool, List localData, Stack stack, List output, ActionGraphSource code, int ip, int lastIp, List constantPools, List visited, int version, int endIp) { boolean debugMode = false; + boolean deobfuscate = (Boolean) Configuration.getConfig("autoDeobfuscate", true); while (((endIp == -1) || (endIp > ip)) && (ip > -1) && ip < code.size()) { if (visited.contains(ip)) { break; } - + for (DisassemblyListener listener : listeners) { + listener.progress("constantpool", ip + 1, code.size()); + } lastIp = ip; GraphSourceItem ins = code.get(ip); if (ins.isIgnored()) { @@ -538,10 +541,12 @@ public class SWFInputStream extends InputStream { List localData2 = Helper.toList(new HashMap(), new HashMap(), new HashMap()); List output2 = new ArrayList(); output2s.add(output2); - getConstantPool(cpool, localData2, new Stack(), output2, code, code.adr2pos(endAddr), lastIp, constantPools, visited, version, code.adr2pos(endAddr + size)); + getConstantPool(listeners, cpool, localData2, new Stack(), output2, code, code.adr2pos(endAddr), lastIp, constantPools, visited, version, code.adr2pos(endAddr + size)); endAddr += size; } - cnt.translateContainer(output2s, stack, output, (HashMap) localData.get(0), (HashMap) localData.get(1), (HashMap) localData.get(2)); + if (deobfuscate) { + cnt.translateContainer(output2s, stack, output, (HashMap) localData.get(0), (HashMap) localData.get(1), (HashMap) localData.get(2)); + } ip = code.adr2pos(endAddr); continue; } @@ -586,13 +591,15 @@ public class SWFInputStream extends InputStream { } //for..in return - if (((ins instanceof ActionEquals) || (ins instanceof ActionEquals2)) && (stack.size() == 1) && (stack.peek() instanceof DirectValueTreeItem)) { - stack.push(new DirectValueTreeItem(null, 0, new Null(), new ArrayList())); - } - try { - ins.translate(localData, stack, output); - } catch (Exception ex) { - Logger.getLogger(SWFInputStream.class.getName()).log(Level.SEVERE, "Error during getting constantpool", ex); + if (deobfuscate) { + if (((ins instanceof ActionEquals) || (ins instanceof ActionEquals2)) && (stack.size() == 1) && (stack.peek() instanceof DirectValueTreeItem)) { + stack.push(new DirectValueTreeItem(null, 0, new Null(), new ArrayList())); + } + try { + ins.translate(localData, stack, output); + } catch (Exception ex) { + Logger.getLogger(SWFInputStream.class.getName()).log(Level.SEVERE, "Error during getting constantpool", ex); + } } if (ins.isExit()) { break; @@ -600,7 +607,7 @@ public class SWFInputStream extends InputStream { if (ins.isBranch() || ins.isJump()) { - if ((Boolean) Configuration.getConfig("autoDeobfuscate", true) && (ins instanceof ActionIf) && !stack.isEmpty() && (stack.peek().isCompileTime() && (!stack.peek().hasSideEffect()))) { + if (deobfuscate && (ins instanceof ActionIf) && !stack.isEmpty() && (stack.peek().isCompileTime() && (!stack.peek().hasSideEffect()))) { ActionIf aif = (ActionIf) ins; if (aif.ignoreUsed && (!aif.jumpUsed)) { ins.setIgnored(true); @@ -636,9 +643,9 @@ public class SWFInputStream extends InputStream { } } stack.pop(); - getConstantPool(cpool, localData, stack, output, code, condition ? (code.adr2pos(((ActionIf) ins).getAddress() + ((ActionIf) ins).getBytes(code.version).length + ((ActionIf) ins).getJumpOffset())) : ip + 1, ip, constantPools, visited, version, endIp); + getConstantPool(listeners, cpool, localData, stack, output, code, condition ? (code.adr2pos(((ActionIf) ins).getAddress() + ((ActionIf) ins).getBytes(code.version).length + ((ActionIf) ins).getJumpOffset())) : ip + 1, ip, constantPools, visited, version, endIp); } else { - if (ins instanceof ActionIf) { + if (deobfuscate && ins instanceof ActionIf) { stack.pop(); } visited.add(ip); @@ -646,7 +653,7 @@ public class SWFInputStream extends InputStream { for (int b : branches) { Stack brStack = (Stack) stack.clone(); if (b >= 0) { - getConstantPool(cpool, localData, brStack, output, code, b, ip, constantPools, visited, version, endIp); + getConstantPool(listeners, cpool, localData, brStack, output, code, b, ip, constantPools, visited, version, endIp); } else { if (debugMode) { System.out.println("Negative branch:" + b); @@ -661,13 +668,16 @@ public class SWFInputStream extends InputStream { if (ip < 0) { System.out.println("Visited Negative: " + ip); } + for (DisassemblyListener listener : listeners) { + listener.progress("constantpool", ip + 1, code.size()); + } } - public static List getConstantPool(ActionGraphSource code, int addr, int version) { + public static List getConstantPool(List listeners, ActionGraphSource code, int addr, int version) { List ret = new ArrayList(); List localData = Helper.toList(new HashMap(), new HashMap(), new HashMap()); try { - getConstantPool(null, localData, new Stack(), new ArrayList(), code, code.adr2pos(addr), 0, ret, new ArrayList(), version, -1); + getConstantPool(listeners, null, localData, new Stack(), new ArrayList(), code, code.adr2pos(addr), 0, ret, new ArrayList(), version, -1); } catch (Exception ex) { log.log(Level.SEVERE, "Error during getting constantpool", ex); } @@ -681,7 +691,7 @@ public class SWFInputStream extends InputStream { * @return List of actions * @throws IOException */ - public static List readActionList(long address, long containerSWFOffset, ReReadableInputStream rri, int version, int ip, int endip) throws IOException { + public static List readActionList(List listeners, long address, long containerSWFOffset, ReReadableInputStream rri, int version, int ip, int endip) throws IOException { List retdups = new ArrayList(); ConstantPool cpool = new ConstantPool(); @@ -699,7 +709,7 @@ public class SWFInputStream extends InputStream { method = 2; goesPrev = readActionListAtPos(true, localData, stack, cpool, sis, rri, ip, retdups, ip); }*/ - goesPrev = readActionListAtPos(new ArrayList(), new HashMap>(), address, containerSWFOffset, false, true, localData, stack, cpool, sis, rri, ip, retdups, ip, endip); + goesPrev = readActionListAtPos(listeners, new ArrayList(), new HashMap>(), address, containerSWFOffset, false, true, localData, stack, cpool, sis, rri, ip, retdups, ip, endip); if (goesPrev) { } else { @@ -739,7 +749,7 @@ public class SWFInputStream extends InputStream { br.append(((Action) ret.get(i)).getASMSource(new ArrayList(), new ArrayList(), cpool.constants, version, false)); br.append("\r\n"); } - pools = getConstantPool(new ActionGraphSource(ret, version, new HashMap(), new HashMap(), new HashMap()), ip, version); + pools = getConstantPool(listeners, new ActionGraphSource(ret, version, new HashMap(), new HashMap(), new HashMap()), ip, version); if (pools.size() == 1) { Action.setConstantPool(ret, pools.get(0)); @@ -766,9 +776,11 @@ public class SWFInputStream extends InputStream { return reta; } - private static boolean readActionListAtPos(List output, HashMap> containers, long address, long containerSWFOffset, boolean notCompileTime, boolean enableVariables, List localData, Stack stack, ConstantPool cpool, SWFInputStream sis, ReReadableInputStream rri, int ip, List ret, int startIp, int endip) throws IOException { + private static boolean readActionListAtPos(List listeners, List output, HashMap> containers, long address, long containerSWFOffset, boolean notCompileTime, boolean enableVariables, List localData, Stack stack, ConstantPool cpool, SWFInputStream sis, ReReadableInputStream rri, int ip, List ret, int startIp, int endip) throws IOException { boolean debugMode = false; boolean decideBranch = false; + + boolean deobfuscate = (Boolean) Configuration.getConfig("autoDeobfuscate", true); boolean retv = false; rri.setPos(ip); Action a; @@ -776,6 +788,9 @@ public class SWFInputStream extends InputStream { Scanner sc = new Scanner(System.in); int prevIp = ip; while (((endip == -1) || (endip > ip)) && (a = sis.readAction(rri)) != null) { + for (DisassemblyListener listener : listeners) { + listener.progress("Reading", rri.getCount(), rri.length()); + } if ((ip < ret.size()) && (!(ret.get(ip) instanceof ActionNop))) { a = ret.get(ip); if (a.getAddress() != ip) { @@ -870,9 +885,11 @@ public class SWFInputStream extends InputStream { try { if (a instanceof ActionIf) { aif = (ActionIf) a; - GraphTargetItem top = null; - top = stack.pop(); + GraphTargetItem top = null; + if (deobfuscate) { + top = stack.pop(); + } int nip = rri.getPos() + aif.getJumpOffset(); if (decideBranch) { @@ -887,7 +904,7 @@ public class SWFInputStream extends InputStream { } else if (next.equals("c")) { goaif = true; } - } else if ((Boolean) Configuration.getConfig("autoDeobfuscate", true) && top.isCompileTime() && (!top.hasSideEffect()) && ((!top.isVariableComputed()) || (top.isVariableComputed() && enableVariables && (!notCompileTime)))) { + } else if (deobfuscate && top.isCompileTime() && (!top.hasSideEffect()) && ((!top.isVariableComputed()) || (top.isVariableComputed() && enableVariables && (!notCompileTime)))) { //if(top.isCompileTime()) { //if(false){ if (enableVariables) { @@ -957,14 +974,16 @@ public class SWFInputStream extends InputStream { //rri.setPos(newip); //} } else if (!(a instanceof GraphSourceItemContainer)) { - //return in for..in, TODO:Handle this better way - if (((a instanceof ActionEquals) || (a instanceof ActionEquals2)) && (stack.size() == 1) && (stack.peek() instanceof DirectValueTreeItem)) { - stack.push(new DirectValueTreeItem(null, 0, new Null(), new ArrayList())); + if (deobfuscate) { + //return in for..in, TODO:Handle this better way + if (((a instanceof ActionEquals) || (a instanceof ActionEquals2)) && (stack.size() == 1) && (stack.peek() instanceof DirectValueTreeItem)) { + stack.push(new DirectValueTreeItem(null, 0, new Null(), new ArrayList())); + } + if ((a instanceof ActionStoreRegister) && stack.isEmpty()) { + stack.push(new DirectValueTreeItem(null, 0, new Null(), new ArrayList())); + } + a.translate(localData, stack, output); } - if ((a instanceof ActionStoreRegister) && stack.isEmpty()) { - stack.push(new DirectValueTreeItem(null, 0, new Null(), new ArrayList())); - } - a.translate(localData, stack, output); } } catch (RuntimeException ex) { if (!enableVariables) { @@ -1012,11 +1031,13 @@ public class SWFInputStream extends InputStream { } List localData2 = Helper.toList(new HashMap(), new HashMap(), new HashMap()); List output2 = new ArrayList(); - readActionListAtPos(output2, containers, address, containerSWFOffset, notCompileTime, enableVariables, localData2, new Stack(), cpool, sis, rri, (int) endAddr, ret, startIp, (int) (endAddr + size)); + readActionListAtPos(listeners, output2, containers, address, containerSWFOffset, notCompileTime, enableVariables, localData2, new Stack(), cpool, sis, rri, (int) endAddr, ret, startIp, (int) (endAddr + size)); output2s.add(output2); endAddr += size; } - cnt.translateContainer(output2s, stack, output, (HashMap) localData.get(0), (HashMap) localData.get(1), (HashMap) localData.get(2)); + if (deobfuscate) { + cnt.translateContainer(output2s, stack, output, (HashMap) localData.get(0), (HashMap) localData.get(1), (HashMap) localData.get(2)); + } ip = (int) endAddr; prevIp = ip; rri.setPos(ip); @@ -1044,7 +1065,7 @@ public class SWFInputStream extends InputStream { aif.jumpUsed = true; int oldPos = rri.getPos(); Stack substack = (Stack) stack.clone(); - if (readActionListAtPos(output, containers, address, containerSWFOffset, true, enableVariables, localData, substack, cpool, sis, rri, rri.getPos() + aif.getJumpOffset(), ret, startIp, endip)) { + if (readActionListAtPos(listeners, output, containers, address, containerSWFOffset, true, enableVariables, localData, substack, cpool, sis, rri, rri.getPos() + aif.getJumpOffset(), ret, startIp, endip)) { retv = true; } rri.setPos(oldPos); @@ -1052,6 +1073,9 @@ public class SWFInputStream extends InputStream { } prevIp = ip; } + for (DisassemblyListener listener : listeners) { + listener.progress("Reading", rri.getCount(), rri.length()); + } return retv; } diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/operations/DivideTreeItem.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/operations/DivideTreeItem.java index 66ebca0db..f33e32c63 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/operations/DivideTreeItem.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/operations/DivideTreeItem.java @@ -28,6 +28,9 @@ public class DivideTreeItem extends BinaryOpItem { @Override public double toNumber() { + if (Double.compare(rightSide.toNumber(), 0) == 0) { + return Double.NaN; + } return leftSide.toNumber() / rightSide.toNumber(); } } diff --git a/trunk/src/com/jpexs/decompiler/flash/action/Action.java b/trunk/src/com/jpexs/decompiler/flash/action/Action.java index 5703ad890..c342b5db3 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.DisassemblyListener; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; @@ -364,8 +365,8 @@ public class Action implements GraphSourceItem { * @param hex Add hexadecimal? * @return ASM source as String */ - public static String actionsToString(long address, List list, List importantOffsets, int version, boolean hex, long swfPos) { - return actionsToString(address, list, importantOffsets, new ArrayList(), version, hex, swfPos); + public static String actionsToString(List listeners, long address, List list, List importantOffsets, int version, boolean hex, long swfPos) { + return actionsToString(listeners, address, list, importantOffsets, new ArrayList(), version, hex, swfPos); } /** @@ -378,8 +379,7 @@ public class Action implements GraphSourceItem { * @param hex Add hexadecimal? * @return ASM source as String */ - public static String actionsToString(long address, List list, List importantOffsets, List constantPool, int version, boolean hex, long swfPos) { - String ret = ""; + public static String actionsToString(List listeners, long address, List list, List importantOffsets, List constantPool, int version, boolean hex, long swfPos) { long offset; if (importantOffsets == null) { //setActionsAddresses(list, 0, version); @@ -391,7 +391,7 @@ public class Action implements GraphSourceItem { srcList.add((Action) o); } } - List cps = SWFInputStream.getConstantPool(new ActionGraphSource(srcList, version, new HashMap(), new HashMap(), new HashMap()), 0, version); + List cps = SWFInputStream.getConstantPool(new ArrayList(), new ActionGraphSource(srcList, version, new HashMap(), new HashMap(), new HashMap()), 0, version); if (!cps.isEmpty()) { setConstantPool(list, cps.get(cps.size() - 1)); } @@ -400,14 +400,20 @@ public class Action implements GraphSourceItem { offset = address; int pos = -1; boolean lastPush = false; + StringBuilder ret = new StringBuilder(); for (GraphSourceItem s : srcList) { + for (DisassemblyListener l : listeners) { + l.progress("toString", pos + 2, srcList.size()); + } Action a = null; if (s instanceof Action) { a = (Action) s; } pos++; if (hex) { - ret += "" +/*"0x"+Helper.formatAddress(a.getFileAddress())+": "+*/ Helper.bytesToHexString(a.getBytes(version)) + "\r\n"; + ret.append("");/* +"0x"+Helper.formatAddress(a.getFileAddress())+": "+*/; + ret.append(Helper.bytesToHexString(a.getBytes(version))); + ret.append("\r\n"); } offset = a.getAddress(); @@ -430,10 +436,10 @@ public class Action implements GraphSourceItem { if (containers.containsKey(offset)) { for (int i = 0; i < containers.get(offset).size(); i++) { - ret += "}\r\n"; + ret.append("}\r\n"); GraphSourceItemContainer cnt = containers.get(offset).get(i); int cntPos = containersPos.get(cnt); - ret += cnt.getASMSourceBetween(cntPos); + ret.append(cnt.getASMSourceBetween(cntPos)); cntPos++; containersPos.put(cnt, cntPos); } @@ -441,23 +447,27 @@ public class Action implements GraphSourceItem { if (importantOffsets.contains(offset)) { if (lastPush) { - ret += "\r\n"; + ret.append("\r\n"); lastPush = false; } - ret += "loc" + Helper.formatAddress(offset) + ":"; + ret.append("loc"); + ret.append(Helper.formatAddress(offset)); + ret.append(":"); } if (a.replaceWith != null) { if (lastPush) { - ret += "\r\n"; + ret.append("\r\n"); lastPush = false; } - ret += Highlighting.hilighOffset("", offset) + a.replaceWith.getASMSource(list, importantOffsets, constantPool, version, hex) + "\r\n"; + ret.append(Highlighting.hilighOffset("", offset)); + ret.append(a.replaceWith.getASMSource(list, importantOffsets, constantPool, version, hex)); + ret.append("\r\n"); } else if (a.ignored) { if (lastPush) { - ret += "\r\n"; + ret.append("\r\n"); lastPush = false; } int len = 0; @@ -467,11 +477,12 @@ public class Action implements GraphSourceItem { len = a.getBytes(version).length; } for (int i = 0; i < len; i++) { - ret += "Nop\r\n"; + ret.append("Nop\r\n"); } } else { if (a.beforeInsert != null) { - ret += a.beforeInsert.getASMSource(list, importantOffsets, constantPool, version, hex) + "\r\n"; + ret.append(a.beforeInsert.getASMSource(list, importantOffsets, constantPool, version, hex)); + ret.append("\r\n"); } //if (!(a instanceof ActionNop)) { String add = ""; @@ -484,12 +495,17 @@ public class Action implements GraphSourceItem { add = "; ofs" + Helper.formatAddress(offset) + add; add = ""; if ((a instanceof ActionPush) && lastPush) { - ret += " " + ((ActionPush) a).paramsToStringReplaced(list, importantOffsets, constantPool, version, hex); + ret.append(" "); + ret.append(((ActionPush) a).paramsToStringReplaced(list, importantOffsets, constantPool, version, hex)); } else { if (lastPush) { - ret += "\r\n"; + ret.append("\r\n"); } - ret += Highlighting.hilighOffset("", offset) + a.getASMSourceReplaced(list, importantOffsets, constantPool, version, hex) + (a.ignored ? "; ignored" : "") + add + ((a instanceof ActionPush) ? "" : "\r\n"); + ret.append(Highlighting.hilighOffset("", offset)); + ret.append(a.getASMSourceReplaced(list, importantOffsets, constantPool, version, hex)); + ret.append(a.ignored ? "; ignored" : ""); + ret.append(add); + ret.append((a instanceof ActionPush) ? "" : "\r\n"); } if (a instanceof ActionPush) { lastPush = true; @@ -498,28 +514,31 @@ public class Action implements GraphSourceItem { } //} if (a.afterInsert != null) { - ret += a.afterInsert.getASMSource(list, importantOffsets, constantPool, version, hex) + "\r\n"; + ret.append(a.afterInsert.getASMSource(list, importantOffsets, constantPool, version, hex)); + ret.append("\r\n"); } } offset += a.getBytes(version).length; } if (lastPush) { - ret += "\r\n"; + ret.append("\r\n"); } if (containers.containsKey(offset)) { for (int i = 0; i < containers.get(offset).size(); i++) { - ret += "}\r\n"; + ret.append("}\r\n"); GraphSourceItemContainer cnt = containers.get(offset).get(i); int cntPos = containersPos.get(cnt); - ret += cnt.getASMSourceBetween(cntPos); + ret.append(cnt.getASMSourceBetween(cntPos)); cntPos++; containersPos.put(cnt, cntPos); } } if (importantOffsets.contains(offset)) { - ret += "loc" + Helper.formatAddress(offset) + ":\r\n"; + ret.append("loc"); + ret.append(Helper.formatAddress(offset)); + ret.append(":\r\n"); } - return ret; + return ret.toString(); } /** @@ -1216,7 +1235,7 @@ public class Action implements GraphSourceItem { } String s = null; try { - s = Highlighting.stripHilights(Action.actionsToString(address, ret, null, version, false, swfPos)); + s = Highlighting.stripHilights(Action.actionsToString(new ArrayList(), address, ret, null, version, false, swfPos)); ret = ASMParser.parse(address, swfPos, true, new ByteArrayInputStream(s.getBytes()), SWF.DEFAULT_VERSION); } catch (Exception ex) { diff --git a/trunk/src/com/jpexs/decompiler/flash/action/gui/ActionPanel.java b/trunk/src/com/jpexs/decompiler/flash/action/gui/ActionPanel.java index 56746b8af..0ae5e601e 100644 --- a/trunk/src/com/jpexs/decompiler/flash/action/gui/ActionPanel.java +++ b/trunk/src/com/jpexs/decompiler/flash/action/gui/ActionPanel.java @@ -16,6 +16,7 @@ */ package com.jpexs.decompiler.flash.action.gui; +import com.jpexs.decompiler.flash.DisassemblyListener; import com.jpexs.decompiler.flash.Main; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.abc.gui.LineMarkedEditorPane; @@ -93,8 +94,15 @@ public class ActionPanel extends JPanel implements ActionListener { lastH = h; } long offset = lastH.offset; + editor.setText("; Getting hilights..."); disassembledHilights = Highlighting.getInstrHighlights(text); - editor.setText(Highlighting.stripHilights(text)); + String stripped = Highlighting.stripHilights(text); + /*if(stripped.length()>30000){ + editor.setContentType("text/plain"); + }else{ + editor.setContentType("text/flasm"); + }*/ + editor.setText(stripped); for (Highlighting h : disassembledHilights) { if (h.offset == offset) { editor.setCaretPosition(h.startPos); @@ -117,13 +125,35 @@ public class ActionPanel extends JPanel implements ActionListener { public void run() { editor.setText("; Disassembling..."); if (Main.DO_DECOMPILE) { - decompiledEditor.setText("//Decompiling..."); + decompiledEditor.setText("//Waiting for dissasembly..."); } + DisassemblyListener listener = new DisassemblyListener() { + int percent = 0; + String phase = ""; + + @Override + public void progress(String phase, long pos, long total) { + if (total < 1) { + return; + } + int newpercent = (int) (pos * 100 / total); + if (((newpercent > percent) || (!this.phase.equals(phase))) && newpercent <= 100) { + percent = newpercent; + this.phase = phase; + editor.setText("; Disassembling - " + phase + " " + percent + "%..."); + } + } + }; + asm.addDisassemblyListener(listener); lastDisasm = asm.getASMSource(SWF.DEFAULT_VERSION, true); + asm.removeDisassemblyListener(listener); + editor.setText("; Disassembled"); srcWithHex = Helper.hexToComments(lastDisasm); srcNoHex = Helper.stripComments(lastDisasm); + editor.setText("; Disassembling - setting"); setHex(hexButton.isSelected()); if (Main.DO_DECOMPILE) { + decompiledEditor.setText("//Decompiling..."); List as = asm.getActions(SWF.DEFAULT_VERSION); lastCode = as; //com.jpexs.decompiler.flash.action.Action.setActionsAddresses(as, 0, SWF.DEFAULT_VERSION); @@ -138,13 +168,19 @@ public class ActionPanel extends JPanel implements ActionListener { } catch (IOException ex) { Logger.getLogger(ActionPanel.class.getName()).log(Level.SEVERE, null, ex); }*/ - decompiledEditor.setText(lastDecompiled = stripped); + lastDecompiled = stripped; + /*if(lastDecompiled.length()>30000){ + decompiledEditor.setContentType("text/plain"); + }else{ + decompiledEditor.setContentType("text/actionscript"); + }*/ + decompiledEditor.setText(lastDecompiled); if (debugRecompile) { try { ActionScriptParser ps = new ActionScriptParser(); - recompiledEditor.setText(Highlighting.stripHilights(com.jpexs.decompiler.flash.action.Action.actionsToString(0, ps.parse(stripped), null, SWF.DEFAULT_VERSION, false, 0))); + recompiledEditor.setText(Highlighting.stripHilights(com.jpexs.decompiler.flash.action.Action.actionsToString(new ArrayList(), 0, ps.parse(stripped), null, SWF.DEFAULT_VERSION, false, 0))); } catch (ParseException ex) { Logger.getLogger(ActionPanel.class.getName()).log(Level.SEVERE, null, ex); } catch (IOException ex) { diff --git a/trunk/src/com/jpexs/decompiler/flash/action/treemodel/operations/ModuloTreeItem.java b/trunk/src/com/jpexs/decompiler/flash/action/treemodel/operations/ModuloTreeItem.java index 2cc74eadb..d916e8405 100644 --- a/trunk/src/com/jpexs/decompiler/flash/action/treemodel/operations/ModuloTreeItem.java +++ b/trunk/src/com/jpexs/decompiler/flash/action/treemodel/operations/ModuloTreeItem.java @@ -28,6 +28,9 @@ public class ModuloTreeItem extends BinaryOpItem { @Override public double toNumber() { + if (Double.compare(rightSide.toNumber(), 0) == 0) { + return Double.NaN; + } return ((int) leftSide.toNumber()) % ((int) rightSide.toNumber()); } } diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java b/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java index b4bae6516..ff08cb88f 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java @@ -489,10 +489,24 @@ public class MainFrame extends JFrame implements ActionListener, TreeSelectionLi List list2 = new ArrayList(); list2.addAll(swf.tags); parseCharacters(list2); - JPanel textPanel = new JPanel(new BorderLayout()); - textPanel.add(textValue, BorderLayout.CENTER); + JPanel textTopPanel = new JPanel(new BorderLayout()); + textTopPanel.add(textValue, BorderLayout.CENTER); textValue.setEditable(false); + + /*JPanel textBottomPanel = new JPanel(); + textBottomPanel.setLayout(new BoxLayout(textBottomPanel, BoxLayout.X_AXIS)); + textBottomPanel.add(new JLabel("Xmin:")); + textBottomPanel.add(textRectXmin); + textBottomPanel.add(new JLabel("Ymin:")); + textBottomPanel.add(textRectYmin); + textBottomPanel.add(new JLabel("Xmax:")); + textBottomPanel.add(textRectXmax); + textBottomPanel.add(new JLabel("Ymax:")); + textBottomPanel.add(textRectYmax);*/ + + + JPanel buttonsPanel = new JPanel(); buttonsPanel.setLayout(new BoxLayout(buttonsPanel, BoxLayout.X_AXIS)); @@ -519,9 +533,16 @@ public class MainFrame extends JFrame implements ActionListener, TreeSelectionLi textSaveButton.setVisible(false); textCancelButton.setVisible(false); - textPanel.add(buttonsPanel, BorderLayout.EAST); + textTopPanel.add(buttonsPanel, BorderLayout.EAST); displayWithPreview = new JPanel(new CardLayout()); + + + JPanel textPanel = new JPanel(); + textPanel.setLayout(new BoxLayout(textPanel, BoxLayout.Y_AXIS)); + textPanel.add(textTopPanel); + //textPanel.add(textBottomPanel); + displayWithPreview.add(textPanel, CARDTEXTPANEL); displayWithPreview.setVisible(false); diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java index b031e05ee..231569fa6 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java @@ -16,6 +16,8 @@ */ package com.jpexs.decompiler.flash.tags; +import com.jpexs.decompiler.flash.Configuration; +import com.jpexs.decompiler.flash.DisassemblyListener; import com.jpexs.decompiler.flash.Main; import com.jpexs.decompiler.flash.ReReadableInputStream; import com.jpexs.decompiler.flash.SWFInputStream; @@ -119,7 +121,7 @@ public class DefineButtonTag extends CharacterTag implements ASMSource, BoundedT */ @Override public String getASMSource(int version, boolean hex) { - return Action.actionsToString(0, getActions(version), null, version, hex, getPos() + hdrSize); + return Action.actionsToString(listeners, 0, getActions(version), null, version, hex, getPos() + hdrSize); } /** @@ -151,7 +153,13 @@ public class DefineButtonTag extends CharacterTag implements ASMSource, BoundedT baos.write(actionBytes); ReReadableInputStream rri = new ReReadableInputStream(new ByteArrayInputStream(baos.toByteArray())); rri.setPos(prevLength); - return Action.removeNops(0, SWFInputStream.readActionList(0, getPos() + hdrSize - prevLength, rri, version, prevLength, -1), version, getPos() + hdrSize); + + boolean deobfuscate = (Boolean) Configuration.getConfig("autoDeobfuscate", true); + List list = SWFInputStream.readActionList(listeners, 0, getPos() + hdrSize - prevLength, rri, version, prevLength, -1); + if (deobfuscate) { + list = Action.removeNops(0, list, version, getPos() + hdrSize); + } + return list; } catch (Exception ex) { Logger.getLogger(DoActionTag.class.getName()).log(Level.SEVERE, null, ex); return new ArrayList(); @@ -197,4 +205,15 @@ public class DefineButtonTag extends CharacterTag implements ASMSource, BoundedT } return rect; } + List listeners = new ArrayList(); + + @Override + public void addDisassemblyListener(DisassemblyListener listener) { + listeners.add(listener); + } + + @Override + public void removeDisassemblyListener(DisassemblyListener listener) { + listeners.remove(listener); + } } diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java index 84f9c310e..915c9942e 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java @@ -22,16 +22,23 @@ import com.jpexs.decompiler.flash.tags.base.BoundedTag; import com.jpexs.decompiler.flash.tags.base.CharacterTag; import com.jpexs.decompiler.flash.tags.base.TextTag; import com.jpexs.decompiler.flash.tags.text.ParseException; +import com.jpexs.decompiler.flash.tags.text.ParsedSymbol; +import com.jpexs.decompiler.flash.tags.text.TextLexer; import com.jpexs.decompiler.flash.types.RECT; import com.jpexs.decompiler.flash.types.RGBA; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.InputStreamReader; import java.io.OutputStream; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * @@ -71,6 +78,16 @@ public class DefineEditTextTag extends CharacterTag implements BoundedTag, TextT public String variableName; public String initialText; + @Override + public RECT getBounds() { + return bounds; + } + + @Override + public void setBounds(RECT r) { + bounds = r; + } + private String stripTags(String inp) { boolean intag = false; String outp = ""; @@ -110,16 +127,247 @@ public class DefineEditTextTag extends CharacterTag implements BoundedTag, TextT @Override public String getFormattedText(List tags) { + String ret = ""; + ret += "["; + String[] alignValues = {"left", "right", "center", "justify"}; + ret += "xmin " + bounds.Xmin + " ymin " + bounds.Ymin + " xmax " + bounds.Xmax + " ymax " + bounds.Ymax + " "; + ret += (wordWrap ? "wordwrap 1 " : "") + (multiline ? "multiline 1 " : "") + + (password ? "password 1 " : "") + (readOnly ? "readonly 1 " : "") + + (autoSize ? "autosize 1 " : "") + (noSelect ? "noselect 1 " : "") + + (border ? "border 1 " : "") + (wasStatic ? "wasstatic 1 " : "") + + (html ? "html 1 " : "") + (useOutlines ? "useoutlines 1 " : "") + + (hasFont ? "font " + fontId + " " : "") + (hasTextColor ? "color " + textColor.toHexARGB() + " " : "") + + (hasFontClass ? "fontclass " + fontClass + " " : "") + (hasMaxLength ? "maxlength " + maxLength + " " : "") + + "align " + alignValues[align] + " " + + (hasLayout ? "leftmargin " + leftMargin + " rightmargin " + rightMargin + " indent " + indent + " leading " + leading + " " : "") + + (!variableName.equals("") ? "variablename " + variableName + " " : ""); + ret = ret.trim() + "]"; if (hasText) { - return initialText; + ret += initialText.replace("\\", "\\\\").replace("[", "\\[").replace("]", "\\]"); } - return ""; + return ret; } @Override public void setFormattedText(List tags, String text) throws ParseException { - initialText = text; - hasText = true; + try { + TextLexer lexer = new TextLexer(new InputStreamReader(new ByteArrayInputStream(text.getBytes("UTF-8")), "UTF-8")); + ParsedSymbol s = null; + text = ""; + RECT bounds = new RECT(this.bounds); + boolean wordWrap = false; + boolean multiline = false; + boolean password = false; + boolean readOnly = false; + boolean autoSize = false; + boolean noSelect = false; + boolean border = false; + boolean wasStatic = false; + boolean html = false; + boolean useOutlines = false; + int fontId = -1; + int fontHeight = -1; + String fontClass = null; + RGBA textColor = null; + int maxLength = -1; + int align = -1; + int leftMargin = -1; + int rightMargin = -1; + int indent = -1; + int leading = -1; + String variableName = null; + + while ((s = lexer.yylex()) != null) { + switch (s.type) { + case PARAMETER: + String paramName = (String) s.values[0]; + String paramValue = (String) s.values[1]; + if (paramName.equals("xmin")) { + try { + bounds.Xmin = Integer.parseInt(paramValue); + } catch (NumberFormatException nfe) { + throw new ParseException("Invalid xmin value. Number expected.", lexer.yyline()); + } + } else if (paramName.equals("ymin")) { + try { + bounds.Ymin = Integer.parseInt(paramValue); + } catch (NumberFormatException nfe) { + throw new ParseException("Invalid ymin value. Number expected.", lexer.yyline()); + } + } else if (paramName.equals("xmax")) { + try { + bounds.Xmax = Integer.parseInt(paramValue); + } catch (NumberFormatException nfe) { + throw new ParseException("Invalid xmax value. Number expected.", lexer.yyline()); + } + } else if (paramName.equals("ymax")) { + try { + bounds.Ymax = Integer.parseInt(paramValue); + } catch (NumberFormatException nfe) { + throw new ParseException("Invalid ymax value. Number expected.", lexer.yyline()); + } + } else if (paramName.equals("wordwrap")) { + if (paramValue.equals("1")) { + wordWrap = true; + } + } else if (paramName.equals("multiline")) { + if (paramValue.equals("1")) { + multiline = true; + } + } else if (paramName.equals("password")) { + if (paramValue.equals("1")) { + password = true; + } + } else if (paramName.equals("readonly")) { + if (paramValue.equals("1")) { + readOnly = true; + } + } else if (paramName.equals("autosize")) { + if (paramValue.equals("1")) { + autoSize = true; + } + } else if (paramName.equals("noselect")) { + if (paramValue.equals("1")) { + noSelect = true; + } + } else if (paramName.equals("border")) { + if (paramValue.equals("1")) { + border = true; + } + } else if (paramName.equals("wasstatic")) { + if (paramValue.equals("1")) { + wasStatic = true; + } + } else if (paramName.equals("html")) { + if (paramValue.equals("1")) { + html = true; + } + } else if (paramName.equals("useoutlines")) { + if (paramValue.equals("1")) { + useOutlines = true; + } + } else if (paramName.equals("font")) { + try { + fontId = Integer.parseInt(paramValue); + } catch (NumberFormatException ne) { + throw new ParseException("Invalid font value. Number expected.", lexer.yyline()); + } + } else if (paramName.equals("fontclass")) { + fontClass = paramValue; + } else if (paramName.equals("height")) { + try { + fontHeight = Integer.parseInt(paramValue); + } catch (NumberFormatException ne) { + throw new ParseException("Invalid height value. Number expected.", lexer.yyline()); + } + } else if (paramName.equals("color")) { + Matcher m = Pattern.compile("#([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])").matcher(paramValue); + if (m.matches()) { + textColor = new RGBA(Integer.parseInt(m.group(2), 16), Integer.parseInt(m.group(3), 16), Integer.parseInt(m.group(4), 16), Integer.parseInt(m.group(1), 16)); + } else { + throw new ParseException("Invalid color. Valid format is #aarrggbb.", lexer.yyline()); + } + } else if (paramName.equals("maxlength")) { + try { + maxLength = Integer.parseInt(paramValue); + } catch (NumberFormatException ne) { + throw new ParseException("Invalid maxLength value. Number expected.", lexer.yyline()); + } + } else if (paramName.equals("align")) { + if (paramValue.equals("left")) { + align = 0; + } else if (paramValue.equals("right")) { + align = 1; + } else if (paramValue.equals("center")) { + align = 2; + } else if (paramValue.equals("justify")) { + align = 3; + } else { + throw new ParseException("Invalid align value. Expected one of: left,right,center or justify.", lexer.yyline()); + } + + } else if (paramName.equals("leftmargin")) { + try { + leftMargin = Integer.parseInt(paramValue); + } catch (NumberFormatException ne) { + throw new ParseException("Invalid leftmargin value. Number expected.", lexer.yyline()); + } + } else if (paramName.equals("rightmargin")) { + try { + rightMargin = Integer.parseInt(paramValue); + } catch (NumberFormatException ne) { + throw new ParseException("Invalid rightmargin value. Number expected.", lexer.yyline()); + } + } else if (paramName.equals("indent")) { + try { + indent = Integer.parseInt(paramValue); + } catch (NumberFormatException ne) { + throw new ParseException("Invalid indent value. Number expected.", lexer.yyline()); + } + } else if (paramName.equals("leading")) { + try { + leading = Integer.parseInt(paramValue); + } catch (NumberFormatException ne) { + throw new ParseException("Invalid leading value. Number expected.", lexer.yyline()); + } + } else if (paramName.equals("variablename")) { + variableName = paramValue; + } else { + throw new ParseException("Unrecognized parameter name", lexer.yyline()); + } + break; + case TEXT: + text += (String) s.values[0]; + break; + } + } + + if (text.length() > 0) { + initialText = text; + this.hasText = true; + } else { + this.hasText = false; + } + this.wordWrap = wordWrap; + this.multiline = multiline; + this.password = password; + this.readOnly = readOnly; + if (textColor != null) { + hasTextColor = true; + this.textColor = textColor; + } + if (maxLength > -1) { + this.maxLength = maxLength; + hasMaxLength = true; + } + if (fontId > -1) { + this.fontId = fontId; + } + if (fontClass != null) { + this.fontClass = fontClass; + hasFontClass = true; + } + this.autoSize = autoSize; + if ((leftMargin > -1) + || (rightMargin > -1) + || (indent > -1) + || (leading > -1)) { + this.leftMargin = leftMargin; + this.rightMargin = rightMargin; + this.indent = indent; + this.leading = leading; + hasLayout = true; + } + if (variableName == null) { + variableName = ""; + } + this.variableName = variableName; + + } catch (IOException ex) { + Logger.getLogger(DefineEditTextTag.class.getName()).log(Level.SEVERE, null, ex); + } + + } @Override diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineFont2Tag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineFont2Tag.java index 4142ae06c..2fac0efa9 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineFont2Tag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineFont2Tag.java @@ -69,7 +69,7 @@ public class DefineFont2Tag extends CharacterTag implements FontTag { if (fontFlagsHasLayout) { return fontAdvanceTable[glyphIndex]; } else { - return glyphShapeTable[glyphIndex].getBounds().getWidth(); + return getGlyphWidth(glyphIndex) + 20; } } diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineFont3Tag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineFont3Tag.java index 60348fa84..7d0ec120f 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineFont3Tag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineFont3Tag.java @@ -67,7 +67,7 @@ public class DefineFont3Tag extends CharacterTag implements FontTag { if (fontFlagsHasLayout) { return fontAdvanceTable[glyphIndex] / 20; } else { - return glyphShapeTable[glyphIndex].getBounds().getWidth(); + return getGlyphWidth(glyphIndex) + 20; } } diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineText2Tag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineText2Tag.java index ec826723a..729fa2329 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineText2Tag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineText2Tag.java @@ -26,11 +26,6 @@ import com.jpexs.decompiler.flash.tags.base.FontTag; import com.jpexs.decompiler.flash.tags.base.TextTag; import com.jpexs.decompiler.flash.tags.text.ParseException; import com.jpexs.decompiler.flash.tags.text.ParsedSymbol; -import static com.jpexs.decompiler.flash.tags.text.SymbolType.COLOR; -import static com.jpexs.decompiler.flash.tags.text.SymbolType.FONT; -import static com.jpexs.decompiler.flash.tags.text.SymbolType.TEXT; -import static com.jpexs.decompiler.flash.tags.text.SymbolType.X; -import static com.jpexs.decompiler.flash.tags.text.SymbolType.Y; import com.jpexs.decompiler.flash.tags.text.TextLexer; import com.jpexs.decompiler.flash.types.GLYPHENTRY; import com.jpexs.decompiler.flash.types.MATRIX; @@ -67,6 +62,16 @@ public class DefineText2Tag extends CharacterTag implements BoundedTag, TextTag public int advanceBits; public List textRecords; + @Override + public RECT getBounds() { + return textBounds; + } + + @Override + public void setBounds(RECT r) { + textBounds = r; + } + @Override public String getText(List tags) { FontTag fnt = null; @@ -91,7 +96,24 @@ public class DefineText2Tag extends CharacterTag implements BoundedTag, TextTag public String getFormattedText(List tags) { FontTag fnt = null; String ret = ""; + ret += "[xmin " + textBounds.Xmin + " ymin " + textBounds.Ymin + " xmax " + textBounds.Xmax + " ymax " + textBounds.Ymax; + if (textMatrix.translateX != 0) { + ret += " translatex " + textMatrix.translateX; + } + if (textMatrix.translateY != 0) { + ret += " translatey " + textMatrix.translateY; + } + if (textMatrix.hasScale) { + ret += " scalex " + textMatrix.scaleX; + ret += " scaley " + textMatrix.scaleY; + } + if (textMatrix.hasRotate) { + ret += " rotateskew0 " + textMatrix.rotateSkew0; + ret += " rotateskew1 " + textMatrix.rotateSkew1; + } + ret += "]"; for (TEXTRECORD rec : textRecords) { + String params = ""; if (rec.styleFlagsHasFont) { for (Tag t : tags) { if (t instanceof FontTag) { @@ -101,16 +123,19 @@ public class DefineText2Tag extends CharacterTag implements BoundedTag, TextTag } } } - ret += "[font " + rec.fontId + " height " + rec.textHeight + "]"; + params += " font " + rec.fontId + " height " + rec.textHeight; } if (rec.styleFlagsHasColor) { - ret += "[color " + rec.textColorA.toHexARGB() + "]"; + params += " color " + rec.textColorA.toHexARGB(); } if (rec.styleFlagsHasXOffset) { - ret += "[x " + rec.xOffset + "]"; + params += " x " + rec.xOffset; } if (rec.styleFlagsHasYOffset) { - ret += "[y " + rec.yOffset + "]"; + params += " y " + rec.yOffset; + } + if (params.length() > 0) { + ret += "[" + params.trim() + "]"; } ret += Helper.escapeString(rec.getText(tags, fnt)).replace("[", "\\[").replace("]", "\\]"); } @@ -135,39 +160,128 @@ public class DefineText2Tag extends CharacterTag implements BoundedTag, TextTag int advanceBits = 0; int maxX = Integer.MIN_VALUE; int minX = Integer.MAX_VALUE; + MATRIX textMatrix = new MATRIX(); + textMatrix.hasRotate = false; + textMatrix.hasScale = false; + RECT textBounds = new RECT(); while ((s = lexer.yylex()) != null) { switch (s.type) { - case COLOR: - Matcher m = Pattern.compile("([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])").matcher(s.values[0].toString()); - if (m.matches()) { - colorA = new RGBA(Integer.parseInt(m.group(2), 16), Integer.parseInt(m.group(3), 16), Integer.parseInt(m.group(4), 16), Integer.parseInt(m.group(1), 16)); - } - break; - case FONT: - fontId = (Integer) s.values[0]; - textHeight = (Integer) s.values[1]; - for (Tag t : tags) { - if (t instanceof FontTag) { - if (((FontTag) t).getFontId() == fontId) { - font = (FontTag) t; - break; - } + case PARAMETER: + String paramName = (String) s.values[0]; + String paramValue = (String) s.values[1]; + if (paramName.equals("color")) { + Matcher m = Pattern.compile("#([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])").matcher(s.values[0].toString()); + if (m.matches()) { + colorA = new RGBA(Integer.parseInt(m.group(2), 16), Integer.parseInt(m.group(3), 16), Integer.parseInt(m.group(4), 16), Integer.parseInt(m.group(1), 16)); + } else { + throw new ParseException("Invalid color. Valid format is #aarrggbb.", lexer.yyline()); } } - break; - case X: - x = (Integer) s.values[0]; - currentX = x; - if (currentX < minX) { - minX = currentX; + if (paramName.equals("font")) { + try { + fontId = Integer.parseInt(paramValue); + + for (Tag t : tags) { + if (t instanceof FontTag) { + if (((FontTag) t).getFontId() == fontId) { + font = (FontTag) t; + break; + } + } + } + if (font == null) { + throw new ParseException("Font not found", lexer.yyline()); + } + } catch (NumberFormatException nfe) { + throw new ParseException("Invalid font id - number expected.", lexer.yyline()); + } + } else if (paramName.equals("height")) { + try { + textHeight = Integer.parseInt(paramValue); + } catch (NumberFormatException nfe) { + throw new ParseException("Invalid font height - number expected.", lexer.yyline()); + } + } else if (paramName.equals("x")) { + + try { + x = Integer.parseInt(paramValue); + currentX = x; + } catch (NumberFormatException nfe) { + throw new ParseException("Invalid x position - number expected.", lexer.yyline()); + } + } else if (paramName.equals("y")) { + + try { + y = Integer.parseInt(paramValue); + currentY = y; + } catch (NumberFormatException nfe) { + throw new ParseException("Invalid y position - number expected.", lexer.yyline()); + } + } else if (paramName.equals("xmin")) { + try { + textBounds.Xmin = Integer.parseInt(paramValue); + } catch (NumberFormatException nfe) { + throw new ParseException("Invalid xmin position - number expected.", lexer.yyline()); + } + } else if (paramName.equals("xmax")) { + try { + textBounds.Xmax = Integer.parseInt(paramValue); + } catch (NumberFormatException nfe) { + throw new ParseException("Invalid xmax position - number expected.", lexer.yyline()); + } + } else if (paramName.equals("ymin")) { + try { + textBounds.Ymin = Integer.parseInt(paramValue); + } catch (NumberFormatException nfe) { + throw new ParseException("Invalid ymin position - number expected.", lexer.yyline()); + } + } else if (paramName.equals("ymax")) { + try { + textBounds.Ymax = Integer.parseInt(paramValue); + } catch (NumberFormatException nfe) { + throw new ParseException("Invalid ymax position - number expected.", lexer.yyline()); + } + } else if (paramName.equals("scalex")) { + try { + textMatrix.scaleX = Integer.parseInt(paramValue); + textMatrix.hasScale = true; + } catch (NumberFormatException nfe) { + throw new ParseException("Invalid scalex value - number expected.", lexer.yyline()); + } + } else if (paramName.equals("scaley")) { + try { + textMatrix.scaleY = Integer.parseInt(paramValue); + textMatrix.hasScale = true; + } catch (NumberFormatException nfe) { + throw new ParseException("Invalid scalex value - number expected.", lexer.yyline()); + } + } else if (paramName.equals("rotateskew0")) { + try { + textMatrix.rotateSkew0 = Integer.parseInt(paramValue); + textMatrix.hasRotate = true; + } catch (NumberFormatException nfe) { + throw new ParseException("Invalid rotateskew0 value - number expected.", lexer.yyline()); + } + } else if (paramName.equals("rotateskew1")) { + try { + textMatrix.rotateSkew1 = Integer.parseInt(paramValue); + textMatrix.hasRotate = true; + } catch (NumberFormatException nfe) { + throw new ParseException("Invalid rotateskew1 value - number expected.", lexer.yyline()); + } + } else if (paramName.equals("translatex")) { + try { + textMatrix.translateX = Integer.parseInt(paramValue); + } catch (NumberFormatException nfe) { + throw new ParseException("Invalid translatex value - number expected.", lexer.yyline()); + } + } else if (paramName.equals("translatey")) { + try { + textMatrix.translateY = Integer.parseInt(paramValue); + } catch (NumberFormatException nfe) { + throw new ParseException("Invalid translatey value - number expected.", lexer.yyline()); + } } - if (currentX > maxX) { - maxX = currentX; - } - break; - case Y: - y = (Integer) s.values[0]; - currentY = y; break; case TEXT: if (font == null) { @@ -215,8 +329,8 @@ public class DefineText2Tag extends CharacterTag implements BoundedTag, TextTag } else { currentX += tr.glyphEntries[i].glyphAdvance; } - if (SWFOutputStream.getNeededBitsS(tr.glyphEntries[i].glyphIndex) > glyphBits) { - glyphBits = SWFOutputStream.getNeededBitsS(tr.glyphEntries[i].glyphIndex); + if (SWFOutputStream.getNeededBitsU(tr.glyphEntries[i].glyphIndex) > glyphBits) { + glyphBits = SWFOutputStream.getNeededBitsU(tr.glyphEntries[i].glyphIndex); } if (SWFOutputStream.getNeededBitsS(tr.glyphEntries[i].glyphAdvance) > advanceBits) { advanceBits = SWFOutputStream.getNeededBitsS(tr.glyphEntries[i].glyphAdvance); @@ -237,8 +351,9 @@ public class DefineText2Tag extends CharacterTag implements BoundedTag, TextTag this.advanceBits = advanceBits; this.glyphBits = glyphBits; this.textRecords = textRecords; - this.textBounds.Xmin = minX; - this.textBounds.Xmax = maxX; + this.textBounds = textBounds; + //this.textBounds.Xmin = minX; + //this.textBounds.Xmax = maxX; } catch (UnsupportedEncodingException ex) { Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, null, ex); } catch (IOException ex) { diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineTextTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineTextTag.java index f59456d0b..c98b00806 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineTextTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineTextTag.java @@ -62,6 +62,16 @@ public class DefineTextTag extends CharacterTag implements BoundedTag, TextTag { public int advanceBits; public List textRecords; + @Override + public RECT getBounds() { + return textBounds; + } + + @Override + public void setBounds(RECT r) { + textBounds = r; + } + @Override public String getText(List tags) { FontTag fnt = null; @@ -86,7 +96,24 @@ public class DefineTextTag extends CharacterTag implements BoundedTag, TextTag { public String getFormattedText(List tags) { FontTag fnt = null; String ret = ""; + ret += "[xmin " + textBounds.Xmin + " ymin " + textBounds.Ymin + " xmax " + textBounds.Xmax + " ymax " + textBounds.Ymax; + if (textMatrix.translateX != 0) { + ret += " translatex " + textMatrix.translateX; + } + if (textMatrix.translateY != 0) { + ret += " translatey " + textMatrix.translateY; + } + if (textMatrix.hasScale) { + ret += " scalex " + textMatrix.scaleX; + ret += " scaley " + textMatrix.scaleY; + } + if (textMatrix.hasRotate) { + ret += " rotateskew0 " + textMatrix.rotateSkew0; + ret += " rotateskew1 " + textMatrix.rotateSkew1; + } + ret += "]"; for (TEXTRECORD rec : textRecords) { + String params = ""; if (rec.styleFlagsHasFont) { for (Tag t : tags) { if (t instanceof FontTag) { @@ -96,16 +123,19 @@ public class DefineTextTag extends CharacterTag implements BoundedTag, TextTag { } } } - ret += "[font " + rec.fontId + " height " + rec.textHeight + "]"; + params += " font " + rec.fontId + " height " + rec.textHeight; } if (rec.styleFlagsHasColor) { - ret += "[color " + rec.textColor.toHexRGB() + "]"; + params += " color " + rec.textColor.toHexRGB(); } if (rec.styleFlagsHasXOffset) { - ret += "[x " + rec.xOffset + "]"; + params += " x " + rec.xOffset; } if (rec.styleFlagsHasYOffset) { - ret += "[y " + rec.yOffset + "]"; + params += " y " + rec.yOffset; + } + if (params.length() > 0) { + ret += "[" + params.trim() + "]"; } ret += Helper.escapeString(rec.getText(tags, fnt)).replace("[", "\\[").replace("]", "\\]"); } @@ -130,40 +160,128 @@ public class DefineTextTag extends CharacterTag implements BoundedTag, TextTag { int advanceBits = 0; int maxX = Integer.MIN_VALUE; int minX = Integer.MAX_VALUE; + MATRIX textMatrix = new MATRIX(); + textMatrix.hasRotate = false; + textMatrix.hasScale = false; + RECT textBounds = new RECT(); while ((s = lexer.yylex()) != null) { switch (s.type) { - case COLOR: - Matcher m = Pattern.compile("([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])").matcher(s.values[0].toString()); - if (m.matches()) { - color = new RGB(Integer.parseInt(m.group(1), 16), Integer.parseInt(m.group(2), 16), Integer.parseInt(m.group(3), 16)); - } - break; - case FONT: - fontId = (Integer) s.values[0]; - textHeight = (Integer) s.values[1]; - for (Tag t : tags) { - if (t instanceof FontTag) { - if (((FontTag) t).getFontId() == fontId) { - font = (FontTag) t; - break; + case PARAMETER: + String paramName = (String) s.values[0]; + String paramValue = (String) s.values[1]; + if (paramName.equals("color")) { + Matcher m = Pattern.compile("#([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])").matcher(paramValue); + if (m.matches()) { + color = new RGB(Integer.parseInt(m.group(1), 16), Integer.parseInt(m.group(2), 16), Integer.parseInt(m.group(3), 16)); + } else { + throw new ParseException("Invalid color. Valid format is #rrggbb.", lexer.yyline()); + } + } else if (paramName.equals("font")) { + try { + fontId = Integer.parseInt(paramValue); + + for (Tag t : tags) { + if (t instanceof FontTag) { + if (((FontTag) t).getFontId() == fontId) { + font = (FontTag) t; + break; + } + } } + if (font == null) { + throw new ParseException("Font not found", lexer.yyline()); + } + } catch (NumberFormatException nfe) { + throw new ParseException("Invalid font id - number expected.", lexer.yyline()); + } + } else if (paramName.equals("height")) { + try { + textHeight = Integer.parseInt(paramValue); + } catch (NumberFormatException nfe) { + throw new ParseException("Invalid font height - number expected.", lexer.yyline()); + } + } else if (paramName.equals("x")) { + + try { + x = Integer.parseInt(paramValue); + currentX = x; + } catch (NumberFormatException nfe) { + throw new ParseException("Invalid x position - number expected.", lexer.yyline()); + } + } else if (paramName.equals("y")) { + + try { + y = Integer.parseInt(paramValue); + currentY = y; + } catch (NumberFormatException nfe) { + throw new ParseException("Invalid y position - number expected.", lexer.yyline()); + } + } else if (paramName.equals("xmin")) { + try { + textBounds.Xmin = Integer.parseInt(paramValue); + } catch (NumberFormatException nfe) { + throw new ParseException("Invalid xmin position - number expected.", lexer.yyline()); + } + } else if (paramName.equals("xmax")) { + try { + textBounds.Xmax = Integer.parseInt(paramValue); + } catch (NumberFormatException nfe) { + throw new ParseException("Invalid xmax position - number expected.", lexer.yyline()); + } + } else if (paramName.equals("ymin")) { + try { + textBounds.Ymin = Integer.parseInt(paramValue); + } catch (NumberFormatException nfe) { + throw new ParseException("Invalid ymin position - number expected.", lexer.yyline()); + } + } else if (paramName.equals("ymax")) { + try { + textBounds.Ymax = Integer.parseInt(paramValue); + } catch (NumberFormatException nfe) { + throw new ParseException("Invalid ymax position - number expected.", lexer.yyline()); + } + } else if (paramName.equals("scalex")) { + try { + textMatrix.scaleX = Integer.parseInt(paramValue); + textMatrix.hasScale = true; + } catch (NumberFormatException nfe) { + throw new ParseException("Invalid scalex value - number expected.", lexer.yyline()); + } + } else if (paramName.equals("scaley")) { + try { + textMatrix.scaleY = Integer.parseInt(paramValue); + textMatrix.hasScale = true; + } catch (NumberFormatException nfe) { + throw new ParseException("Invalid scalex value - number expected.", lexer.yyline()); + } + } else if (paramName.equals("rotateskew0")) { + try { + textMatrix.rotateSkew0 = Integer.parseInt(paramValue); + textMatrix.hasRotate = true; + } catch (NumberFormatException nfe) { + throw new ParseException("Invalid rotateskew0 value - number expected.", lexer.yyline()); + } + } else if (paramName.equals("rotateskew1")) { + try { + textMatrix.rotateSkew1 = Integer.parseInt(paramValue); + textMatrix.hasRotate = true; + } catch (NumberFormatException nfe) { + throw new ParseException("Invalid rotateskew1 value - number expected.", lexer.yyline()); + } + } else if (paramName.equals("translatex")) { + try { + textMatrix.translateX = Integer.parseInt(paramValue); + } catch (NumberFormatException nfe) { + throw new ParseException("Invalid translatex value - number expected.", lexer.yyline()); + } + } else if (paramName.equals("translatey")) { + try { + textMatrix.translateY = Integer.parseInt(paramValue); + } catch (NumberFormatException nfe) { + throw new ParseException("Invalid translatey value - number expected.", lexer.yyline()); } } break; - case X: - x = (Integer) s.values[0]; - currentX = x; - if (currentX < minX) { - minX = currentX; - } - if (currentX > maxX) { - maxX = currentX; - } - break; - case Y: - y = (Integer) s.values[0]; - currentY = y; - break; case TEXT: if (font == null) { throw new ParseException("Font not defined", lexer.yyline()); @@ -210,8 +328,8 @@ public class DefineTextTag extends CharacterTag implements BoundedTag, TextTag { } else { currentX += tr.glyphEntries[i].glyphAdvance; } - if (SWFOutputStream.getNeededBitsS(tr.glyphEntries[i].glyphIndex) > glyphBits) { - glyphBits = SWFOutputStream.getNeededBitsS(tr.glyphEntries[i].glyphIndex); + if (SWFOutputStream.getNeededBitsU(tr.glyphEntries[i].glyphIndex) > glyphBits) { + glyphBits = SWFOutputStream.getNeededBitsU(tr.glyphEntries[i].glyphIndex); } if (SWFOutputStream.getNeededBitsS(tr.glyphEntries[i].glyphAdvance) > advanceBits) { advanceBits = SWFOutputStream.getNeededBitsS(tr.glyphEntries[i].glyphAdvance); @@ -232,8 +350,10 @@ public class DefineTextTag extends CharacterTag implements BoundedTag, TextTag { this.advanceBits = advanceBits; this.glyphBits = glyphBits; this.textRecords = textRecords; - this.textBounds.Xmin = minX; - this.textBounds.Xmax = maxX; + this.textMatrix = textMatrix; + this.textBounds = textBounds; + //this.textBounds.Xmin = minX; + //this.textBounds.Xmax = maxX; } catch (UnsupportedEncodingException ex) { Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, null, ex); } catch (IOException ex) { diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DoActionTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DoActionTag.java index ca727b3bc..6047f772c 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DoActionTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DoActionTag.java @@ -16,6 +16,8 @@ */ package com.jpexs.decompiler.flash.tags; +import com.jpexs.decompiler.flash.Configuration; +import com.jpexs.decompiler.flash.DisassemblyListener; import com.jpexs.decompiler.flash.ReReadableInputStream; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; @@ -72,7 +74,7 @@ public class DoActionTag extends Tag implements ASMSource { */ @Override public String getASMSource(int version, boolean hex) { - return Action.actionsToString(0, getActions(version), null, version, hex, getPos()); + return Action.actionsToString(listeners, 0, getActions(version), null, version, hex, getPos()); } /** @@ -111,7 +113,12 @@ public class DoActionTag extends Tag implements ASMSource { baos.write(actionBytes); ReReadableInputStream rri = new ReReadableInputStream(new ByteArrayInputStream(baos.toByteArray())); rri.setPos(prevLength); - return Action.removeNops(0, SWFInputStream.readActionList(0, getPos() - prevLength, rri, version, prevLength, -1), version, getPos()); + boolean deobfuscate = (Boolean) Configuration.getConfig("autoDeobfuscate", true); + List list = SWFInputStream.readActionList(listeners, 0, getPos() - prevLength, rri, version, prevLength, -1); + if (deobfuscate) { + list = Action.removeNops(0, list, version, getPos()); + } + return list; } catch (Exception ex) { Logger.getLogger(DoActionTag.class.getName()).log(Level.SEVERE, null, ex); return new ArrayList(); @@ -132,4 +139,15 @@ public class DoActionTag extends Tag implements ASMSource { public void setActionBytes(byte[] actionBytes) { this.actionBytes = actionBytes; } + List listeners = new ArrayList(); + + @Override + public void addDisassemblyListener(DisassemblyListener listener) { + listeners.add(listener); + } + + @Override + public void removeDisassemblyListener(DisassemblyListener listener) { + listeners.remove(listener); + } } diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DoInitActionTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DoInitActionTag.java index c2cb8563e..230d5c0d7 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DoInitActionTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DoInitActionTag.java @@ -16,6 +16,8 @@ */ package com.jpexs.decompiler.flash.tags; +import com.jpexs.decompiler.flash.Configuration; +import com.jpexs.decompiler.flash.DisassemblyListener; import com.jpexs.decompiler.flash.ReReadableInputStream; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; @@ -95,7 +97,7 @@ public class DoInitActionTag extends CharacterTag implements ASMSource { */ @Override public String getASMSource(int version, boolean hex) { - return Action.actionsToString(0, getActions(version), null, version, hex, getPos() + 2); + return Action.actionsToString(listeners, 0, getActions(version), null, version, hex, getPos() + 2); } @Override @@ -117,7 +119,12 @@ public class DoInitActionTag extends CharacterTag implements ASMSource { baos.write(actionBytes); ReReadableInputStream rri = new ReReadableInputStream(new ByteArrayInputStream(baos.toByteArray())); rri.setPos(prevLength); - return Action.removeNops(0, SWFInputStream.readActionList(0, getPos() + 2 - prevLength, rri, version, prevLength, -1), version, getPos() + 2); + boolean deobfuscate = (Boolean) Configuration.getConfig("autoDeobfuscate", true); + List list = SWFInputStream.readActionList(listeners, 0, getPos() + 2 - prevLength, rri, version, prevLength, -1); + if (deobfuscate) { + list = Action.removeNops(0, list, version, getPos() + 2); + } + return list; } catch (Exception ex) { Logger.getLogger(DoActionTag.class.getName()).log(Level.SEVERE, null, ex); return new ArrayList(); @@ -143,4 +150,15 @@ public class DoInitActionTag extends CharacterTag implements ASMSource { public int getCharacterID() { return spriteId; } + List listeners = new ArrayList(); + + @Override + public void addDisassemblyListener(DisassemblyListener listener) { + listeners.add(listener); + } + + @Override + public void removeDisassemblyListener(DisassemblyListener listener) { + listeners.remove(listener); + } } diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/base/ASMSource.java b/trunk/src/com/jpexs/decompiler/flash/tags/base/ASMSource.java index 3e933d55d..91ae1587b 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/base/ASMSource.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/base/ASMSource.java @@ -16,6 +16,7 @@ */ package com.jpexs.decompiler.flash.tags.base; +import com.jpexs.decompiler.flash.DisassemblyListener; import com.jpexs.decompiler.flash.action.Action; import java.util.List; @@ -63,4 +64,8 @@ public interface ASMSource { public void setActionBytes(byte actionBytes[]); public long getPos(); + + public void addDisassemblyListener(DisassemblyListener listener); + + public void removeDisassemblyListener(DisassemblyListener listener); } diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/base/TextTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/base/TextTag.java index fd187363e..ae2d70c59 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/base/TextTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/base/TextTag.java @@ -18,6 +18,7 @@ package com.jpexs.decompiler.flash.tags.base; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.text.ParseException; +import com.jpexs.decompiler.flash.types.RECT; import java.util.List; /** @@ -33,4 +34,8 @@ public interface TextTag { public void setFormattedText(List tags, String text) throws ParseException; public int getCharacterID(); + + public RECT getBounds(); + + public void setBounds(RECT r); } diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/text/SymbolType.java b/trunk/src/com/jpexs/decompiler/flash/tags/text/SymbolType.java index bb6fd2d01..c8c7ef3ab 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/text/SymbolType.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/text/SymbolType.java @@ -23,8 +23,5 @@ package com.jpexs.decompiler.flash.tags.text; public enum SymbolType { TEXT, - FONT, - COLOR, - X, - Y + PARAMETER } diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/text/TextLexer.java b/trunk/src/com/jpexs/decompiler/flash/tags/text/TextLexer.java index bb95d691b..7bb6671b3 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/text/TextLexer.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/text/TextLexer.java @@ -1,13 +1,26 @@ -/* The following code was generated by JFlex 1.4.3 on 28.4.13 11:46 */ +/* The following code was generated by JFlex 1.4.3 on 30.4.13 19:25 */ -/* Flash assembler language lexer specification */ +/* + * 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.tags.text; -import java.util.regex.*; - /** * This class is a scanner generated by - * JFlex 1.4.3 on 28.4.13 11:46 from the + * JFlex 1.4.3 on 30.4.13 19:25 from the * specification file * D:/Dokumenty/Programovani/JavaSE/FFDec/trunk/src/com/jpexs/decompiler/flash/tags/text/text.flex */ @@ -25,23 +38,23 @@ public final class TextLexer { * lexical states */ public static final int YYINITIAL = 0; + public static final int VALUE = 4; + public static final int PARAMETER = 2; /** * ZZ_LEXSTATE[l] is the state in the DFA for the lexical state l * ZZ_LEXSTATE[l+1] is the state in the DFA for the lexical state l at the * beginning of a line l is of the form l = 2*k, k a non negative integer */ private static final int ZZ_LEXSTATE[] = { - 0, 0 + 0, 0, 1, 1, 2, 2 }; /** * Translates characters to character classes */ private static final String ZZ_CMAP_PACKED = - "\12\0\1\32\25\0\1\12\1\0\1\30\1\23\3\0\1\31\5\0" - + "\1\3\2\0\1\1\11\2\41\0\1\5\1\26\1\17\3\0\1\4" - + "\1\27\1\20\1\4\1\14\1\6\1\16\1\13\1\15\2\0\1\21" - + "\1\0\1\10\1\7\2\0\1\22\1\0\1\11\3\0\1\24\1\25" - + "\uff86\0"; + "\12\0\1\15\25\0\1\2\1\0\1\13\4\0\1\14\10\0\12\1" + + "\41\0\1\3\1\4\1\5\1\0\1\1\1\0\1\1\1\6\3\1" + + "\1\11\7\1\1\10\3\1\1\12\1\1\1\7\6\1\uff85\0"; /** * Translates characters to character classes */ @@ -51,12 +64,12 @@ public final class TextLexer { */ private static final int[] ZZ_ACTION = zzUnpackAction(); private static final String ZZ_ACTION_PACKED_0 = - "\1\0\3\1\1\2\4\0\1\3\1\4\1\5\1\6" - + "\1\7\1\10\1\11\1\12\1\13\1\14\1\15\16\0" - + "\1\16\1\17\25\0\1\20\3\0\1\21"; + "\3\0\1\1\1\2\1\1\1\3\1\4\1\5\1\6" + + "\1\7\1\10\1\11\1\12\1\13\1\14\1\15\1\16" + + "\1\17\1\20\1\21"; private static int[] zzUnpackAction() { - int[] result = new int[62]; + int[] result = new int[21]; int offset = 0; offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result); return result; @@ -80,17 +93,12 @@ public final class TextLexer { */ private static final int[] ZZ_ROWMAP = zzUnpackRowMap(); private static final String ZZ_ROWMAP_PACKED_0 = - "\0\0\0\33\0\66\0\121\0\33\0\154\0\207\0\242" - + "\0\275\0\33\0\33\0\33\0\33\0\33\0\33\0\33" - + "\0\33\0\33\0\33\0\33\0\330\0\363\0\u010e\0\u0129" - + "\0\u0144\0\u015f\0\u017a\0\u0195\0\u01b0\0\u01cb\0\u01e6\0\u0201" - + "\0\u021c\0\u0237\0\33\0\33\0\u0252\0\u026d\0\u0288\0\u02a3" - + "\0\u02be\0\u02d9\0\u02f4\0\u030f\0\u032a\0\u0345\0\u0360\0\u037b" - + "\0\u0396\0\u03b1\0\u03cc\0\u03e7\0\u0402\0\u041d\0\u0438\0\u0453" - + "\0\u046e\0\33\0\u0489\0\u04a4\0\u04bf\0\33"; + "\0\0\0\16\0\34\0\52\0\52\0\70\0\52\0\106" + + "\0\52\0\124\0\52\0\52\0\52\0\52\0\52\0\52" + + "\0\52\0\52\0\52\0\52\0\52"; private static int[] zzUnpackRowMap() { - int[] result = new int[62]; + int[] result = new int[21]; int offset = 0; offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result); return result; @@ -111,36 +119,14 @@ public final class TextLexer { */ private static final int[] ZZ_TRANS = zzUnpackTrans(); private static final String ZZ_TRANS_PACKED_0 = - "\5\2\1\3\20\2\1\4\3\2\1\5\41\0\1\6" - + "\11\0\1\7\3\0\1\10\1\11\5\0\5\12\1\13" - + "\1\14\1\12\1\15\1\16\5\12\1\17\2\12\1\20" - + "\3\12\1\21\1\22\1\23\1\24\10\0\1\25\32\0" - + "\1\26\35\0\1\27\32\0\1\30\30\0\1\31\43\0" - + "\1\32\12\0\1\33\1\34\1\35\30\0\1\36\1\37" - + "\1\40\40\0\1\41\30\0\1\42\42\0\1\43\14\0" - + "\2\34\14\0\1\43\14\0\1\33\1\34\47\0\1\44" - + "\14\0\2\37\14\0\1\44\14\0\1\36\1\37\42\0" - + "\1\45\42\0\1\46\11\0\1\47\1\50\42\0\1\51" - + "\32\0\1\52\21\0\2\50\7\0\1\52\43\0\1\53" - + "\22\0\1\54\20\0\2\55\1\0\1\55\1\0\1\55" - + "\5\0\1\55\3\0\1\55\6\0\1\55\17\0\1\56" - + "\17\0\2\57\1\0\1\57\1\0\1\57\5\0\1\57" - + "\3\0\1\57\6\0\1\57\20\0\1\60\16\0\2\61" - + "\1\0\1\61\1\0\1\61\5\0\1\61\3\0\1\61" - + "\6\0\1\61\21\0\1\62\15\0\2\63\1\0\1\63" - + "\1\0\1\63\5\0\1\63\3\0\1\63\6\0\1\63" - + "\16\0\1\64\20\0\2\65\1\0\1\65\1\0\1\65" - + "\5\0\1\65\3\0\1\65\6\0\1\65\14\0\1\66" - + "\22\0\2\67\1\0\1\67\1\0\1\67\5\0\1\67" - + "\3\0\1\67\6\0\1\67\15\0\1\70\21\0\2\71" - + "\1\0\1\71\1\0\1\71\5\0\1\71\2\0\1\72" - + "\1\71\6\0\1\71\4\0\1\73\1\74\31\0\2\75" - + "\1\0\1\75\1\0\1\75\5\0\1\75\3\0\1\75" - + "\6\0\1\75\22\0\1\76\14\0\2\74\14\0\1\76" - + "\32\0\1\72\13\0"; + "\3\4\1\5\1\6\10\4\2\7\1\10\3\7\1\11" + + "\5\10\3\7\2\12\1\7\2\12\1\11\10\12\16\0" + + "\3\13\1\14\1\15\1\16\1\17\1\20\1\21\1\22" + + "\1\23\1\24\1\25\2\0\1\10\4\0\5\10\3\0" + + "\2\12\1\0\2\12\1\0\10\12"; private static int[] zzUnpackTrans() { - int[] result = new int[1242]; + int[] result = new int[98]; int offset = 0; offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result); return result; @@ -177,11 +163,10 @@ public final class TextLexer { */ private static final int[] ZZ_ATTRIBUTE = zzUnpackAttribute(); private static final String ZZ_ATTRIBUTE_PACKED_0 = - "\1\0\1\11\2\1\1\11\4\0\13\11\16\0\2\11" - + "\25\0\1\11\3\0\1\11"; + "\3\0\2\11\1\1\1\11\1\1\1\11\1\1\13\11"; private static int[] zzUnpackAttribute() { - int[] result = new int[62]; + int[] result = new int[21]; int offset = 0; offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result); return result; @@ -263,6 +248,7 @@ public final class TextLexer { /* user code: */ StringBuffer string = null; boolean finish = false; + String parameterName = null; /** * Create an empty lexer, yyrset will be called later to reset and assign @@ -309,7 +295,7 @@ public final class TextLexer { char[] map = new char[0x10000]; int i = 0; /* index in packed string */ int j = 0; /* index in unpacked array */ - while (i < 82) { + while (i < 58) { int count = packed.charAt(i++); char value = packed.charAt(i++); do { @@ -633,12 +619,12 @@ public final class TextLexer { } case 18: break; - case 3: { + case 7: { throw new ParseException("Illegal escape sequence \"" + yytext() + "\"", yyline + 1); } case 19: break; - case 6: { + case 13: { if (string == null) { string = new StringBuffer(); } @@ -646,31 +632,25 @@ public final class TextLexer { } case 20: break; + case 2: { + yybegin(PARAMETER); + if (string != null) { + String ret = string.toString(); + string = null; + return new ParsedSymbol(SymbolType.TEXT, ret.toString()); + } + } + case 21: + break; case 11: { if (string == null) { string = new StringBuffer(); } string.append('\b'); } - case 21: - break; - case 17: { - if (string == null) { - Pattern pat = Pattern.compile("\\[font ([0-9]+) height ([0-9]+)\\]"); - Matcher m = pat.matcher(yytext()); - if (m.matches()) { - return new ParsedSymbol(SymbolType.FONT, Integer.parseInt(m.group(1)), Integer.parseInt(m.group(2))); - } - } else { - yypushback(yylength()); - String ret = string.toString(); - string = null; - return new ParsedSymbol(SymbolType.TEXT, ret.toString()); - } - } case 22: break; - case 13: { + case 17: { if (string == null) { string = new StringBuffer(); } @@ -678,99 +658,80 @@ public final class TextLexer { } case 23: break; - case 16: { - if (string == null) { - return new ParsedSymbol(SymbolType.COLOR, yytext().substring(8, yytext().length() - 1)); - } else { - yypushback(yylength()); - String ret = string.toString(); - string = null; - return new ParsedSymbol(SymbolType.TEXT, ret.toString()); - } + case 4: { + parameterName = yytext(); + yybegin(VALUE); } case 24: break; - case 8: { - if (string == null) { - string = new StringBuffer(); - } - string.append(']'); + case 6: { + yybegin(PARAMETER); + return new ParsedSymbol(SymbolType.PARAMETER, new Object[]{parameterName, yytext()}); } case 25: break; - case 15: { - if (string == null) { - return new ParsedSymbol(SymbolType.Y, Integer.parseInt(yytext().substring(3, yytext().length() - 1))); - } else { - yypushback(yylength()); - String ret = string.toString(); - string = null; - return new ParsedSymbol(SymbolType.TEXT, ret.toString()); - } - } - case 26: - break; - case 14: { - if (string == null) { - return new ParsedSymbol(SymbolType.X, Integer.parseInt(yytext().substring(3, yytext().length() - 1))); - } else { - yypushback(yylength()); - String ret = string.toString(); - string = null; - return new ParsedSymbol(SymbolType.TEXT, ret.toString()); - } - } - case 27: - break; - case 7: { - if (string == null) { - string = new StringBuffer(); - } - string.append('\t'); - } - case 28: - break; - case 4: { - if (string == null) { - string = new StringBuffer(); - } - string.append('['); - } - case 29: - break; case 10: { if (string == null) { string = new StringBuffer(); } - string.append('\\'); + string.append(']'); } - case 30: + case 26: break; case 12: { if (string == null) { string = new StringBuffer(); } - string.append('\"'); + string.append('\t'); } - case 31: + case 27: + break; + case 8: { + if (string == null) { + string = new StringBuffer(); + } + string.append('['); + } + case 28: break; case 9: { + if (string == null) { + string = new StringBuffer(); + } + string.append('\\'); + } + case 29: + break; + case 16: { + if (string == null) { + string = new StringBuffer(); + } + string.append('\"'); + } + case 30: + break; + case 15: { if (string == null) { string = new StringBuffer(); } string.append('\r'); } - case 32: + case 31: break; - case 5: { + case 14: { if (string == null) { string = new StringBuffer(); } string.append('\f'); } + case 32: + break; + case 5: { + yybegin(YYINITIAL); + } case 33: break; - case 2: { + case 3: { } case 34: break; @@ -786,7 +747,7 @@ public final class TextLexer { return new ParsedSymbol(SymbolType.TEXT, string.toString()); } } - case 63: + case 22: break; default: { return null; diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/text/text.flex b/trunk/src/com/jpexs/decompiler/flash/tags/text/text.flex index eb0af0abb..01dc7b211 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/text/text.flex +++ b/trunk/src/com/jpexs/decompiler/flash/tags/text/text.flex @@ -1,8 +1,21 @@ -/* Flash assembler language lexer specification */ - +/* + * 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.tags.text; -import java.util.regex.*; %% @@ -20,6 +33,7 @@ import java.util.regex.*; StringBuffer string = null; boolean finish=false; + String parameterName=null; /** @@ -40,60 +54,17 @@ import java.util.regex.*; %} -PositiveNumber = 0 | [1-9][0-9]* -NegativeNumber = - {PositiveNumber} -Number = {PositiveNumber}|{NegativeNumber} -Hex = [0-9a-f][0-9a-f] - -Font = "[font " {PositiveNumber} " height " {PositiveNumber} "]" -Color = "[color #" {Hex}{Hex}{Hex} "]" -ColorA = "[color #" {Hex}{Hex}{Hex}{Hex} "]" -X = "[x " {Number} "]" -Y = "[y " {Number} "]" +Parameter = [a-z0-9_]+ +Value = [^ \]]+ +%state PARAMETER,VALUE %% { - {Font} { - if(string==null){ - Pattern pat = Pattern.compile("\\[font ([0-9]+) height ([0-9]+)\\]"); - Matcher m=pat.matcher(yytext()); - if(m.matches()){ - return new ParsedSymbol(SymbolType.FONT,Integer.parseInt(m.group(1)),Integer.parseInt(m.group(2))); - } - }else{ - yypushback(yylength()); - String ret=string.toString(); - string = null; - return new ParsedSymbol(SymbolType.TEXT,ret.toString()); - } - } - {Color}|{ColorA} { - if(string==null){ - return new ParsedSymbol(SymbolType.COLOR,yytext().substring(8,yytext().length()-1)); - }else{ - yypushback(yylength()); - String ret=string.toString(); - string = null; - return new ParsedSymbol(SymbolType.TEXT,ret.toString()); - } - } - {X} { - if(string==null){ - return new ParsedSymbol(SymbolType.X,Integer.parseInt(yytext().substring(3,yytext().length()-1))); - }else{ - yypushback(yylength()); - String ret=string.toString(); - string = null; - return new ParsedSymbol(SymbolType.TEXT,ret.toString()); - } - } - {Y} { - if(string==null){ - return new ParsedSymbol(SymbolType.Y,Integer.parseInt(yytext().substring(3,yytext().length()-1))); - }else{ - yypushback(yylength()); + "[" { + yybegin(PARAMETER); + if(string!=null){ String ret=string.toString(); string = null; return new ParsedSymbol(SymbolType.TEXT,ret.toString()); @@ -117,6 +88,28 @@ Y = "[y " {Number} "]" <> { if(finish){return null;}else{finish=true; return new ParsedSymbol(SymbolType.TEXT,string.toString());}} } + { + " " {} + {Parameter} { + parameterName = yytext(); + yybegin(VALUE); + } + "]" { + yybegin(YYINITIAL); + } +} + + { + " " {} + {Value} { + yybegin(PARAMETER); + return new ParsedSymbol(SymbolType.PARAMETER,new Object[]{parameterName,yytext()}); + } + "]" { + yybegin(YYINITIAL); + } +} + /* error fallback */ .|\n { } <> { return null; } diff --git a/trunk/src/com/jpexs/decompiler/flash/types/BUTTONCONDACTION.java b/trunk/src/com/jpexs/decompiler/flash/types/BUTTONCONDACTION.java index 07fa3fbe2..a8305af5e 100644 --- a/trunk/src/com/jpexs/decompiler/flash/types/BUTTONCONDACTION.java +++ b/trunk/src/com/jpexs/decompiler/flash/types/BUTTONCONDACTION.java @@ -16,6 +16,8 @@ */ package com.jpexs.decompiler.flash.types; +import com.jpexs.decompiler.flash.Configuration; +import com.jpexs.decompiler.flash.DisassemblyListener; import com.jpexs.decompiler.flash.ReReadableInputStream; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.action.Action; @@ -142,7 +144,7 @@ public class BUTTONCONDACTION implements ASMSource { */ @Override public String getASMSource(int version, boolean hex) { - return Action.actionsToString(0, getActions(version), null, version, hex, getPos() + 4); + return Action.actionsToString(listeners, 0, getActions(version), null, version, hex, getPos() + 4); } /** @@ -164,7 +166,13 @@ public class BUTTONCONDACTION implements ASMSource { @Override public List getActions(int version) { try { - return Action.removeNops(0, SWFInputStream.readActionList(0, getPos() + 4, new ReReadableInputStream(new ByteArrayInputStream(actionBytes)), version, 0, -1), version, getPos() + 4); + boolean deobfuscate = (Boolean) Configuration.getConfig("autoDeobfuscate", true); + List list = SWFInputStream.readActionList(listeners, 0, getPos() + 4, new ReReadableInputStream(new ByteArrayInputStream(actionBytes)), version, 0, -1); + if (deobfuscate) { + list = Action.removeNops(0, list, version, getPos() + 4); + } + return list; + } catch (Exception ex) { Logger.getLogger(BUTTONCONDACTION.class.getName()).log(Level.SEVERE, null, ex); return new ArrayList(); @@ -185,4 +193,15 @@ public class BUTTONCONDACTION implements ASMSource { public void setActionBytes(byte[] actionBytes) { this.actionBytes = actionBytes; } + List listeners = new ArrayList(); + + @Override + public void addDisassemblyListener(DisassemblyListener listener) { + listeners.add(listener); + } + + @Override + public void removeDisassemblyListener(DisassemblyListener listener) { + listeners.remove(listener); + } } diff --git a/trunk/src/com/jpexs/decompiler/flash/types/CLIPACTIONRECORD.java b/trunk/src/com/jpexs/decompiler/flash/types/CLIPACTIONRECORD.java index 115842189..55bd5de81 100644 --- a/trunk/src/com/jpexs/decompiler/flash/types/CLIPACTIONRECORD.java +++ b/trunk/src/com/jpexs/decompiler/flash/types/CLIPACTIONRECORD.java @@ -16,6 +16,8 @@ */ package com.jpexs.decompiler.flash.types; +import com.jpexs.decompiler.flash.Configuration; +import com.jpexs.decompiler.flash.DisassemblyListener; import com.jpexs.decompiler.flash.ReReadableInputStream; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.action.Action; @@ -105,7 +107,7 @@ public class CLIPACTIONRECORD implements ASMSource { */ @Override public String getASMSource(int version, boolean hex) { - return Action.actionsToString(0, getActions(version), null, version, hex, getPos() + hdrPos); + return Action.actionsToString(listeners, 0, getActions(version), null, version, hex, getPos() + hdrPos); } /** @@ -121,7 +123,12 @@ public class CLIPACTIONRECORD implements ASMSource { @Override public List getActions(int version) { try { - return Action.removeNops(0, SWFInputStream.readActionList(0, getPos() + hdrPos, new ReReadableInputStream(new ByteArrayInputStream(actionBytes)), version, 0, -1), version, getPos() + hdrPos); + boolean deobfuscate = (Boolean) Configuration.getConfig("autoDeobfuscate", true); + List list = SWFInputStream.readActionList(listeners, 0, getPos() + hdrPos, new ReReadableInputStream(new ByteArrayInputStream(actionBytes)), version, 0, -1); + if (deobfuscate) { + list = Action.removeNops(0, list, version, getPos() + hdrPos); + } + return list; } catch (Exception ex) { Logger.getLogger(BUTTONCONDACTION.class.getName()).log(Level.SEVERE, null, ex); return new ArrayList(); @@ -142,4 +149,15 @@ public class CLIPACTIONRECORD implements ASMSource { public void setActionBytes(byte[] actionBytes) { this.actionBytes = actionBytes; } + List listeners = new ArrayList(); + + @Override + public void addDisassemblyListener(DisassemblyListener listener) { + listeners.add(listener); + } + + @Override + public void removeDisassemblyListener(DisassemblyListener listener) { + listeners.remove(listener); + } } diff --git a/trunk/src/com/jpexs/decompiler/flash/types/RECT.java b/trunk/src/com/jpexs/decompiler/flash/types/RECT.java index 80e59f51a..e7777c430 100644 --- a/trunk/src/com/jpexs/decompiler/flash/types/RECT.java +++ b/trunk/src/com/jpexs/decompiler/flash/types/RECT.java @@ -51,6 +51,13 @@ public class RECT { public RECT() { } + public RECT(RECT r) { + Xmin = r.Xmin; + Xmax = r.Xmax; + Ymin = r.Ymin; + Ymax = r.Ymax; + } + @Override public String toString() { return "[RECT x=" + Xmin + " to " + Xmax + ", y=" + Ymin + " to " + Ymax + "]";