diff --git a/src/com/jpexs/decompiler/flash/SWF.java b/src/com/jpexs/decompiler/flash/SWF.java index 7e66be9de..77d1c001c 100644 --- a/src/com/jpexs/decompiler/flash/SWF.java +++ b/src/com/jpexs/decompiler/flash/SWF.java @@ -381,7 +381,9 @@ public final class SWF implements TreeItem, Timelined { sos.writeUI8(frameRate); sos.writeUI16(frameCount); - sos.writeTags(tags); + Map tagPositions = new HashMap<>(); + Map tagLengths = new HashMap<>(); + sos.writeTags(tags, tagPositions, tagLengths); if (hasEndTag) { sos.writeUI16(0); } @@ -507,7 +509,7 @@ public final class SWF implements TreeItem, Timelined { compression = header.compression; uncompressedData = baos.toByteArray(); - SWFInputStream sis = new SWFInputStream(uncompressedData, version); + SWFInputStream sis = new SWFInputStream(this, uncompressedData); sis.read(new byte[8], 0, 8); // skip the header if (listener != null) { sis.addPercentListener(listener); @@ -703,7 +705,7 @@ public final class SWF implements TreeItem, Timelined { } int version = hdr[3]; - SWFInputStream sis = new SWFInputStream(Arrays.copyOfRange(hdr, 4, 8), version, 4); + SWFInputStream sis = new SWFInputStream(null, Arrays.copyOfRange(hdr, 4, 8), 4); long fileSize = sis.readUI32(); SWFHeader header = new SWFHeader(); header.version = version; diff --git a/src/com/jpexs/decompiler/flash/SWFInputStream.java b/src/com/jpexs/decompiler/flash/SWFInputStream.java index 9bcd950f9..8b1ed6f2e 100644 --- a/src/com/jpexs/decompiler/flash/SWFInputStream.java +++ b/src/com/jpexs/decompiler/flash/SWFInputStream.java @@ -291,14 +291,10 @@ public class SWFInputStream implements AutoCloseable { private SeekableInputStream is; private long pos; - private int version; private static final Logger logger = Logger.getLogger(SWFInputStream.class.getName()); private final List listeners = new ArrayList<>(); private long percentMax; - - public int getVersion() { - return version; - } + public SWF swf; public void addPercentListener(ProgressListener listener) { listeners.add(listener); @@ -318,12 +314,12 @@ public class SWFInputStream implements AutoCloseable { /** * Constructor * + * @param swf SWF to read * @param data SWF data - * @param version Version of SWF to read * @param startingPos */ - public SWFInputStream(byte[] data, int version, long startingPos) { - this.version = version; + public SWFInputStream(SWF swf, byte[] data, long startingPos) { + this.swf = swf; this.is = new MemoryInputStream(data); pos = startingPos; } @@ -331,34 +327,11 @@ public class SWFInputStream implements AutoCloseable { /** * Constructor * + * @param swf SWF to read * @param data SWF data - * @param version Version of SWF to read */ - public SWFInputStream(byte[] data, int version) { - this(data, version, 0L); - } - - /** - * Constructor - * - * @param is Existing inputstream - * @param version Version of SWF to read - * @param startingPos - */ - public SWFInputStream(SeekableInputStream is, int version, long startingPos) { - this.version = version; - this.is = is; - pos = startingPos; - } - - /** - * Constructor - * - * @param is Existing inputstream - * @param version Version of SWF to read - */ - public SWFInputStream(SeekableInputStream is, int version) { - this(is, version, 0L); + public SWFInputStream(SWF swf, byte[] data) { + this(swf, data, 0L); } /** @@ -888,7 +861,7 @@ public class SWFInputStream implements AutoCloseable { tags.add(tag); } if (Configuration.dumpTags.get() && level == 0) { - dumpTag(System.out, version, tag, level); + dumpTag(System.out, swf.version, tag, level); } boolean doParse; @@ -970,7 +943,7 @@ public class SWFInputStream implements AutoCloseable { byte[] data = tag.getData(); long pos = tag.getPos(); int length = tag.getOriginalLength(); - SWFLimitedInputStream sis = new SWFLimitedInputStream(swf, new SWFInputStream(data, swf.version), length); + SWFLimitedInputStream sis = new SWFLimitedInputStream(swf, new SWFInputStream(swf, data, tag.getDataPos()), length); try { switch (tag.getId()) { @@ -1354,7 +1327,7 @@ public class SWFInputStream implements AutoCloseable { case 0x81: return new ActionGotoFrame(actionLength, this); case 0x83: - return new ActionGetURL(actionLength, this, version); + return new ActionGetURL(actionLength, this, swf.version); case 0x04: return new ActionNextFrame(); case 0x05: @@ -1370,12 +1343,12 @@ public class SWFInputStream implements AutoCloseable { case 0x8A: return new ActionWaitForFrame(actionLength, this, cpool); case 0x8B: - return new ActionSetTarget(actionLength, this, version); + return new ActionSetTarget(actionLength, this, swf.version); case 0x8C: - return new ActionGoToLabel(actionLength, this, version); + return new ActionGoToLabel(actionLength, this, swf.version); //SWF4 Actions case 0x96: - return new ActionPush(actionLength, this, version); + return new ActionPush(actionLength, this, swf.version); case 0x17: return new ActionPop(); case 0x0A: @@ -1462,9 +1435,9 @@ public class SWFInputStream implements AutoCloseable { case 0x52: return new ActionCallMethod(); case 0x88: - return new ActionConstantPool(actionLength, this, version); + return new ActionConstantPool(actionLength, this, swf.version); case 0x9B: - return new ActionDefineFunction(actionLength, this, version); + return new ActionDefineFunction(actionLength, this, swf.version); case 0x3C: return new ActionDefineLocal(); case 0x41: @@ -1492,7 +1465,7 @@ public class SWFInputStream implements AutoCloseable { case 0x45: return new ActionTargetPath(); case 0x94: - return new ActionWith(actionLength, this, version); + return new ActionWith(actionLength, this, swf.version); case 0x4A: return new ActionToNumber(); case 0x4B: @@ -1542,7 +1515,7 @@ public class SWFInputStream implements AutoCloseable { return new ActionStringGreater(); //SWF7 Actions case 0x8E: - return new ActionDefineFunction2(actionLength, this, version); + return new ActionDefineFunction2(actionLength, this, swf.version); case 0x69: return new ActionExtends(); case 0x2B: @@ -1550,7 +1523,7 @@ public class SWFInputStream implements AutoCloseable { case 0x2C: return new ActionImplementsOp(); case 0x8F: - return new ActionTry(actionLength, this, version); + return new ActionTry(actionLength, this, swf.version); case 0x2A: return new ActionThrow(); default: @@ -1677,7 +1650,7 @@ public class SWFInputStream implements AutoCloseable { ret.clipEventPress = readUB(1) == 1; ret.clipEventInitialize = readUB(1) == 1; ret.clipEventData = readUB(1) == 1; - if (version >= 6) { + if (swf.version >= 6) { ret.reserved = (int) readUB(5); ret.clipEventConstruct = readUB(1) == 1; ret.clipEventKeyPress = readUB(1) == 1; diff --git a/src/com/jpexs/decompiler/flash/SWFLimitedInputStream.java b/src/com/jpexs/decompiler/flash/SWFLimitedInputStream.java index 2cc2db392..07629f96e 100644 --- a/src/com/jpexs/decompiler/flash/SWFLimitedInputStream.java +++ b/src/com/jpexs/decompiler/flash/SWFLimitedInputStream.java @@ -48,10 +48,12 @@ import java.util.List; public class SWFLimitedInputStream { private SWFInputStream sis; + private long limit; public SWF swf; - public SWFLimitedInputStream(SWF swf, SWFInputStream sis, long limit) { + public SWFLimitedInputStream(SWF swf, SWFInputStream sis, long limit) { this.swf = swf; + this.limit = limit; this.sis = sis; } diff --git a/src/com/jpexs/decompiler/flash/SWFOutputStream.java b/src/com/jpexs/decompiler/flash/SWFOutputStream.java index ac4ff0092..f6378b660 100644 --- a/src/com/jpexs/decompiler/flash/SWFOutputStream.java +++ b/src/com/jpexs/decompiler/flash/SWFOutputStream.java @@ -79,6 +79,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.List; +import java.util.Map; import java.util.zip.Deflater; import java.util.zip.DeflaterOutputStream; @@ -414,11 +415,17 @@ public class SWFOutputStream extends OutputStream { * Writes list of Tag values to the stream * * @param tags List of tag values + * @param tagPositions + * @param tagLengths * @throws IOException */ - public void writeTags(List tags) throws IOException { + public void writeTags(List tags, Map tagPositions, Map tagLengths) throws IOException { for (Tag tag : tags) { + long pos = getPos(); tag.writeTag(this); + int length = (int) (getPos() - pos); + tagPositions.put(tag, pos); + tagLengths.put(tag, length); } } diff --git a/src/com/jpexs/decompiler/flash/action/ActionListReader.java b/src/com/jpexs/decompiler/flash/action/ActionListReader.java index f1b1a835d..b863dd152 100644 --- a/src/com/jpexs/decompiler/flash/action/ActionListReader.java +++ b/src/com/jpexs/decompiler/flash/action/ActionListReader.java @@ -1,968 +1,965 @@ -/* - * Copyright (C) 2010-2014 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.AppStrings; -import com.jpexs.decompiler.flash.DisassemblyListener; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.action.model.ConstantPool; -import com.jpexs.decompiler.flash.action.model.DirectValueActionItem; -import com.jpexs.decompiler.flash.action.special.ActionEnd; -import com.jpexs.decompiler.flash.action.special.ActionNop; -import com.jpexs.decompiler.flash.action.special.ActionStore; -import com.jpexs.decompiler.flash.action.swf4.ActionEquals; -import com.jpexs.decompiler.flash.action.swf4.ActionIf; -import com.jpexs.decompiler.flash.action.swf4.ActionJump; -import com.jpexs.decompiler.flash.action.swf4.ActionPush; -import com.jpexs.decompiler.flash.action.swf5.ActionConstantPool; -import com.jpexs.decompiler.flash.action.swf5.ActionDefineFunction; -import com.jpexs.decompiler.flash.action.swf5.ActionEquals2; -import com.jpexs.decompiler.flash.action.swf5.ActionStoreRegister; -import com.jpexs.decompiler.flash.action.swf7.ActionDefineFunction2; -import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.decompiler.flash.ecma.EcmaScript; -import com.jpexs.decompiler.flash.ecma.Null; -import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; -import com.jpexs.decompiler.graph.Graph; -import com.jpexs.decompiler.graph.GraphSourceItem; -import com.jpexs.decompiler.graph.GraphSourceItemContainer; -import com.jpexs.decompiler.graph.GraphTargetItem; -import com.jpexs.decompiler.graph.NotCompileTimeItem; -import com.jpexs.decompiler.graph.TranslateException; -import com.jpexs.decompiler.graph.model.LocalData; -import com.jpexs.helpers.CancellableWorker; -import com.jpexs.helpers.Helper; -import com.jpexs.helpers.MemoryInputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Queue; -import java.util.Scanner; -import java.util.Stack; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Class for reading data from SWF file - * - * @author JPEXS - */ -public class ActionListReader { - - private static final Logger logger = Logger.getLogger(SWFInputStream.class.getName()); - - /** - * Reads list of actions from the stream. Reading ends with - * ActionEndFlag(=0) or end of the stream. - * - * @param listeners - * @param containerSWFOffset - * @param mis - * @param version - * @param ip - * @param endIp - * @param path - * @return List of actions - * @throws IOException - * @throws java.lang.InterruptedException - * @throws java.util.concurrent.TimeoutException - */ - public static List readActionListTimeout(final List listeners, final long containerSWFOffset, final MemoryInputStream mis, final int version, final int ip, final int endIp, final String path) throws IOException, InterruptedException, TimeoutException { - try { - return CancellableWorker.call(new Callable>() { - - @Override - public List call() throws IOException, InterruptedException { - return readActionList(listeners, containerSWFOffset, mis, version, ip, endIp, path); - } - }, Configuration.decompilationTimeoutSingleMethod.get(), TimeUnit.SECONDS); - } catch (ExecutionException ex) { - Throwable cause = ex.getCause(); - if (cause instanceof InterruptedException) { - throw (InterruptedException) cause; - } else if (cause instanceof InterruptedException) { - throw (IOException) cause; - } else { - Logger.getLogger(ActionListReader.class.getName()).log(Level.SEVERE, null, ex); - } - } - return new ArrayList<>(); - } - - /** - * Reads list of actions from the stream. Reading ends with - * ActionEndFlag(=0) or end of the stream. - * - * @param listeners - * @param containerSWFOffset - * @param mis - * @param version - * @param ip - * @param endIp - * @param path - * @return List of actions - * @throws IOException - * @throws java.lang.InterruptedException - */ - public static List readActionList(List listeners, long containerSWFOffset, MemoryInputStream mis, int version, int ip, int endIp, String path) throws IOException, InterruptedException { - boolean deobfuscate = Configuration.autoDeobfuscate.get(); - - ConstantPool cpool = new ConstantPool(); - - SWFInputStream sis = new SWFInputStream(mis, version); - - // List of the actions. N. item contains the action which starts in offset N. - List actionMap = new ArrayList<>(); - List nextOffsets = new ArrayList<>(); - Action entryAction = readActionListAtPos(listeners, containerSWFOffset, cpool, - sis, actionMap, nextOffsets, - ip, ip, endIp, version, path, false, new ArrayList()); - - Map> containerLastActions = new HashMap<>(); - getContainerLastActions(actionMap, containerLastActions); - - List actions = new ArrayList<>(); - - // jump to the entry action when it is diffrent from the first action in the map - int index = getNextNotNullIndex(actionMap, 0); - if (index != -1 && entryAction != actionMap.get(index)) { - ActionJump jump = new ActionJump(0); - int size = getTotalActionLength(jump); - jump.setJumpOffset((int) (entryAction.getAddress() - size)); - actions.add(jump); - } - - // remove nulls - index = getNextNotNullIndex(actionMap, index); - while (index > -1) { - Action action = actionMap.get(index); - long nextOffset = nextOffsets.get(index); - int nextIndex = getNextNotNullIndex(actionMap, index + 1); - actions.add(action); - if (nextIndex != -1 && nextOffset != nextIndex) { - if (!action.isExit() && !(action instanceof ActionJump)) { - ActionJump jump = new ActionJump(0); - jump.setAddress(action.getAddress(), version); - int size = getTotalActionLength(jump); - jump.setJumpOffset((int) (nextOffset - action.getAddress() - size)); - actions.add(jump); - } - } - index = nextIndex; - } - - // Map for storing the targers of the "jump" actions - // "jump" action can be ActionIf, ActionJump and any ActionStore - Map jumps = new HashMap<>(); - getJumps(actions, jumps); - - long endAddress = updateAddresses(actions, ip, version); - - // add end action - Action lastAction = actions.get(actions.size() - 1); - Action aEnd = new ActionEnd(); - if (!(lastAction instanceof ActionEnd)) { - aEnd.setAddress(endAddress, version); - actions.add(aEnd); - } else { - endAddress -= getTotalActionLength(aEnd); - } - - updateJumps(actions, jumps, containerLastActions, endAddress, version); - //updateActionStores(actions, jumps); - updateContainerSizes(actions, containerLastActions); - updateActionLengths(actions, version); - - if (deobfuscate) { - try { - actions = deobfuscateActionList(listeners, containerSWFOffset, actions, version, ip, path); - updateActionLengths(actions, version); - removeZeroJumps(actions, version); - } catch (OutOfMemoryError | StackOverflowError | TranslateException ex) { - // keep orignal (not deobfuscated) actions - Logger.getLogger(ActionListReader.class.getName()).log(Level.SEVERE, null, ex); - } - } - - return actions; - } - - /** - * Reads list of actions from the stream. Reading ends with - * ActionEndFlag(=0) or end of the stream. - * - * @param listeners - * @param containerSWFOffset - * @param actions - * @param version - * @param ip - * @param path - * @return List of actions - * @throws IOException - * @throws java.lang.InterruptedException - */ - public static List deobfuscateActionList(List listeners, long containerSWFOffset, List actions, int version, int ip, String path) throws IOException, InterruptedException { - if (actions.isEmpty()) { - return actions; - } - - Action lastAction = actions.get(actions.size() - 1); - int endIp = (int) lastAction.getAddress(); - - List retdups = new ArrayList<>(); - for (int i = 0; i < endIp; i++) { - Action a = new ActionNop(); - a.setAddress(i, version); - retdups.add(a); - } - List actionMap = new ArrayList<>(endIp); - for (int i = 0; i <= endIp; i++) { - actionMap.add(null); - } - for (Action a : actions) { - actionMap.set((int) a.getAddress(), a); - } - - ConstantPool cpool = new ConstantPool(); - - Stack stack = new Stack<>(); - - ActionLocalData localData = new ActionLocalData(); - - int maxRecursionLevel = 0; - for (int i = 0; i < actions.size(); i++) { - Action a = actions.get(i); - if (a instanceof ActionIf || a instanceof GraphSourceItemContainer) { - maxRecursionLevel++; - } - if (a instanceof ActionIf) { - ActionIf aif = (ActionIf) a; - aif.ignoreUsed = false; - aif.jumpUsed = false; - } - } - - deobfustaceActionListAtPosRecursive(listeners, new ArrayList(), new HashMap>(), containerSWFOffset, localData, stack, cpool, actionMap, ip, retdups, ip, endIp, path, new HashMap(), false, new HashMap>(), version, 0, maxRecursionLevel); - - if (!retdups.isEmpty()) { - for (int i = 0; i < ip; i++) { - retdups.remove(0); - } - } - List ret = new ArrayList<>(); - Action last = null; - for (Action a : retdups) { - if (a != last) { - ret.add(a); - } - last = a; - } - for (int i = 0; i < retdups.size(); i++) { - Action a = retdups.get(i); - if (a instanceof ActionEnd) { - if (i < retdups.size() - 1) { - ActionJump jmp = new ActionJump(0); - jmp.setJumpOffset(retdups.size() - i - jmp.getBytes(version).length); - a.replaceWith = jmp; - } - } - } - - ret = Action.removeNops(0, ret, version, 0, path); - List reta = new ArrayList<>(); - for (Object o : ret) { - if (o instanceof Action) { - reta.add((Action) o); - } - } - return reta; - } - - private static int getPrevNotNullIndex(List actionMap, int startIndex) { - startIndex = Math.min(startIndex, actionMap.size() - 1); - for (int i = startIndex; i >= 0; i--) { - if (actionMap.get(i) != null) { - return i; - } - } - return -1; - } - - private static int getNextNotNullIndex(List actionMap, int startIndex) { - for (int i = startIndex; i < actionMap.size(); i++) { - if (actionMap.get(i) != null) { - return i; - } - } - return -1; - } - - private static Map actionListToMap(List actions) { - Map map = new HashMap<>(actions.size()); - for (Action a : actions) { - long address = a.getAddress(); - // There are multiple actions in the same address (2nd action is a jump for obfuscated code) - // So this check is required - if (!map.containsKey(address)) { - map.put(a.getAddress(), a); - } - } - return map; - } - - private static void getJumps(List actions, Map jumps) { - Map actionMap = actionListToMap(actions); - for (Action a : actions) { - long target = -1; - if (a instanceof ActionIf) { - ActionIf aIf = (ActionIf) a; - target = aIf.getAddress() + getTotalActionLength(a) + aIf.getJumpOffset(); - } else if (a instanceof ActionJump) { - ActionJump aJump = (ActionJump) a; - target = aJump.getAddress() + getTotalActionLength(a) + aJump.getJumpOffset(); - } else if (a instanceof ActionStore) { - ActionStore aStore = (ActionStore) a; - int storeSize = aStore.getStoreSize(); - // skip storeSize + 1 actions (+1 is the current action) - Action targetAction = a; - for (int i = 0; i <= storeSize; i++) { - long address = targetAction.getAddress() + getTotalActionLength(targetAction); - targetAction = actionMap.get(address); - if (targetAction == null) { - break; - } - } - jumps.put(a, targetAction); - } - if (target >= 0) { - Action targetAction = actionMap.get(target); - jumps.put(a, targetAction); - } - } - } - - private static void getContainerLastActions(List actionMap, Map> lastActions) { - for (int i = 0; i < actionMap.size(); i++) { - Action a = actionMap.get(i); - if (a == null) { - continue; - } - - if (a instanceof GraphSourceItemContainer) { - GraphSourceItemContainer container = (GraphSourceItemContainer) a; - List sizes = container.getContainerSizes(); - long endAddress = a.getAddress() + container.getHeaderSize(); - List lasts = new ArrayList<>(sizes.size()); - for (long size : sizes) { - endAddress += size; - int lastActionIndex = getPrevNotNullIndex(actionMap, (int) (endAddress - 1)); - Action lastAction = null; - if (lastActionIndex != -1) { - lastAction = actionMap.get(lastActionIndex); - } - lasts.add(lastAction); - } - lastActions.put(a, lasts); - } - } - } - - private static long updateAddresses(List actions, long address, int version) { - for (int i = 0; i < actions.size(); i++) { - Action a = actions.get(i); - a.setAddress(address, version); - int length = a.getBytes(version).length; - if ((i != actions.size() - 1) && (a instanceof ActionEnd)) { - // placeholder for jump action - length = getTotalActionLength(new ActionJump(0)); - } - address += length; - } - return address; - } - - private static void updateActionLengths(List actions, int version) { - for (int i = 0; i < actions.size(); i++) { - Action a = actions.get(i); - int length = a.getBytes(version).length; - a.actionLength = length - 1 - ((a.actionCode >= 0x80) ? 2 : 0); - } - } - - private static void updateActionStores(List actions, Map jumps) { - Map actionMap = actionListToMap(actions); - for (int i = 0; i < actions.size(); i++) { - Action a = actions.get(i); - if (a instanceof ActionStore) { - ActionStore aStore = (ActionStore) a; - Action nextActionAfterStore = jumps.get(a); - Action a1 = a; - List store = new ArrayList<>(); - while (true) { - long address = a1.getAddress() + getTotalActionLength(a1); - a1 = actionMap.get(address); - if (a1 == null || a1 == nextActionAfterStore) { - break; - } - actions.remove(a1); - store.add(a1); - } - aStore.setStore(store); - } - } - } - - private static void updateContainerSizes(List actions, Map> containerLastActions) { - for (int i = 0; i < actions.size(); i++) { - Action a = actions.get(i); - if (a instanceof GraphSourceItemContainer) { - GraphSourceItemContainer container = (GraphSourceItemContainer) a; - List lastActions = containerLastActions.get(a); - long startAddress = a.getAddress() + container.getHeaderSize(); - for (int j = 0; j < lastActions.size(); j++) { - Action lastAction = lastActions.get(j); - int length = (int) (lastAction.getAddress() + getTotalActionLength(lastAction) - startAddress); - container.setContainerSize(j, length); - startAddress += length; - } - } - } - } - - private static void replaceJumpTargets(Map jumps, Action oldTarget, Action newTarget) { - for (Action a : jumps.keySet()) { - if (jumps.get(a) == oldTarget) { - jumps.put(a, newTarget); - } - } - } - - private static void replaceContainerLastActions(Map> containerLastActions, Action oldTarget, Action newTarget) { - for (Action a : containerLastActions.keySet()) { - List targets = containerLastActions.get(a); - for (int i = 0; i < targets.size(); i++) { - if (targets.get(i) == oldTarget) { - targets.set(i, newTarget); - } - } - } - } - - private static void updateJumps(List actions, Map jumps, Map> containerLastActions, long endAddress, int version) { - if (actions.isEmpty()) { - return; - } - - for (int i = 0; i < actions.size(); i++) { - Action a = actions.get(i); - if ((i != actions.size() - 1) && (a instanceof ActionEnd)) { - ActionJump aJump = new ActionJump(0); - aJump.setJumpOffset((int) (endAddress - a.getAddress() - getTotalActionLength(aJump))); - aJump.setAddress(a.getAddress(), version); - replaceJumpTargets(jumps, a, aJump); - replaceContainerLastActions(containerLastActions, a, aJump); - a = aJump; - actions.set(i, a); - } else if (a instanceof ActionIf) { - ActionIf aIf = (ActionIf) a; - Action target = jumps.get(a); - long offset; - if (target != null) { - offset = target.getAddress() - a.getAddress() - getTotalActionLength(a); - } else { - offset = endAddress - a.getAddress() - getTotalActionLength(a); - } - aIf.setJumpOffset((int) offset); - } else if (a instanceof ActionJump) { - ActionJump aJump = (ActionJump) a; - Action target = jumps.get(a); - long offset; - if (target != null) { - offset = target.getAddress() - a.getAddress() - getTotalActionLength(a); - } else { - offset = endAddress - a.getAddress() - getTotalActionLength(a); - } - aJump.setJumpOffset((int) offset); - } - } - } - - private static void removeZeroJumps(List actions, int version) { - for (int i = 0; i < actions.size(); i++) { - Action a = actions.get(i); - if (a instanceof ActionJump) { - ActionJump aJump = (ActionJump) a; - if (aJump.getJumpOffset() == 0) { - if (removeAction(actions, i, version, false)) { - i--; - } - } - } - } - } - - /** - * Removes an action from the action list, and updates all references - * - * @param actions - * @param index - * @param version - * @param removeWhenLast - * @return - */ - public static boolean removeAction(List actions, int index, int version, boolean removeWhenLast) { - - if (index < 0 || actions.size() <= index) { - return false; - } - - long startIp = actions.get(0).getAddress(); - Action lastAction = actions.get(actions.size() - 1); - int lastIdx = (int) lastAction.getAddress(); - long endAddress = lastAction.getAddress() + getTotalActionLength(lastAction); - - List actionMap = new ArrayList<>(lastIdx); - for (int i = 0; i <= lastIdx; i++) { - actionMap.add(null); - } - for (Action a : actions) { - actionMap.set((int) a.getAddress(), a); - } - - Map> containerLastActions = new HashMap<>(); - getContainerLastActions(actionMap, containerLastActions); - - Map jumps = new HashMap<>(); - getJumps(actions, jumps); - - Action prevAction = index > 0 ? actions.get(index - 1) : null; - Action nextAction = index + 1 < actions.size() ? actions.get(index + 1) : null; - Action actionToRemove = actions.get(index); - for (Action a : containerLastActions.keySet()) { - List lastActions = containerLastActions.get(a); - for (int i = 0; i < lastActions.size(); i++) { - if (lastActions.get(i) == actionToRemove) { - if (!removeWhenLast) { - return false; - } - lastActions.set(i, prevAction); - } - } - } - for (Action a : jumps.keySet()) { - Action targetAction = jumps.get(a); - if (targetAction == actionToRemove) { - jumps.put(a, nextAction); - } - } - if (containerLastActions.containsKey(actionToRemove)) { - containerLastActions.remove(actionToRemove); - } - if (jumps.containsKey(actionToRemove)) { - jumps.remove(actionToRemove); - } - - actions.remove(index); - - updateAddresses(actions, startIp, version); - updateJumps(actions, jumps, containerLastActions, endAddress, version); - //updateActionStores(actions, jumps); - updateContainerSizes(actions, containerLastActions); - updateActionLengths(actions, version); - - return true; - } - - private static Action readActionListAtPos(List listeners, long containerSWFOffset, ConstantPool cpool, - SWFInputStream sis, List actions, List nextOffsets, - long ip, long startIp, long endIp, int version, String path, boolean indeterminate, List visitedContainers) throws IOException { - - Action entryAction = null; - - if (visitedContainers.contains(ip)) { - return null; - } - visitedContainers.add(ip); - - Queue jumpQueue = new LinkedList<>(); - jumpQueue.add(ip); - while (!jumpQueue.isEmpty()) { - ip = jumpQueue.remove(); - while ((endIp == -1) || (endIp > ip)) { - sis.seek((int) ip); - - Action a; - if ((a = sis.readAction(cpool)) == null) { - break; - } - - int actionLengthWithHeader = getTotalActionLength(a); - - // unknown action, replace with jump - if (a instanceof ActionNop) { - ActionJump aJump = new ActionJump(0); - int jumpLength = getTotalActionLength(aJump); - aJump.setAddress(a.getAddress(), version); - aJump.setJumpOffset(actionLengthWithHeader - jumpLength); - a = aJump; - actionLengthWithHeader = getTotalActionLength(a); - } - - if (entryAction == null) { - entryAction = a; - } - - ensureCapacity(actions, nextOffsets, ip); - - Action existingAction = actions.get((int) ip); - if (existingAction != null) { - break; - } - - actions.set((int) ip, a); - nextOffsets.set((int) ip, ip + actionLengthWithHeader); - - long pos = sis.getPos(); - long length = pos + sis.available(); - for (int i = 0; i < listeners.size(); i++) { - listeners.get(i).progress(AppStrings.translate("disassemblingProgress.reading"), pos, length); - } - - a.containerSWFOffset = containerSWFOffset; - a.setAddress(ip, version, false); - - if (a instanceof ActionPush && cpool != null) { - ((ActionPush) a).constantPool = cpool.constants; - } else if (a instanceof ActionConstantPool) { - if (cpool == null) { - cpool = new ConstantPool(); - } - cpool.setNew(((ActionConstantPool) a).constantPool); - } else if (a instanceof ActionIf) { - ActionIf aIf = (ActionIf) a; - long nIp = ip + actionLengthWithHeader + aIf.getJumpOffset(); - if (nIp >= 0) { - jumpQueue.add(nIp); - } - } else if (a instanceof ActionJump) { - ActionJump aJump = (ActionJump) a; - long nIp = ip + actionLengthWithHeader + aJump.getJumpOffset(); - if (nIp >= 0) { - jumpQueue.add(nIp); - } - break; - } else if (a instanceof GraphSourceItemContainer) { - GraphSourceItemContainer cnt = (GraphSourceItemContainer) a; - String cntName = cnt.getName(); - String newPath = path + (cntName == null ? "" : "/" + cntName); - for (long size : cnt.getContainerSizes()) { - if (size != 0) { - long ip2 = ip + actionLengthWithHeader; - //long endIp2 = ip + actionLengthWithHeader + size; - readActionListAtPos(listeners, containerSWFOffset, cpool, - sis, actions, nextOffsets, - ip2, startIp, endIp, version, newPath, indeterminate, visitedContainers); - actionLengthWithHeader += size; - } - } - } - - ip += actionLengthWithHeader; - - if (a.isExit()) { - break; - } - } - } - return entryAction; - } - - private static int getTotalActionLength(Action action) { - return action.actionLength + 1 + ((action.actionCode >= 0x80) ? 2 : 0); - } - - private static void ensureCapacity(List actions, List nextOffsets, long index) { - while (actions.size() <= index) { - actions.add(null); - nextOffsets.add(-1L); - } - } - - private static void deobfustaceActionListAtPosRecursive(List listeners, List output, HashMap> containers, long containerSWFOffset, ActionLocalData localData, Stack stack, ConstantPool cpool, List actions, int ip, List ret, int startIp, int endip, String path, Map visited, boolean indeterminate, Map> decisionStates, int version, int recursionLevel, int maxRecursionLevel) throws IOException, InterruptedException { - boolean debugMode = false; - boolean decideBranch = false; - - if (recursionLevel > maxRecursionLevel + 1) { - throw new TranslateException("deobfustaceActionListAtPosRecursive max recursion level reached."); - } - - Action a; - Scanner sc = new Scanner(System.in); - loopip: - while (((endip == -1) || (endip > ip)) && (a = actions.get(ip)) != null) { - if (Thread.currentThread().isInterrupted()) { - throw new InterruptedException(); - } - - int actionLen = getTotalActionLength(a); - if (!visited.containsKey(ip)) { - visited.put(ip, 0); - } - int curVisited = visited.get(ip); - curVisited++; - visited.put(ip, curVisited); - for (int i = 0; i < listeners.size(); i++) { - listeners.get(i).progress(AppStrings.translate("disassemblingProgress.deobfuscating"), ip, actions.size()); - } - int info = a.actionLength + 1 + ((a.actionCode >= 0x80) ? 2 : 0); - - if (a instanceof ActionPush) { - if (cpool != null) { - ((ActionPush) a).constantPool = cpool.constants; - } - } - - if (debugMode) { - String atos = a.getASMSource(new ArrayList(), new ArrayList(), cpool.constants, version, ScriptExportMode.PCODE); - if (a instanceof GraphSourceItemContainer) { - atos = a.toString(); - } - System.err.println("readActionListAtPos ip: " + (ip - startIp) + " (0x" + Helper.formatAddress(ip - startIp) + ") " + " action(len " + a.actionLength + "): " + atos + (a.isIgnored() ? " (ignored)" : "") + " stack:" + Helper.stackToString(stack, LocalData.create(cpool)) + " " + Helper.byteArrToString(a.getBytes(version))); - System.err.print("variables: "); - for (Map.Entry v : localData.variables.entrySet()) { - System.err.print("'" + v + "' = " + v.getValue().toString(LocalData.create(cpool)) + ", "); - } - System.err.println(); - String add = ""; - if (a instanceof ActionIf) { - add = " change: " + ((ActionIf) a).getJumpOffset(); - } - if (a instanceof ActionJump) { - add = " change: " + ((ActionJump) a).getJumpOffset(); - } - System.err.println(add); - } - - int newip = -1; - - if (a instanceof ActionConstantPool) { - if (cpool == null) { - cpool = new ConstantPool(); - } - cpool.setNew(((ActionConstantPool) a).constantPool); - } - 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; - - GraphTargetItem top = stack.pop(); - int nip = ip + actionLen + aif.getJumpOffset(); - - if (decideBranch) { - System.out.print("newip " + nip + ", "); - System.out.print("Action: jump(j),ignore(i),compute(c)?"); - String next = sc.next(); - switch (next) { - case "j": - newip = nip; - break; - case "i": - break; - case "c": - goaif = true; - break; - } - } else if (top.isCompileTime() && (!top.hasSideEffect())) { - if (debugMode) { - System.err.print("is compiletime -> "); - } - if (EcmaScript.toBoolean(top.getResult())) { - newip = nip; - aif.jumpUsed = true; - if (debugMode) { - System.err.println("jump"); - } - } else { - aif.ignoreUsed = true; - if (debugMode) { - System.err.println("ignore"); - } - } - } else { - if (debugMode) { - System.err.println("goaif"); - } - goaif = true; - } - } else if (a instanceof ActionJump) { - newip = ip + actionLen + ((ActionJump) a).getJumpOffset(); - } 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 DirectValueActionItem)) { - stack.push(new DirectValueActionItem(null, 0, new Null(), new ArrayList())); - } - if ((a instanceof ActionStoreRegister) && stack.isEmpty()) { - stack.push(new DirectValueActionItem(null, 0, new Null(), new ArrayList())); - } - a.translate(localData, stack, output, Graph.SOP_USE_STATIC/*Graph.SOP_SKIP_STATIC*/, path); - } - } catch (RuntimeException ex) { - logger.log(Level.SEVERE, "Disassembly exception", ex); - break; - } - - HashMap vars = localData.variables; - if (varname != null) { - GraphTargetItem varval = vars.get(varname); - if (varval != null && varval.isCompileTime() && indeterminate) { - vars.put(varname, new NotCompileTimeItem(null, varval)); - } - } - } - int nopos = -1; - for (int i = 0; i < actionLen; i++) { - if (a instanceof ActionNop) { - int prevPos = (int) a.getAddress(); - a = new ActionNop(); - a.setAddress(prevPos, version); - nopos++; - if (nopos > 0) { - a.setAddress(a.getAddress() + 1, version); - } - - } - ret.set(ip + i, a); - } - - if (a instanceof GraphSourceItemContainer) { - GraphSourceItemContainer cnt = (GraphSourceItemContainer) a; - if (a instanceof Action) { - long endAddr = a.getAddress() + cnt.getHeaderSize(); - String cntName = cnt.getName(); - List> output2s = new ArrayList<>(); - for (long size : cnt.getContainerSizes()) { - if (size == 0) { - output2s.add(new ArrayList()); - continue; - } - ActionLocalData localData2; - List output2 = new ArrayList<>(); - if ((cnt instanceof ActionDefineFunction) || (cnt instanceof ActionDefineFunction2)) { - localData2 = new ActionLocalData(); - } else { - localData2 = localData; - } - deobfustaceActionListAtPosRecursive(listeners, output2, containers, containerSWFOffset, localData2, new Stack(), cpool, actions, (int) endAddr, ret, startIp, (int) (endAddr + size), path + (cntName == null ? "" : "/" + cntName), visited, indeterminate, decisionStates, version, recursionLevel + 1, maxRecursionLevel); - output2s.add(output2); - endAddr += size; - } - cnt.translateContainer(output2s, stack, output, localData.regNames, localData.variables, localData.functions); - ip = (int) endAddr; - continue; - } - } - - if (a instanceof ActionEnd) { - break; - } - if (goaif) { - aif.ignoreUsed = true; - aif.jumpUsed = true; - indeterminate = true; - - HashMap vars = localData.variables; - 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(ip + actionLen + aif.getJumpOffset()); - branches.add(ip + actionLen); - for (int br : branches) { - int visc = 0; - if (visited.containsKey(br)) { - visc = visited.get(br); - } - if (visc == 0) {// substack = (Stack) stack.clone(); - deobfustaceActionListAtPosRecursive(listeners, output, containers, containerSWFOffset, prepareLocalBranch(localData), substack, cpool, actions, ip + actionLen + aif.getJumpOffset(), ret, startIp, endip, path, visited, indeterminate, decisionStates, version, recursionLevel + 1, maxRecursionLevel); - } - - if (newip > -1) { - ip = newip; - } else { - ip += info; - } - - if (a.isExit()) { - break; - } - } - for (DisassemblyListener listener : listeners) { - listener.progress(AppStrings.translate("disassemblingProgress.deobfuscating"), ip, actions.size()); - } - } - - private static ActionLocalData prepareLocalBranch(ActionLocalData localData) { - - return new ActionLocalData(new HashMap<>(localData.regNames), - new HashMap<>(localData.variables), new HashMap<>(localData.functions)); - } -} +/* + * Copyright (C) 2010-2014 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.AppStrings; +import com.jpexs.decompiler.flash.DisassemblyListener; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.action.model.ConstantPool; +import com.jpexs.decompiler.flash.action.model.DirectValueActionItem; +import com.jpexs.decompiler.flash.action.special.ActionEnd; +import com.jpexs.decompiler.flash.action.special.ActionNop; +import com.jpexs.decompiler.flash.action.special.ActionStore; +import com.jpexs.decompiler.flash.action.swf4.ActionEquals; +import com.jpexs.decompiler.flash.action.swf4.ActionIf; +import com.jpexs.decompiler.flash.action.swf4.ActionJump; +import com.jpexs.decompiler.flash.action.swf4.ActionPush; +import com.jpexs.decompiler.flash.action.swf5.ActionConstantPool; +import com.jpexs.decompiler.flash.action.swf5.ActionDefineFunction; +import com.jpexs.decompiler.flash.action.swf5.ActionEquals2; +import com.jpexs.decompiler.flash.action.swf5.ActionStoreRegister; +import com.jpexs.decompiler.flash.action.swf7.ActionDefineFunction2; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.ecma.EcmaScript; +import com.jpexs.decompiler.flash.ecma.Null; +import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; +import com.jpexs.decompiler.graph.Graph; +import com.jpexs.decompiler.graph.GraphSourceItem; +import com.jpexs.decompiler.graph.GraphSourceItemContainer; +import com.jpexs.decompiler.graph.GraphTargetItem; +import com.jpexs.decompiler.graph.NotCompileTimeItem; +import com.jpexs.decompiler.graph.TranslateException; +import com.jpexs.decompiler.graph.model.LocalData; +import com.jpexs.helpers.CancellableWorker; +import com.jpexs.helpers.Helper; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Queue; +import java.util.Scanner; +import java.util.Stack; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Class for reading data from SWF file + * + * @author JPEXS + */ +public class ActionListReader { + + private static final Logger logger = Logger.getLogger(SWFInputStream.class.getName()); + + /** + * Reads list of actions from the stream. Reading ends with + * ActionEndFlag(=0) or end of the stream. + * + * @param listeners + * @param containerSWFOffset + * @param sis + * @param version + * @param ip + * @param endIp + * @param path + * @return List of actions + * @throws IOException + * @throws java.lang.InterruptedException + * @throws java.util.concurrent.TimeoutException + */ + public static List readActionListTimeout(final List listeners, final long containerSWFOffset, final SWFInputStream sis, final int version, final int ip, final int endIp, final String path) throws IOException, InterruptedException, TimeoutException { + try { + return CancellableWorker.call(new Callable>() { + + @Override + public List call() throws IOException, InterruptedException { + return readActionList(listeners, containerSWFOffset, sis, version, ip, endIp, path); + } + }, Configuration.decompilationTimeoutSingleMethod.get(), TimeUnit.SECONDS); + } catch (ExecutionException ex) { + Throwable cause = ex.getCause(); + if (cause instanceof InterruptedException) { + throw (InterruptedException) cause; + } else if (cause instanceof InterruptedException) { + throw (IOException) cause; + } else { + Logger.getLogger(ActionListReader.class.getName()).log(Level.SEVERE, null, ex); + } + } + return new ArrayList<>(); + } + + /** + * Reads list of actions from the stream. Reading ends with + * ActionEndFlag(=0) or end of the stream. + * + * @param listeners + * @param containerSWFOffset + * @param sis + * @param version + * @param ip + * @param endIp + * @param path + * @return List of actions + * @throws IOException + * @throws java.lang.InterruptedException + */ + public static List readActionList(List listeners, long containerSWFOffset, SWFInputStream sis, int version, int ip, int endIp, String path) throws IOException, InterruptedException { + boolean deobfuscate = Configuration.autoDeobfuscate.get(); + + ConstantPool cpool = new ConstantPool(); + + // List of the actions. N. item contains the action which starts in offset N. + List actionMap = new ArrayList<>(); + List nextOffsets = new ArrayList<>(); + Action entryAction = readActionListAtPos(listeners, containerSWFOffset, cpool, + sis, actionMap, nextOffsets, + ip, ip, endIp, version, path, false, new ArrayList()); + + Map> containerLastActions = new HashMap<>(); + getContainerLastActions(actionMap, containerLastActions); + + List actions = new ArrayList<>(); + + // jump to the entry action when it is diffrent from the first action in the map + int index = getNextNotNullIndex(actionMap, 0); + if (index != -1 && entryAction != actionMap.get(index)) { + ActionJump jump = new ActionJump(0); + int size = getTotalActionLength(jump); + jump.setJumpOffset((int) (entryAction.getAddress() - size)); + actions.add(jump); + } + + // remove nulls + index = getNextNotNullIndex(actionMap, index); + while (index > -1) { + Action action = actionMap.get(index); + long nextOffset = nextOffsets.get(index); + int nextIndex = getNextNotNullIndex(actionMap, index + 1); + actions.add(action); + if (nextIndex != -1 && nextOffset != nextIndex) { + if (!action.isExit() && !(action instanceof ActionJump)) { + ActionJump jump = new ActionJump(0); + jump.setAddress(action.getAddress(), version); + int size = getTotalActionLength(jump); + jump.setJumpOffset((int) (nextOffset - action.getAddress() - size)); + actions.add(jump); + } + } + index = nextIndex; + } + + // Map for storing the targers of the "jump" actions + // "jump" action can be ActionIf, ActionJump and any ActionStore + Map jumps = new HashMap<>(); + getJumps(actions, jumps); + + long endAddress = updateAddresses(actions, ip, version); + + // add end action + Action lastAction = actions.get(actions.size() - 1); + Action aEnd = new ActionEnd(); + if (!(lastAction instanceof ActionEnd)) { + aEnd.setAddress(endAddress, version); + actions.add(aEnd); + } else { + endAddress -= getTotalActionLength(aEnd); + } + + updateJumps(actions, jumps, containerLastActions, endAddress, version); + //updateActionStores(actions, jumps); + updateContainerSizes(actions, containerLastActions); + updateActionLengths(actions, version); + + if (deobfuscate) { + try { + actions = deobfuscateActionList(listeners, containerSWFOffset, actions, version, ip, path); + updateActionLengths(actions, version); + removeZeroJumps(actions, version); + } catch (OutOfMemoryError | StackOverflowError | TranslateException ex) { + // keep orignal (not deobfuscated) actions + Logger.getLogger(ActionListReader.class.getName()).log(Level.SEVERE, null, ex); + } + } + + return actions; + } + + /** + * Reads list of actions from the stream. Reading ends with + * ActionEndFlag(=0) or end of the stream. + * + * @param listeners + * @param containerSWFOffset + * @param actions + * @param version + * @param ip + * @param path + * @return List of actions + * @throws IOException + * @throws java.lang.InterruptedException + */ + public static List deobfuscateActionList(List listeners, long containerSWFOffset, List actions, int version, int ip, String path) throws IOException, InterruptedException { + if (actions.isEmpty()) { + return actions; + } + + Action lastAction = actions.get(actions.size() - 1); + int endIp = (int) lastAction.getAddress(); + + List retdups = new ArrayList<>(); + for (int i = 0; i < endIp; i++) { + Action a = new ActionNop(); + a.setAddress(i, version); + retdups.add(a); + } + List actionMap = new ArrayList<>(endIp); + for (int i = 0; i <= endIp; i++) { + actionMap.add(null); + } + for (Action a : actions) { + actionMap.set((int) a.getAddress(), a); + } + + ConstantPool cpool = new ConstantPool(); + + Stack stack = new Stack<>(); + + ActionLocalData localData = new ActionLocalData(); + + int maxRecursionLevel = 0; + for (int i = 0; i < actions.size(); i++) { + Action a = actions.get(i); + if (a instanceof ActionIf || a instanceof GraphSourceItemContainer) { + maxRecursionLevel++; + } + if (a instanceof ActionIf) { + ActionIf aif = (ActionIf) a; + aif.ignoreUsed = false; + aif.jumpUsed = false; + } + } + + deobfustaceActionListAtPosRecursive(listeners, new ArrayList(), new HashMap>(), containerSWFOffset, localData, stack, cpool, actionMap, ip, retdups, ip, endIp, path, new HashMap(), false, new HashMap>(), version, 0, maxRecursionLevel); + + if (!retdups.isEmpty()) { + for (int i = 0; i < ip; i++) { + retdups.remove(0); + } + } + List ret = new ArrayList<>(); + Action last = null; + for (Action a : retdups) { + if (a != last) { + ret.add(a); + } + last = a; + } + for (int i = 0; i < retdups.size(); i++) { + Action a = retdups.get(i); + if (a instanceof ActionEnd) { + if (i < retdups.size() - 1) { + ActionJump jmp = new ActionJump(0); + jmp.setJumpOffset(retdups.size() - i - jmp.getBytes(version).length); + a.replaceWith = jmp; + } + } + } + + ret = Action.removeNops(0, ret, version, 0, path); + List reta = new ArrayList<>(); + for (Object o : ret) { + if (o instanceof Action) { + reta.add((Action) o); + } + } + return reta; + } + + private static int getPrevNotNullIndex(List actionMap, int startIndex) { + startIndex = Math.min(startIndex, actionMap.size() - 1); + for (int i = startIndex; i >= 0; i--) { + if (actionMap.get(i) != null) { + return i; + } + } + return -1; + } + + private static int getNextNotNullIndex(List actionMap, int startIndex) { + for (int i = startIndex; i < actionMap.size(); i++) { + if (actionMap.get(i) != null) { + return i; + } + } + return -1; + } + + private static Map actionListToMap(List actions) { + Map map = new HashMap<>(actions.size()); + for (Action a : actions) { + long address = a.getAddress(); + // There are multiple actions in the same address (2nd action is a jump for obfuscated code) + // So this check is required + if (!map.containsKey(address)) { + map.put(a.getAddress(), a); + } + } + return map; + } + + private static void getJumps(List actions, Map jumps) { + Map actionMap = actionListToMap(actions); + for (Action a : actions) { + long target = -1; + if (a instanceof ActionIf) { + ActionIf aIf = (ActionIf) a; + target = aIf.getAddress() + getTotalActionLength(a) + aIf.getJumpOffset(); + } else if (a instanceof ActionJump) { + ActionJump aJump = (ActionJump) a; + target = aJump.getAddress() + getTotalActionLength(a) + aJump.getJumpOffset(); + } else if (a instanceof ActionStore) { + ActionStore aStore = (ActionStore) a; + int storeSize = aStore.getStoreSize(); + // skip storeSize + 1 actions (+1 is the current action) + Action targetAction = a; + for (int i = 0; i <= storeSize; i++) { + long address = targetAction.getAddress() + getTotalActionLength(targetAction); + targetAction = actionMap.get(address); + if (targetAction == null) { + break; + } + } + jumps.put(a, targetAction); + } + if (target >= 0) { + Action targetAction = actionMap.get(target); + jumps.put(a, targetAction); + } + } + } + + private static void getContainerLastActions(List actionMap, Map> lastActions) { + for (int i = 0; i < actionMap.size(); i++) { + Action a = actionMap.get(i); + if (a == null) { + continue; + } + + if (a instanceof GraphSourceItemContainer) { + GraphSourceItemContainer container = (GraphSourceItemContainer) a; + List sizes = container.getContainerSizes(); + long endAddress = a.getAddress() + container.getHeaderSize(); + List lasts = new ArrayList<>(sizes.size()); + for (long size : sizes) { + endAddress += size; + int lastActionIndex = getPrevNotNullIndex(actionMap, (int) (endAddress - 1)); + Action lastAction = null; + if (lastActionIndex != -1) { + lastAction = actionMap.get(lastActionIndex); + } + lasts.add(lastAction); + } + lastActions.put(a, lasts); + } + } + } + + private static long updateAddresses(List actions, long address, int version) { + for (int i = 0; i < actions.size(); i++) { + Action a = actions.get(i); + a.setAddress(address, version); + int length = a.getBytes(version).length; + if ((i != actions.size() - 1) && (a instanceof ActionEnd)) { + // placeholder for jump action + length = getTotalActionLength(new ActionJump(0)); + } + address += length; + } + return address; + } + + private static void updateActionLengths(List actions, int version) { + for (int i = 0; i < actions.size(); i++) { + Action a = actions.get(i); + int length = a.getBytes(version).length; + a.actionLength = length - 1 - ((a.actionCode >= 0x80) ? 2 : 0); + } + } + + private static void updateActionStores(List actions, Map jumps) { + Map actionMap = actionListToMap(actions); + for (int i = 0; i < actions.size(); i++) { + Action a = actions.get(i); + if (a instanceof ActionStore) { + ActionStore aStore = (ActionStore) a; + Action nextActionAfterStore = jumps.get(a); + Action a1 = a; + List store = new ArrayList<>(); + while (true) { + long address = a1.getAddress() + getTotalActionLength(a1); + a1 = actionMap.get(address); + if (a1 == null || a1 == nextActionAfterStore) { + break; + } + actions.remove(a1); + store.add(a1); + } + aStore.setStore(store); + } + } + } + + private static void updateContainerSizes(List actions, Map> containerLastActions) { + for (int i = 0; i < actions.size(); i++) { + Action a = actions.get(i); + if (a instanceof GraphSourceItemContainer) { + GraphSourceItemContainer container = (GraphSourceItemContainer) a; + List lastActions = containerLastActions.get(a); + long startAddress = a.getAddress() + container.getHeaderSize(); + for (int j = 0; j < lastActions.size(); j++) { + Action lastAction = lastActions.get(j); + int length = (int) (lastAction.getAddress() + getTotalActionLength(lastAction) - startAddress); + container.setContainerSize(j, length); + startAddress += length; + } + } + } + } + + private static void replaceJumpTargets(Map jumps, Action oldTarget, Action newTarget) { + for (Action a : jumps.keySet()) { + if (jumps.get(a) == oldTarget) { + jumps.put(a, newTarget); + } + } + } + + private static void replaceContainerLastActions(Map> containerLastActions, Action oldTarget, Action newTarget) { + for (Action a : containerLastActions.keySet()) { + List targets = containerLastActions.get(a); + for (int i = 0; i < targets.size(); i++) { + if (targets.get(i) == oldTarget) { + targets.set(i, newTarget); + } + } + } + } + + private static void updateJumps(List actions, Map jumps, Map> containerLastActions, long endAddress, int version) { + if (actions.isEmpty()) { + return; + } + + for (int i = 0; i < actions.size(); i++) { + Action a = actions.get(i); + if ((i != actions.size() - 1) && (a instanceof ActionEnd)) { + ActionJump aJump = new ActionJump(0); + aJump.setJumpOffset((int) (endAddress - a.getAddress() - getTotalActionLength(aJump))); + aJump.setAddress(a.getAddress(), version); + replaceJumpTargets(jumps, a, aJump); + replaceContainerLastActions(containerLastActions, a, aJump); + a = aJump; + actions.set(i, a); + } else if (a instanceof ActionIf) { + ActionIf aIf = (ActionIf) a; + Action target = jumps.get(a); + long offset; + if (target != null) { + offset = target.getAddress() - a.getAddress() - getTotalActionLength(a); + } else { + offset = endAddress - a.getAddress() - getTotalActionLength(a); + } + aIf.setJumpOffset((int) offset); + } else if (a instanceof ActionJump) { + ActionJump aJump = (ActionJump) a; + Action target = jumps.get(a); + long offset; + if (target != null) { + offset = target.getAddress() - a.getAddress() - getTotalActionLength(a); + } else { + offset = endAddress - a.getAddress() - getTotalActionLength(a); + } + aJump.setJumpOffset((int) offset); + } + } + } + + private static void removeZeroJumps(List actions, int version) { + for (int i = 0; i < actions.size(); i++) { + Action a = actions.get(i); + if (a instanceof ActionJump) { + ActionJump aJump = (ActionJump) a; + if (aJump.getJumpOffset() == 0) { + if (removeAction(actions, i, version, false)) { + i--; + } + } + } + } + } + + /** + * Removes an action from the action list, and updates all references + * + * @param actions + * @param index + * @param version + * @param removeWhenLast + * @return + */ + public static boolean removeAction(List actions, int index, int version, boolean removeWhenLast) { + + if (index < 0 || actions.size() <= index) { + return false; + } + + long startIp = actions.get(0).getAddress(); + Action lastAction = actions.get(actions.size() - 1); + int lastIdx = (int) lastAction.getAddress(); + long endAddress = lastAction.getAddress() + getTotalActionLength(lastAction); + + List actionMap = new ArrayList<>(lastIdx); + for (int i = 0; i <= lastIdx; i++) { + actionMap.add(null); + } + for (Action a : actions) { + actionMap.set((int) a.getAddress(), a); + } + + Map> containerLastActions = new HashMap<>(); + getContainerLastActions(actionMap, containerLastActions); + + Map jumps = new HashMap<>(); + getJumps(actions, jumps); + + Action prevAction = index > 0 ? actions.get(index - 1) : null; + Action nextAction = index + 1 < actions.size() ? actions.get(index + 1) : null; + Action actionToRemove = actions.get(index); + for (Action a : containerLastActions.keySet()) { + List lastActions = containerLastActions.get(a); + for (int i = 0; i < lastActions.size(); i++) { + if (lastActions.get(i) == actionToRemove) { + if (!removeWhenLast) { + return false; + } + lastActions.set(i, prevAction); + } + } + } + for (Action a : jumps.keySet()) { + Action targetAction = jumps.get(a); + if (targetAction == actionToRemove) { + jumps.put(a, nextAction); + } + } + if (containerLastActions.containsKey(actionToRemove)) { + containerLastActions.remove(actionToRemove); + } + if (jumps.containsKey(actionToRemove)) { + jumps.remove(actionToRemove); + } + + actions.remove(index); + + updateAddresses(actions, startIp, version); + updateJumps(actions, jumps, containerLastActions, endAddress, version); + //updateActionStores(actions, jumps); + updateContainerSizes(actions, containerLastActions); + updateActionLengths(actions, version); + + return true; + } + + private static Action readActionListAtPos(List listeners, long containerSWFOffset, ConstantPool cpool, + SWFInputStream sis, List actions, List nextOffsets, + long ip, long startIp, long endIp, int version, String path, boolean indeterminate, List visitedContainers) throws IOException { + + Action entryAction = null; + + if (visitedContainers.contains(ip)) { + return null; + } + visitedContainers.add(ip); + + Queue jumpQueue = new LinkedList<>(); + jumpQueue.add(ip); + while (!jumpQueue.isEmpty()) { + ip = jumpQueue.remove(); + while ((endIp == -1) || (endIp > ip)) { + sis.seek((int) ip); + + Action a; + if ((a = sis.readAction(cpool)) == null) { + break; + } + + int actionLengthWithHeader = getTotalActionLength(a); + + // unknown action, replace with jump + if (a instanceof ActionNop) { + ActionJump aJump = new ActionJump(0); + int jumpLength = getTotalActionLength(aJump); + aJump.setAddress(a.getAddress(), version); + aJump.setJumpOffset(actionLengthWithHeader - jumpLength); + a = aJump; + actionLengthWithHeader = getTotalActionLength(a); + } + + if (entryAction == null) { + entryAction = a; + } + + ensureCapacity(actions, nextOffsets, ip); + + Action existingAction = actions.get((int) ip); + if (existingAction != null) { + break; + } + + actions.set((int) ip, a); + nextOffsets.set((int) ip, ip + actionLengthWithHeader); + + long pos = sis.getPos(); + long length = pos + sis.available(); + for (int i = 0; i < listeners.size(); i++) { + listeners.get(i).progress(AppStrings.translate("disassemblingProgress.reading"), pos, length); + } + + a.containerSWFOffset = containerSWFOffset; + a.setAddress(ip, version, false); + + if (a instanceof ActionPush && cpool != null) { + ((ActionPush) a).constantPool = cpool.constants; + } else if (a instanceof ActionConstantPool) { + if (cpool == null) { + cpool = new ConstantPool(); + } + cpool.setNew(((ActionConstantPool) a).constantPool); + } else if (a instanceof ActionIf) { + ActionIf aIf = (ActionIf) a; + long nIp = ip + actionLengthWithHeader + aIf.getJumpOffset(); + if (nIp >= 0) { + jumpQueue.add(nIp); + } + } else if (a instanceof ActionJump) { + ActionJump aJump = (ActionJump) a; + long nIp = ip + actionLengthWithHeader + aJump.getJumpOffset(); + if (nIp >= 0) { + jumpQueue.add(nIp); + } + break; + } else if (a instanceof GraphSourceItemContainer) { + GraphSourceItemContainer cnt = (GraphSourceItemContainer) a; + String cntName = cnt.getName(); + String newPath = path + (cntName == null ? "" : "/" + cntName); + for (long size : cnt.getContainerSizes()) { + if (size != 0) { + long ip2 = ip + actionLengthWithHeader; + //long endIp2 = ip + actionLengthWithHeader + size; + readActionListAtPos(listeners, containerSWFOffset, cpool, + sis, actions, nextOffsets, + ip2, startIp, endIp, version, newPath, indeterminate, visitedContainers); + actionLengthWithHeader += size; + } + } + } + + ip += actionLengthWithHeader; + + if (a.isExit()) { + break; + } + } + } + return entryAction; + } + + private static int getTotalActionLength(Action action) { + return action.actionLength + 1 + ((action.actionCode >= 0x80) ? 2 : 0); + } + + private static void ensureCapacity(List actions, List nextOffsets, long index) { + while (actions.size() <= index) { + actions.add(null); + nextOffsets.add(-1L); + } + } + + private static void deobfustaceActionListAtPosRecursive(List listeners, List output, HashMap> containers, long containerSWFOffset, ActionLocalData localData, Stack stack, ConstantPool cpool, List actions, int ip, List ret, int startIp, int endip, String path, Map visited, boolean indeterminate, Map> decisionStates, int version, int recursionLevel, int maxRecursionLevel) throws IOException, InterruptedException { + boolean debugMode = false; + boolean decideBranch = false; + + if (recursionLevel > maxRecursionLevel + 1) { + throw new TranslateException("deobfustaceActionListAtPosRecursive max recursion level reached."); + } + + Action a; + Scanner sc = new Scanner(System.in); + loopip: + while (((endip == -1) || (endip > ip)) && (a = actions.get(ip)) != null) { + if (Thread.currentThread().isInterrupted()) { + throw new InterruptedException(); + } + + int actionLen = getTotalActionLength(a); + if (!visited.containsKey(ip)) { + visited.put(ip, 0); + } + int curVisited = visited.get(ip); + curVisited++; + visited.put(ip, curVisited); + for (int i = 0; i < listeners.size(); i++) { + listeners.get(i).progress(AppStrings.translate("disassemblingProgress.deobfuscating"), ip, actions.size()); + } + int info = a.actionLength + 1 + ((a.actionCode >= 0x80) ? 2 : 0); + + if (a instanceof ActionPush) { + if (cpool != null) { + ((ActionPush) a).constantPool = cpool.constants; + } + } + + if (debugMode) { + String atos = a.getASMSource(new ArrayList(), new ArrayList(), cpool.constants, version, ScriptExportMode.PCODE); + if (a instanceof GraphSourceItemContainer) { + atos = a.toString(); + } + System.err.println("readActionListAtPos ip: " + (ip - startIp) + " (0x" + Helper.formatAddress(ip - startIp) + ") " + " action(len " + a.actionLength + "): " + atos + (a.isIgnored() ? " (ignored)" : "") + " stack:" + Helper.stackToString(stack, LocalData.create(cpool)) + " " + Helper.byteArrToString(a.getBytes(version))); + System.err.print("variables: "); + for (Map.Entry v : localData.variables.entrySet()) { + System.err.print("'" + v + "' = " + v.getValue().toString(LocalData.create(cpool)) + ", "); + } + System.err.println(); + String add = ""; + if (a instanceof ActionIf) { + add = " change: " + ((ActionIf) a).getJumpOffset(); + } + if (a instanceof ActionJump) { + add = " change: " + ((ActionJump) a).getJumpOffset(); + } + System.err.println(add); + } + + int newip = -1; + + if (a instanceof ActionConstantPool) { + if (cpool == null) { + cpool = new ConstantPool(); + } + cpool.setNew(((ActionConstantPool) a).constantPool); + } + 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; + + GraphTargetItem top = stack.pop(); + int nip = ip + actionLen + aif.getJumpOffset(); + + if (decideBranch) { + System.out.print("newip " + nip + ", "); + System.out.print("Action: jump(j),ignore(i),compute(c)?"); + String next = sc.next(); + switch (next) { + case "j": + newip = nip; + break; + case "i": + break; + case "c": + goaif = true; + break; + } + } else if (top.isCompileTime() && (!top.hasSideEffect())) { + if (debugMode) { + System.err.print("is compiletime -> "); + } + if (EcmaScript.toBoolean(top.getResult())) { + newip = nip; + aif.jumpUsed = true; + if (debugMode) { + System.err.println("jump"); + } + } else { + aif.ignoreUsed = true; + if (debugMode) { + System.err.println("ignore"); + } + } + } else { + if (debugMode) { + System.err.println("goaif"); + } + goaif = true; + } + } else if (a instanceof ActionJump) { + newip = ip + actionLen + ((ActionJump) a).getJumpOffset(); + } 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 DirectValueActionItem)) { + stack.push(new DirectValueActionItem(null, 0, new Null(), new ArrayList())); + } + if ((a instanceof ActionStoreRegister) && stack.isEmpty()) { + stack.push(new DirectValueActionItem(null, 0, new Null(), new ArrayList())); + } + a.translate(localData, stack, output, Graph.SOP_USE_STATIC/*Graph.SOP_SKIP_STATIC*/, path); + } + } catch (RuntimeException ex) { + logger.log(Level.SEVERE, "Disassembly exception", ex); + break; + } + + HashMap vars = localData.variables; + if (varname != null) { + GraphTargetItem varval = vars.get(varname); + if (varval != null && varval.isCompileTime() && indeterminate) { + vars.put(varname, new NotCompileTimeItem(null, varval)); + } + } + } + int nopos = -1; + for (int i = 0; i < actionLen; i++) { + if (a instanceof ActionNop) { + int prevPos = (int) a.getAddress(); + a = new ActionNop(); + a.setAddress(prevPos, version); + nopos++; + if (nopos > 0) { + a.setAddress(a.getAddress() + 1, version); + } + + } + ret.set(ip + i, a); + } + + if (a instanceof GraphSourceItemContainer) { + GraphSourceItemContainer cnt = (GraphSourceItemContainer) a; + if (a instanceof Action) { + long endAddr = a.getAddress() + cnt.getHeaderSize(); + String cntName = cnt.getName(); + List> output2s = new ArrayList<>(); + for (long size : cnt.getContainerSizes()) { + if (size == 0) { + output2s.add(new ArrayList()); + continue; + } + ActionLocalData localData2; + List output2 = new ArrayList<>(); + if ((cnt instanceof ActionDefineFunction) || (cnt instanceof ActionDefineFunction2)) { + localData2 = new ActionLocalData(); + } else { + localData2 = localData; + } + deobfustaceActionListAtPosRecursive(listeners, output2, containers, containerSWFOffset, localData2, new Stack(), cpool, actions, (int) endAddr, ret, startIp, (int) (endAddr + size), path + (cntName == null ? "" : "/" + cntName), visited, indeterminate, decisionStates, version, recursionLevel + 1, maxRecursionLevel); + output2s.add(output2); + endAddr += size; + } + cnt.translateContainer(output2s, stack, output, localData.regNames, localData.variables, localData.functions); + ip = (int) endAddr; + continue; + } + } + + if (a instanceof ActionEnd) { + break; + } + if (goaif) { + aif.ignoreUsed = true; + aif.jumpUsed = true; + indeterminate = true; + + HashMap vars = localData.variables; + 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(ip + actionLen + aif.getJumpOffset()); + branches.add(ip + actionLen); + for (int br : branches) { + int visc = 0; + if (visited.containsKey(br)) { + visc = visited.get(br); + } + if (visc == 0) {// substack = (Stack) stack.clone(); + deobfustaceActionListAtPosRecursive(listeners, output, containers, containerSWFOffset, prepareLocalBranch(localData), substack, cpool, actions, ip + actionLen + aif.getJumpOffset(), ret, startIp, endip, path, visited, indeterminate, decisionStates, version, recursionLevel + 1, maxRecursionLevel); + } + + if (newip > -1) { + ip = newip; + } else { + ip += info; + } + + if (a.isExit()) { + break; + } + } + for (DisassemblyListener listener : listeners) { + listener.progress(AppStrings.translate("disassemblingProgress.deobfuscating"), ip, actions.size()); + } + } + + private static ActionLocalData prepareLocalBranch(ActionLocalData localData) { + + return new ActionLocalData(new HashMap<>(localData.regNames), + new HashMap<>(localData.variables), new HashMap<>(localData.functions)); + } +} diff --git a/src/com/jpexs/decompiler/flash/action/swf4/ActionPush.java b/src/com/jpexs/decompiler/flash/action/swf4/ActionPush.java index 05ae8a0e0..17dd8834c 100644 --- a/src/com/jpexs/decompiler/flash/action/swf4/ActionPush.java +++ b/src/com/jpexs/decompiler/flash/action/swf4/ActionPush.java @@ -77,7 +77,7 @@ public class ActionPush extends Action { super(0x96, actionLength); int type; values = new ArrayList<>(); - sis = new SWFInputStream(sis.readBytesEx(actionLength), version); + sis = new SWFInputStream(sis.swf, sis.readBytesEx(actionLength)); try { while (sis.available() > 0) { type = sis.readUI8(); diff --git a/src/com/jpexs/decompiler/flash/exporters/MovieExporter.java b/src/com/jpexs/decompiler/flash/exporters/MovieExporter.java index dee2f5aeb..fc6cf3f77 100644 --- a/src/com/jpexs/decompiler/flash/exporters/MovieExporter.java +++ b/src/com/jpexs/decompiler/flash/exporters/MovieExporter.java @@ -101,7 +101,7 @@ public class MovieExporter { if ((videoStream.codecID == DefineVideoStreamTag.CODEC_VP6) || (videoStream.codecID == DefineVideoStreamTag.CODEC_VP6_ALPHA)) { - SWFInputStream sis = new SWFInputStream(tag.videoData, swf.version); + SWFInputStream sis = new SWFInputStream(swf, tag.videoData); if (videoStream.codecID == DefineVideoStreamTag.CODEC_VP6_ALPHA) { sis.readUI24(); //offsetToAlpha } @@ -135,7 +135,7 @@ public class MovieExporter { sos.writeUB(4, verticalAdjustment); } if (videoStream.codecID == DefineVideoStreamTag.CODEC_SORENSON_H263) { - SWFInputStream sis = new SWFInputStream(tag.videoData, swf.version); + SWFInputStream sis = new SWFInputStream(swf, tag.videoData); sis.readUB(17);//pictureStartCode sis.readUB(5); //version sis.readUB(8); //temporalReference diff --git a/src/com/jpexs/decompiler/flash/gui/Main.java b/src/com/jpexs/decompiler/flash/gui/Main.java index 648802f0e..54dbb18ac 100644 --- a/src/com/jpexs/decompiler/flash/gui/Main.java +++ b/src/com/jpexs/decompiler/flash/gui/Main.java @@ -1,1247 +1,1253 @@ -/* - * Copyright (C) 2010-2014 JPEXS - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.jpexs.decompiler.flash.gui; - -import com.jpexs.decompiler.flash.AppStrings; -import com.jpexs.decompiler.flash.ApplicationInfo; -import com.jpexs.decompiler.flash.EventListener; -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFBundle; -import com.jpexs.decompiler.flash.SWFSourceInfo; -import com.jpexs.decompiler.flash.SearchMode; -import com.jpexs.decompiler.flash.Version; -import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; -import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.decompiler.flash.console.CommandLineArgumentParser; -import com.jpexs.decompiler.flash.console.ContextMenuTools; -import com.jpexs.decompiler.flash.gui.proxy.ProxyFrame; -import com.jpexs.decompiler.flash.tags.base.FontTag; -import com.jpexs.decompiler.flash.treeitems.SWFList; -import com.jpexs.helpers.Cache; -import com.jpexs.helpers.CancellableWorker; -import com.jpexs.helpers.Helper; -import com.jpexs.helpers.Path; -import com.jpexs.helpers.ProgressListener; -import com.jpexs.helpers.Stopwatch; -import com.jpexs.helpers.streams.SeekableInputStream; -import com.sun.jna.Platform; -import java.awt.AWTException; -import java.awt.Frame; -import java.awt.GraphicsEnvironment; -import java.awt.MenuItem; -import java.awt.PopupMenu; -import java.awt.SystemTray; -import java.awt.TrayIcon; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.io.BufferedInputStream; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.lang.reflect.Field; -import java.net.Socket; -import java.net.URLEncoder; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Date; -import java.util.List; -import java.util.Locale; -import java.util.Map.Entry; -import java.util.logging.ConsoleHandler; -import java.util.logging.FileHandler; -import java.util.logging.Formatter; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.logging.SimpleFormatter; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import javax.swing.JFileChooser; -import javax.swing.JFrame; -import javax.swing.JOptionPane; -import javax.swing.SwingWorker; -import javax.swing.UIManager; -import javax.swing.UnsupportedLookAndFeelException; -import javax.swing.filechooser.FileFilter; - -/** - * Main executable class - * - * @author JPEXS - */ -public class Main { - - public static ProxyFrame proxyFrame; - private static List sourceInfos = new ArrayList<>(); - public static LoadingDialog loadingDialog; - public static ModeFrame modeFrame; - private static boolean working = false; - private static TrayIcon trayIcon; - private static MenuItem stopMenuItem; - private static MainFrame mainFrame; - public static final int UPDATE_SYSTEM_MAJOR = 1; - public static final int UPDATE_SYSTEM_MINOR = 1; - public static LoadFromMemoryFrame loadFromMemoryFrame; - public static LoadFromCacheFrame loadFromCacheFrame; - private static final Logger logger = Logger.getLogger(Main.class.getName()); - - public static void ensureMainFrame() { - if (mainFrame == null) { - if (Configuration.useRibbonInterface.get()) { - mainFrame = new MainFrameRibbon(); - } else { - mainFrame = new MainFrameClassic(); - } - mainFrame.getPanel().setErrorState(ErrorLogFrame.getInstance().getErrorState()); - } - } - - public static MainFrame getMainFrame() { - return mainFrame; - } - - public static void loadFromCache() { - if (loadFromCacheFrame == null) { - loadFromCacheFrame = new LoadFromCacheFrame(); - } - loadFromCacheFrame.setVisible(true); - } - - public static void loadFromMemory() { - if (loadFromMemoryFrame == null) { - loadFromMemoryFrame = new LoadFromMemoryFrame(mainFrame); - } - loadFromMemoryFrame.setVisible(true); - } - - public static void setSubLimiter(boolean value) { - if (value) { - AVM2Code.toSourceLimit = Configuration.sublimiter.get(); - } else { - AVM2Code.toSourceLimit = -1; - } - } - - public static boolean isWorking() { - return working; - } - - public static void startProxy(int port) { - View.execInEventDispatch(new Runnable() { - @Override - public void run() { - if (proxyFrame == null) { - proxyFrame = new ProxyFrame(mainFrame); - } - } - }); - proxyFrame.setPort(port); - addTrayIcon(); - switchProxy(); - } - - public static void showProxy() { - if (proxyFrame == null) { - proxyFrame = new ProxyFrame(mainFrame); - } - proxyFrame.setVisible(true); - proxyFrame.setState(Frame.NORMAL); - } - - public static void startWork(String name) { - startWork(name, -1, null); - } - - public static void startWork(String name, int percent) { - startWork(name, percent, null); - } - - public static void startWork(String name, CancellableWorker worker) { - startWork(name, -1, worker); - } - - public static void startWork(final String name, final int percent, final CancellableWorker worker) { - working = true; - View.execInEventDispatchLater(new Runnable() { - @Override - public void run() { - if (mainFrame != null) { - mainFrame.getPanel().setWorkStatus(name, worker); - if (percent == -1) { - mainFrame.getPanel().hidePercent(); - } else { - mainFrame.getPanel().setPercent(percent); - } - } - if (loadingDialog != null) { - loadingDialog.setDetail(name); - if (percent == -1) { - loadingDialog.hidePercent(); - } else { - loadingDialog.setPercent(percent); - } - } - if (CommandLineArgumentParser.isCommandLineMode()) { - System.out.println(name); - } - } - }); - - } - - public static void stopWork() { - working = false; - View.execInEventDispatchLater(new Runnable() { - @Override - public void run() { - if (mainFrame != null) { - mainFrame.getPanel().setWorkStatus("", null); - } - if (loadingDialog != null) { - loadingDialog.setDetail(""); - } - } - }); - } - - public static SWFList parseSWF(SWFSourceInfo sourceInfo) throws Exception { - SWFList result = new SWFList(); - - InputStream inputStream = sourceInfo.getInputStream(); - SWFBundle bundle = null; - if (inputStream == null) { - inputStream = new BufferedInputStream(new FileInputStream(sourceInfo.getFile())); - bundle = sourceInfo.getBundle(false, SearchMode.ALL); - logger.log(Level.INFO, "Load file: {0}", sourceInfo.getFile()); - } else if (inputStream instanceof SeekableInputStream - || inputStream instanceof BufferedInputStream) { - try { - inputStream.reset(); - } catch (IOException ex) { - logger.log(Level.SEVERE, null, ex); - } - logger.log(Level.INFO, "Load stream: {0}", sourceInfo.getFileTitle()); - } - - Stopwatch sw = Stopwatch.startNew(); - if (bundle != null) { - result.isBundle = true; - result.name = new File(sourceInfo.getFileTitleOrName()).getName(); - for (Entry streamEntry : bundle.getAll().entrySet()) { - InputStream stream = streamEntry.getValue(); - stream.reset(); - SWF swf = new SWF(stream, new ProgressListener() { - @Override - public void progress(int p) { - startWork(AppStrings.translate("work.reading.swf"), p); - } - }, Configuration.parallelSpeedUp.get()); - swf.fileTitle = streamEntry.getKey(); - swf.readOnly = true; - result.add(swf); - } - } else { - SWF swf = new SWF(inputStream, new ProgressListener() { - @Override - public void progress(int p) { - startWork(AppStrings.translate("work.reading.swf"), p); - } - }, Configuration.parallelSpeedUp.get()); - swf.file = sourceInfo.getFile(); - swf.fileTitle = sourceInfo.getFileTitle(); - result.add(swf); - } - - if (inputStream instanceof FileInputStream) { - logger.log(Level.INFO, "File loaded in {0} seconds.", (sw.getElapsedMilliseconds() / 1000)); - inputStream.close(); - } else { - logger.log(Level.INFO, "Stream loaded in {0} seconds.", (sw.getElapsedMilliseconds() / 1000)); - } - - result.sourceInfo = sourceInfo; - for (SWF swf : result) { - logger.log(Level.INFO, ""); - logger.log(Level.INFO, "== File information =="); - logger.log(Level.INFO, "Size: {0}", Helper.formatFileSize(swf.fileSize)); - logger.log(Level.INFO, "Flash version: {0}", swf.version); - int width = (int) ((swf.displayRect.Xmax - swf.displayRect.Xmin) / SWF.unitDivisor); - int height = (int) ((swf.displayRect.Ymax - swf.displayRect.Ymin) / SWF.unitDivisor); - logger.log(Level.INFO, "Width: {0}", width); - logger.log(Level.INFO, "Height: {0}", height); - - swf.swfList = result; - swf.addEventListener(new EventListener() { - @Override - public void handleEvent(String event, Object data) { - if (event.equals("exporting")) { - startWork((String) data); - } - if (event.equals("getVariables")) { - startWork(AppStrings.translate("work.gettingvariables") + "..." + (String) data); - } - if (event.equals("deobfuscate")) { - startWork(AppStrings.translate("work.deobfuscating") + "..." + (String) data); - } - if (event.equals("rename")) { - startWork(AppStrings.translate("work.renaming") + "..." + (String) data); - } - } - }); - } - - return result; - } - - public static void saveFile(SWF swf, String outfile) throws IOException { - saveFile(swf, outfile, SaveFileMode.SAVE); - } - - public static void saveFile(SWF swf, String outfile, SaveFileMode mode) throws IOException { - if (mode == SaveFileMode.SAVEAS) { - swf.file = outfile; - } - File outfileF = new File(outfile); - File tmpFile = new File(outfile + ".tmp"); - FileOutputStream fos = new FileOutputStream(tmpFile); - if (mode == SaveFileMode.EXE) { - InputStream exeStream = View.class.getClassLoader().getResourceAsStream("com/jpexs/helpers/resource/Swf2Exe.bin"); - byte[] buffer = new byte[4096]; - int bytesRead = 0; - while ((bytesRead = exeStream.read(buffer)) != -1) { - fos.write(buffer, 0, bytesRead); - } - int width = swf.displayRect.Xmax - swf.displayRect.Xmin; - int height = swf.displayRect.Ymax - swf.displayRect.Ymin; - fos.write(width & 0xff); - fos.write((width >> 8) & 0xff); - fos.write((width >> 16) & 0xff); - fos.write((width >> 24) & 0xff); - fos.write(height & 0xff); - fos.write((height >> 8) & 0xff); - fos.write((height >> 16) & 0xff); - fos.write((height >> 24) & 0xff); - fos.write(Configuration.saveAsExeScaleMode.get()); - } - swf.saveTo(fos); - if (tmpFile.exists()) { - if (tmpFile.length() > 0) { - outfileF.delete(); - if (!tmpFile.renameTo(outfileF)) { - tmpFile.delete(); - throw new IOException("Cannot access " + outfile); - } - } else { - throw new IOException("Output is empty"); - } - } - } - - private static class OpenFileWorker extends SwingWorker { - - private final SWFSourceInfo[] sourceInfos; - - public OpenFileWorker(SWFSourceInfo sourceInfo) { - this.sourceInfos = new SWFSourceInfo[]{sourceInfo}; - } - - public OpenFileWorker(SWFSourceInfo[] sourceInfos) { - this.sourceInfos = sourceInfos; - } - - @Override - protected Object doInBackground() throws Exception { - boolean first = true; - SWF firstSWF = null; - for (final SWFSourceInfo sourceInfo : sourceInfos) { - SWFList swfs = null; - try { - Main.startWork(AppStrings.translate("work.reading.swf") + "..."); - swfs = parseSWF(sourceInfo); - } catch (OutOfMemoryError ex) { - logger.log(Level.SEVERE, null, ex); - View.showMessageDialog(null, "Cannot load SWF file. Out of memory."); - } catch (Exception ex) { - logger.log(Level.SEVERE, null, ex); - View.showMessageDialog(null, "Cannot load SWF file."); - } - - final SWFList swfs1 = swfs; - final boolean first1 = first; - first = false; - if (firstSWF == null) { - firstSWF = swfs1.get(0); - } - try { - Main.startWork(AppStrings.translate("work.creatingwindow") + "..."); - View.execInEventDispatch(new Runnable() { - @Override - public void run() { - ensureMainFrame(); - mainFrame.getPanel().load(swfs1, first1); - } - }); - - } catch (Exception ex) { - logger.log(Level.SEVERE, null, ex); - } - } - - loadingDialog.setVisible(false); - final SWF fswf = firstSWF; - View.execInEventDispatch(new Runnable() { - @Override - public void run() { - if (mainFrame != null) { - mainFrame.setVisible(true); - } - Main.stopWork(); - if (mainFrame != null && Configuration.gotoMainClassOnStartup.get()) { - mainFrame.getPanel().gotoDocumentClass(fswf); - } - } - }); - - return true; - } - } - - public static boolean reloadSWFs() { - CancellableWorker.cancelBackgroundThreads(); - if (mainFrame != null) { - mainFrame.getPanel().closeAll(); - } - if (Main.sourceInfos.isEmpty()) { - Cache.clearAll(); - System.gc(); - showModeFrame(); - return true; - } else { - SWFSourceInfo[] sourceInfosCopy = new SWFSourceInfo[sourceInfos.size()]; - sourceInfos.toArray(sourceInfosCopy); - sourceInfos.clear(); - openFile(sourceInfosCopy); - return true; - } - } - - public static void reloadApp() { - if (loadingDialog != null) { - loadingDialog.setVisible(false); - loadingDialog = null; - } - if (proxyFrame != null) { - proxyFrame.setVisible(false); - proxyFrame = null; - } - if (loadFromMemoryFrame != null) { - loadFromMemoryFrame.setVisible(false); - loadFromMemoryFrame = null; - } - if (loadFromCacheFrame != null) { - loadFromCacheFrame.setVisible(false); - loadFromCacheFrame = null; - } - if (mainFrame != null) { - mainFrame.setVisible(false); - mainFrame = null; - } - FontTag.reload(); - Cache.clearAll(); - initGui(); - reloadSWFs(); - } - - public static OpenFileResult openFile(String swfFile, String fileTitle) { - try { - File file = new File(swfFile); - if (!file.exists()) { - View.showMessageDialog(null, AppStrings.translate("open.error.fileNotFound"), AppStrings.translate("open.error"), JOptionPane.ERROR_MESSAGE); - return OpenFileResult.NOT_FOUND; - } - swfFile = file.getCanonicalPath(); - Configuration.addRecentFile(swfFile); - SWFSourceInfo sourceInfo = new SWFSourceInfo(null, swfFile, fileTitle); - OpenFileResult openResult = openFile(sourceInfo); - return openResult; - } catch (IOException ex) { - View.showMessageDialog(null, AppStrings.translate("open.error.cannotOpen"), AppStrings.translate("open.error"), JOptionPane.ERROR_MESSAGE); - return OpenFileResult.ERROR; - } - } - - public static OpenFileResult openFile(SWFSourceInfo sourceInfo) { - return openFile(new SWFSourceInfo[]{sourceInfo}); - } - - public static OpenFileResult openFile(SWFSourceInfo[] newSourceInfos) { - if (mainFrame != null && !Configuration.openMultipleFiles.get()) { - sourceInfos.clear(); - mainFrame.getPanel().closeAll(); - mainFrame.setVisible(false); - Cache.clearAll(); - System.gc(); - } - - View.execInEventDispatch(new Runnable() { - @Override - public void run() { - if (Main.loadingDialog == null) { - Main.loadingDialog = new LoadingDialog(); - } - } - }); - - Main.loadingDialog.setVisible(true); - OpenFileWorker wrk = new OpenFileWorker(newSourceInfos); - wrk.execute(); - sourceInfos.addAll(Arrays.asList(newSourceInfos)); - return OpenFileResult.OK; - } - - public static void closeFile(SWFList swf) { - sourceInfos.remove(swf.sourceInfo); - mainFrame.getPanel().close(swf); - } - - public static void closeAll() { - sourceInfos.clear(); - mainFrame.getPanel().closeAll(); - } - - public static boolean saveFileDialog(SWF swf, final SaveFileMode mode) { - JFileChooser fc = new JFileChooser(); - fc.setCurrentDirectory(new File(Configuration.lastSaveDir.get())); - String ext = ".swf"; - switch (mode) { - case SAVE: - case SAVEAS: - if (swf.file != null) { - ext = Path.getExtension(swf.file); - } - break; - case EXE: - ext = ".exe"; - break; - } - final String extension = ext; - FileFilter swfFilter = new FileFilter() { - @Override - public boolean accept(File f) { - return (f.getName().toLowerCase().endsWith(extension)) || (f.isDirectory()); - } - - @Override - public String getDescription() { - return AppStrings.translate("filter" + extension); - } - }; - if (!swf.gfx) { - fc.setFileFilter(swfFilter); - } else { - fc.addChoosableFileFilter(swfFilter); - } - FileFilter gfxFilter = new FileFilter() { - @Override - public boolean accept(File f) { - return (f.getName().toLowerCase().endsWith(".gfx")) || (f.isDirectory()); - } - - @Override - public String getDescription() { - return AppStrings.translate("filter.gfx"); - } - }; - if (mode == SaveFileMode.SAVE || mode == SaveFileMode.SAVEAS) { - if (swf.gfx) { - fc.setFileFilter(gfxFilter); - } else { - fc.addChoosableFileFilter(gfxFilter); - } - } - fc.setAcceptAllFileFilterUsed(false); - JFrame f = new JFrame(); - View.setWindowIcon(f); - int returnVal = fc.showSaveDialog(f); - if (returnVal == JFileChooser.APPROVE_OPTION) { - File file = Helper.fixDialogFile(fc.getSelectedFile()); - FileFilter selFilter = fc.getFileFilter(); - try { - String fileName = file.getAbsolutePath(); - if (selFilter == swfFilter) { - if (!fileName.toLowerCase().endsWith(extension)) { - fileName += extension; - } - swf.gfx = false; - } - if (selFilter == gfxFilter) { - if (!fileName.toLowerCase().endsWith(".gfx")) { - fileName += ".gfx"; - } - swf.gfx = true; - } - Main.saveFile(swf, fileName, mode); - Configuration.lastSaveDir.set(file.getParentFile().getAbsolutePath()); - return true; - } catch (IOException ex) { - View.showMessageDialog(null, AppStrings.translate("error.file.write")); - } - } - return false; - } - - public static boolean openFileDialog() { - JFileChooser fc = new JFileChooser(); - fc.setCurrentDirectory(new File(Configuration.lastOpenDir.get())); - FileFilter allSupportedFilter = new FileFilter() { - private final String[] supportedExtensions = new String[]{".swf", ".gfx", ".swc", ".zip"}; - - @Override - public boolean accept(File f) { - String name = f.getName().toLowerCase(); - for (String ext : supportedExtensions) { - if (name.endsWith(ext)) { - return true; - } - } - return f.isDirectory(); - } - - @Override - public String getDescription() { - String exts = Helper.joinStrings(supportedExtensions, "*%s", "; "); - return AppStrings.translate("filter.supported") + " (" + exts + ")"; - } - }; - fc.setFileFilter(allSupportedFilter); - FileFilter swfFilter = new FileFilter() { - @Override - public boolean accept(File f) { - return (f.getName().toLowerCase().endsWith(".swf")) || (f.isDirectory()); - } - - @Override - public String getDescription() { - return AppStrings.translate("filter.swf"); - } - }; - fc.addChoosableFileFilter(swfFilter); - - FileFilter swcFilter = new FileFilter() { - @Override - public boolean accept(File f) { - return (f.getName().toLowerCase().endsWith(".swc")) || (f.isDirectory()); - } - - @Override - public String getDescription() { - return AppStrings.translate("filter.swc"); - } - }; - fc.addChoosableFileFilter(swcFilter); - - FileFilter gfxFilter = new FileFilter() { - @Override - public boolean accept(File f) { - return (f.getName().toLowerCase().endsWith(".gfx")) || (f.isDirectory()); - } - - @Override - public String getDescription() { - return AppStrings.translate("filter.gfx"); - } - }; - fc.addChoosableFileFilter(gfxFilter); - - FileFilter zipFilter = new FileFilter() { - @Override - public boolean accept(File f) { - return (f.getName().toLowerCase().endsWith(".zip")) || (f.isDirectory()); - } - - @Override - public String getDescription() { - return AppStrings.translate("filter.zip"); - } - }; - fc.addChoosableFileFilter(zipFilter); - - FileFilter binaryFilter = new FileFilter() { - @Override - public boolean accept(File f) { - return true; - } - - @Override - public String getDescription() { - return AppStrings.translate("filter.binary"); - } - }; - fc.addChoosableFileFilter(binaryFilter); - - fc.setAcceptAllFileFilterUsed(false); - JFrame f = new JFrame(); - View.setWindowIcon(f); - int returnVal = fc.showOpenDialog(f); - if (returnVal == JFileChooser.APPROVE_OPTION) { - Configuration.lastOpenDir.set(Helper.fixDialogFile(fc.getSelectedFile()).getParentFile().getAbsolutePath()); - File selfile = Helper.fixDialogFile(fc.getSelectedFile()); - Main.openFile(selfile.getAbsolutePath(), null); - return true; - } else { - return false; - } - } - - public static void displayErrorFrame() { - ErrorLogFrame.getInstance().setVisible(true); - } - - private static void initGui() { - if (GraphicsEnvironment.isHeadless()) { - System.err.println("Error: Your system does not support Graphic User Interface"); - exit(); - } - if (Configuration.useRibbonInterface.get()) { - View.setLookAndFeel(); - } else { - try { - UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { - logger.log(Level.SEVERE, null, ex); - } - } - autoCheckForUpdates(); - offerAssociation(); - } - - public static void showModeFrame() { - View.execInEventDispatch(new Runnable() { - @Override - public void run() { - ensureMainFrame(); - mainFrame.setVisible(true); - } - }); - - } - - private static void offerAssociation() { - boolean offered = Configuration.offeredAssociation.get(); - if (!offered) { - if (Platform.isWindows()) { - if ((!ContextMenuTools.isAddedToContextMenu()) && View.showConfirmDialog(null, "Do you want to add FFDec to context menu of SWF files?\n(Can be changed later from main menu)", "Context menu", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) { - ContextMenuTools.addToContextMenu(true, false); - } - } - } - Configuration.offeredAssociation.set(true); - } - - public static void initLang() { - if (GraphicsEnvironment.isHeadless()) { //No GUI in OS - return; - } - Locale.setDefault(Locale.forLanguageTag(Configuration.locale.get())); - AppStrings.updateLanguage(); - ErrorLogFrame.createNewInstance(); - - try { - Class cl = Class.forName("org.pushingpixels.substance.api.SubstanceLookAndFeel"); - Field field = cl.getDeclaredField("LABEL_BUNDLE"); - field.setAccessible(true); - field.set(null, null); - } catch (Throwable ex) { - Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); - } - - UIManager.put("OptionPane.okButtonText", AppStrings.translate("button.ok")); - UIManager.put("OptionPane.yesButtonText", AppStrings.translate("button.yes")); - UIManager.put("OptionPane.noButtonText", AppStrings.translate("button.no")); - UIManager.put("OptionPane.cancelButtonText", AppStrings.translate("button.cancel")); - UIManager.put("OptionPane.messageDialogTitle", AppStrings.translate("dialog.message.title")); - UIManager.put("OptionPane.titleText", AppStrings.translate("dialog.select.title")); - - UIManager.put("FileChooser.acceptAllFileFilterText", AppStrings.translate("FileChooser.acceptAllFileFilterText")); - UIManager.put("FileChooser.lookInLabelText", AppStrings.translate("FileChooser.lookInLabelText")); - UIManager.put("FileChooser.cancelButtonText", AppStrings.translate("button.cancel")); - UIManager.put("FileChooser.cancelButtonToolTipText", AppStrings.translate("button.cancel")); - UIManager.put("FileChooser.openButtonText", AppStrings.translate("FileChooser.openButtonText")); - UIManager.put("FileChooser.openButtonToolTipText", AppStrings.translate("FileChooser.openButtonToolTipText")); - UIManager.put("FileChooser.filesOfTypeLabelText", AppStrings.translate("FileChooser.filesOfTypeLabelText")); - UIManager.put("FileChooser.fileNameLabelText", AppStrings.translate("FileChooser.fileNameLabelText")); - UIManager.put("FileChooser.listViewButtonToolTipText", AppStrings.translate("FileChooser.listViewButtonToolTipText")); - UIManager.put("FileChooser.listViewButtonAccessibleName", AppStrings.translate("FileChooser.listViewButtonAccessibleName")); - UIManager.put("FileChooser.detailsViewButtonToolTipText", AppStrings.translate("FileChooser.detailsViewButtonToolTipText")); - UIManager.put("FileChooser.detailsViewButtonAccessibleName", AppStrings.translate("FileChooser.detailsViewButtonAccessibleName")); - UIManager.put("FileChooser.upFolderToolTipText", AppStrings.translate("FileChooser.upFolderToolTipText")); - UIManager.put("FileChooser.upFolderAccessibleName", AppStrings.translate("FileChooser.upFolderAccessibleName")); - UIManager.put("FileChooser.homeFolderToolTipText", AppStrings.translate("FileChooser.homeFolderToolTipText")); - UIManager.put("FileChooser.homeFolderAccessibleName", AppStrings.translate("FileChooser.homeFolderAccessibleName")); - UIManager.put("FileChooser.fileNameHeaderText", AppStrings.translate("FileChooser.fileNameHeaderText")); - UIManager.put("FileChooser.fileSizeHeaderText", AppStrings.translate("FileChooser.fileSizeHeaderText")); - UIManager.put("FileChooser.fileTypeHeaderText", AppStrings.translate("FileChooser.fileTypeHeaderText")); - UIManager.put("FileChooser.fileDateHeaderText", AppStrings.translate("FileChooser.fileDateHeaderText")); - UIManager.put("FileChooser.fileAttrHeaderText", AppStrings.translate("FileChooser.fileAttrHeaderText")); - UIManager.put("FileChooser.openDialogTitleText", AppStrings.translate("FileChooser.openDialogTitleText")); - UIManager.put("FileChooser.directoryDescriptionText", AppStrings.translate("FileChooser.directoryDescriptionText")); - UIManager.put("FileChooser.directoryOpenButtonText", AppStrings.translate("FileChooser.directoryOpenButtonText")); - UIManager.put("FileChooser.directoryOpenButtonToolTipText", AppStrings.translate("FileChooser.directoryOpenButtonToolTipText")); - UIManager.put("FileChooser.fileDescriptionText", AppStrings.translate("FileChooser.fileDescriptionText")); - UIManager.put("FileChooser.fileNameLabelText", AppStrings.translate("FileChooser.fileNameLabelText")); - UIManager.put("FileChooser.helpButtonText", AppStrings.translate("FileChooser.helpButtonText")); - UIManager.put("FileChooser.helpButtonToolTipText", AppStrings.translate("FileChooser.helpButtonToolTipText")); - UIManager.put("FileChooser.newFolderAccessibleName", AppStrings.translate("FileChooser.newFolderAccessibleName")); - UIManager.put("FileChooser.newFolderErrorText", AppStrings.translate("FileChooser.newFolderErrorText")); - UIManager.put("FileChooser.newFolderToolTipText", AppStrings.translate("FileChooser.newFolderToolTipText")); - UIManager.put("FileChooser.other.newFolder", AppStrings.translate("FileChooser.other.newFolder")); - UIManager.put("FileChooser.other.newFolder.subsequent", AppStrings.translate("FileChooser.other.newFolder.subsequent")); - UIManager.put("FileChooser.win32.newFolder", AppStrings.translate("FileChooser.win32.newFolder")); - UIManager.put("FileChooser.win32.newFolder.subsequent", AppStrings.translate("FileChooser.win32.newFolder.subsequent")); - UIManager.put("FileChooser.saveButtonText", AppStrings.translate("FileChooser.saveButtonText")); - UIManager.put("FileChooser.saveButtonToolTipText", AppStrings.translate("FileChooser.saveButtonToolTipText")); - UIManager.put("FileChooser.saveDialogTitleText", AppStrings.translate("FileChooser.saveDialogTitleText")); - UIManager.put("FileChooser.saveInLabelText", AppStrings.translate("FileChooser.saveInLabelText")); - UIManager.put("FileChooser.updateButtonText", AppStrings.translate("FileChooser.updateButtonText")); - UIManager.put("FileChooser.updateButtonToolTipText", AppStrings.translate("FileChooser.updateButtonToolTipText")); - - UIManager.put("FileChooser.detailsViewActionLabel.textAndMnemonic", AppStrings.translate("FileChooser.detailsViewActionLabel.textAndMnemonic")); - UIManager.put("FileChooser.detailsViewButtonToolTip.textAndMnemonic", AppStrings.translate("FileChooser.detailsViewButtonToolTip.textAndMnemonic")); - UIManager.put("FileChooser.fileAttrHeader.textAndMnemonic", AppStrings.translate("FileChooser.fileAttrHeader.textAndMnemonic")); - UIManager.put("FileChooser.fileDateHeader.textAndMnemonic", AppStrings.translate("FileChooser.fileDateHeader.textAndMnemonic")); - UIManager.put("FileChooser.fileNameHeader.textAndMnemonic", AppStrings.translate("FileChooser.fileNameHeader.textAndMnemonic")); - UIManager.put("FileChooser.fileNameLabel.textAndMnemonic", AppStrings.translate("FileChooser.fileNameLabel.textAndMnemonic")); - UIManager.put("FileChooser.fileSizeHeader.textAndMnemonic", AppStrings.translate("FileChooser.fileSizeHeader.textAndMnemonic")); - UIManager.put("FileChooser.fileTypeHeader.textAndMnemonic", AppStrings.translate("FileChooser.fileTypeHeader.textAndMnemonic")); - UIManager.put("FileChooser.filesOfTypeLabel.textAndMnemonic", AppStrings.translate("FileChooser.filesOfTypeLabel.textAndMnemonic")); - UIManager.put("FileChooser.folderNameLabel.textAndMnemonic", AppStrings.translate("FileChooser.folderNameLabel.textAndMnemonic")); - UIManager.put("FileChooser.homeFolderToolTip.textAndMnemonic", AppStrings.translate("FileChooser.homeFolderToolTip.textAndMnemonic")); - UIManager.put("FileChooser.listViewActionLabel.textAndMnemonic", AppStrings.translate("FileChooser.listViewActionLabel.textAndMnemonic")); - UIManager.put("FileChooser.listViewButtonToolTip.textAndMnemonic", AppStrings.translate("FileChooser.listViewButtonToolTip.textAndMnemonic")); - UIManager.put("FileChooser.lookInLabel.textAndMnemonic", AppStrings.translate("FileChooser.lookInLabel.textAndMnemonic")); - UIManager.put("FileChooser.newFolderActionLabel.textAndMnemonic", AppStrings.translate("FileChooser.newFolderActionLabel.textAndMnemonic")); - UIManager.put("FileChooser.newFolderToolTip.textAndMnemonic", AppStrings.translate("FileChooser.newFolderToolTip.textAndMnemonic")); - UIManager.put("FileChooser.refreshActionLabel.textAndMnemonic", AppStrings.translate("FileChooser.refreshActionLabel.textAndMnemonic")); - UIManager.put("FileChooser.saveInLabel.textAndMnemonic", AppStrings.translate("FileChooser.saveInLabel.textAndMnemonic")); - UIManager.put("FileChooser.upFolderToolTip.textAndMnemonic", AppStrings.translate("FileChooser.upFolderToolTip.textAndMnemonic")); - UIManager.put("FileChooser.viewMenuButtonAccessibleName", AppStrings.translate("FileChooser.viewMenuButtonAccessibleName")); - UIManager.put("FileChooser.viewMenuButtonToolTipText", AppStrings.translate("FileChooser.viewMenuButtonToolTipText")); - UIManager.put("FileChooser.viewMenuLabel.textAndMnemonic", AppStrings.translate("FileChooser.viewMenuLabel.textAndMnemonic")); - UIManager.put("FileChooser.newFolderActionLabelText", AppStrings.translate("FileChooser.newFolderActionLabelText")); - UIManager.put("FileChooser.listViewActionLabelText", AppStrings.translate("FileChooser.listViewActionLabelText")); - UIManager.put("FileChooser.detailsViewActionLabelText", AppStrings.translate("FileChooser.detailsViewActionLabelText")); - UIManager.put("FileChooser.refreshActionLabelText", AppStrings.translate("FileChooser.refreshActionLabelText")); - UIManager.put("FileChooser.sortMenuLabelText", AppStrings.translate("FileChooser.sortMenuLabelText")); - UIManager.put("FileChooser.viewMenuLabelText", AppStrings.translate("FileChooser.viewMenuLabelText")); - UIManager.put("FileChooser.fileSizeKiloBytes", AppStrings.translate("FileChooser.fileSizeKiloBytes")); - UIManager.put("FileChooser.fileSizeMegaBytes", AppStrings.translate("FileChooser.fileSizeMegaBytes")); - UIManager.put("FileChooser.fileSizeGigaBytes", AppStrings.translate("FileChooser.fileSizeGigaBytes")); - UIManager.put("FileChooser.folderNameLabelText", AppStrings.translate("FileChooser.folderNameLabelText")); - - UIManager.put("ColorChooser.okText", AppStrings.translate("ColorChooser.okText")); - UIManager.put("ColorChooser.cancelText", AppStrings.translate("ColorChooser.cancelText")); - UIManager.put("ColorChooser.resetText", AppStrings.translate("ColorChooser.resetText")); - UIManager.put("ColorChooser.previewText", AppStrings.translate("ColorChooser.previewText")); - UIManager.put("ColorChooser.swatchesNameText", AppStrings.translate("ColorChooser.swatchesNameText")); - UIManager.put("ColorChooser.swatchesRecentText", AppStrings.translate("ColorChooser.swatchesRecentText")); - UIManager.put("ColorChooser.sampleText", AppStrings.translate("ColorChooser.sampleText")); - } - - /** - * This may help to free some memory when not needed (maybe?) - */ - private static void startFreeMemThread() { - new Thread() { - @Override - public void run() { - try { - while (true) { - Thread.sleep(5000); - System.gc(); - } - } catch (InterruptedException ex) { - logger.log(Level.SEVERE, null, ex); - } - } - }.start(); - } - - /** - * @param args the command line arguments - * @throws IOException - */ - public static void main(String[] args) throws IOException { - AppStrings.setResourceClass(MainFrame.class); - startFreeMemThread(); - initLogging(Configuration.debugMode.get()); - initLang(); - - if (Configuration.cacheOnDisk.get()) { - Cache.setStorageType(Cache.STORAGE_FILES); - } else { - Cache.setStorageType(Cache.STORAGE_MEMORY); - } - - if (args.length == 0) { - initGui(); - showModeFrame(); - } else { - String fileToOpen = CommandLineArgumentParser.parseArguments(args); - if (fileToOpen != null) { - initGui(); - openFile(fileToOpen, null); - } - } - } - - public static String tempFile(String url) throws IOException { - File f = new File(Configuration.getFFDecHome() + "saved" + File.separator); - if (!f.exists()) { - if (!f.mkdirs()) { - if (!f.exists()) { - throw new IOException("cannot create directory " + f); - } - } - } - return Configuration.getFFDecHome() + "saved" + File.separator + "asdec_" + Integer.toHexString(url.hashCode()) + ".tmp"; - - } - - public static void removeTrayIcon() { - if (SystemTray.isSupported()) { - SystemTray tray = SystemTray.getSystemTray(); - if (trayIcon != null) { - tray.remove(trayIcon); - trayIcon = null; - } - } - } - - public static void switchProxy() { - proxyFrame.switchState(); - if (stopMenuItem != null) { - if (proxyFrame.isRunning()) { - stopMenuItem.setLabel(AppStrings.translate("proxy.stop")); - } else { - stopMenuItem.setLabel(AppStrings.translate("proxy.start")); - } - } - } - - public static void addTrayIcon() { - if (trayIcon != null) { - return; - } - if (SystemTray.isSupported()) { - SystemTray tray = SystemTray.getSystemTray(); - trayIcon = new TrayIcon(View.loadImage("proxy16"), ApplicationInfo.VENDOR + " " + ApplicationInfo.SHORT_APPLICATION_NAME + " " + AppStrings.translate("proxy")); - trayIcon.setImageAutoSize(true); - PopupMenu trayPopup = new PopupMenu(); - - ActionListener trayListener = new ActionListener() { - /** - * Invoked when an action occurs. - */ - @Override - public void actionPerformed(ActionEvent e) { - if (e.getActionCommand().equals("EXIT")) { - Main.exit(); - } - if (e.getActionCommand().equals("SHOW")) { - Main.showProxy(); - } - if (e.getActionCommand().equals("SWITCH")) { - Main.switchProxy(); - } - } - }; - - MenuItem showMenuItem = new MenuItem(AppStrings.translate("proxy.show")); - showMenuItem.setActionCommand("SHOW"); - showMenuItem.addActionListener(trayListener); - trayPopup.add(showMenuItem); - stopMenuItem = new MenuItem(AppStrings.translate("proxy.start")); - stopMenuItem.setActionCommand("SWITCH"); - stopMenuItem.addActionListener(trayListener); - trayPopup.add(stopMenuItem); - trayPopup.addSeparator(); - MenuItem exitMenuItem = new MenuItem(AppStrings.translate("exit")); - exitMenuItem.setActionCommand("EXIT"); - exitMenuItem.addActionListener(trayListener); - trayPopup.add(exitMenuItem); - - trayIcon.setPopupMenu(trayPopup); - trayIcon.addMouseListener(new MouseAdapter() { - /** - * {@inheritDoc} - */ - @Override - public void mouseClicked(MouseEvent e) { - if (e.getButton() == MouseEvent.BUTTON1) { - Main.showProxy(); - } - } - }); - try { - tray.add(trayIcon); - } catch (AWTException ex) { - } - } - } - - public static void exit() { - Configuration.saveConfig(); - /*if (proxyFrame != null && Main.proxyFrame.isVisible()) { - return; - } - if (loadFromMemoryFrame != null && Main.loadFromMemoryFrame.isVisible()) { - return; - } - if (loadFromCacheFrame != null && loadFromCacheFrame.isVisible()) { - return; - }*/ - if (mainFrame != null && mainFrame.getPanel() != null) { - mainFrame.getPanel().unloadFlashPlayer(); - } - System.exit(0); - } - - public static void about() { - (new AboutDialog()).setVisible(true); - } - - public static void advancedSettings() { - (new AdvancedSettingsDialog()).setVisible(true); - } - - public static void autoCheckForUpdates() { - if (Configuration.checkForUpdatesAuto.get()) { - Calendar lastUpdatesCheckDate = Configuration.lastUpdatesCheckDate.get(); - if ((lastUpdatesCheckDate == null) || (lastUpdatesCheckDate.getTime().getTime() < Calendar.getInstance().getTime().getTime() - Configuration.checkForUpdatesDelay.get())) { - checkForUpdates(); - } - } - } - - public static boolean checkForUpdates() { - List accepted = new ArrayList<>(); - if (Configuration.checkForUpdatesStable.get()) { - accepted.add("stable"); - } - if (Configuration.checkForUpdatesNightly.get()) { - accepted.add("nightly"); - } - - if (accepted.isEmpty()) { - return false; - } - - String acceptVersions = ""; - for (String a : accepted) { - if (!acceptVersions.isEmpty()) { - acceptVersions += ","; - } - acceptVersions += a; - } - try { - Socket sock = new Socket("www.free-decompiler.com", 80); - OutputStream os = sock.getOutputStream(); - String currentLoc = Configuration.locale.get("en"); - os.write(("GET /flash/update.html?action=check¤tVersion=" + URLEncoder.encode(ApplicationInfo.version, "UTF-8") + "¤tBuild=" + URLEncoder.encode(ApplicationInfo.build, "UTF-8") + "¤tNightly=" + (ApplicationInfo.nightly ? "1" : "0") + " HTTP/1.1\r\n" - + "Host: www.free-decompiler.com\r\n" - + "X-Accept-Versions: " + acceptVersions + "\r\n" - + "X-Update-Major: " + UPDATE_SYSTEM_MAJOR + "\r\n" - + "X-Update-Minor: " + UPDATE_SYSTEM_MINOR + "\r\n" - + "User-Agent: " + ApplicationInfo.shortApplicationVerName + "\r\n" - + "Accept-Language: " + currentLoc + ("en".equals(currentLoc) ? "" : ", en;q=0.8") + "\r\n" - + "Connection: close\r\n" - + "\r\n").getBytes()); - BufferedReader br = new BufferedReader(new InputStreamReader(sock.getInputStream())); - String s; - boolean start = false; - final java.util.List versions = new ArrayList<>(); - String header = ""; - Pattern headerPat = Pattern.compile("\\[([a-zA-Z0-9]+)\\]"); - int updateMajor = 0; - int updateMinor = 0; - Version ver = null; - while ((s = br.readLine()) != null) { - if (start) { - Matcher m = headerPat.matcher(s); - if (m.matches()) { - header = m.group(1); - if (header.equals("version")) { - ver = new Version(); - versions.add(ver); - } - if (header.equals("noversion")) { - break; - } - } else { - if (s.contains("=")) { - String key = s.substring(0, s.indexOf('=')); - String val = s.substring(s.indexOf('=') + 1); - if ("updateSystem".equals(header)) { - if (key.equals("majorVersion")) { - updateMajor = Integer.parseInt(val); - if (updateMajor > UPDATE_SYSTEM_MAJOR) { - break; - } - } - if (key.equals("minorVersion")) { - updateMinor = Integer.parseInt(val); - } - } - if ("version".equals(header) && (ver != null)) { - if (key.equals("versionId")) { - ver.versionId = Integer.parseInt(val); - } - if (key.equals("versionName")) { - ver.versionName = val; - } - if (key.equals("nightly")) { - ver.nightly = val.equals("true"); - } - if (key.equals("revision")) { - ver.revision = val; - } - if (key.equals("longVersionName")) { - ver.longVersionName = val; - } - if (key.equals("releaseDate")) { - ver.releaseDate = val; - } - if (key.equals("appName")) { - ver.appName = val; - } - if (key.equals("appFullName")) { - ver.appFullName = val; - } - if (key.equals("updateLink")) { - ver.updateLink = val; - } - if (key.equals("change[]")) { - String changeType = val.substring(0, val.indexOf('|')); - String change = val.substring(val.indexOf('|') + 1); - if (!ver.changes.containsKey(changeType)) { - ver.changes.put(changeType, new ArrayList()); - } - java.util.List chlist = ver.changes.get(changeType); - chlist.add(change); - } - } - } - } - } - if (s.isEmpty()) { - start = true; - } - } - - if (!versions.isEmpty()) { - View.execInEventDispatch(new Runnable() { - @Override - public void run() { - NewVersionDialog newVersionDialog = new NewVersionDialog(versions); - newVersionDialog.setVisible(true); - Configuration.lastUpdatesCheckDate.set(Calendar.getInstance()); - } - }); - - return true; - } - } catch (IOException | NumberFormatException ex) { - return false; - } - Configuration.lastUpdatesCheckDate.set(Calendar.getInstance()); - return false; - } - private static FileHandler fileTxt; - - public static void clearLogFile() { - Logger logger = Logger.getLogger(""); - if (fileTxt != null) { - fileTxt.flush(); - fileTxt.close(); - logger.removeHandler(fileTxt); - } - - String fileName; - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-hh-mm-ss"); - - try { - fileName = Configuration.getFFDecHome() + File.separator + "logs" + File.separator; - if (Configuration.useDetailedLogging.get()) { - fileName += "log-" + sdf.format(new Date()) + ".txt"; - } else { - fileName += "log.txt"; - } - File f = new File(fileName).getParentFile(); - if (!f.exists()) { - f.mkdir(); - } - fileTxt = new FileHandler(fileName); - } catch (IOException | SecurityException ex) { - logger.log(Level.SEVERE, null, ex); - } - - Formatter formatterTxt = new LogFormatter(); - fileTxt.setFormatter(formatterTxt); - logger.addHandler(fileTxt); - - if (!GraphicsEnvironment.isHeadless()) { - ErrorLogFrame.getInstance().clearErrorState(); - } - - sdf = new SimpleDateFormat("yyyy-MM-dd"); - logger.log(Level.INFO, "Date: {0}", sdf.format(new Date())); - logger.log(Level.INFO, ApplicationInfo.applicationVerName); - logger.log(Level.INFO, "{0} {1} {2}", new Object[]{ - System.getProperty("os.name"), System.getProperty("os.version"), System.getProperty("os.arch")}); - logger.log(Level.INFO, "{0} {1} {2}", new Object[]{ - System.getProperty("java.version"), System.getProperty("java.vendor"), System.getProperty("os.arch")}); - } - - public static void initLogging(boolean debug) { - try { - Logger logger = Logger.getLogger(""); - logger.setLevel(Configuration.logLevel); - - int handlerCount = logger.getHandlers().length; - for (int i = handlerCount - 1; i >= 0; i--) { - logger.removeHandler(logger.getHandlers()[i]); - } - ConsoleHandler conHan = new ConsoleHandler(); - conHan.setLevel(debug ? Level.CONFIG : Level.WARNING); - SimpleFormatter formatterTxt = new SimpleFormatter(); - conHan.setFormatter(formatterTxt); - logger.addHandler(conHan); - clearLogFile(); - - } catch (Exception ex) { - throw new RuntimeException("Problems with creating the log files"); - } - } -} +/* + * Copyright (C) 2010-2014 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.jpexs.decompiler.flash.gui; + +import com.jpexs.decompiler.flash.AppStrings; +import com.jpexs.decompiler.flash.ApplicationInfo; +import com.jpexs.decompiler.flash.EventListener; +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFBundle; +import com.jpexs.decompiler.flash.SWFSourceInfo; +import com.jpexs.decompiler.flash.SearchMode; +import com.jpexs.decompiler.flash.Version; +import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.console.CommandLineArgumentParser; +import com.jpexs.decompiler.flash.console.ContextMenuTools; +import com.jpexs.decompiler.flash.gui.proxy.ProxyFrame; +import com.jpexs.decompiler.flash.tags.base.FontTag; +import com.jpexs.decompiler.flash.treeitems.SWFList; +import com.jpexs.helpers.Cache; +import com.jpexs.helpers.CancellableWorker; +import com.jpexs.helpers.Helper; +import com.jpexs.helpers.Path; +import com.jpexs.helpers.ProgressListener; +import com.jpexs.helpers.Stopwatch; +import com.jpexs.helpers.streams.SeekableInputStream; +import com.sun.jna.Platform; +import java.awt.AWTException; +import java.awt.Frame; +import java.awt.GraphicsEnvironment; +import java.awt.MenuItem; +import java.awt.PopupMenu; +import java.awt.SystemTray; +import java.awt.TrayIcon; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.lang.reflect.Field; +import java.net.Socket; +import java.net.URLEncoder; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.Locale; +import java.util.Map.Entry; +import java.util.logging.ConsoleHandler; +import java.util.logging.FileHandler; +import java.util.logging.Formatter; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.logging.SimpleFormatter; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.swing.JFileChooser; +import javax.swing.JFrame; +import javax.swing.JOptionPane; +import javax.swing.SwingWorker; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; +import javax.swing.filechooser.FileFilter; + +/** + * Main executable class + * + * @author JPEXS + */ +public class Main { + + public static ProxyFrame proxyFrame; + private static List sourceInfos = new ArrayList<>(); + public static LoadingDialog loadingDialog; + public static ModeFrame modeFrame; + private static boolean working = false; + private static TrayIcon trayIcon; + private static MenuItem stopMenuItem; + private static MainFrame mainFrame; + public static final int UPDATE_SYSTEM_MAJOR = 1; + public static final int UPDATE_SYSTEM_MINOR = 1; + public static LoadFromMemoryFrame loadFromMemoryFrame; + public static LoadFromCacheFrame loadFromCacheFrame; + private static final Logger logger = Logger.getLogger(Main.class.getName()); + + public static void ensureMainFrame() { + if (mainFrame == null) { + if (Configuration.useRibbonInterface.get()) { + mainFrame = new MainFrameRibbon(); + } else { + mainFrame = new MainFrameClassic(); + } + mainFrame.getPanel().setErrorState(ErrorLogFrame.getInstance().getErrorState()); + } + } + + public static MainFrame getMainFrame() { + return mainFrame; + } + + public static void loadFromCache() { + if (loadFromCacheFrame == null) { + loadFromCacheFrame = new LoadFromCacheFrame(); + } + loadFromCacheFrame.setVisible(true); + } + + public static void loadFromMemory() { + if (loadFromMemoryFrame == null) { + loadFromMemoryFrame = new LoadFromMemoryFrame(mainFrame); + } + loadFromMemoryFrame.setVisible(true); + } + + public static void setSubLimiter(boolean value) { + if (value) { + AVM2Code.toSourceLimit = Configuration.sublimiter.get(); + } else { + AVM2Code.toSourceLimit = -1; + } + } + + public static boolean isWorking() { + return working; + } + + public static void startProxy(int port) { + View.execInEventDispatch(new Runnable() { + @Override + public void run() { + if (proxyFrame == null) { + proxyFrame = new ProxyFrame(mainFrame); + } + } + }); + proxyFrame.setPort(port); + addTrayIcon(); + switchProxy(); + } + + public static void showProxy() { + if (proxyFrame == null) { + proxyFrame = new ProxyFrame(mainFrame); + } + proxyFrame.setVisible(true); + proxyFrame.setState(Frame.NORMAL); + } + + public static void startWork(String name) { + startWork(name, -1, null); + } + + public static void startWork(String name, int percent) { + startWork(name, percent, null); + } + + public static void startWork(String name, CancellableWorker worker) { + startWork(name, -1, worker); + } + + public static void startWork(final String name, final int percent, final CancellableWorker worker) { + working = true; + View.execInEventDispatchLater(new Runnable() { + @Override + public void run() { + if (mainFrame != null) { + mainFrame.getPanel().setWorkStatus(name, worker); + if (percent == -1) { + mainFrame.getPanel().hidePercent(); + } else { + mainFrame.getPanel().setPercent(percent); + } + } + if (loadingDialog != null) { + loadingDialog.setDetail(name); + if (percent == -1) { + loadingDialog.hidePercent(); + } else { + loadingDialog.setPercent(percent); + } + } + if (CommandLineArgumentParser.isCommandLineMode()) { + System.out.println(name); + } + } + }); + + } + + public static void stopWork() { + working = false; + View.execInEventDispatchLater(new Runnable() { + @Override + public void run() { + if (mainFrame != null) { + mainFrame.getPanel().setWorkStatus("", null); + } + if (loadingDialog != null) { + loadingDialog.setDetail(""); + } + } + }); + } + + public static SWFList parseSWF(SWFSourceInfo sourceInfo) throws Exception { + SWFList result = new SWFList(); + + InputStream inputStream = sourceInfo.getInputStream(); + SWFBundle bundle = null; + if (inputStream == null) { + inputStream = new BufferedInputStream(new FileInputStream(sourceInfo.getFile())); + bundle = sourceInfo.getBundle(false, SearchMode.ALL); + logger.log(Level.INFO, "Load file: {0}", sourceInfo.getFile()); + } else if (inputStream instanceof SeekableInputStream + || inputStream instanceof BufferedInputStream) { + try { + inputStream.reset(); + } catch (IOException ex) { + logger.log(Level.SEVERE, null, ex); + } + logger.log(Level.INFO, "Load stream: {0}", sourceInfo.getFileTitle()); + } + + Stopwatch sw = Stopwatch.startNew(); + if (bundle != null) { + result.isBundle = true; + result.name = new File(sourceInfo.getFileTitleOrName()).getName(); + for (Entry streamEntry : bundle.getAll().entrySet()) { + InputStream stream = streamEntry.getValue(); + stream.reset(); + SWF swf = new SWF(stream, new ProgressListener() { + @Override + public void progress(int p) { + startWork(AppStrings.translate("work.reading.swf"), p); + } + }, Configuration.parallelSpeedUp.get()); + swf.fileTitle = streamEntry.getKey(); + swf.readOnly = true; + result.add(swf); + } + } else { + SWF swf = new SWF(inputStream, new ProgressListener() { + @Override + public void progress(int p) { + startWork(AppStrings.translate("work.reading.swf"), p); + } + }, Configuration.parallelSpeedUp.get()); + swf.file = sourceInfo.getFile(); + swf.fileTitle = sourceInfo.getFileTitle(); + result.add(swf); + } + + if (inputStream instanceof FileInputStream) { + logger.log(Level.INFO, "File loaded in {0} seconds.", (sw.getElapsedMilliseconds() / 1000)); + inputStream.close(); + } else { + logger.log(Level.INFO, "Stream loaded in {0} seconds.", (sw.getElapsedMilliseconds() / 1000)); + } + + result.sourceInfo = sourceInfo; + for (SWF swf : result) { + logger.log(Level.INFO, ""); + logger.log(Level.INFO, "== File information =="); + logger.log(Level.INFO, "Size: {0}", Helper.formatFileSize(swf.fileSize)); + logger.log(Level.INFO, "Flash version: {0}", swf.version); + int width = (int) ((swf.displayRect.Xmax - swf.displayRect.Xmin) / SWF.unitDivisor); + int height = (int) ((swf.displayRect.Ymax - swf.displayRect.Ymin) / SWF.unitDivisor); + logger.log(Level.INFO, "Width: {0}", width); + logger.log(Level.INFO, "Height: {0}", height); + + swf.swfList = result; + swf.addEventListener(new EventListener() { + @Override + public void handleEvent(String event, Object data) { + if (event.equals("exporting")) { + startWork((String) data); + } + if (event.equals("getVariables")) { + startWork(AppStrings.translate("work.gettingvariables") + "..." + (String) data); + } + if (event.equals("deobfuscate")) { + startWork(AppStrings.translate("work.deobfuscating") + "..." + (String) data); + } + if (event.equals("rename")) { + startWork(AppStrings.translate("work.renaming") + "..." + (String) data); + } + } + }); + } + + return result; + } + + public static void saveFile(SWF swf, String outfile) throws IOException { + saveFile(swf, outfile, SaveFileMode.SAVE); + } + + public static void saveFile(SWF swf, String outfile, SaveFileMode mode) throws IOException { + if (mode == SaveFileMode.SAVEAS) { + swf.file = outfile; + } + File outfileF = new File(outfile); + File tmpFile = new File(outfile + ".tmp"); + FileOutputStream fos = new FileOutputStream(tmpFile); + if (mode == SaveFileMode.EXE) { + InputStream exeStream = View.class.getClassLoader().getResourceAsStream("com/jpexs/helpers/resource/Swf2Exe.bin"); + byte[] buffer = new byte[4096]; + int bytesRead = 0; + while ((bytesRead = exeStream.read(buffer)) != -1) { + fos.write(buffer, 0, bytesRead); + } + int width = swf.displayRect.Xmax - swf.displayRect.Xmin; + int height = swf.displayRect.Ymax - swf.displayRect.Ymin; + fos.write(width & 0xff); + fos.write((width >> 8) & 0xff); + fos.write((width >> 16) & 0xff); + fos.write((width >> 24) & 0xff); + fos.write(height & 0xff); + fos.write((height >> 8) & 0xff); + fos.write((height >> 16) & 0xff); + fos.write((height >> 24) & 0xff); + fos.write(Configuration.saveAsExeScaleMode.get()); + } + swf.saveTo(fos); + if (tmpFile.exists()) { + if (tmpFile.length() > 0) { + outfileF.delete(); + if (!tmpFile.renameTo(outfileF)) { + tmpFile.delete(); + throw new IOException("Cannot access " + outfile); + } + } else { + throw new IOException("Output is empty"); + } + } + } + + private static class OpenFileWorker extends SwingWorker { + + private final SWFSourceInfo[] sourceInfos; + + public OpenFileWorker(SWFSourceInfo sourceInfo) { + this.sourceInfos = new SWFSourceInfo[]{sourceInfo}; + } + + public OpenFileWorker(SWFSourceInfo[] sourceInfos) { + this.sourceInfos = sourceInfos; + } + + @Override + protected Object doInBackground() throws Exception { + boolean first = true; + SWF firstSWF = null; + for (final SWFSourceInfo sourceInfo : sourceInfos) { + SWFList swfs = null; + try { + Main.startWork(AppStrings.translate("work.reading.swf") + "..."); + swfs = parseSWF(sourceInfo); + } catch (OutOfMemoryError ex) { + logger.log(Level.SEVERE, null, ex); + View.showMessageDialog(null, "Cannot load SWF file. Out of memory."); + } catch (Exception ex) { + logger.log(Level.SEVERE, null, ex); + View.showMessageDialog(null, "Cannot load SWF file."); + } + + final SWFList swfs1 = swfs; + final boolean first1 = first; + first = false; + if (firstSWF == null) { + firstSWF = swfs1.get(0); + } + try { + Main.startWork(AppStrings.translate("work.creatingwindow") + "..."); + View.execInEventDispatch(new Runnable() { + @Override + public void run() { + ensureMainFrame(); + mainFrame.getPanel().load(swfs1, first1); + } + }); + + } catch (Exception ex) { + logger.log(Level.SEVERE, null, ex); + } + } + + loadingDialog.setVisible(false); + final SWF fswf = firstSWF; + View.execInEventDispatch(new Runnable() { + @Override + public void run() { + if (mainFrame != null) { + mainFrame.setVisible(true); + } + Main.stopWork(); + if (mainFrame != null && Configuration.gotoMainClassOnStartup.get()) { + mainFrame.getPanel().gotoDocumentClass(fswf); + } + } + }); + + return true; + } + } + + public static boolean reloadSWFs() { + CancellableWorker.cancelBackgroundThreads(); + if (mainFrame != null) { + mainFrame.getPanel().closeAll(); + } + if (Main.sourceInfos.isEmpty()) { + Cache.clearAll(); + System.gc(); + showModeFrame(); + return true; + } else { + SWFSourceInfo[] sourceInfosCopy = new SWFSourceInfo[sourceInfos.size()]; + sourceInfos.toArray(sourceInfosCopy); + sourceInfos.clear(); + openFile(sourceInfosCopy); + return true; + } + } + + public static void reloadApp() { + if (loadingDialog != null) { + loadingDialog.setVisible(false); + loadingDialog = null; + } + if (proxyFrame != null) { + proxyFrame.setVisible(false); + proxyFrame = null; + } + if (loadFromMemoryFrame != null) { + loadFromMemoryFrame.setVisible(false); + loadFromMemoryFrame = null; + } + if (loadFromCacheFrame != null) { + loadFromCacheFrame.setVisible(false); + loadFromCacheFrame = null; + } + if (mainFrame != null) { + mainFrame.setVisible(false); + mainFrame = null; + } + FontTag.reload(); + Cache.clearAll(); + initGui(); + reloadSWFs(); + } + + public static OpenFileResult openFile(String swfFile, String fileTitle) { + try { + File file = new File(swfFile); + if (!file.exists()) { + View.showMessageDialog(null, AppStrings.translate("open.error.fileNotFound"), AppStrings.translate("open.error"), JOptionPane.ERROR_MESSAGE); + return OpenFileResult.NOT_FOUND; + } + swfFile = file.getCanonicalPath(); + Configuration.addRecentFile(swfFile); + SWFSourceInfo sourceInfo = new SWFSourceInfo(null, swfFile, fileTitle); + OpenFileResult openResult = openFile(sourceInfo); + return openResult; + } catch (IOException ex) { + View.showMessageDialog(null, AppStrings.translate("open.error.cannotOpen"), AppStrings.translate("open.error"), JOptionPane.ERROR_MESSAGE); + return OpenFileResult.ERROR; + } + } + + public static OpenFileResult openFile(SWFSourceInfo sourceInfo) { + return openFile(new SWFSourceInfo[]{sourceInfo}); + } + + public static OpenFileResult openFile(SWFSourceInfo[] newSourceInfos) { + if (mainFrame != null && !Configuration.openMultipleFiles.get()) { + sourceInfos.clear(); + mainFrame.getPanel().closeAll(); + mainFrame.setVisible(false); + Cache.clearAll(); + System.gc(); + } + + View.execInEventDispatch(new Runnable() { + @Override + public void run() { + if (Main.loadingDialog == null) { + Main.loadingDialog = new LoadingDialog(); + } + } + }); + + Main.loadingDialog.setVisible(true); + OpenFileWorker wrk = new OpenFileWorker(newSourceInfos); + wrk.execute(); + sourceInfos.addAll(Arrays.asList(newSourceInfos)); + return OpenFileResult.OK; + } + + public static void closeFile(SWFList swf) { + sourceInfos.remove(swf.sourceInfo); + mainFrame.getPanel().close(swf); + } + + public static void closeAll() { + sourceInfos.clear(); + mainFrame.getPanel().closeAll(); + } + + public static boolean saveFileDialog(SWF swf, final SaveFileMode mode) { + JFileChooser fc = new JFileChooser(); + fc.setCurrentDirectory(new File(Configuration.lastSaveDir.get())); + String ext = ".swf"; + switch (mode) { + case SAVE: + case SAVEAS: + if (swf.file != null) { + ext = Path.getExtension(swf.file); + } + break; + case EXE: + ext = ".exe"; + break; + } + final String extension = ext; + FileFilter swfFilter = new FileFilter() { + @Override + public boolean accept(File f) { + return (f.getName().toLowerCase().endsWith(extension)) || (f.isDirectory()); + } + + @Override + public String getDescription() { + return AppStrings.translate("filter" + extension); + } + }; + if (!swf.gfx) { + fc.setFileFilter(swfFilter); + } else { + fc.addChoosableFileFilter(swfFilter); + } + FileFilter gfxFilter = new FileFilter() { + @Override + public boolean accept(File f) { + return (f.getName().toLowerCase().endsWith(".gfx")) || (f.isDirectory()); + } + + @Override + public String getDescription() { + return AppStrings.translate("filter.gfx"); + } + }; + if (mode == SaveFileMode.SAVE || mode == SaveFileMode.SAVEAS) { + if (swf.gfx) { + fc.setFileFilter(gfxFilter); + } else { + fc.addChoosableFileFilter(gfxFilter); + } + } + fc.setAcceptAllFileFilterUsed(false); + JFrame f = new JFrame(); + View.setWindowIcon(f); + int returnVal = fc.showSaveDialog(f); + if (returnVal == JFileChooser.APPROVE_OPTION) { + File file = Helper.fixDialogFile(fc.getSelectedFile()); + FileFilter selFilter = fc.getFileFilter(); + try { + String fileName = file.getAbsolutePath(); + if (selFilter == swfFilter) { + if (!fileName.toLowerCase().endsWith(extension)) { + fileName += extension; + } + swf.gfx = false; + } + if (selFilter == gfxFilter) { + if (!fileName.toLowerCase().endsWith(".gfx")) { + fileName += ".gfx"; + } + swf.gfx = true; + } + Main.saveFile(swf, fileName, mode); + Configuration.lastSaveDir.set(file.getParentFile().getAbsolutePath()); + return true; + } catch (IOException ex) { + View.showMessageDialog(null, AppStrings.translate("error.file.write")); + } + } + return false; + } + + public static boolean openFileDialog() { + JFileChooser fc = new JFileChooser(); + fc.setCurrentDirectory(new File(Configuration.lastOpenDir.get())); + FileFilter allSupportedFilter = new FileFilter() { + private final String[] supportedExtensions = new String[]{".swf", ".gfx", ".swc", ".zip"}; + + @Override + public boolean accept(File f) { + String name = f.getName().toLowerCase(); + for (String ext : supportedExtensions) { + if (name.endsWith(ext)) { + return true; + } + } + return f.isDirectory(); + } + + @Override + public String getDescription() { + String exts = Helper.joinStrings(supportedExtensions, "*%s", "; "); + return AppStrings.translate("filter.supported") + " (" + exts + ")"; + } + }; + fc.setFileFilter(allSupportedFilter); + FileFilter swfFilter = new FileFilter() { + @Override + public boolean accept(File f) { + return (f.getName().toLowerCase().endsWith(".swf")) || (f.isDirectory()); + } + + @Override + public String getDescription() { + return AppStrings.translate("filter.swf"); + } + }; + fc.addChoosableFileFilter(swfFilter); + + FileFilter swcFilter = new FileFilter() { + @Override + public boolean accept(File f) { + return (f.getName().toLowerCase().endsWith(".swc")) || (f.isDirectory()); + } + + @Override + public String getDescription() { + return AppStrings.translate("filter.swc"); + } + }; + fc.addChoosableFileFilter(swcFilter); + + FileFilter gfxFilter = new FileFilter() { + @Override + public boolean accept(File f) { + return (f.getName().toLowerCase().endsWith(".gfx")) || (f.isDirectory()); + } + + @Override + public String getDescription() { + return AppStrings.translate("filter.gfx"); + } + }; + fc.addChoosableFileFilter(gfxFilter); + + FileFilter zipFilter = new FileFilter() { + @Override + public boolean accept(File f) { + return (f.getName().toLowerCase().endsWith(".zip")) || (f.isDirectory()); + } + + @Override + public String getDescription() { + return AppStrings.translate("filter.zip"); + } + }; + fc.addChoosableFileFilter(zipFilter); + + FileFilter binaryFilter = new FileFilter() { + @Override + public boolean accept(File f) { + return true; + } + + @Override + public String getDescription() { + return AppStrings.translate("filter.binary"); + } + }; + fc.addChoosableFileFilter(binaryFilter); + + fc.setAcceptAllFileFilterUsed(false); + JFrame f = new JFrame(); + View.setWindowIcon(f); + int returnVal = fc.showOpenDialog(f); + if (returnVal == JFileChooser.APPROVE_OPTION) { + Configuration.lastOpenDir.set(Helper.fixDialogFile(fc.getSelectedFile()).getParentFile().getAbsolutePath()); + File selfile = Helper.fixDialogFile(fc.getSelectedFile()); + Main.openFile(selfile.getAbsolutePath(), null); + return true; + } else { + return false; + } + } + + public static void displayErrorFrame() { + ErrorLogFrame.getInstance().setVisible(true); + } + + private static void initGui() { + if (GraphicsEnvironment.isHeadless()) { + System.err.println("Error: Your system does not support Graphic User Interface"); + exit(); + } + if (Configuration.useRibbonInterface.get()) { + View.setLookAndFeel(); + } else { + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { + logger.log(Level.SEVERE, null, ex); + } + } + autoCheckForUpdates(); + offerAssociation(); + } + + public static void showModeFrame() { + View.execInEventDispatch(new Runnable() { + @Override + public void run() { + ensureMainFrame(); + mainFrame.setVisible(true); + } + }); + + } + + private static void offerAssociation() { + boolean offered = Configuration.offeredAssociation.get(); + if (!offered) { + if (Platform.isWindows()) { + if ((!ContextMenuTools.isAddedToContextMenu()) && View.showConfirmDialog(null, "Do you want to add FFDec to context menu of SWF files?\n(Can be changed later from main menu)", "Context menu", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) { + ContextMenuTools.addToContextMenu(true, false); + } + } + } + Configuration.offeredAssociation.set(true); + } + + public static void initLang() { + if (GraphicsEnvironment.isHeadless()) { //No GUI in OS + return; + } + Locale.setDefault(Locale.forLanguageTag(Configuration.locale.get())); + AppStrings.updateLanguage(); + ErrorLogFrame.createNewInstance(); + + try { + Class cl = Class.forName("org.pushingpixels.substance.api.SubstanceLookAndFeel"); + Field field = cl.getDeclaredField("LABEL_BUNDLE"); + field.setAccessible(true); + field.set(null, null); + } catch (Throwable ex) { + Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); + } + + UIManager.put("OptionPane.okButtonText", AppStrings.translate("button.ok")); + UIManager.put("OptionPane.yesButtonText", AppStrings.translate("button.yes")); + UIManager.put("OptionPane.noButtonText", AppStrings.translate("button.no")); + UIManager.put("OptionPane.cancelButtonText", AppStrings.translate("button.cancel")); + UIManager.put("OptionPane.messageDialogTitle", AppStrings.translate("dialog.message.title")); + UIManager.put("OptionPane.titleText", AppStrings.translate("dialog.select.title")); + + UIManager.put("FileChooser.acceptAllFileFilterText", AppStrings.translate("FileChooser.acceptAllFileFilterText")); + UIManager.put("FileChooser.lookInLabelText", AppStrings.translate("FileChooser.lookInLabelText")); + UIManager.put("FileChooser.cancelButtonText", AppStrings.translate("button.cancel")); + UIManager.put("FileChooser.cancelButtonToolTipText", AppStrings.translate("button.cancel")); + UIManager.put("FileChooser.openButtonText", AppStrings.translate("FileChooser.openButtonText")); + UIManager.put("FileChooser.openButtonToolTipText", AppStrings.translate("FileChooser.openButtonToolTipText")); + UIManager.put("FileChooser.filesOfTypeLabelText", AppStrings.translate("FileChooser.filesOfTypeLabelText")); + UIManager.put("FileChooser.fileNameLabelText", AppStrings.translate("FileChooser.fileNameLabelText")); + UIManager.put("FileChooser.listViewButtonToolTipText", AppStrings.translate("FileChooser.listViewButtonToolTipText")); + UIManager.put("FileChooser.listViewButtonAccessibleName", AppStrings.translate("FileChooser.listViewButtonAccessibleName")); + UIManager.put("FileChooser.detailsViewButtonToolTipText", AppStrings.translate("FileChooser.detailsViewButtonToolTipText")); + UIManager.put("FileChooser.detailsViewButtonAccessibleName", AppStrings.translate("FileChooser.detailsViewButtonAccessibleName")); + UIManager.put("FileChooser.upFolderToolTipText", AppStrings.translate("FileChooser.upFolderToolTipText")); + UIManager.put("FileChooser.upFolderAccessibleName", AppStrings.translate("FileChooser.upFolderAccessibleName")); + UIManager.put("FileChooser.homeFolderToolTipText", AppStrings.translate("FileChooser.homeFolderToolTipText")); + UIManager.put("FileChooser.homeFolderAccessibleName", AppStrings.translate("FileChooser.homeFolderAccessibleName")); + UIManager.put("FileChooser.fileNameHeaderText", AppStrings.translate("FileChooser.fileNameHeaderText")); + UIManager.put("FileChooser.fileSizeHeaderText", AppStrings.translate("FileChooser.fileSizeHeaderText")); + UIManager.put("FileChooser.fileTypeHeaderText", AppStrings.translate("FileChooser.fileTypeHeaderText")); + UIManager.put("FileChooser.fileDateHeaderText", AppStrings.translate("FileChooser.fileDateHeaderText")); + UIManager.put("FileChooser.fileAttrHeaderText", AppStrings.translate("FileChooser.fileAttrHeaderText")); + UIManager.put("FileChooser.openDialogTitleText", AppStrings.translate("FileChooser.openDialogTitleText")); + UIManager.put("FileChooser.directoryDescriptionText", AppStrings.translate("FileChooser.directoryDescriptionText")); + UIManager.put("FileChooser.directoryOpenButtonText", AppStrings.translate("FileChooser.directoryOpenButtonText")); + UIManager.put("FileChooser.directoryOpenButtonToolTipText", AppStrings.translate("FileChooser.directoryOpenButtonToolTipText")); + UIManager.put("FileChooser.fileDescriptionText", AppStrings.translate("FileChooser.fileDescriptionText")); + UIManager.put("FileChooser.fileNameLabelText", AppStrings.translate("FileChooser.fileNameLabelText")); + UIManager.put("FileChooser.helpButtonText", AppStrings.translate("FileChooser.helpButtonText")); + UIManager.put("FileChooser.helpButtonToolTipText", AppStrings.translate("FileChooser.helpButtonToolTipText")); + UIManager.put("FileChooser.newFolderAccessibleName", AppStrings.translate("FileChooser.newFolderAccessibleName")); + UIManager.put("FileChooser.newFolderErrorText", AppStrings.translate("FileChooser.newFolderErrorText")); + UIManager.put("FileChooser.newFolderToolTipText", AppStrings.translate("FileChooser.newFolderToolTipText")); + UIManager.put("FileChooser.other.newFolder", AppStrings.translate("FileChooser.other.newFolder")); + UIManager.put("FileChooser.other.newFolder.subsequent", AppStrings.translate("FileChooser.other.newFolder.subsequent")); + UIManager.put("FileChooser.win32.newFolder", AppStrings.translate("FileChooser.win32.newFolder")); + UIManager.put("FileChooser.win32.newFolder.subsequent", AppStrings.translate("FileChooser.win32.newFolder.subsequent")); + UIManager.put("FileChooser.saveButtonText", AppStrings.translate("FileChooser.saveButtonText")); + UIManager.put("FileChooser.saveButtonToolTipText", AppStrings.translate("FileChooser.saveButtonToolTipText")); + UIManager.put("FileChooser.saveDialogTitleText", AppStrings.translate("FileChooser.saveDialogTitleText")); + UIManager.put("FileChooser.saveInLabelText", AppStrings.translate("FileChooser.saveInLabelText")); + UIManager.put("FileChooser.updateButtonText", AppStrings.translate("FileChooser.updateButtonText")); + UIManager.put("FileChooser.updateButtonToolTipText", AppStrings.translate("FileChooser.updateButtonToolTipText")); + + UIManager.put("FileChooser.detailsViewActionLabel.textAndMnemonic", AppStrings.translate("FileChooser.detailsViewActionLabel.textAndMnemonic")); + UIManager.put("FileChooser.detailsViewButtonToolTip.textAndMnemonic", AppStrings.translate("FileChooser.detailsViewButtonToolTip.textAndMnemonic")); + UIManager.put("FileChooser.fileAttrHeader.textAndMnemonic", AppStrings.translate("FileChooser.fileAttrHeader.textAndMnemonic")); + UIManager.put("FileChooser.fileDateHeader.textAndMnemonic", AppStrings.translate("FileChooser.fileDateHeader.textAndMnemonic")); + UIManager.put("FileChooser.fileNameHeader.textAndMnemonic", AppStrings.translate("FileChooser.fileNameHeader.textAndMnemonic")); + UIManager.put("FileChooser.fileNameLabel.textAndMnemonic", AppStrings.translate("FileChooser.fileNameLabel.textAndMnemonic")); + UIManager.put("FileChooser.fileSizeHeader.textAndMnemonic", AppStrings.translate("FileChooser.fileSizeHeader.textAndMnemonic")); + UIManager.put("FileChooser.fileTypeHeader.textAndMnemonic", AppStrings.translate("FileChooser.fileTypeHeader.textAndMnemonic")); + UIManager.put("FileChooser.filesOfTypeLabel.textAndMnemonic", AppStrings.translate("FileChooser.filesOfTypeLabel.textAndMnemonic")); + UIManager.put("FileChooser.folderNameLabel.textAndMnemonic", AppStrings.translate("FileChooser.folderNameLabel.textAndMnemonic")); + UIManager.put("FileChooser.homeFolderToolTip.textAndMnemonic", AppStrings.translate("FileChooser.homeFolderToolTip.textAndMnemonic")); + UIManager.put("FileChooser.listViewActionLabel.textAndMnemonic", AppStrings.translate("FileChooser.listViewActionLabel.textAndMnemonic")); + UIManager.put("FileChooser.listViewButtonToolTip.textAndMnemonic", AppStrings.translate("FileChooser.listViewButtonToolTip.textAndMnemonic")); + UIManager.put("FileChooser.lookInLabel.textAndMnemonic", AppStrings.translate("FileChooser.lookInLabel.textAndMnemonic")); + UIManager.put("FileChooser.newFolderActionLabel.textAndMnemonic", AppStrings.translate("FileChooser.newFolderActionLabel.textAndMnemonic")); + UIManager.put("FileChooser.newFolderToolTip.textAndMnemonic", AppStrings.translate("FileChooser.newFolderToolTip.textAndMnemonic")); + UIManager.put("FileChooser.refreshActionLabel.textAndMnemonic", AppStrings.translate("FileChooser.refreshActionLabel.textAndMnemonic")); + UIManager.put("FileChooser.saveInLabel.textAndMnemonic", AppStrings.translate("FileChooser.saveInLabel.textAndMnemonic")); + UIManager.put("FileChooser.upFolderToolTip.textAndMnemonic", AppStrings.translate("FileChooser.upFolderToolTip.textAndMnemonic")); + UIManager.put("FileChooser.viewMenuButtonAccessibleName", AppStrings.translate("FileChooser.viewMenuButtonAccessibleName")); + UIManager.put("FileChooser.viewMenuButtonToolTipText", AppStrings.translate("FileChooser.viewMenuButtonToolTipText")); + UIManager.put("FileChooser.viewMenuLabel.textAndMnemonic", AppStrings.translate("FileChooser.viewMenuLabel.textAndMnemonic")); + UIManager.put("FileChooser.newFolderActionLabelText", AppStrings.translate("FileChooser.newFolderActionLabelText")); + UIManager.put("FileChooser.listViewActionLabelText", AppStrings.translate("FileChooser.listViewActionLabelText")); + UIManager.put("FileChooser.detailsViewActionLabelText", AppStrings.translate("FileChooser.detailsViewActionLabelText")); + UIManager.put("FileChooser.refreshActionLabelText", AppStrings.translate("FileChooser.refreshActionLabelText")); + UIManager.put("FileChooser.sortMenuLabelText", AppStrings.translate("FileChooser.sortMenuLabelText")); + UIManager.put("FileChooser.viewMenuLabelText", AppStrings.translate("FileChooser.viewMenuLabelText")); + UIManager.put("FileChooser.fileSizeKiloBytes", AppStrings.translate("FileChooser.fileSizeKiloBytes")); + UIManager.put("FileChooser.fileSizeMegaBytes", AppStrings.translate("FileChooser.fileSizeMegaBytes")); + UIManager.put("FileChooser.fileSizeGigaBytes", AppStrings.translate("FileChooser.fileSizeGigaBytes")); + UIManager.put("FileChooser.folderNameLabelText", AppStrings.translate("FileChooser.folderNameLabelText")); + + UIManager.put("ColorChooser.okText", AppStrings.translate("ColorChooser.okText")); + UIManager.put("ColorChooser.cancelText", AppStrings.translate("ColorChooser.cancelText")); + UIManager.put("ColorChooser.resetText", AppStrings.translate("ColorChooser.resetText")); + UIManager.put("ColorChooser.previewText", AppStrings.translate("ColorChooser.previewText")); + UIManager.put("ColorChooser.swatchesNameText", AppStrings.translate("ColorChooser.swatchesNameText")); + UIManager.put("ColorChooser.swatchesRecentText", AppStrings.translate("ColorChooser.swatchesRecentText")); + UIManager.put("ColorChooser.sampleText", AppStrings.translate("ColorChooser.sampleText")); + } + + /** + * This may help to free some memory when not needed (maybe?) + */ + private static void startFreeMemThread() { + new Thread() { + @Override + public void run() { + try { + while (true) { + Thread.sleep(5000); + System.gc(); + } + } catch (InterruptedException ex) { + logger.log(Level.SEVERE, null, ex); + } + } + }.start(); + } + + /** + * @param args the command line arguments + * @throws IOException + */ + public static void main(String[] args) throws IOException { + AppStrings.setResourceClass(MainFrame.class); + startFreeMemThread(); + initLogging(Configuration.debugMode.get()); + initLang(); + + if (Configuration.cacheOnDisk.get()) { + Cache.setStorageType(Cache.STORAGE_FILES); + } else { + Cache.setStorageType(Cache.STORAGE_MEMORY); + } + + if (args.length == 0) { + initGui(); + showModeFrame(); + } else { + String fileToOpen = CommandLineArgumentParser.parseArguments(args); + if (fileToOpen != null) { + initGui(); + openFile(fileToOpen, null); + } + } + } + + public static String tempFile(String url) throws IOException { + File f = new File(Configuration.getFFDecHome() + "saved" + File.separator); + if (!f.exists()) { + if (!f.mkdirs()) { + if (!f.exists()) { + throw new IOException("cannot create directory " + f); + } + } + } + return Configuration.getFFDecHome() + "saved" + File.separator + "asdec_" + Integer.toHexString(url.hashCode()) + ".tmp"; + + } + + public static void removeTrayIcon() { + if (SystemTray.isSupported()) { + SystemTray tray = SystemTray.getSystemTray(); + if (trayIcon != null) { + tray.remove(trayIcon); + trayIcon = null; + } + } + } + + public static void switchProxy() { + proxyFrame.switchState(); + if (stopMenuItem != null) { + if (proxyFrame.isRunning()) { + stopMenuItem.setLabel(AppStrings.translate("proxy.stop")); + } else { + stopMenuItem.setLabel(AppStrings.translate("proxy.start")); + } + } + } + + public static void addTrayIcon() { + if (trayIcon != null) { + return; + } + if (SystemTray.isSupported()) { + SystemTray tray = SystemTray.getSystemTray(); + trayIcon = new TrayIcon(View.loadImage("proxy16"), ApplicationInfo.VENDOR + " " + ApplicationInfo.SHORT_APPLICATION_NAME + " " + AppStrings.translate("proxy")); + trayIcon.setImageAutoSize(true); + PopupMenu trayPopup = new PopupMenu(); + + ActionListener trayListener = new ActionListener() { + /** + * Invoked when an action occurs. + */ + @Override + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().equals("EXIT")) { + Main.exit(); + } + if (e.getActionCommand().equals("SHOW")) { + Main.showProxy(); + } + if (e.getActionCommand().equals("SWITCH")) { + Main.switchProxy(); + } + } + }; + + MenuItem showMenuItem = new MenuItem(AppStrings.translate("proxy.show")); + showMenuItem.setActionCommand("SHOW"); + showMenuItem.addActionListener(trayListener); + trayPopup.add(showMenuItem); + stopMenuItem = new MenuItem(AppStrings.translate("proxy.start")); + stopMenuItem.setActionCommand("SWITCH"); + stopMenuItem.addActionListener(trayListener); + trayPopup.add(stopMenuItem); + trayPopup.addSeparator(); + MenuItem exitMenuItem = new MenuItem(AppStrings.translate("exit")); + exitMenuItem.setActionCommand("EXIT"); + exitMenuItem.addActionListener(trayListener); + trayPopup.add(exitMenuItem); + + trayIcon.setPopupMenu(trayPopup); + trayIcon.addMouseListener(new MouseAdapter() { + /** + * {@inheritDoc} + */ + @Override + public void mouseClicked(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON1) { + Main.showProxy(); + } + } + }); + try { + tray.add(trayIcon); + } catch (AWTException ex) { + } + } + } + + public static void exit() { + Configuration.saveConfig(); + /*if (proxyFrame != null && Main.proxyFrame.isVisible()) { + return; + } + if (loadFromMemoryFrame != null && Main.loadFromMemoryFrame.isVisible()) { + return; + } + if (loadFromCacheFrame != null && loadFromCacheFrame.isVisible()) { + return; + }*/ + if (mainFrame != null && mainFrame.getPanel() != null) { + mainFrame.getPanel().unloadFlashPlayer(); + } + System.exit(0); + } + + public static void about() { + (new AboutDialog()).setVisible(true); + } + + public static void advancedSettings() { + (new AdvancedSettingsDialog()).setVisible(true); + } + + public static void autoCheckForUpdates() { + if (Configuration.checkForUpdatesAuto.get()) { + Calendar lastUpdatesCheckDate = Configuration.lastUpdatesCheckDate.get(); + if ((lastUpdatesCheckDate == null) || (lastUpdatesCheckDate.getTime().getTime() < Calendar.getInstance().getTime().getTime() - Configuration.checkForUpdatesDelay.get())) { + checkForUpdates(); + } + } + } + + public static boolean checkForUpdates() { + String currentVersion = ApplicationInfo.version; + if (currentVersion.equals("unknown")) { + // sometimes during development the version information is not available + return false; + } + + List accepted = new ArrayList<>(); + if (Configuration.checkForUpdatesStable.get()) { + accepted.add("stable"); + } + if (Configuration.checkForUpdatesNightly.get()) { + accepted.add("nightly"); + } + + if (accepted.isEmpty()) { + return false; + } + + String acceptVersions = ""; + for (String a : accepted) { + if (!acceptVersions.isEmpty()) { + acceptVersions += ","; + } + acceptVersions += a; + } + try { + Socket sock = new Socket("www.free-decompiler.com", 80); + OutputStream os = sock.getOutputStream(); + String currentLoc = Configuration.locale.get("en"); + os.write(("GET /flash/update.html?action=check¤tVersion=" + URLEncoder.encode(currentVersion, "UTF-8") + "¤tBuild=" + URLEncoder.encode(ApplicationInfo.build, "UTF-8") + "¤tNightly=" + (ApplicationInfo.nightly ? "1" : "0") + " HTTP/1.1\r\n" + + "Host: www.free-decompiler.com\r\n" + + "X-Accept-Versions: " + acceptVersions + "\r\n" + + "X-Update-Major: " + UPDATE_SYSTEM_MAJOR + "\r\n" + + "X-Update-Minor: " + UPDATE_SYSTEM_MINOR + "\r\n" + + "User-Agent: " + ApplicationInfo.shortApplicationVerName + "\r\n" + + "Accept-Language: " + currentLoc + ("en".equals(currentLoc) ? "" : ", en;q=0.8") + "\r\n" + + "Connection: close\r\n" + + "\r\n").getBytes()); + BufferedReader br = new BufferedReader(new InputStreamReader(sock.getInputStream())); + String s; + boolean start = false; + final java.util.List versions = new ArrayList<>(); + String header = ""; + Pattern headerPat = Pattern.compile("\\[([a-zA-Z0-9]+)\\]"); + int updateMajor = 0; + int updateMinor = 0; + Version ver = null; + while ((s = br.readLine()) != null) { + if (start) { + Matcher m = headerPat.matcher(s); + if (m.matches()) { + header = m.group(1); + if (header.equals("version")) { + ver = new Version(); + versions.add(ver); + } + if (header.equals("noversion")) { + break; + } + } else { + if (s.contains("=")) { + String key = s.substring(0, s.indexOf('=')); + String val = s.substring(s.indexOf('=') + 1); + if ("updateSystem".equals(header)) { + if (key.equals("majorVersion")) { + updateMajor = Integer.parseInt(val); + if (updateMajor > UPDATE_SYSTEM_MAJOR) { + break; + } + } + if (key.equals("minorVersion")) { + updateMinor = Integer.parseInt(val); + } + } + if ("version".equals(header) && (ver != null)) { + if (key.equals("versionId")) { + ver.versionId = Integer.parseInt(val); + } + if (key.equals("versionName")) { + ver.versionName = val; + } + if (key.equals("nightly")) { + ver.nightly = val.equals("true"); + } + if (key.equals("revision")) { + ver.revision = val; + } + if (key.equals("longVersionName")) { + ver.longVersionName = val; + } + if (key.equals("releaseDate")) { + ver.releaseDate = val; + } + if (key.equals("appName")) { + ver.appName = val; + } + if (key.equals("appFullName")) { + ver.appFullName = val; + } + if (key.equals("updateLink")) { + ver.updateLink = val; + } + if (key.equals("change[]")) { + String changeType = val.substring(0, val.indexOf('|')); + String change = val.substring(val.indexOf('|') + 1); + if (!ver.changes.containsKey(changeType)) { + ver.changes.put(changeType, new ArrayList()); + } + java.util.List chlist = ver.changes.get(changeType); + chlist.add(change); + } + } + } + } + } + if (s.isEmpty()) { + start = true; + } + } + + if (!versions.isEmpty()) { + View.execInEventDispatch(new Runnable() { + @Override + public void run() { + NewVersionDialog newVersionDialog = new NewVersionDialog(versions); + newVersionDialog.setVisible(true); + Configuration.lastUpdatesCheckDate.set(Calendar.getInstance()); + } + }); + + return true; + } + } catch (IOException | NumberFormatException ex) { + return false; + } + Configuration.lastUpdatesCheckDate.set(Calendar.getInstance()); + return false; + } + private static FileHandler fileTxt; + + public static void clearLogFile() { + Logger logger = Logger.getLogger(""); + if (fileTxt != null) { + fileTxt.flush(); + fileTxt.close(); + logger.removeHandler(fileTxt); + } + + String fileName; + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-hh-mm-ss"); + + try { + fileName = Configuration.getFFDecHome() + File.separator + "logs" + File.separator; + if (Configuration.useDetailedLogging.get()) { + fileName += "log-" + sdf.format(new Date()) + ".txt"; + } else { + fileName += "log.txt"; + } + File f = new File(fileName).getParentFile(); + if (!f.exists()) { + f.mkdir(); + } + fileTxt = new FileHandler(fileName); + } catch (IOException | SecurityException ex) { + logger.log(Level.SEVERE, null, ex); + } + + Formatter formatterTxt = new LogFormatter(); + fileTxt.setFormatter(formatterTxt); + logger.addHandler(fileTxt); + + if (!GraphicsEnvironment.isHeadless()) { + ErrorLogFrame.getInstance().clearErrorState(); + } + + sdf = new SimpleDateFormat("yyyy-MM-dd"); + logger.log(Level.INFO, "Date: {0}", sdf.format(new Date())); + logger.log(Level.INFO, ApplicationInfo.applicationVerName); + logger.log(Level.INFO, "{0} {1} {2}", new Object[]{ + System.getProperty("os.name"), System.getProperty("os.version"), System.getProperty("os.arch")}); + logger.log(Level.INFO, "{0} {1} {2}", new Object[]{ + System.getProperty("java.version"), System.getProperty("java.vendor"), System.getProperty("os.arch")}); + } + + public static void initLogging(boolean debug) { + try { + Logger logger = Logger.getLogger(""); + logger.setLevel(Configuration.logLevel); + + int handlerCount = logger.getHandlers().length; + for (int i = handlerCount - 1; i >= 0; i--) { + logger.removeHandler(logger.getHandlers()[i]); + } + ConsoleHandler conHan = new ConsoleHandler(); + conHan.setLevel(debug ? Level.CONFIG : Level.WARNING); + SimpleFormatter formatterTxt = new SimpleFormatter(); + conHan.setFormatter(formatterTxt); + logger.addHandler(conHan); + clearLogFile(); + + } catch (Exception ex) { + throw new RuntimeException("Problems with creating the log files"); + } + } +} diff --git a/src/com/jpexs/decompiler/flash/tags/CSMTextSettingsTag.java b/src/com/jpexs/decompiler/flash/tags/CSMTextSettingsTag.java index a2e7069ad..3fb0d4449 100644 --- a/src/com/jpexs/decompiler/flash/tags/CSMTextSettingsTag.java +++ b/src/com/jpexs/decompiler/flash/tags/CSMTextSettingsTag.java @@ -83,10 +83,8 @@ public class CSMTextSettingsTag extends Tag { /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/DebugIDTag.java b/src/com/jpexs/decompiler/flash/tags/DebugIDTag.java index 662e12987..d4ad11238 100644 --- a/src/com/jpexs/decompiler/flash/tags/DebugIDTag.java +++ b/src/com/jpexs/decompiler/flash/tags/DebugIDTag.java @@ -56,10 +56,8 @@ public class DebugIDTag extends Tag { /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG4Tag.java b/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG4Tag.java index 1d6e35e83..1f02075c9 100644 --- a/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG4Tag.java +++ b/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG4Tag.java @@ -132,10 +132,8 @@ public class DefineBitsJPEG4Tag extends ImageTag implements AloneTag { /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/DefineBitsLossless2Tag.java b/src/com/jpexs/decompiler/flash/tags/DefineBitsLossless2Tag.java index bb3b30bee..015fbc48a 100644 --- a/src/com/jpexs/decompiler/flash/tags/DefineBitsLossless2Tag.java +++ b/src/com/jpexs/decompiler/flash/tags/DefineBitsLossless2Tag.java @@ -16,7 +16,6 @@ */ package com.jpexs.decompiler.flash.tags; -import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFLimitedInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; @@ -140,7 +139,7 @@ public class DefineBitsLossless2Tag extends ImageTag implements AloneTag { private void uncompressData() { try { - SWFInputStream sis = new SWFInputStream(Helper.readStream(new InflaterInputStream(new ByteArrayInputStream(zlibBitmapData))), SWF.DEFAULT_VERSION); + SWFInputStream sis = new SWFInputStream(swf, Helper.readStream(new InflaterInputStream(new ByteArrayInputStream(zlibBitmapData)))); if (bitmapFormat == FORMAT_8BIT_COLORMAPPED) { colorMapData = sis.readALPHACOLORMAPDATA(bitmapColorTableSize, bitmapWidth, bitmapHeight); } diff --git a/src/com/jpexs/decompiler/flash/tags/DefineBitsLosslessTag.java b/src/com/jpexs/decompiler/flash/tags/DefineBitsLosslessTag.java index 2fe5d7971..ed3e77249 100644 --- a/src/com/jpexs/decompiler/flash/tags/DefineBitsLosslessTag.java +++ b/src/com/jpexs/decompiler/flash/tags/DefineBitsLosslessTag.java @@ -16,7 +16,6 @@ */ package com.jpexs.decompiler.flash.tags; -import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFLimitedInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; @@ -171,7 +170,7 @@ public class DefineBitsLosslessTag extends ImageTag implements AloneTag { private void uncompressData() { try { - SWFInputStream sis = new SWFInputStream(Helper.readStream(new InflaterInputStream(new ByteArrayInputStream(zlibBitmapData))), SWF.DEFAULT_VERSION); + SWFInputStream sis = new SWFInputStream(swf, Helper.readStream(new InflaterInputStream(new ByteArrayInputStream(zlibBitmapData)))); if (bitmapFormat == FORMAT_8BIT_COLORMAPPED) { colorMapData = sis.readCOLORMAPDATA(bitmapColorTableSize, bitmapWidth, bitmapHeight); } diff --git a/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java b/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java index 877bb81b7..5fcaf7dfa 100644 --- a/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java +++ b/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java @@ -96,10 +96,8 @@ public class DefineButton2Tag extends ButtonTag implements Container { /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/DefineButtonCxformTag.java b/src/com/jpexs/decompiler/flash/tags/DefineButtonCxformTag.java index 489444c89..77f9093f8 100644 --- a/src/com/jpexs/decompiler/flash/tags/DefineButtonCxformTag.java +++ b/src/com/jpexs/decompiler/flash/tags/DefineButtonCxformTag.java @@ -58,10 +58,8 @@ public class DefineButtonCxformTag extends Tag { /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/DefineButtonSoundTag.java b/src/com/jpexs/decompiler/flash/tags/DefineButtonSoundTag.java index c21bd7c9b..bb1bf7b67 100644 --- a/src/com/jpexs/decompiler/flash/tags/DefineButtonSoundTag.java +++ b/src/com/jpexs/decompiler/flash/tags/DefineButtonSoundTag.java @@ -98,10 +98,8 @@ public class DefineButtonSoundTag extends CharacterIdTag { /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java b/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java index f88b82396..eb99742b9 100644 --- a/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java +++ b/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java @@ -17,6 +17,7 @@ package com.jpexs.decompiler.flash.tags; import com.jpexs.decompiler.flash.DisassemblyListener; +import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFLimitedInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; import com.jpexs.decompiler.flash.abc.CopyOutputStream; @@ -41,7 +42,6 @@ import com.jpexs.decompiler.flash.types.annotations.Internal; import com.jpexs.decompiler.flash.types.annotations.SWFType; import com.jpexs.helpers.Cache; import com.jpexs.helpers.Helper; -import com.jpexs.helpers.MemoryInputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -95,10 +95,8 @@ public class DefineButtonTag extends ButtonTag implements ASMSource { /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ @@ -106,7 +104,6 @@ public class DefineButtonTag extends ButtonTag implements ASMSource { super(sis.swf, ID, "DefineButton", pos, length); buttonId = sis.readUI16(); characters = sis.readBUTTONRECORDList(false); - //actions = sis.readActionList(); hdrSize = sis.getPos(); actionBytes = sis.readBytesEx(sis.available()); } @@ -148,7 +145,7 @@ public class DefineButtonTag extends ButtonTag implements ASMSource { if (actions == null) { actions = getActions(); } - return Action.actionsToString(listeners, 0, actions, null, swf.version, exportMode, writer, getPos() + hdrSize, toString()/*FIXME?*/); + return Action.actionsToString(listeners, 0, actions, null, swf.version, exportMode, writer, getDataPos() + hdrSize, toString()/*FIXME?*/); } /** @@ -170,11 +167,17 @@ public class DefineButtonTag extends ButtonTag implements ASMSource { @Override public List getActions() throws InterruptedException { try { - int prevLength = (int) (getPos() + hdrSize); - MemoryInputStream rri = new MemoryInputStream(swf.uncompressedData); - rri.seek(prevLength); - - List list = ActionListReader.readActionListTimeout(listeners, getPos() + hdrSize - prevLength, rri, getVersion(), prevLength, -1, toString()/*FIXME?*/); + int prevLength; + SWFInputStream rri; + if (actionBytes == null) { + prevLength = (int) (getDataPos() + hdrSize); + rri = new SWFInputStream(swf, swf.uncompressedData); + rri.seek(prevLength); + } else { + prevLength = 0; + rri = new SWFInputStream(swf, actionBytes); + } + List list = ActionListReader.readActionListTimeout(listeners, getDataPos() + hdrSize - prevLength, rri, getVersion(), prevLength, -1, toString()/*FIXME?*/); return list; } catch (InterruptedException ex) { throw ex; diff --git a/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java b/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java index bc3444f5d..baedecd37 100644 --- a/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java +++ b/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java @@ -694,10 +694,8 @@ public class DefineEditTextTag extends TextTag { /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/DefineFont2Tag.java b/src/com/jpexs/decompiler/flash/tags/DefineFont2Tag.java index d6860282e..e8153d237 100644 --- a/src/com/jpexs/decompiler/flash/tags/DefineFont2Tag.java +++ b/src/com/jpexs/decompiler/flash/tags/DefineFont2Tag.java @@ -191,10 +191,8 @@ public class DefineFont2Tag extends FontTag { /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/DefineFontInfo2Tag.java b/src/com/jpexs/decompiler/flash/tags/DefineFontInfo2Tag.java index 8351fcfca..1951d9400 100644 --- a/src/com/jpexs/decompiler/flash/tags/DefineFontInfo2Tag.java +++ b/src/com/jpexs/decompiler/flash/tags/DefineFontInfo2Tag.java @@ -87,10 +87,8 @@ public class DefineFontInfo2Tag extends Tag { /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/DefineFontInfoTag.java b/src/com/jpexs/decompiler/flash/tags/DefineFontInfoTag.java index 059a95bf8..e9f8e7296 100644 --- a/src/com/jpexs/decompiler/flash/tags/DefineFontInfoTag.java +++ b/src/com/jpexs/decompiler/flash/tags/DefineFontInfoTag.java @@ -88,10 +88,8 @@ public class DefineFontInfoTag extends Tag { /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/DefineFontTag.java b/src/com/jpexs/decompiler/flash/tags/DefineFontTag.java index ab72132ee..fbefab67b 100644 --- a/src/com/jpexs/decompiler/flash/tags/DefineFontTag.java +++ b/src/com/jpexs/decompiler/flash/tags/DefineFontTag.java @@ -135,10 +135,8 @@ public class DefineFontTag extends FontTag { /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java b/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java index c9798dd48..c4eb1f0d3 100644 --- a/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java +++ b/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java @@ -147,10 +147,8 @@ public class DefineMorphShape2Tag extends CharacterTag implements MorphShapeTag /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/DefineMorphShapeTag.java b/src/com/jpexs/decompiler/flash/tags/DefineMorphShapeTag.java index 97ca9307f..65890c9a4 100644 --- a/src/com/jpexs/decompiler/flash/tags/DefineMorphShapeTag.java +++ b/src/com/jpexs/decompiler/flash/tags/DefineMorphShapeTag.java @@ -125,10 +125,8 @@ public class DefineMorphShapeTag extends CharacterTag implements MorphShapeTag { /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/DefineSceneAndFrameLabelDataTag.java b/src/com/jpexs/decompiler/flash/tags/DefineSceneAndFrameLabelDataTag.java index ac2a51a95..e39bb25c8 100644 --- a/src/com/jpexs/decompiler/flash/tags/DefineSceneAndFrameLabelDataTag.java +++ b/src/com/jpexs/decompiler/flash/tags/DefineSceneAndFrameLabelDataTag.java @@ -77,10 +77,8 @@ public class DefineSceneAndFrameLabelDataTag extends Tag { /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/DefineSoundTag.java b/src/com/jpexs/decompiler/flash/tags/DefineSoundTag.java index 717721a21..d958ae8f6 100644 --- a/src/com/jpexs/decompiler/flash/tags/DefineSoundTag.java +++ b/src/com/jpexs/decompiler/flash/tags/DefineSoundTag.java @@ -95,10 +95,8 @@ public class DefineSoundTag extends CharacterTag implements SoundTag { /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ @@ -237,7 +235,7 @@ public class DefineSoundTag extends CharacterTag implements SoundTag { } } try { - MP3SOUNDDATA snd = new MP3SOUNDDATA(mp3data, swf.version, true); + MP3SOUNDDATA snd = new MP3SOUNDDATA(swf, mp3data, true); if (!snd.frames.isEmpty()) { MP3FRAME fr = snd.frames.get(0); newSoundRate = fr.getSamplingRate(); diff --git a/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java b/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java index 3ea919a0b..b8d798c2b 100644 --- a/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java +++ b/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java @@ -50,6 +50,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; /** @@ -191,9 +192,8 @@ public class DefineSpriteTag extends CharacterTag implements Container, Drawable /** * Constructor * - * @param swf - * @param headerData - * @param data Data bytes + * @param sis + * @param length * @param level * @param pos * @param parallel @@ -230,7 +230,9 @@ public class DefineSpriteTag extends CharacterTag implements Container, Drawable try { sos.writeUI16(spriteId); sos.writeUI16(frameCount); - sos.writeTags(subTags); + Map tagPositions = new HashMap<>(); + Map tagLengths = new HashMap<>(); + sos.writeTags(subTags, tagPositions, tagLengths); if (hasEndTag) { sos.writeUI16(0); } diff --git a/src/com/jpexs/decompiler/flash/tags/DefineText2Tag.java b/src/com/jpexs/decompiler/flash/tags/DefineText2Tag.java index 0ffc588ec..2f41304f1 100644 --- a/src/com/jpexs/decompiler/flash/tags/DefineText2Tag.java +++ b/src/com/jpexs/decompiler/flash/tags/DefineText2Tag.java @@ -459,10 +459,8 @@ public class DefineText2Tag extends TextTag { /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/DefineTextTag.java b/src/com/jpexs/decompiler/flash/tags/DefineTextTag.java index bb8d348f4..1c1bedc44 100644 --- a/src/com/jpexs/decompiler/flash/tags/DefineTextTag.java +++ b/src/com/jpexs/decompiler/flash/tags/DefineTextTag.java @@ -470,10 +470,8 @@ public class DefineTextTag extends TextTag { /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/DefineVideoStreamTag.java b/src/com/jpexs/decompiler/flash/tags/DefineVideoStreamTag.java index 0307fcb07..3d1d948bd 100644 --- a/src/com/jpexs/decompiler/flash/tags/DefineVideoStreamTag.java +++ b/src/com/jpexs/decompiler/flash/tags/DefineVideoStreamTag.java @@ -98,10 +98,8 @@ public class DefineVideoStreamTag extends CharacterTag implements BoundedTag { /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/DoABCDefineTag.java b/src/com/jpexs/decompiler/flash/tags/DoABCDefineTag.java index 48dd30461..02949df0a 100644 --- a/src/com/jpexs/decompiler/flash/tags/DoABCDefineTag.java +++ b/src/com/jpexs/decompiler/flash/tags/DoABCDefineTag.java @@ -65,10 +65,8 @@ public class DoABCDefineTag extends Tag implements ABCContainerTag { /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/DoABCTag.java b/src/com/jpexs/decompiler/flash/tags/DoABCTag.java index 93b7d7824..d1f96fdac 100644 --- a/src/com/jpexs/decompiler/flash/tags/DoABCTag.java +++ b/src/com/jpexs/decompiler/flash/tags/DoABCTag.java @@ -52,10 +52,8 @@ public class DoABCTag extends Tag implements ABCContainerTag { /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/DoActionTag.java b/src/com/jpexs/decompiler/flash/tags/DoActionTag.java index 659e866c3..7d92a5d57 100644 --- a/src/com/jpexs/decompiler/flash/tags/DoActionTag.java +++ b/src/com/jpexs/decompiler/flash/tags/DoActionTag.java @@ -18,6 +18,7 @@ package com.jpexs.decompiler.flash.tags; import com.jpexs.decompiler.flash.DisassemblyListener; import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFLimitedInputStream; import com.jpexs.decompiler.flash.action.Action; import com.jpexs.decompiler.flash.action.ActionListReader; @@ -26,7 +27,6 @@ import com.jpexs.decompiler.flash.helpers.GraphTextWriter; import com.jpexs.decompiler.flash.tags.base.ASMSource; import com.jpexs.decompiler.flash.types.annotations.Internal; import com.jpexs.helpers.Helper; -import com.jpexs.helpers.MemoryInputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -50,22 +50,22 @@ public class DoActionTag extends Tag implements ASMSource { /** * Constructor * - * @param swf - * @param headerData - * @param data Data bytes + * @param sis + * @param length * @param pos + * @throws java.io.IOException */ public DoActionTag(SWFLimitedInputStream sis, long pos, int length) throws IOException { super(sis.swf, ID, "DoAction", pos, length); - actionBytes = sis.readBytesEx(sis.available()); + //do not load actionBytes. Disassebler will use the original SWF stream in this case + //actionBytes = sis.readBytesEx(sis.available()); } /** * Constructor * * @param swf - * @param headerData - * @param data Data bytes + * @param length * @param pos */ public DoActionTag(SWF swf, long pos, int length) { @@ -96,7 +96,7 @@ public class DoActionTag extends Tag implements ASMSource { if (actions == null) { actions = getActions(); } - return Action.actionsToString(listeners, 0, actions, null, swf.version, exportMode, writer, getPos(), toString()/*FIXME?*/); + return Action.actionsToString(listeners, 0, actions, null, swf.version, exportMode, writer, getDataPos(), toString()/*FIXME?*/); } /** @@ -122,10 +122,17 @@ public class DoActionTag extends Tag implements ASMSource { @Override public List getActions() throws InterruptedException { try { - int prevLength = (int) getPos(); - MemoryInputStream rri = new MemoryInputStream(swf.uncompressedData); - rri.seek(prevLength); - List list = ActionListReader.readActionListTimeout(listeners, getPos() - prevLength, rri, getVersion(), prevLength, -1, toString()/*FIXME?*/); + int prevLength; + SWFInputStream rri; + if (actionBytes == null) { + prevLength = (int) getDataPos(); + rri = new SWFInputStream(swf, swf.uncompressedData); + rri.seek(prevLength); + } else { + prevLength = 0; + rri = new SWFInputStream(swf, actionBytes); + } + List list = ActionListReader.readActionListTimeout(listeners, getDataPos() - prevLength, rri, getVersion(), prevLength, -1, toString()/*FIXME?*/); return list; } catch (InterruptedException ex) { throw ex; diff --git a/src/com/jpexs/decompiler/flash/tags/DoInitActionTag.java b/src/com/jpexs/decompiler/flash/tags/DoInitActionTag.java index dee0415a4..6265f9327 100644 --- a/src/com/jpexs/decompiler/flash/tags/DoInitActionTag.java +++ b/src/com/jpexs/decompiler/flash/tags/DoInitActionTag.java @@ -17,6 +17,7 @@ package com.jpexs.decompiler.flash.tags; import com.jpexs.decompiler.flash.DisassemblyListener; +import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFLimitedInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; import com.jpexs.decompiler.flash.action.Action; @@ -29,7 +30,6 @@ import com.jpexs.decompiler.flash.types.BasicType; import com.jpexs.decompiler.flash.types.annotations.Internal; import com.jpexs.decompiler.flash.types.annotations.SWFType; import com.jpexs.helpers.Helper; -import com.jpexs.helpers.MemoryInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.ArrayList; @@ -55,10 +55,8 @@ public class DoInitActionTag extends CharacterIdTag implements ASMSource { /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ @@ -111,16 +109,23 @@ public class DoInitActionTag extends CharacterIdTag implements ASMSource { if (actions == null) { actions = getActions(); } - return Action.actionsToString(listeners, 0, actions, null, swf.version, exportMode, writer, getPos() + 2, toString()/*FIXME?*/); + return Action.actionsToString(listeners, 0, actions, null, swf.version, exportMode, writer, getDataPos() + 2, toString()/*FIXME?*/); } @Override public List getActions() throws InterruptedException { try { - int prevLength = (int) (getPos() + 2); - MemoryInputStream rri = new MemoryInputStream(swf.uncompressedData); - rri.seek(prevLength); - List list = ActionListReader.readActionListTimeout(listeners, getPos() + 2 - prevLength, rri, getVersion(), prevLength, -1, toString()/*FIXME?*/); + int prevLength; + SWFInputStream rri; + if (actionBytes == null) { + prevLength = (int) (getDataPos() + 2); + rri = new SWFInputStream(swf, swf.uncompressedData); + rri.seek(prevLength); + } else { + prevLength = 0; + rri = new SWFInputStream(swf, actionBytes); + } + List list = ActionListReader.readActionListTimeout(listeners, getDataPos() + 2 - prevLength, rri, getVersion(), prevLength, -1, toString()/*FIXME?*/); return list; } catch (InterruptedException ex) { throw ex; diff --git a/src/com/jpexs/decompiler/flash/tags/EnableDebugger2Tag.java b/src/com/jpexs/decompiler/flash/tags/EnableDebugger2Tag.java index 7c7023de4..d98fed5cb 100644 --- a/src/com/jpexs/decompiler/flash/tags/EnableDebugger2Tag.java +++ b/src/com/jpexs/decompiler/flash/tags/EnableDebugger2Tag.java @@ -63,10 +63,8 @@ public class EnableDebugger2Tag extends Tag { /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/EnableDebuggerTag.java b/src/com/jpexs/decompiler/flash/tags/EnableDebuggerTag.java index cdf2f4e63..20a3a2a26 100644 --- a/src/com/jpexs/decompiler/flash/tags/EnableDebuggerTag.java +++ b/src/com/jpexs/decompiler/flash/tags/EnableDebuggerTag.java @@ -57,10 +57,8 @@ public class EnableDebuggerTag extends Tag { /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/EnableTelemetryTag.java b/src/com/jpexs/decompiler/flash/tags/EnableTelemetryTag.java index fae9cfa61..c874a399a 100644 --- a/src/com/jpexs/decompiler/flash/tags/EnableTelemetryTag.java +++ b/src/com/jpexs/decompiler/flash/tags/EnableTelemetryTag.java @@ -66,10 +66,8 @@ public class EnableTelemetryTag extends Tag { /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/EndTag.java b/src/com/jpexs/decompiler/flash/tags/EndTag.java index c2d81f890..813f172cc 100644 --- a/src/com/jpexs/decompiler/flash/tags/EndTag.java +++ b/src/com/jpexs/decompiler/flash/tags/EndTag.java @@ -41,9 +41,7 @@ public class EndTag extends Tag { * Constructor * * @param swf - * @param headerData * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/ExportAssetsTag.java b/src/com/jpexs/decompiler/flash/tags/ExportAssetsTag.java index 4b0d309b1..aa263a6c9 100644 --- a/src/com/jpexs/decompiler/flash/tags/ExportAssetsTag.java +++ b/src/com/jpexs/decompiler/flash/tags/ExportAssetsTag.java @@ -55,9 +55,8 @@ public class ExportAssetsTag extends Tag { /** * Constructor * - * @param swf - * @param headerData - * @param data Data bytes + * @param sis + * @param length * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/ImportAssets2Tag.java b/src/com/jpexs/decompiler/flash/tags/ImportAssets2Tag.java index 7be353412..7fafabb26 100644 --- a/src/com/jpexs/decompiler/flash/tags/ImportAssets2Tag.java +++ b/src/com/jpexs/decompiler/flash/tags/ImportAssets2Tag.java @@ -58,10 +58,8 @@ public class ImportAssets2Tag extends Tag implements ImportTag { /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/ImportAssetsTag.java b/src/com/jpexs/decompiler/flash/tags/ImportAssetsTag.java index 7e356a559..ef4632ead 100644 --- a/src/com/jpexs/decompiler/flash/tags/ImportAssetsTag.java +++ b/src/com/jpexs/decompiler/flash/tags/ImportAssetsTag.java @@ -51,10 +51,8 @@ public class ImportAssetsTag extends Tag implements ImportTag { /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/PlaceObject2Tag.java b/src/com/jpexs/decompiler/flash/tags/PlaceObject2Tag.java index babdfcca3..a63aeff4f 100644 --- a/src/com/jpexs/decompiler/flash/tags/PlaceObject2Tag.java +++ b/src/com/jpexs/decompiler/flash/tags/PlaceObject2Tag.java @@ -213,10 +213,8 @@ public class PlaceObject2Tag extends CharacterIdTag implements Container, PlaceO /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/PlaceObject3Tag.java b/src/com/jpexs/decompiler/flash/tags/PlaceObject3Tag.java index 0d006d169..cf2eb74a3 100644 --- a/src/com/jpexs/decompiler/flash/tags/PlaceObject3Tag.java +++ b/src/com/jpexs/decompiler/flash/tags/PlaceObject3Tag.java @@ -297,10 +297,8 @@ public class PlaceObject3Tag extends CharacterIdTag implements Container, PlaceO /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/PlaceObject4Tag.java b/src/com/jpexs/decompiler/flash/tags/PlaceObject4Tag.java index d7678240b..dce9d30ac 100644 --- a/src/com/jpexs/decompiler/flash/tags/PlaceObject4Tag.java +++ b/src/com/jpexs/decompiler/flash/tags/PlaceObject4Tag.java @@ -298,10 +298,8 @@ public class PlaceObject4Tag extends CharacterIdTag implements Container, PlaceO /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/PlaceObjectTag.java b/src/com/jpexs/decompiler/flash/tags/PlaceObjectTag.java index 1e4c70355..ae1a7e251 100644 --- a/src/com/jpexs/decompiler/flash/tags/PlaceObjectTag.java +++ b/src/com/jpexs/decompiler/flash/tags/PlaceObjectTag.java @@ -99,10 +99,8 @@ public class PlaceObjectTag extends CharacterIdTag implements PlaceObjectTypeTag /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/ProtectTag.java b/src/com/jpexs/decompiler/flash/tags/ProtectTag.java index de19bb115..3be488b3c 100644 --- a/src/com/jpexs/decompiler/flash/tags/ProtectTag.java +++ b/src/com/jpexs/decompiler/flash/tags/ProtectTag.java @@ -57,10 +57,8 @@ public class ProtectTag extends Tag { /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/RemoveObjectTag.java b/src/com/jpexs/decompiler/flash/tags/RemoveObjectTag.java index c44a26a28..97987afcf 100644 --- a/src/com/jpexs/decompiler/flash/tags/RemoveObjectTag.java +++ b/src/com/jpexs/decompiler/flash/tags/RemoveObjectTag.java @@ -66,10 +66,8 @@ public class RemoveObjectTag extends CharacterIdTag implements RemoveTag { /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/SetTabIndexTag.java b/src/com/jpexs/decompiler/flash/tags/SetTabIndexTag.java index 002dc455d..44be7f654 100644 --- a/src/com/jpexs/decompiler/flash/tags/SetTabIndexTag.java +++ b/src/com/jpexs/decompiler/flash/tags/SetTabIndexTag.java @@ -64,10 +64,8 @@ public class SetTabIndexTag extends Tag { /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/ShowFrameTag.java b/src/com/jpexs/decompiler/flash/tags/ShowFrameTag.java index ab8b7c4bc..d1765636f 100644 --- a/src/com/jpexs/decompiler/flash/tags/ShowFrameTag.java +++ b/src/com/jpexs/decompiler/flash/tags/ShowFrameTag.java @@ -51,10 +51,8 @@ public class ShowFrameTag extends Tag { * Constructor * * @param swf - * @param headerData * @param length * @param pos - * @param data */ public ShowFrameTag(SWF swf, long pos, int length) { super(swf, ID, "ShowFrame", pos, length); diff --git a/src/com/jpexs/decompiler/flash/tags/SoundStreamBlockTag.java b/src/com/jpexs/decompiler/flash/tags/SoundStreamBlockTag.java index 5f821e88f..3e690c7a7 100644 --- a/src/com/jpexs/decompiler/flash/tags/SoundStreamBlockTag.java +++ b/src/com/jpexs/decompiler/flash/tags/SoundStreamBlockTag.java @@ -35,10 +35,8 @@ public class SoundStreamBlockTag extends Tag { /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/SoundStreamHead2Tag.java b/src/com/jpexs/decompiler/flash/tags/SoundStreamHead2Tag.java index 5baa19cb7..c7e12126c 100644 --- a/src/com/jpexs/decompiler/flash/tags/SoundStreamHead2Tag.java +++ b/src/com/jpexs/decompiler/flash/tags/SoundStreamHead2Tag.java @@ -136,10 +136,8 @@ public class SoundStreamHead2Tag extends CharacterIdTag implements SoundStreamHe /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/SoundStreamHeadTag.java b/src/com/jpexs/decompiler/flash/tags/SoundStreamHeadTag.java index d045cefd4..8062c903a 100644 --- a/src/com/jpexs/decompiler/flash/tags/SoundStreamHeadTag.java +++ b/src/com/jpexs/decompiler/flash/tags/SoundStreamHeadTag.java @@ -129,10 +129,8 @@ public class SoundStreamHeadTag extends CharacterIdTag implements SoundStreamHea /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/StartSound2Tag.java b/src/com/jpexs/decompiler/flash/tags/StartSound2Tag.java index 35e0cd4bc..ab1d3b6c9 100644 --- a/src/com/jpexs/decompiler/flash/tags/StartSound2Tag.java +++ b/src/com/jpexs/decompiler/flash/tags/StartSound2Tag.java @@ -54,10 +54,8 @@ public class StartSound2Tag extends Tag { /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/StartSoundTag.java b/src/com/jpexs/decompiler/flash/tags/StartSoundTag.java index 6078d3a40..0b78c3d1d 100644 --- a/src/com/jpexs/decompiler/flash/tags/StartSoundTag.java +++ b/src/com/jpexs/decompiler/flash/tags/StartSoundTag.java @@ -58,10 +58,8 @@ public class StartSoundTag extends Tag { /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/Tag.java b/src/com/jpexs/decompiler/flash/tags/Tag.java index 5c5370329..85fa1c603 100644 --- a/src/com/jpexs/decompiler/flash/tags/Tag.java +++ b/src/com/jpexs/decompiler/flash/tags/Tag.java @@ -331,16 +331,13 @@ public class Tag implements NeedsCharacters, Exportable, ContainerItem, Serializ * @throws IOException */ public void writeTag(SWFOutputStream sos) throws IOException { - int newLength; if (isModified()) { byte[] newData = getData(); byte[] newHeaderData = getHeader(newData); sos.write(newHeaderData); sos.write(newData); - newLength = newData.length + newHeaderData.length; } else { sos.write(swf.uncompressedData, (int) pos, length); - newLength = length; } //todo: honfika: update pos and length during save @@ -365,6 +362,10 @@ public class Tag implements NeedsCharacters, Exportable, ContainerItem, Serializ return getOriginalData(); } + public final int getOriginalLength() { + return length; + } + public final byte[] getOriginalData() { // todo honfika: do not copy data int dataLength = getOriginalDataLength(); @@ -373,16 +374,13 @@ public class Tag implements NeedsCharacters, Exportable, ContainerItem, Serializ return data; } - public final int getOriginalLength() { - return length; + public final int getOriginalDataLength() { + return length - (isLongOriginal() ? 6 : 2); } - public final int getOriginalDataLength() { + public final boolean isLongOriginal() { int shortLength = swf.uncompressedData[(int) pos] & 0x003F; - if (shortLength == 0x3f) { - return length - 6; - } - return length - 2; + return shortLength == 0x3f; } public boolean hasSubTags() { @@ -397,6 +395,10 @@ public class Tag implements NeedsCharacters, Exportable, ContainerItem, Serializ return pos; } + public long getDataPos() { + return pos + (isLongOriginal() ? 6 : 2); + } + public void setModified(boolean value) { modified = value; } diff --git a/src/com/jpexs/decompiler/flash/tags/TagStub.java b/src/com/jpexs/decompiler/flash/tags/TagStub.java index d7ec611e7..987ff7ea4 100644 --- a/src/com/jpexs/decompiler/flash/tags/TagStub.java +++ b/src/com/jpexs/decompiler/flash/tags/TagStub.java @@ -42,8 +42,7 @@ public class TagStub extends Tag { * Constructor * * @param swf - * @param headerData - * @param data Data bytes + * @param length * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/VideoFrameTag.java b/src/com/jpexs/decompiler/flash/tags/VideoFrameTag.java index 58029eaed..7582a5446 100644 --- a/src/com/jpexs/decompiler/flash/tags/VideoFrameTag.java +++ b/src/com/jpexs/decompiler/flash/tags/VideoFrameTag.java @@ -60,9 +60,8 @@ public class VideoFrameTag extends Tag { /** * Constructor * - * @param swf - * @param headerData - * @param data Data bytes + * @param sis + * @param length * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/gfx/DefineCompactedFont.java b/src/com/jpexs/decompiler/flash/tags/gfx/DefineCompactedFont.java index efdc387a9..564e30d6e 100644 --- a/src/com/jpexs/decompiler/flash/tags/gfx/DefineCompactedFont.java +++ b/src/com/jpexs/decompiler/flash/tags/gfx/DefineCompactedFont.java @@ -83,9 +83,8 @@ public final class DefineCompactedFont extends FontTag implements DrawableTag { /** * Constructor * - * @param swf - * @param headerData - * @param data Data bytes + * @param sis + * @param length * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalGradient.java b/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalGradient.java index ab4057a12..0c09eea5a 100644 --- a/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalGradient.java +++ b/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalGradient.java @@ -64,10 +64,8 @@ public class DefineExternalGradient extends Tag { /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalImage.java b/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalImage.java index 93bb5599c..a0dd38c2a 100644 --- a/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalImage.java +++ b/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalImage.java @@ -66,10 +66,8 @@ public class DefineExternalImage extends Tag { /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalImage2.java b/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalImage2.java index 6cb1f0079..0c3d32690 100644 --- a/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalImage2.java +++ b/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalImage2.java @@ -74,10 +74,8 @@ public class DefineExternalImage2 extends Tag { /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalSound.java b/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalSound.java index 21f416a01..d7152fd1f 100644 --- a/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalSound.java +++ b/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalSound.java @@ -74,10 +74,8 @@ public class DefineExternalSound extends Tag { /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalStreamSound.java b/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalStreamSound.java index bd64b535e..e9d00b979 100644 --- a/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalStreamSound.java +++ b/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalStreamSound.java @@ -72,10 +72,8 @@ public class DefineExternalStreamSound extends Tag { /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/gfx/DefineGradientMap.java b/src/com/jpexs/decompiler/flash/tags/gfx/DefineGradientMap.java index c26559ea0..7d5f9f6f5 100644 --- a/src/com/jpexs/decompiler/flash/tags/gfx/DefineGradientMap.java +++ b/src/com/jpexs/decompiler/flash/tags/gfx/DefineGradientMap.java @@ -56,10 +56,8 @@ public class DefineGradientMap extends Tag { /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/gfx/DefineSubImage.java b/src/com/jpexs/decompiler/flash/tags/gfx/DefineSubImage.java index ddb0ed78d..fad0ca99f 100644 --- a/src/com/jpexs/decompiler/flash/tags/gfx/DefineSubImage.java +++ b/src/com/jpexs/decompiler/flash/tags/gfx/DefineSubImage.java @@ -63,10 +63,8 @@ public class DefineSubImage extends Tag { /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/gfx/ExporterInfoTag.java b/src/com/jpexs/decompiler/flash/tags/gfx/ExporterInfoTag.java index dc2fed7e3..568237d7a 100644 --- a/src/com/jpexs/decompiler/flash/tags/gfx/ExporterInfoTag.java +++ b/src/com/jpexs/decompiler/flash/tags/gfx/ExporterInfoTag.java @@ -82,10 +82,8 @@ public class ExporterInfoTag extends Tag { /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/tags/gfx/FontTextureInfo.java b/src/com/jpexs/decompiler/flash/tags/gfx/FontTextureInfo.java index c1cbe6f66..3ae340aa9 100644 --- a/src/com/jpexs/decompiler/flash/tags/gfx/FontTextureInfo.java +++ b/src/com/jpexs/decompiler/flash/tags/gfx/FontTextureInfo.java @@ -84,10 +84,8 @@ public class FontTextureInfo extends Tag { /** * Constructor * - * @param swf - * @param headerData + * @param sis * @param length - * @param data Data bytes * @param pos * @throws IOException */ diff --git a/src/com/jpexs/decompiler/flash/types/BUTTONCONDACTION.java b/src/com/jpexs/decompiler/flash/types/BUTTONCONDACTION.java index 99342c399..1e3988e89 100644 --- a/src/com/jpexs/decompiler/flash/types/BUTTONCONDACTION.java +++ b/src/com/jpexs/decompiler/flash/types/BUTTONCONDACTION.java @@ -31,7 +31,6 @@ import com.jpexs.decompiler.flash.types.annotations.Conditional; import com.jpexs.decompiler.flash.types.annotations.Internal; import com.jpexs.decompiler.flash.types.annotations.SWFType; import com.jpexs.helpers.Helper; -import com.jpexs.helpers.MemoryInputStream; import java.io.IOException; import java.io.Serializable; import java.util.ArrayList; @@ -192,7 +191,7 @@ public class BUTTONCONDACTION implements ASMSource, Exportable, ContainerItem, S @Override public List getActions() throws InterruptedException { try { - List list = ActionListReader.readActionListTimeout(listeners, getPos() + 4, new MemoryInputStream(actionBytes), swf.version, 0, -1, toString()/*FIXME?*/); + List list = ActionListReader.readActionListTimeout(listeners, getPos() + 4, new SWFInputStream(swf, actionBytes), swf.version, 0, -1, toString()/*FIXME?*/); return list; } catch (InterruptedException ex) { diff --git a/src/com/jpexs/decompiler/flash/types/CLIPACTIONRECORD.java b/src/com/jpexs/decompiler/flash/types/CLIPACTIONRECORD.java index 7abcf2099..4e3edbe0e 100644 --- a/src/com/jpexs/decompiler/flash/types/CLIPACTIONRECORD.java +++ b/src/com/jpexs/decompiler/flash/types/CLIPACTIONRECORD.java @@ -30,7 +30,6 @@ import com.jpexs.decompiler.flash.tags.base.Exportable; import com.jpexs.decompiler.flash.types.annotations.Conditional; import com.jpexs.decompiler.flash.types.annotations.Internal; import com.jpexs.helpers.Helper; -import com.jpexs.helpers.MemoryInputStream; import java.io.IOException; import java.io.Serializable; import java.util.ArrayList; @@ -201,7 +200,7 @@ public class CLIPACTIONRECORD implements ASMSource, Exportable, ContainerItem, S @Override public List getActions() throws InterruptedException { try { - List list = ActionListReader.readActionListTimeout(listeners, getPos() + hdrPos, new MemoryInputStream(actionBytes), swf.version, 0, -1, toString()/*FIXME?*/); + List list = ActionListReader.readActionListTimeout(listeners, getPos() + hdrPos, new SWFInputStream(swf, actionBytes, 0), swf.version, 0, -1, toString()/*FIXME?*/); return list; } catch (InterruptedException ex) { throw ex; diff --git a/src/com/jpexs/decompiler/flash/types/FILLSTYLE.java b/src/com/jpexs/decompiler/flash/types/FILLSTYLE.java index 631d57f1e..8c5f41d51 100644 --- a/src/com/jpexs/decompiler/flash/types/FILLSTYLE.java +++ b/src/com/jpexs/decompiler/flash/types/FILLSTYLE.java @@ -77,6 +77,9 @@ public class FILLSTYLE implements NeedsCharacters, Serializable { || (fillStyleType == NON_SMOOTHED_REPEATING_BITMAP) || (fillStyleType == NON_SMOOTHED_CLIPPED_BITMAP)) { fillStyleType = SOLID; + if (color == null) { + color = inShape3 ? new RGBA(0, 0, 0, 0) : new RGB(0, 0, 0); + } } bitmapId = 0; return true; diff --git a/src/com/jpexs/decompiler/flash/types/sound/AdpcmDecoder.java b/src/com/jpexs/decompiler/flash/types/sound/AdpcmDecoder.java index a4cc77a0c..92190873b 100644 --- a/src/com/jpexs/decompiler/flash/types/sound/AdpcmDecoder.java +++ b/src/com/jpexs/decompiler/flash/types/sound/AdpcmDecoder.java @@ -204,7 +204,7 @@ public class AdpcmDecoder extends SoundDecoder { @Override public void decode(byte[] data, OutputStream os) throws IOException { int adpcm_code_size; - SWFInputStream sis = new SWFInputStream(data, SWF.DEFAULT_VERSION); + SWFInputStream sis = new SWFInputStream(null, data); SWFOutputStream sos = new SWFOutputStream(os, SWF.DEFAULT_VERSION); adpcm_code_size = (int) sis.readUB(2); int bits_per_code = adpcm_code_size + 2; diff --git a/src/com/jpexs/decompiler/flash/types/sound/MP3SOUNDDATA.java b/src/com/jpexs/decompiler/flash/types/sound/MP3SOUNDDATA.java index fef368f45..4ca3464b4 100644 --- a/src/com/jpexs/decompiler/flash/types/sound/MP3SOUNDDATA.java +++ b/src/com/jpexs/decompiler/flash/types/sound/MP3SOUNDDATA.java @@ -16,6 +16,7 @@ */ package com.jpexs.decompiler.flash.types.sound; +import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -33,8 +34,8 @@ public class MP3SOUNDDATA { public int seekSamples; public List frames; - public MP3SOUNDDATA(byte[] data, int version, boolean raw) throws IOException { - SWFInputStream sis = new SWFInputStream(data, version); + public MP3SOUNDDATA(SWF swf, byte[] data, boolean raw) throws IOException { + SWFInputStream sis = new SWFInputStream(swf, data); if (!raw) { seekSamples = sis.readSI16(); } diff --git a/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java b/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java index 4d6bb209a..eeb24ec0c 100644 --- a/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java +++ b/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java @@ -1437,7 +1437,7 @@ public class XFLConverter { bits = 18; } if (soundFormat == SoundFormat.FORMAT_ADPCM) { - SWFInputStream sis = new SWFInputStream(soundData, swf.version); + SWFInputStream sis = new SWFInputStream(swf, soundData); exportFormat = "wav"; try { int adpcmCodeSize = (int) sis.readUB(2); @@ -1453,7 +1453,7 @@ public class XFLConverter { } format += 4; //quality best try { - MP3SOUNDDATA s = new MP3SOUNDDATA(soundData, swf.version, false); + MP3SOUNDDATA s = new MP3SOUNDDATA(swf, soundData, false); //sis.readSI16(); //MP3FRAME frame = new MP3FRAME(sis); MP3FRAME frame = s.frames.get(0); diff --git a/test/com/jpexs/decompiler/flash/SWFStreamTest.java b/test/com/jpexs/decompiler/flash/SWFStreamTest.java index 3e5bc951a..09f8e580b 100644 --- a/test/com/jpexs/decompiler/flash/SWFStreamTest.java +++ b/test/com/jpexs/decompiler/flash/SWFStreamTest.java @@ -56,7 +56,7 @@ public class SWFStreamTest { try (SWFOutputStream sos = new SWFOutputStream(baos, SWF.DEFAULT_VERSION)) { sos.writeFB(20, f); } - try (SWFInputStream sis = new SWFInputStream(baos.toByteArray(), SWF.DEFAULT_VERSION)) { + try (SWFInputStream sis = new SWFInputStream(null, baos.toByteArray())) { assertTrue(Double.compare(f, sis.readFB(20)) == 0); } } @@ -71,7 +71,7 @@ public class SWFStreamTest { sos.writeUB(8, 4); sos.writeUB(9, 5); } - try (SWFInputStream sis = new SWFInputStream(baos.toByteArray(), SWF.DEFAULT_VERSION)) { + try (SWFInputStream sis = new SWFInputStream(null, baos.toByteArray())) { assertEquals(1, sis.readUB(5)); assertEquals(2, sis.readUB(6)); assertEquals(3, sis.readUB(7)); @@ -90,7 +90,7 @@ public class SWFStreamTest { sos.writeSB(8, 4); sos.writeSB(9, -5); } - try (SWFInputStream sis = new SWFInputStream(baos.toByteArray(), SWF.DEFAULT_VERSION)) { + try (SWFInputStream sis = new SWFInputStream(null, baos.toByteArray())) { assertEquals(-1, sis.readSB(5)); assertEquals(2, sis.readSB(6)); assertEquals(-3, sis.readSB(7)); @@ -106,7 +106,7 @@ public class SWFStreamTest { float f = 5.25f; sos.writeFLOAT(f); sos.close(); - SWFInputStream sis = new SWFInputStream(baos.toByteArray(), SWF.DEFAULT_VERSION); + SWFInputStream sis = new SWFInputStream(null, baos.toByteArray()); assertEquals(f, sis.readFLOAT()); sis.close(); @@ -115,7 +115,7 @@ public class SWFStreamTest { f = 5.25f; sos.writeFLOAT16(f); sos.close(); - sis = new SWFInputStream(baos.toByteArray(), SWF.DEFAULT_VERSION); + sis = new SWFInputStream(null, baos.toByteArray()); assertEquals(f, sis.readFLOAT16()); sis.close(); @@ -124,7 +124,7 @@ public class SWFStreamTest { double d = 5.25; sos.writeDOUBLE(d); sos.close(); - sis = new SWFInputStream(baos.toByteArray(), SWF.DEFAULT_VERSION); + sis = new SWFInputStream(null, baos.toByteArray()); assertEquals(d, sis.readDOUBLE()); sis.close(); } @@ -133,7 +133,7 @@ public class SWFStreamTest { public void testFIXEDandFIXED8() throws IOException { //example from specification byte[] data = new byte[]{(byte) 0x00, (byte) 0x80, (byte) 0x07, (byte) 0x00}; - SWFInputStream sis = new SWFInputStream(data, SWF.DEFAULT_VERSION); + SWFInputStream sis = new SWFInputStream(null, data); assertTrue(Double.compare(7.5, sis.readFIXED()) == 0); sis.close(); @@ -142,7 +142,7 @@ public class SWFStreamTest { double dd = 5.25; sos.writeFIXED(dd); sos.close(); - sis = new SWFInputStream(baos.toByteArray(), SWF.DEFAULT_VERSION); + sis = new SWFInputStream(null, baos.toByteArray()); assertTrue(Double.compare(dd, sis.readFIXED()) == 0); sis.close(); @@ -151,7 +151,7 @@ public class SWFStreamTest { float ff = 5.25f; sos.writeFIXED8(ff); sos.close(); - sis = new SWFInputStream(baos.toByteArray(), SWF.DEFAULT_VERSION); + sis = new SWFInputStream(null, baos.toByteArray()); assertEquals(ff, sis.readFIXED8()); sis.close(); } @@ -164,7 +164,7 @@ public class SWFStreamTest { rect = new RECT(-0x80000000, 0x7FFFFFFF, -0x80000000, 0x7FFFFFFF); sos.writeRECT(rect); } - try (SWFInputStream sis = new SWFInputStream(baos.toByteArray(), SWF.DEFAULT_VERSION)) { + try (SWFInputStream sis = new SWFInputStream(null, baos.toByteArray())) { RECT readRECT = sis.readRECT(); assertEquals(readRECT.Xmin, -0x3FFFFFFF); assertEquals(readRECT.Xmax, 0x3FFFFFFF);