mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-09-27 00:50:47 +00:00
More documentation.
This commit is contained in:
@@ -17,22 +17,46 @@
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
/**
|
||||
*
|
||||
* A handler for abort, retry, ignore, ignore all dialog
|
||||
* @author JPEXS
|
||||
*/
|
||||
public interface AbortRetryIgnoreHandler {
|
||||
|
||||
/**
|
||||
* Undefined result
|
||||
*/
|
||||
public static int UNDEFINED = -1;
|
||||
|
||||
/**
|
||||
* Abort result
|
||||
*/
|
||||
public static int ABORT = 0;
|
||||
|
||||
/**
|
||||
* Retry result
|
||||
*/
|
||||
public static int RETRY = 1;
|
||||
|
||||
/**
|
||||
* Ignore result
|
||||
*/
|
||||
public static int IGNORE = 2;
|
||||
|
||||
/**
|
||||
* Ignore all result
|
||||
*/
|
||||
public static int IGNORE_ALL = 3;
|
||||
|
||||
/**
|
||||
* Handles the thrown exception
|
||||
* @param thrown The thrown exception
|
||||
* @return The result
|
||||
*/
|
||||
public int handle(Throwable thrown);
|
||||
|
||||
/**
|
||||
* Returns a new instance of this handler
|
||||
* @return A new instance of this handler
|
||||
*/
|
||||
public AbortRetryIgnoreHandler getNewInstance();
|
||||
}
|
||||
|
||||
@@ -19,17 +19,31 @@ package com.jpexs.decompiler.flash;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
*
|
||||
* Application resources
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class AppResources {
|
||||
|
||||
/**
|
||||
* Resource bundle
|
||||
*/
|
||||
private static final ResourceBundle resourceBundle = ResourceBundle.getBundle("com.jpexs.decompiler.flash.locales.AppResources");
|
||||
|
||||
/**
|
||||
* Translates a key
|
||||
* @param key The key
|
||||
* @return The translated key
|
||||
*/
|
||||
public static String translate(String key) {
|
||||
return resourceBundle.getString(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates a key from a bundle
|
||||
* @param bundle The bundle
|
||||
* @param key The key
|
||||
* @return The translated key
|
||||
*/
|
||||
public static String translate(String bundle, String key) {
|
||||
ResourceBundle b = ResourceBundle.getBundle(bundle);
|
||||
return b.getString(key);
|
||||
|
||||
@@ -20,43 +20,94 @@ import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
*
|
||||
* Application information
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ApplicationInfo {
|
||||
|
||||
/**
|
||||
* Application name
|
||||
*/
|
||||
public static final String APPLICATION_NAME = "JPEXS Free Flash Decompiler";
|
||||
|
||||
/**
|
||||
* CLI application name
|
||||
*/
|
||||
public static final String CLI_APPLICATION_NAME = "@|blue JPEXS|@ @|green Free|@ @|red Flash Decompiler|@";
|
||||
|
||||
/**
|
||||
* Short application name
|
||||
*/
|
||||
public static final String SHORT_APPLICATION_NAME = "FFDec";
|
||||
|
||||
/**
|
||||
* Vendor
|
||||
*/
|
||||
public static final String VENDOR = "JPEXS";
|
||||
|
||||
/**
|
||||
* Library version
|
||||
*/
|
||||
public static String libraryVersion = "";
|
||||
|
||||
/**
|
||||
* Version
|
||||
*/
|
||||
public static String version = "";
|
||||
|
||||
/**
|
||||
* Revision
|
||||
*/
|
||||
public static String revision = "";
|
||||
|
||||
/**
|
||||
* Version major
|
||||
*/
|
||||
public static int version_major = 4;
|
||||
|
||||
/**
|
||||
* Version minor
|
||||
*/
|
||||
public static int version_minor = 0;
|
||||
|
||||
/**
|
||||
* Version release
|
||||
*/
|
||||
public static int version_release = 0;
|
||||
|
||||
/**
|
||||
* Version build
|
||||
*/
|
||||
public static int version_build = 0;
|
||||
|
||||
/**
|
||||
* Nightly
|
||||
*/
|
||||
public static boolean nightly = false;
|
||||
|
||||
/**
|
||||
* CLI application version name
|
||||
*/
|
||||
public static String cliApplicationVerName;
|
||||
|
||||
/**
|
||||
* Application version name
|
||||
*/
|
||||
public static String applicationVerName;
|
||||
|
||||
/**
|
||||
* Short application version name
|
||||
*/
|
||||
public static String shortApplicationVerName;
|
||||
|
||||
/**
|
||||
* Git hub project
|
||||
*/
|
||||
public static final String GIT_HUB_PROJECT = "jindrapetrik/jpexs-decompiler";
|
||||
|
||||
/**
|
||||
* Project page
|
||||
*/
|
||||
public static final String PROJECT_PAGE = "https://github.com/" + GIT_HUB_PROJECT;
|
||||
|
||||
/**
|
||||
@@ -79,6 +130,9 @@ public class ApplicationInfo {
|
||||
loadLibraryVersion();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads library version
|
||||
*/
|
||||
private static void loadLibraryVersion() {
|
||||
Properties prop = new Properties();
|
||||
try {
|
||||
@@ -97,6 +151,9 @@ public class ApplicationInfo {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads properties.
|
||||
*/
|
||||
private static void loadProperties() {
|
||||
Properties prop = new Properties();
|
||||
try {
|
||||
|
||||
@@ -19,18 +19,28 @@ package com.jpexs.decompiler.flash;
|
||||
import com.jpexs.decompiler.graph.GraphPart;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItem;
|
||||
import com.jpexs.decompiler.graph.SecondPassData;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* Base local data
|
||||
* @author JPEXS
|
||||
*/
|
||||
public abstract class BaseLocalData {
|
||||
|
||||
/**
|
||||
* Line start instruction
|
||||
*/
|
||||
public GraphSourceItem lineStartInstruction;
|
||||
|
||||
/**
|
||||
* Set of all switch parts
|
||||
*/
|
||||
public Set<GraphPart> allSwitchParts = new HashSet<>();
|
||||
|
||||
/**
|
||||
* Second pass data
|
||||
*/
|
||||
public SecondPassData secondPassData = null;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.jpexs.decompiler.flash;
|
||||
|
||||
import com.jpexs.helpers.SwfHeaderStreamSearch;
|
||||
import com.jpexs.helpers.streams.SeekableInputStream;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -26,23 +27,41 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* Binary search SWF bundle
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class BinarySWFBundle implements Bundle {
|
||||
|
||||
/**
|
||||
* SWF search
|
||||
*/
|
||||
private final SWFSearch search;
|
||||
|
||||
/**
|
||||
* Constructs a new BinarySWFBundle.
|
||||
* @param is Input stream
|
||||
* @param noCheck Do not check
|
||||
* @param searchMode Search mode
|
||||
* @throws IOException
|
||||
*/
|
||||
public BinarySWFBundle(InputStream is, boolean noCheck, SearchMode searchMode) throws IOException {
|
||||
search = new SWFSearch(new SwfHeaderStreamSearch(is), noCheck, searchMode);
|
||||
search.process();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets size of the search.
|
||||
* @return Size of the search
|
||||
*/
|
||||
@Override
|
||||
public int length() {
|
||||
return search.length();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets keys.
|
||||
* @return Keys
|
||||
*/
|
||||
@Override
|
||||
public Set<String> getKeys() {
|
||||
Set<String> ret = new LinkedHashSet<>();
|
||||
@@ -52,6 +71,11 @@ public class BinarySWFBundle implements Bundle {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets openable.
|
||||
* @param key Key
|
||||
* @return Openable
|
||||
*/
|
||||
@Override
|
||||
public SeekableInputStream getOpenable(String key) {
|
||||
if (!key.startsWith("[")) {
|
||||
@@ -69,6 +93,10 @@ public class BinarySWFBundle implements Bundle {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all.
|
||||
* @return Map of string to seekable input stream
|
||||
*/
|
||||
@Override
|
||||
public Map<String, SeekableInputStream> getAll() {
|
||||
Map<String, SeekableInputStream> ret = new LinkedHashMap<>();
|
||||
@@ -78,16 +106,30 @@ public class BinarySWFBundle implements Bundle {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets extension.
|
||||
* @return Extension
|
||||
*/
|
||||
@Override
|
||||
public String getExtension() {
|
||||
return "bin";
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if read only.
|
||||
* @return True if read only, false otherwise
|
||||
*/
|
||||
@Override
|
||||
public boolean isReadOnly() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces openable.
|
||||
* @param key Key
|
||||
* @param is Input stream
|
||||
* @return True if successful, false otherwise
|
||||
*/
|
||||
@Override
|
||||
public boolean putOpenable(String key, InputStream is) {
|
||||
throw new UnsupportedOperationException("Save not supported for this type of bundle");
|
||||
|
||||
@@ -17,28 +17,64 @@
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
import com.jpexs.helpers.streams.SeekableInputStream;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* Bundle interface.
|
||||
* A bundle is a collection of openable files. (e.g. SWC, ZIP, etc.)
|
||||
* @author JPEXS
|
||||
*/
|
||||
public interface Bundle {
|
||||
|
||||
/**
|
||||
* Gets number of openable files in the bundle.
|
||||
* @return Number of openable files in the bundle
|
||||
*/
|
||||
public int length();
|
||||
|
||||
/**
|
||||
* Gets keys of openable files in the bundle.
|
||||
* @return Keys of openable files in the bundle
|
||||
*/
|
||||
public Set<String> getKeys();
|
||||
|
||||
/**
|
||||
* Gets openable file by key.
|
||||
* @param key Key
|
||||
* @return Openable file
|
||||
* @throws IOException
|
||||
*/
|
||||
public SeekableInputStream getOpenable(String key) throws IOException;
|
||||
|
||||
/**
|
||||
* Gets all openable files in the bundle.
|
||||
* @return Map from key to seekable input stream
|
||||
* @throws IOException
|
||||
*/
|
||||
public Map<String, SeekableInputStream> getAll() throws IOException;
|
||||
|
||||
/**
|
||||
* Gets extension of the bundle. (without dot)
|
||||
* @return Extension of the bundle
|
||||
*/
|
||||
public String getExtension();
|
||||
|
||||
/**
|
||||
* Checks if the bundle is read-only.
|
||||
* @return True if the bundle is read-only, false otherwise
|
||||
*/
|
||||
public boolean isReadOnly();
|
||||
|
||||
/**
|
||||
* Replace openable file by key.
|
||||
* @param key Key
|
||||
* @param is New input stream
|
||||
* @return True if the file was replaced, false otherwise
|
||||
* @throws IOException
|
||||
*/
|
||||
public boolean putOpenable(String key, InputStream is) throws IOException;
|
||||
}
|
||||
|
||||
@@ -30,29 +30,34 @@ import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter;
|
||||
import com.jpexs.decompiler.flash.tags.base.ASMSource;
|
||||
import com.jpexs.decompiler.flash.treeitems.Openable;
|
||||
import com.jpexs.helpers.ImmediateFuture;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* Decompiler thread pool.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class DecompilerPool {
|
||||
|
||||
/**
|
||||
* Executor
|
||||
*/
|
||||
private final ThreadPoolExecutor executor;
|
||||
|
||||
/**
|
||||
* Openable to futures map
|
||||
*/
|
||||
private Map<Openable, List<Future<HighlightedText>>> openableToFutures = new WeakHashMap<>();
|
||||
|
||||
/**
|
||||
* Constructs a new DecompilerPool.
|
||||
*/
|
||||
public DecompilerPool() {
|
||||
int threadCount = Configuration.getParallelThreadCount();
|
||||
executor = new ThreadPoolExecutor(threadCount, threadCount,
|
||||
@@ -60,6 +65,13 @@ public class DecompilerPool {
|
||||
new LinkedBlockingQueue<>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits a task.
|
||||
* @param src Source
|
||||
* @param actions Actions
|
||||
* @param listener Listener
|
||||
* @return Future
|
||||
*/
|
||||
public Future<HighlightedText> submitTask(ASMSource src, ActionList actions, ScriptDecompiledListener<HighlightedText> listener) {
|
||||
Callable<HighlightedText> callable = new Callable<HighlightedText>() {
|
||||
@Override
|
||||
@@ -92,6 +104,13 @@ public class DecompilerPool {
|
||||
return submit(callable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits a task.
|
||||
* @param abcIndex ABC index
|
||||
* @param pack Script pack
|
||||
* @param listener Listener
|
||||
* @return Future
|
||||
*/
|
||||
public Future<HighlightedText> submitTask(AbcIndexing abcIndex, ScriptPack pack, ScriptDecompiledListener<HighlightedText> listener) {
|
||||
Callable<HighlightedText> callable = new Callable<HighlightedText>() {
|
||||
@Override
|
||||
@@ -128,6 +147,11 @@ public class DecompilerPool {
|
||||
return submit(callable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits a task.
|
||||
* @param callable Callable
|
||||
* @return Future
|
||||
*/
|
||||
private Future<HighlightedText> submit(Callable<HighlightedText> callable) {
|
||||
boolean parallel = Configuration.parallelSpeedUp.get();
|
||||
if (parallel) {
|
||||
@@ -149,6 +173,10 @@ public class DecompilerPool {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets statistics.
|
||||
* @return Statistics
|
||||
*/
|
||||
public String getStat() {
|
||||
return "core: " + executor.getCorePoolSize()
|
||||
+ " size: " + executor.getPoolSize()
|
||||
@@ -159,6 +187,13 @@ public class DecompilerPool {
|
||||
+ " completed: " + executor.getCompletedTaskCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Decompiles ASM source.
|
||||
* @param src ASM source
|
||||
* @param actions Actions
|
||||
* @return Highlighted text
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public HighlightedText decompile(ASMSource src, ActionList actions) throws InterruptedException {
|
||||
Future<HighlightedText> future = submitTask(src, actions, null);
|
||||
SWF swf = src.getSwf();
|
||||
@@ -183,6 +218,13 @@ public class DecompilerPool {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decompiles a script pack.
|
||||
* @param abcIndex ABC indexing
|
||||
* @param pack Script pack
|
||||
* @return Highlighted text
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public HighlightedText decompile(AbcIndexing abcIndex, ScriptPack pack) throws InterruptedException {
|
||||
Future<HighlightedText> future = submitTask(abcIndex, pack, null);
|
||||
|
||||
@@ -208,11 +250,19 @@ public class DecompilerPool {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shuts down the pool.
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public void shutdown() throws InterruptedException {
|
||||
executor.shutdown();
|
||||
executor.awaitTermination(100, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys a SWF.
|
||||
* @param swf SWF
|
||||
*/
|
||||
public void destroySwf(SWF swf) {
|
||||
List<Future<HighlightedText>> futures = openableToFutures.get(swf);
|
||||
if (futures != null) {
|
||||
|
||||
@@ -17,10 +17,13 @@
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
/**
|
||||
*
|
||||
* Listener for deobfuscation events.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public interface DeobfuscationListener {
|
||||
|
||||
/**
|
||||
* Called when an item is deobfuscated.
|
||||
*/
|
||||
public void itemDeobfuscated();
|
||||
}
|
||||
|
||||
@@ -17,14 +17,29 @@
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
/**
|
||||
*
|
||||
* Listener for disassembly events.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public interface DisassemblyListener {
|
||||
|
||||
/**
|
||||
* Called on progress of reading.
|
||||
* @param pos Position
|
||||
* @param total Total length
|
||||
*/
|
||||
public void progressReading(long pos, long total);
|
||||
|
||||
/**
|
||||
* Called on progress of deobfuscating.
|
||||
* @param pos Position
|
||||
* @param total Total length
|
||||
*/
|
||||
public void progressToString(long pos, long total);
|
||||
|
||||
/**
|
||||
* Called on progress of deobfuscating.
|
||||
* @param pos Position
|
||||
* @param total Total length
|
||||
*/
|
||||
public void progressDeobfuscating(long pos, long total);
|
||||
}
|
||||
|
||||
@@ -19,11 +19,14 @@ package com.jpexs.decompiler.flash;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
*
|
||||
* Exception thrown when end of stream is reached.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class EndOfStreamException extends IOException {
|
||||
|
||||
/**
|
||||
* Constructs a new EndOfStreamException.
|
||||
*/
|
||||
public EndOfStreamException() {
|
||||
super("Premature end of the stream reached");
|
||||
}
|
||||
|
||||
@@ -17,14 +17,33 @@
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
/**
|
||||
*
|
||||
* Interface for listening to events.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public interface EventListener {
|
||||
|
||||
/**
|
||||
* Handles exporting event.
|
||||
* @param type Event type
|
||||
* @param index Index of the exported item
|
||||
* @param count Total count of exported items
|
||||
* @param data Data
|
||||
*/
|
||||
public void handleExportingEvent(String type, int index, int count, Object data);
|
||||
|
||||
/**
|
||||
* Handles exported event.
|
||||
* @param type Event type
|
||||
* @param index Index of the exported item
|
||||
* @param count Total count of exported items
|
||||
* @param data Data
|
||||
*/
|
||||
public void handleExportedEvent(String type, int index, int count, Object data);
|
||||
|
||||
/**
|
||||
* Handles event.
|
||||
* @param event Event name
|
||||
* @param data Data
|
||||
*/
|
||||
public void handleEvent(String event, Object data);
|
||||
}
|
||||
|
||||
@@ -17,32 +17,49 @@
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
import com.jpexs.decompiler.graph.Loop;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* Final decompilation processing local d ata.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class FinalProcessLocalData {
|
||||
|
||||
/**
|
||||
* Temporary registers used in the code.
|
||||
*/
|
||||
public final HashSet<Integer> temporaryRegisters;
|
||||
|
||||
/**
|
||||
* Loops in the code.
|
||||
*/
|
||||
public final List<Loop> loops;
|
||||
|
||||
/**
|
||||
* Register usage. Map of setLocal ip to set of getLocal ips.
|
||||
*/
|
||||
public Map<Integer, Set<Integer>> registerUsage;
|
||||
|
||||
public Set<Integer> getRegisterUsage(int regIndex) {
|
||||
/**
|
||||
* Returns register usage for given setLocal ip.
|
||||
* @param setLocalIp SetLocal ip
|
||||
* @return Set of getLocal ips
|
||||
*/
|
||||
public Set<Integer> getRegisterUsage(int setLocalIp) {
|
||||
if (registerUsage == null) {
|
||||
return new HashSet<>();
|
||||
}
|
||||
if (!registerUsage.containsKey(regIndex)) {
|
||||
if (!registerUsage.containsKey(setLocalIp)) {
|
||||
return new HashSet<>();
|
||||
}
|
||||
return registerUsage.get(regIndex);
|
||||
return registerUsage.get(setLocalIp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs new FinalProcessLocalData.
|
||||
* @param loops Loops in the code
|
||||
*/
|
||||
public FinalProcessLocalData(List<Loop> loops) {
|
||||
temporaryRegisters = new HashSet<>();
|
||||
registerUsage = new HashMap<>();
|
||||
|
||||
@@ -25,49 +25,90 @@ import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag;
|
||||
import com.jpexs.decompiler.graph.DottedChain;
|
||||
import com.jpexs.helpers.Cache;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
*
|
||||
* Identifiers deobfuscation.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class IdentifiersDeobfuscation {
|
||||
|
||||
/**
|
||||
* Random number generator.
|
||||
*/
|
||||
private static final Random rnd = new Random();
|
||||
|
||||
/**
|
||||
* Default size of random string.
|
||||
*/
|
||||
private final int DEFAULT_FOO_SIZE = 10;
|
||||
|
||||
/**
|
||||
* All variable names.
|
||||
*/
|
||||
public HashSet<String> allVariableNamesStr = new HashSet<>();
|
||||
|
||||
/**
|
||||
* Type counts.
|
||||
*/
|
||||
private final HashMap<String, Integer> typeCounts = new HashMap<>();
|
||||
|
||||
/**
|
||||
* AS2 name cache.
|
||||
*/
|
||||
private static final Cache<String, String> as2NameCache = Cache.getInstance(false, true, "as2_ident", true);
|
||||
|
||||
/**
|
||||
* AS3 name cache.
|
||||
*/
|
||||
private static final Cache<String, String> as3NameCache = Cache.getInstance(false, true, "as3_ident", true);
|
||||
|
||||
/**
|
||||
* Valid first characters.
|
||||
*/
|
||||
public static final String VALID_FIRST_CHARACTERS = "\\p{Lu}\\p{Ll}\\p{Lt}\\p{Lm}\\p{Lo}_$";
|
||||
|
||||
/**
|
||||
* Valid next characters.
|
||||
*/
|
||||
public static final String VALID_NEXT_CHARACTERS = VALID_FIRST_CHARACTERS + "\\p{Nl}\\p{Mn}\\p{Mc}\\p{Nd}\\p{Pc}";
|
||||
|
||||
/**
|
||||
* Valid name pattern.
|
||||
*/
|
||||
private static final Pattern VALID_NAME_PATTERN = Pattern.compile("^[a-zA-Z_\\$][a-zA-Z0-9_\\$]*$");
|
||||
|
||||
/**
|
||||
* Identifier pattern.
|
||||
*/
|
||||
private static final Pattern IDENTIFIER_PATTERN = Pattern.compile("^[" + VALID_FIRST_CHARACTERS + "][" + VALID_NEXT_CHARACTERS + "]*$");
|
||||
|
||||
/**
|
||||
* Valid name pattern with dot.
|
||||
*/
|
||||
private static final Pattern VALID_NAME_PATTERN_DOT = Pattern.compile("^[a-zA-Z_\\$][a-zA-Z0-9_.\\$]*$");
|
||||
|
||||
/**
|
||||
* Identifier pattern with dot.
|
||||
*/
|
||||
private static final Pattern IDENTIFIER_PATTERN_DOT = Pattern.compile("^[" + VALID_FIRST_CHARACTERS + "][" + VALID_NEXT_CHARACTERS + ".]*$");
|
||||
|
||||
/**
|
||||
* Random name generator characters.
|
||||
*/
|
||||
public static final String FOO_CHARACTERS = "bcdfghjklmnpqrstvwz";
|
||||
|
||||
/**
|
||||
* Random name generator join characters.
|
||||
*/
|
||||
public static final String FOO_JOIN_CHARACTERS = "aeiouy";
|
||||
|
||||
// http://help.adobe.com/en_US/AS2LCR/Flash_10.0/help.html?content=00000477.html
|
||||
/**
|
||||
* Reserved words in AS2.
|
||||
* http://help.adobe.com/en_US/AS2LCR/Flash_10.0/help.html?content=00000477.html
|
||||
*/
|
||||
public static final String[] reservedWordsAS2 = {
|
||||
// is "add" really a keyword? documentation says yes, but I can create "add" variable in CS6...
|
||||
// "add",
|
||||
@@ -99,7 +140,10 @@ public class IdentifiersDeobfuscation {
|
||||
"typeof", "undefined", "var", "void", "while", "with"
|
||||
};
|
||||
|
||||
// http://www.adobe.com/devnet/actionscript/learning/as3-fundamentals/syntax.html
|
||||
/**
|
||||
* Reserved words in AS3.
|
||||
* http://www.adobe.com/devnet/actionscript/learning/as3-fundamentals/syntax.html
|
||||
*/
|
||||
public static final String[] reservedWordsAS3 = {
|
||||
"as", "break", "case", "catch", "class", "const", "continue", "default", "delete", "do", "else",
|
||||
"extends", "false", "finally", "for", "function", "if", "implements", "import", "in", "instanceof",
|
||||
@@ -111,7 +155,9 @@ public class IdentifiersDeobfuscation {
|
||||
"void", "while", "with"
|
||||
};
|
||||
|
||||
// TODO, why do we have 2 different list? Moved from AVM2Deobfuscation
|
||||
/**
|
||||
* TODO, why do we have 2 different list? Moved from AVM2Deobfuscation
|
||||
*/
|
||||
public static final String[] reservedWordsAS3_2 = {
|
||||
"as", "break", "case", "catch", "class", "const", "continue", "default", "delete", "do", "each", "else",
|
||||
"extends", "false", "finally", "for", "function", "get", "if", "implements", "import", "in", "instanceof",
|
||||
@@ -119,9 +165,16 @@ public class IdentifiersDeobfuscation {
|
||||
"return", "set", "super", "switch", "this", "throw", "true", "try", "typeof", "use", "var", /*"void",*/ "while",
|
||||
"with", "dynamic", "default", "final", "in", "static"};
|
||||
|
||||
//syntactic keywords - can be used as identifiers, but that have special meaning in certain contexts
|
||||
/**
|
||||
* Syntactic keywords - can be used as identifiers, but that have special meaning in certain contexts
|
||||
*/
|
||||
public static final String[] syntacticKeywordsAS3 = {"each", "get", "set", "namespace", "include", "dynamic", "final", "native", "override", "static"};
|
||||
|
||||
/**
|
||||
* Checks if string is reserved word.
|
||||
* @param s String
|
||||
* @param as3 Is ActionScript3
|
||||
*/
|
||||
public static boolean isReservedWord(String s, boolean as3) {
|
||||
if (s == null) {
|
||||
return false;
|
||||
@@ -136,7 +189,11 @@ public class IdentifiersDeobfuscation {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Why do we need this method???
|
||||
/**
|
||||
* TODO: Why do we need this method???
|
||||
* @param s String
|
||||
* @return True if string is reserved word
|
||||
*/
|
||||
public static boolean isReservedWord2(String s) {
|
||||
if (s == null) {
|
||||
return false;
|
||||
@@ -151,6 +208,12 @@ public class IdentifiersDeobfuscation {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates random string.
|
||||
* @param firstUppercase First character uppercase
|
||||
* @param rndSize Random size
|
||||
* @return Random string
|
||||
*/
|
||||
public static String fooString(boolean firstUppercase, int rndSize) {
|
||||
int len = 3 + rnd.nextInt(rndSize - 3);
|
||||
StringBuilder sb = new StringBuilder(len);
|
||||
@@ -170,6 +233,14 @@ public class IdentifiersDeobfuscation {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deobfuscates instance names.
|
||||
* @param as3 Is ActionScript3
|
||||
* @param namesMap Names map
|
||||
* @param renameType Rename type
|
||||
* @param tags Tags
|
||||
* @param selected Preselected names
|
||||
*/
|
||||
public void deobfuscateInstanceNames(boolean as3, HashMap<DottedChain, DottedChain> namesMap, RenameType renameType, Iterable<Tag> tags, Map<DottedChain, DottedChain> selected) {
|
||||
for (Tag t : tags) {
|
||||
if (t instanceof DefineSpriteTag) {
|
||||
@@ -197,6 +268,15 @@ public class IdentifiersDeobfuscation {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deobfuscates package names.
|
||||
* @param as3 Is ActionScript3
|
||||
* @param pkg Package
|
||||
* @param namesMap Names map
|
||||
* @param renameType Rename type
|
||||
* @param selected Preselected names
|
||||
* @return Deobfuscated package
|
||||
*/
|
||||
public DottedChain deobfuscatePackage(boolean as3, DottedChain pkg, HashMap<DottedChain, DottedChain> namesMap, RenameType renameType, Map<DottedChain, DottedChain> selected) {
|
||||
if (namesMap.containsKey(pkg)) {
|
||||
return namesMap.get(pkg);
|
||||
@@ -221,6 +301,15 @@ public class IdentifiersDeobfuscation {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deobfuscates name with package.
|
||||
* @param as3 Is ActionScript3
|
||||
* @param n Name
|
||||
* @param namesMap Names map
|
||||
* @param renameType Rename type
|
||||
* @param selected Preselected names
|
||||
* @return Deobfuscated name
|
||||
*/
|
||||
public String deobfuscateNameWithPackage(boolean as3, String n, HashMap<DottedChain, DottedChain> namesMap, RenameType renameType, Map<DottedChain, DottedChain> selected) {
|
||||
DottedChain nChain = DottedChain.parseNoSuffix(n);
|
||||
DottedChain pkg = nChain.getWithoutLast();
|
||||
@@ -251,6 +340,12 @@ public class IdentifiersDeobfuscation {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if string is valid slash path.
|
||||
* @param s String
|
||||
* @param exceptions Exceptions
|
||||
* @return True if string is valid slash path
|
||||
*/
|
||||
private static boolean isValidSlashPath(String s, String... exceptions) {
|
||||
String[] slashParts = s.split("\\/");
|
||||
if (s.isEmpty()) {
|
||||
@@ -274,6 +369,12 @@ public class IdentifiersDeobfuscation {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if string is valid name with slash.
|
||||
* @param s String
|
||||
* @param exceptions Exceptions
|
||||
* @return True if string is valid name with slash
|
||||
*/
|
||||
public static boolean isValidNameWithSlash(String s, String... exceptions) {
|
||||
if (s.contains(":")) {
|
||||
String[] pathVar = s.split(":");
|
||||
@@ -291,6 +392,13 @@ public class IdentifiersDeobfuscation {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if string is valid name with dot.
|
||||
* @param as3 Is ActionScript3
|
||||
* @param s String
|
||||
* @param exceptions Exceptions
|
||||
* @return True if string is valid name with dot
|
||||
*/
|
||||
public static boolean isValidNameWithDot(boolean as3, String s, String... exceptions) {
|
||||
for (String e : exceptions) {
|
||||
if (e.equals(s)) {
|
||||
@@ -313,6 +421,13 @@ public class IdentifiersDeobfuscation {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if string is valid name.
|
||||
* @param as3 Is ActionScript3
|
||||
* @param s String
|
||||
* @param exceptions Exceptions
|
||||
* @return True if string is valid name
|
||||
*/
|
||||
public static boolean isValidName(boolean as3, String s, String... exceptions) {
|
||||
for (String e : exceptions) {
|
||||
if (e.equals(s)) {
|
||||
@@ -335,6 +450,17 @@ public class IdentifiersDeobfuscation {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deobfuscates name.
|
||||
* @param as3 Is ActionScript3
|
||||
* @param s String
|
||||
* @param firstUppercase First character uppercase
|
||||
* @param usageType Usage type
|
||||
* @param namesMap Names map
|
||||
* @param renameType Rename type
|
||||
* @param selected Preselected names
|
||||
* @return Deobfuscated name
|
||||
*/
|
||||
public String deobfuscateName(boolean as3, String s, boolean firstUppercase, String usageType, HashMap<DottedChain, DottedChain> namesMap, RenameType renameType, Map<DottedChain, DottedChain> selected) {
|
||||
if (usageType == null) {
|
||||
usageType = "name";
|
||||
@@ -380,6 +506,12 @@ public class IdentifiersDeobfuscation {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends obfuscated identifier.
|
||||
* @param s String
|
||||
* @param writer Writer
|
||||
* @return Writer
|
||||
*/
|
||||
public static GraphTextWriter appendObfuscatedIdentifier(String s, GraphTextWriter writer) {
|
||||
writer.append("\u00A7");
|
||||
escapeOIdentifier(s, writer);
|
||||
@@ -387,7 +519,7 @@ public class IdentifiersDeobfuscation {
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures identifier is valid and if not, uses paragraph syntax
|
||||
* Ensures identifier is valid and if not, uses paragraph syntax.
|
||||
*
|
||||
* @param as3 Is ActionScript3
|
||||
* @param s Identifier
|
||||
@@ -426,6 +558,12 @@ public class IdentifiersDeobfuscation {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes obfuscated identifier.
|
||||
* @param s String
|
||||
* @param writer Writer
|
||||
* @return Writer
|
||||
*/
|
||||
public static GraphTextWriter escapeOIdentifier(String s, GraphTextWriter writer) {
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
char c = s.charAt(i);
|
||||
@@ -465,6 +603,11 @@ public class IdentifiersDeobfuscation {
|
||||
return writer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes obfuscated identifier.
|
||||
* @param s String
|
||||
* @return Escaped string
|
||||
*/
|
||||
public static String escapeOIdentifier(String s) {
|
||||
StringBuilder ret = new StringBuilder(s.length());
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
@@ -505,6 +648,9 @@ public class IdentifiersDeobfuscation {
|
||||
return ret.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears cache.
|
||||
*/
|
||||
public static void clearCache() {
|
||||
as2NameCache.clear();
|
||||
as3NameCache.clear();
|
||||
|
||||
@@ -18,43 +18,79 @@ package com.jpexs.decompiler.flash;
|
||||
|
||||
import com.jpexs.decompiler.flash.iggy.conversion.IggySwfBundle;
|
||||
import com.jpexs.helpers.Path;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* Information about openable source.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class OpenableSourceInfo {
|
||||
|
||||
/**
|
||||
* Input stream of the source
|
||||
*/
|
||||
private final InputStream inputStream;
|
||||
|
||||
/**
|
||||
* File path of the source
|
||||
*/
|
||||
private String file;
|
||||
|
||||
/**
|
||||
* Title of the file
|
||||
*/
|
||||
private String fileTitle;
|
||||
|
||||
/**
|
||||
* Whether to auto-detect bundle
|
||||
*/
|
||||
private final boolean detectBundle;
|
||||
|
||||
/**
|
||||
* Whether the source is empty
|
||||
*/
|
||||
private boolean empty = false;
|
||||
|
||||
/**
|
||||
* Kind of the source
|
||||
*/
|
||||
private OpenableSourceKind kind;
|
||||
|
||||
/**
|
||||
* Constructs OpenableSourceInfo with empty source
|
||||
* @param fileTitle Title of the file
|
||||
*/
|
||||
public OpenableSourceInfo(String fileTitle) {
|
||||
this(null, null, fileTitle, false);
|
||||
empty = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the source is empty
|
||||
* @return true if the source is empty
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return empty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs OpenableSourceInfo with input stream
|
||||
* @param inputStream Input stream of the source
|
||||
* @param file File path of the source
|
||||
* @param fileTitle Title of the file
|
||||
*/
|
||||
public OpenableSourceInfo(InputStream inputStream, String file, String fileTitle) {
|
||||
this(inputStream, file, fileTitle, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs OpenableSourceInfo with input stream
|
||||
* @param inputStream Input stream of the source
|
||||
* @param file File path of the source
|
||||
* @param fileTitle Title of the file
|
||||
* @param detectBundle Whether to auto-detect bundle
|
||||
*/
|
||||
public OpenableSourceInfo(InputStream inputStream, String file, String fileTitle, boolean detectBundle) {
|
||||
this.inputStream = inputStream;
|
||||
this.file = file;
|
||||
@@ -63,10 +99,17 @@ public class OpenableSourceInfo {
|
||||
detectKind();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets kind of the source.
|
||||
* @return Kind of the source
|
||||
*/
|
||||
public OpenableSourceKind getKind() {
|
||||
return kind;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects kind of the source.
|
||||
*/
|
||||
private void detectKind() {
|
||||
if (isBundle()) {
|
||||
kind = OpenableSourceKind.BUNDLE;
|
||||
@@ -77,32 +120,54 @@ public class OpenableSourceInfo {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets input stream of the source.
|
||||
* @return Input stream of the source
|
||||
*/
|
||||
public InputStream getInputStream() {
|
||||
return inputStream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets file path of the source.
|
||||
* @return File path of the source
|
||||
*/
|
||||
public String getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets file path of the source.
|
||||
* @param file File path of the source
|
||||
*/
|
||||
public void setFile(String file) {
|
||||
this.file = file;
|
||||
detectKind();
|
||||
empty = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets title of the file.
|
||||
*
|
||||
* @param fileTitle File title
|
||||
*/
|
||||
public void setFileTitle(String fileTitle) {
|
||||
this.fileTitle = fileTitle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets title of the file.
|
||||
*
|
||||
* @return File title
|
||||
*/
|
||||
public String getFileTitle() {
|
||||
return fileTitle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get title of the file
|
||||
* Gets title of the file.
|
||||
*
|
||||
* @return file title
|
||||
* @return File title
|
||||
*/
|
||||
public String getFileTitleOrName() {
|
||||
if (fileTitle != null) {
|
||||
@@ -111,11 +176,15 @@ public class OpenableSourceInfo {
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the source is a bundle.
|
||||
* @return True if the source is a bundle
|
||||
*/
|
||||
public boolean isBundle() {
|
||||
if (inputStream == null && file != null) {
|
||||
File fileObj = new File(file);
|
||||
String fileName = fileObj.getName();
|
||||
if (fileName.startsWith("asdec_") && fileName.endsWith(".tmp")) {
|
||||
if (fileName.startsWith("asdec_") && fileName.endsWith(".tmp")) { //FIXME: is this still needed?
|
||||
return false;
|
||||
}
|
||||
String extension = Path.getExtension(fileObj);
|
||||
@@ -124,6 +193,13 @@ public class OpenableSourceInfo {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets bundle from the source.
|
||||
* @param noCheck Whether to check the bundle
|
||||
* @param searchMode Search mode
|
||||
* @return Bundle or null
|
||||
* @throws IOException
|
||||
*/
|
||||
public Bundle getBundle(boolean noCheck, SearchMode searchMode) throws IOException {
|
||||
if (!isBundle()) {
|
||||
return null;
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
/**
|
||||
*
|
||||
* Openable source kind.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public enum OpenableSourceKind {
|
||||
|
||||
@@ -17,15 +17,26 @@
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
/**
|
||||
*
|
||||
* Parse exception.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public abstract class ParseException extends Exception {
|
||||
|
||||
/**
|
||||
* Line number where the exception occurred.
|
||||
*/
|
||||
public long line;
|
||||
|
||||
/**
|
||||
* Text of the exception.
|
||||
*/
|
||||
public String text;
|
||||
|
||||
/**
|
||||
* Constructs a new parse exception.
|
||||
* @param text
|
||||
* @param line
|
||||
*/
|
||||
public ParseException(String text, long line) {
|
||||
super("ParseException:" + text + " on line " + line);
|
||||
this.line = line;
|
||||
|
||||
@@ -17,45 +17,82 @@
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* Tag list that is read-only.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ReadOnlyTagList implements Iterable<Tag> {
|
||||
|
||||
/**
|
||||
* Empty read-only tag list.
|
||||
*/
|
||||
public static final ReadOnlyTagList EMPTY = new ReadOnlyTagList(new ArrayList<>());
|
||||
|
||||
/**
|
||||
* List of tags.
|
||||
*/
|
||||
private final List<Tag> list;
|
||||
|
||||
/**
|
||||
* Constructs read-only tag list.
|
||||
* @param list List of tags
|
||||
*/
|
||||
public ReadOnlyTagList(List<Tag> list) {
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns iterator for tags.
|
||||
* @return Iterator for tags
|
||||
*/
|
||||
@Override
|
||||
public Iterator<Tag> iterator() {
|
||||
return list.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns number of tags.
|
||||
* @return Number of tags
|
||||
*/
|
||||
public int size() {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if list is empty.
|
||||
* @return True if list is empty
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return list.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns tag at index.
|
||||
* @param index Index
|
||||
* @return Tag
|
||||
*/
|
||||
public Tag get(int index) {
|
||||
return list.get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns index of tag.
|
||||
* @param tag Tag
|
||||
* @return Index of tag or -1 if not found
|
||||
*/
|
||||
public int indexOf(Tag tag) {
|
||||
return list.indexOf(tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts list to array list.
|
||||
* @return Array list
|
||||
*/
|
||||
public ArrayList<Tag> toArrayList() {
|
||||
return new ArrayList<>(list);
|
||||
}
|
||||
|
||||
@@ -19,20 +19,36 @@ package com.jpexs.decompiler.flash;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
*
|
||||
* Task that can be retried on error.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class RetryTask {
|
||||
|
||||
/**
|
||||
* Runnable that can throw IOException.
|
||||
*/
|
||||
private final RunnableIOEx r;
|
||||
|
||||
/**
|
||||
* Handler for retrying.
|
||||
*/
|
||||
private final AbortRetryIgnoreHandler handler;
|
||||
|
||||
/**
|
||||
* Constructs a new RetryTask.
|
||||
* @param r Runnable that can throw IOException
|
||||
* @param handler Handler for retrying
|
||||
*/
|
||||
public RetryTask(RunnableIOEx r, AbortRetryIgnoreHandler handler) {
|
||||
this.r = r;
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the task.
|
||||
* @throws IOException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public void run() throws IOException, InterruptedException {
|
||||
boolean retry;
|
||||
do {
|
||||
|
||||
@@ -19,11 +19,16 @@ package com.jpexs.decompiler.flash;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
*
|
||||
* Runnable with IOException and InterruptedException.
|
||||
* @author JPEXS
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface RunnableIOEx {
|
||||
|
||||
/**
|
||||
* Run method.
|
||||
* @throws IOException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public void run() throws IOException, InterruptedException;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
/**
|
||||
*
|
||||
* Interface for runnable with result.
|
||||
* @param <T> Type of result
|
||||
* @author JPEXS
|
||||
*/
|
||||
|
||||
@@ -16,31 +16,48 @@
|
||||
*/
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
/**
|
||||
*
|
||||
* SWC file.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class SWC extends ZippedBundle {
|
||||
|
||||
/**
|
||||
* Constructs SWC from input stream.
|
||||
* @param is Input stream
|
||||
* @throws IOException
|
||||
*/
|
||||
public SWC(InputStream is) throws IOException {
|
||||
super(is);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs SWC from file.
|
||||
* @param filename File
|
||||
* @throws IOException
|
||||
*/
|
||||
public SWC(File filename) throws IOException {
|
||||
super(filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes SWC bundle.
|
||||
* @param is Input stream
|
||||
* @param filename File
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
protected void initBundle(InputStream is, File filename) throws IOException {
|
||||
super.initBundle(is, filename);
|
||||
@@ -76,6 +93,10 @@ public class SWC extends ZippedBundle {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns extension of SWC file.
|
||||
* @return Extension
|
||||
*/
|
||||
@Override
|
||||
public String getExtension() {
|
||||
return "swc";
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -17,7 +17,7 @@
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
/**
|
||||
*
|
||||
* SWF compression types.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public enum SWFCompression {
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
/**
|
||||
*
|
||||
* SWF header information.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class SWFHeader {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -16,11 +16,8 @@
|
||||
*/
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
import com.jpexs.helpers.Helper;
|
||||
import com.jpexs.helpers.MemoryInputStream;
|
||||
import com.jpexs.helpers.PosMarkedInputStream;
|
||||
import com.jpexs.helpers.ProgressListener;
|
||||
import com.jpexs.helpers.Searchable;
|
||||
import com.jpexs.helpers.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashSet;
|
||||
@@ -29,43 +26,82 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* SWF search class.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class SWFSearch {
|
||||
|
||||
/**
|
||||
* Searchable object
|
||||
*/
|
||||
protected Searchable s;
|
||||
|
||||
/**
|
||||
* No check for validity
|
||||
*/
|
||||
private final boolean noCheck;
|
||||
|
||||
/**
|
||||
* Search mode
|
||||
*/
|
||||
private final SearchMode searchMode;
|
||||
|
||||
/**
|
||||
* Already processed
|
||||
*/
|
||||
private boolean processed = false;
|
||||
|
||||
/**
|
||||
* Progress listeners
|
||||
*/
|
||||
private final Set<ProgressListener> listeners = new HashSet<>();
|
||||
|
||||
/**
|
||||
* SWF streams
|
||||
*/
|
||||
private final Map<Long, MemoryInputStream> swfStreams = new LinkedHashMap<>();
|
||||
|
||||
/**
|
||||
* Constructs SWF search object.
|
||||
* @param s Searchable object
|
||||
* @param noCheck No check for validity
|
||||
* @param searchMode Search mode
|
||||
*/
|
||||
public SWFSearch(Searchable s, boolean noCheck, SearchMode searchMode) {
|
||||
this.s = s;
|
||||
this.noCheck = noCheck;
|
||||
this.searchMode = searchMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds progress listener.
|
||||
* @param l
|
||||
*/
|
||||
public void addProgressListener(ProgressListener l) {
|
||||
listeners.add(l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes progress listener.
|
||||
* @param l
|
||||
*/
|
||||
public void removeProgressListener(ProgressListener l) {
|
||||
listeners.remove(l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets progress.
|
||||
* @param p Progress
|
||||
*/
|
||||
private void setProgress(int p) {
|
||||
for (ProgressListener l : listeners) {
|
||||
l.progress(p);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes SWF search.
|
||||
*/
|
||||
public void process() {
|
||||
Map<Long, InputStream> ret;
|
||||
ret = s.search(new ProgressListener() {
|
||||
@@ -144,6 +180,13 @@ public class SWFSearch {
|
||||
processed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets SWF stream.
|
||||
* @param listener Progress listener
|
||||
* @param address Address
|
||||
* @return SWF stream
|
||||
* @throws IOException
|
||||
*/
|
||||
public MemoryInputStream get(ProgressListener listener, long address) throws IOException {
|
||||
if (!processed) {
|
||||
return null;
|
||||
@@ -154,10 +197,18 @@ public class SWFSearch {
|
||||
return swfStreams.get(address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets list of addresses.
|
||||
* @return List of addresses
|
||||
*/
|
||||
public Set<Long> getAddresses() {
|
||||
return swfStreams.keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets number of SWF streams.
|
||||
* @return Number of SWF streams
|
||||
*/
|
||||
public int length() {
|
||||
if (!processed) {
|
||||
return 0;
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
/**
|
||||
*
|
||||
* Search mode for searching in SWF file.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public enum SearchMode {
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.ScriptInfo;
|
||||
import com.jpexs.decompiler.graph.DottedChain;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@@ -28,71 +29,167 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* Local data for source generator.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class SourceGeneratorLocalData implements Serializable {
|
||||
|
||||
/**
|
||||
* Map of variable name to register number.
|
||||
*/
|
||||
public HashMap<String, Integer> registerVars;
|
||||
|
||||
/**
|
||||
* In function level.
|
||||
*/
|
||||
public Integer inFunction;
|
||||
|
||||
/**
|
||||
* In method.
|
||||
*/
|
||||
public Boolean inMethod;
|
||||
|
||||
/**
|
||||
* For in level.
|
||||
*/
|
||||
public Integer forInLevel;
|
||||
|
||||
// TODO: handle AVM2 separately
|
||||
//TODO: handle AVM2 separately
|
||||
/**
|
||||
* List of AVM2 exceptions.
|
||||
*/
|
||||
public List<ABCException> exceptions = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* List of finally Ids
|
||||
*/
|
||||
public List<Integer> finallyCatches = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* List of finally opened loops
|
||||
*/
|
||||
public List<List<Long>> finallyOpenedLoops = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Counter of finally uses
|
||||
*/
|
||||
public Map<Integer, Integer> finallyCounter = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Register number for finally block
|
||||
*/
|
||||
public int finallyRegister = -1;
|
||||
|
||||
/**
|
||||
* Current class base name
|
||||
*/
|
||||
public String currentClassBaseName; //FIXME! Suffixed or not?
|
||||
|
||||
/**
|
||||
* Super class name
|
||||
*/
|
||||
public String superClass = null;
|
||||
|
||||
/**
|
||||
* Super package name
|
||||
*/
|
||||
public DottedChain superPkg = null;
|
||||
|
||||
/**
|
||||
* Activation register number
|
||||
*/
|
||||
public int activationReg = 0;
|
||||
|
||||
/**
|
||||
* Call stack
|
||||
*/
|
||||
public List<MethodBody> callStack = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* MethodBody trait usages. Map of MethodBody to list of used trait indexes.
|
||||
*/
|
||||
public Map<MethodBody, List<Integer>> traitUsages = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Current package
|
||||
*/
|
||||
public DottedChain pkg = DottedChain.TOPLEVEL;
|
||||
|
||||
/**
|
||||
* Scope stack
|
||||
*/
|
||||
public List<GraphTargetItem> scopeStack = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Current script
|
||||
*/
|
||||
public ScriptInfo currentScript;
|
||||
|
||||
/**
|
||||
* Current script index
|
||||
*/
|
||||
public int scriptIndex;
|
||||
|
||||
/**
|
||||
* Is in sub method
|
||||
*/
|
||||
public boolean subMethod = false;
|
||||
|
||||
/**
|
||||
* Current private namespace id
|
||||
*/
|
||||
public int privateNs = 0;
|
||||
|
||||
/**
|
||||
* Current protected namespace id
|
||||
*/
|
||||
public int protectedNs = 0;
|
||||
|
||||
/**
|
||||
* Is in static method
|
||||
*/
|
||||
public boolean isStatic = false;
|
||||
|
||||
/**
|
||||
* Opened loop ids
|
||||
*/
|
||||
public List<Long> openedLoops = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Opened loop ids for catch blocks
|
||||
*/
|
||||
public List<List<Long>> catchesOpenedLoops = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Temp registers used in catch blocks
|
||||
*/
|
||||
public List<Integer> catchesTempRegs = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Document class
|
||||
*/
|
||||
public String documentClass;
|
||||
|
||||
/**
|
||||
* Is second run
|
||||
*/
|
||||
public boolean secondRun = false;
|
||||
|
||||
/**
|
||||
* Gets full class name.
|
||||
* @return Full class name
|
||||
*/
|
||||
public String getFullClass() {
|
||||
return pkg == null ? currentClassBaseName : pkg.addWithSuffix(currentClassBaseName).toRawString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs new SourceGeneratorLocalData.
|
||||
* @param registerVars Map of variable name to register number
|
||||
* @param inFunction In function level
|
||||
* @param inMethod In method
|
||||
* @param forInLevel For in level
|
||||
*/
|
||||
public SourceGeneratorLocalData(HashMap<String, Integer> registerVars, Integer inFunction, Boolean inMethod, Integer forInLevel) {
|
||||
this.registerVars = registerVars;
|
||||
this.inFunction = inFunction;
|
||||
|
||||
@@ -19,7 +19,7 @@ package com.jpexs.decompiler.flash;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
*
|
||||
* Exception thrown when SWF file cannot be opened.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class SwfOpenException extends IOException {
|
||||
|
||||
@@ -19,10 +19,14 @@ package com.jpexs.decompiler.flash;
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
|
||||
/**
|
||||
*
|
||||
* Listener for tag removal.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public interface TagRemoveListener {
|
||||
|
||||
/**
|
||||
* Called when a tag is removed.
|
||||
* @param tag Removed tag
|
||||
*/
|
||||
public void tagRemoved(Tag tag);
|
||||
}
|
||||
|
||||
@@ -17,10 +17,15 @@
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
/**
|
||||
*
|
||||
* URL resolver interface.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public interface UrlResolver {
|
||||
|
||||
/**
|
||||
* Resolves URL to SWF object.
|
||||
* @param url URL
|
||||
* @return SWF object or null if not valid
|
||||
*/
|
||||
public SWF resolveUrl(String url);
|
||||
}
|
||||
|
||||
@@ -17,24 +17,43 @@
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
/**
|
||||
*
|
||||
* Exception thrown when a value is too large for a specific type.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ValueTooLargeException extends IllegalArgumentException {
|
||||
|
||||
/**
|
||||
* Type of the value
|
||||
*/
|
||||
private final String type;
|
||||
/**
|
||||
* Value that is too large
|
||||
*/
|
||||
private final Object value;
|
||||
|
||||
/**
|
||||
* Constructs a new ValueTooLargeException with the specified type and value.
|
||||
* @param type Type of the value
|
||||
* @param value Value that is too large
|
||||
*/
|
||||
public ValueTooLargeException(String type, Object value) {
|
||||
super("Value is too large for " + type + ": " + value);
|
||||
this.type = type;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of the value.
|
||||
* @return Type of the value
|
||||
*/
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value that is too large.
|
||||
* @return Value that is too large
|
||||
*/
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -17,18 +17,33 @@
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
/**
|
||||
*
|
||||
* FFDec version information.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class Version {
|
||||
|
||||
/**
|
||||
* Git tag name
|
||||
*/
|
||||
public String tagName;
|
||||
|
||||
/**
|
||||
* Version name
|
||||
*/
|
||||
public String versionName;
|
||||
|
||||
/**
|
||||
* Release date
|
||||
*/
|
||||
public String releaseDate;
|
||||
|
||||
/**
|
||||
* Is this a prerelease version?
|
||||
*/
|
||||
public boolean prerelease;
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
public String description;
|
||||
}
|
||||
|
||||
@@ -20,12 +20,8 @@ import com.jpexs.helpers.Helper;
|
||||
import com.jpexs.helpers.MemoryInputStream;
|
||||
import com.jpexs.helpers.ReReadableInputStream;
|
||||
import com.jpexs.helpers.streams.SeekableInputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
@@ -35,31 +31,65 @@ import java.util.zip.ZipInputStream;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
/**
|
||||
*
|
||||
* Bundle implementation for ZIP files.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ZippedBundle implements Bundle {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
protected Set<String> keySet = new HashSet<>();
|
||||
|
||||
/**
|
||||
* File input stream for the ZIP file.
|
||||
*/
|
||||
protected FileInputStream fis;
|
||||
|
||||
/**
|
||||
* Re-readable input stream for the ZIP file.
|
||||
*/
|
||||
protected ReReadableInputStream is;
|
||||
|
||||
/**
|
||||
* File name of the ZIP file.
|
||||
*/
|
||||
protected File filename;
|
||||
|
||||
/**
|
||||
* Constructs a new ZippedBundle from an input stream.
|
||||
* @param is Input stream
|
||||
* @throws IOException
|
||||
*/
|
||||
public ZippedBundle(InputStream is) throws IOException {
|
||||
this(is, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new ZippedBundle from a file.
|
||||
* @param filename File
|
||||
* @throws IOException
|
||||
*/
|
||||
public ZippedBundle(File filename) throws IOException {
|
||||
this(null, filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new ZippedBundle from an input stream and a file.
|
||||
* @param is Input stream
|
||||
* @param filename File
|
||||
* @throws IOException
|
||||
*/
|
||||
protected ZippedBundle(InputStream is, File filename) throws IOException {
|
||||
initBundle(is, filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the bundle.
|
||||
* @param is Input stream
|
||||
* @param filename File
|
||||
* @throws IOException
|
||||
*/
|
||||
protected void initBundle(InputStream is, File filename) throws IOException {
|
||||
if (filename != null) {
|
||||
fis = new FileInputStream(filename);
|
||||
@@ -80,16 +110,30 @@ public class ZippedBundle implements Bundle {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of entries in the bundle.
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public int length() {
|
||||
return keySet.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the keys in the bundle.
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Set<String> getKeys() {
|
||||
return keySet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the input stream for a key.
|
||||
* @param key Key
|
||||
* @return Input stream
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
public SeekableInputStream getOpenable(String key) throws IOException {
|
||||
if (!keySet.contains(key)) {
|
||||
@@ -115,6 +159,11 @@ public class ZippedBundle implements Bundle {
|
||||
//return cachedSWFs.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all input streams in the bundle.
|
||||
* @return Map of key to input stream
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
public Map<String, SeekableInputStream> getAll() throws IOException {
|
||||
Map<String, SeekableInputStream> ret = new HashMap<>();
|
||||
@@ -124,16 +173,32 @@ public class ZippedBundle implements Bundle {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the extension of the bundle.
|
||||
* @return Extension
|
||||
*/
|
||||
@Override
|
||||
public String getExtension() {
|
||||
return "zip";
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the bundle is read-only.
|
||||
* @return Whether the bundle is read-only
|
||||
*/
|
||||
@Override
|
||||
public boolean isReadOnly() {
|
||||
return this.filename == null || !this.filename.canWrite();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Replaces the input stream for a key.
|
||||
* @param key Key
|
||||
* @param swfIs New input stream
|
||||
* @return Whether the operation was successful
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
public boolean putOpenable(String key, InputStream swfIs) throws IOException {
|
||||
if (this.isReadOnly()) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -18,47 +18,61 @@ package com.jpexs.decompiler.flash.abc;
|
||||
|
||||
import com.jpexs.decompiler.flash.EndOfStreamException;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.abc.types.Decimal;
|
||||
import com.jpexs.decompiler.flash.abc.types.Float4;
|
||||
import com.jpexs.decompiler.flash.abc.types.InstanceInfo;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.flash.abc.types.Multiname;
|
||||
import com.jpexs.decompiler.flash.abc.types.Namespace;
|
||||
import com.jpexs.decompiler.flash.abc.types.ValueKind;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.TraitClass;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.TraitFunction;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.TraitMethodGetterSetter;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.TraitSlotConst;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.Traits;
|
||||
import com.jpexs.decompiler.flash.abc.types.*;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.*;
|
||||
import com.jpexs.decompiler.flash.dumpview.DumpInfo;
|
||||
import com.jpexs.decompiler.flash.dumpview.DumpInfoSpecial;
|
||||
import com.jpexs.decompiler.flash.dumpview.DumpInfoSpecialType;
|
||||
import com.jpexs.helpers.MemoryInputStream;
|
||||
import com.jpexs.helpers.utf8.Utf8Helper;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
*
|
||||
* ABC input stream.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ABCInputStream implements AutoCloseable {
|
||||
|
||||
/**
|
||||
* Class has protected namespace
|
||||
*/
|
||||
private static final int CLASS_PROTECTED_NS = 8;
|
||||
|
||||
/**
|
||||
* Trait has metadata
|
||||
*/
|
||||
private static final int ATTR_METADATA = 4;
|
||||
|
||||
/**
|
||||
* Input stream
|
||||
*/
|
||||
private final MemoryInputStream is;
|
||||
|
||||
/**
|
||||
* Buffer output stream
|
||||
*/
|
||||
private ByteArrayOutputStream bufferOs = null;
|
||||
|
||||
/**
|
||||
* Debug read
|
||||
*/
|
||||
public static final boolean DEBUG_READ = false;
|
||||
|
||||
/**
|
||||
* Dump info
|
||||
*/
|
||||
public DumpInfo dumpInfo;
|
||||
|
||||
/**
|
||||
* String data buffer
|
||||
*/
|
||||
private byte[] stringDataBuffer = new byte[256];
|
||||
|
||||
/**
|
||||
* Starts buffering.
|
||||
*/
|
||||
public void startBuffer() {
|
||||
if (bufferOs == null) {
|
||||
bufferOs = new ByteArrayOutputStream();
|
||||
@@ -67,6 +81,10 @@ public class ABCInputStream implements AutoCloseable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops buffering and returns buffered bytes.
|
||||
* @return Buffered bytes
|
||||
*/
|
||||
public byte[] stopBuffer() {
|
||||
if (bufferOs == null) {
|
||||
return SWFInputStream.BYTE_ARRAY_EMPTY;
|
||||
@@ -76,12 +94,16 @@ public class ABCInputStream implements AutoCloseable {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new ABC input stream
|
||||
* @param is Input stream
|
||||
*/
|
||||
public ABCInputStream(MemoryInputStream is) {
|
||||
this.is = is;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets position in bytes in the stream
|
||||
* Sets position in bytes in the stream.
|
||||
*
|
||||
* @param pos Number of bytes
|
||||
* @throws java.io.IOException
|
||||
@@ -90,10 +112,23 @@ public class ABCInputStream implements AutoCloseable {
|
||||
is.seek(pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new dump level.
|
||||
* @param name Name
|
||||
* @param type Type
|
||||
* @return New DumpInfo
|
||||
*/
|
||||
public DumpInfo newDumpLevel(String name, String type) {
|
||||
return newDumpLevel(name, type, DumpInfoSpecialType.NONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new dump level.
|
||||
* @param name Name
|
||||
* @param type Type
|
||||
* @param specialType Special type
|
||||
* @return New DumpInfo
|
||||
*/
|
||||
public DumpInfo newDumpLevel(String name, String type, DumpInfoSpecialType specialType) {
|
||||
if (dumpInfo != null) {
|
||||
long startByte = is.getPos();
|
||||
@@ -108,10 +143,17 @@ public class ABCInputStream implements AutoCloseable {
|
||||
return dumpInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends dump level.
|
||||
*/
|
||||
public void endDumpLevel() {
|
||||
endDumpLevel(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends dump level.
|
||||
* @param value Value
|
||||
*/
|
||||
public void endDumpLevel(Object value) {
|
||||
if (dumpInfo != null) {
|
||||
dumpInfo.lengthBytes = is.getPos() - dumpInfo.startByte;
|
||||
@@ -120,6 +162,10 @@ public class ABCInputStream implements AutoCloseable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends dump level until specified dump info.
|
||||
* @param di Dump info
|
||||
*/
|
||||
public void endDumpLevelUntil(DumpInfo di) {
|
||||
if (di != null) {
|
||||
while (dumpInfo != null && dumpInfo != di) {
|
||||
@@ -128,6 +174,11 @@ public class ABCInputStream implements AutoCloseable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads byte from the stream.
|
||||
* @return Byte
|
||||
* @throws IOException
|
||||
*/
|
||||
private int readInternal() throws IOException {
|
||||
int i = is.read();
|
||||
if (i == -1) {
|
||||
@@ -144,6 +195,12 @@ public class ABCInputStream implements AutoCloseable {
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads byte from the stream.
|
||||
* @param name Name
|
||||
* @return Byte
|
||||
* @throws IOException
|
||||
*/
|
||||
public int read(String name) throws IOException {
|
||||
newDumpLevel(name, "byte");
|
||||
int ret = readInternal();
|
||||
@@ -151,6 +208,12 @@ public class ABCInputStream implements AutoCloseable {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads bytes from the stream.
|
||||
* @param b Bytes
|
||||
* @return Number of bytes read
|
||||
* @throws IOException
|
||||
*/
|
||||
private int read(byte[] b) throws IOException {
|
||||
int currBytesRead = is.read(b);
|
||||
if (DEBUG_READ) {
|
||||
@@ -174,6 +237,12 @@ public class ABCInputStream implements AutoCloseable {
|
||||
return currBytesRead;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads U8 from the stream.
|
||||
* @param name Name
|
||||
* @return U8
|
||||
* @throws IOException
|
||||
*/
|
||||
public int readU8(String name) throws IOException {
|
||||
newDumpLevel(name, "U8");
|
||||
int ret = readInternal();
|
||||
@@ -181,6 +250,11 @@ public class ABCInputStream implements AutoCloseable {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads U32 from the stream.
|
||||
* @return U32
|
||||
* @throws IOException
|
||||
*/
|
||||
private long readU32Internal() throws IOException {
|
||||
int i;
|
||||
long ret = 0;
|
||||
@@ -198,6 +272,12 @@ public class ABCInputStream implements AutoCloseable {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads U32 from the stream.
|
||||
* @param name Name
|
||||
* @return U32
|
||||
* @throws IOException
|
||||
*/
|
||||
public long readU32(String name) throws IOException {
|
||||
newDumpLevel(name, "U32");
|
||||
long ret = readU32Internal();
|
||||
@@ -205,12 +285,23 @@ public class ABCInputStream implements AutoCloseable {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads U30 from the stream.
|
||||
* @return U30
|
||||
* @throws IOException
|
||||
*/
|
||||
private int readU30Internal() throws IOException {
|
||||
long u32 = readU32Internal();
|
||||
//no bits above bit 30
|
||||
return (int) (u32 & 0x3FFFFFFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads U30 from the stream.
|
||||
* @param name Name
|
||||
* @return U30
|
||||
* @throws IOException
|
||||
*/
|
||||
public int readU30(String name) throws IOException {
|
||||
newDumpLevel(name, "U30");
|
||||
int ret = readU30Internal();
|
||||
@@ -218,6 +309,12 @@ public class ABCInputStream implements AutoCloseable {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads S24 from the stream.
|
||||
* @param name Name
|
||||
* @return S24
|
||||
* @throws IOException
|
||||
*/
|
||||
public int readS24(String name) throws IOException {
|
||||
newDumpLevel(name, "S24");
|
||||
int ret = (readInternal()) + (readInternal() << 8) + (readInternal() << 16);
|
||||
@@ -230,6 +327,12 @@ public class ABCInputStream implements AutoCloseable {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads U16 from the stream.
|
||||
* @param name Name
|
||||
* @return U16
|
||||
* @throws IOException
|
||||
*/
|
||||
public int readU16(String name) throws IOException {
|
||||
newDumpLevel(name, "U16");
|
||||
int ret = (readInternal()) + (readInternal() << 8);
|
||||
@@ -237,6 +340,12 @@ public class ABCInputStream implements AutoCloseable {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads S32 from the stream.
|
||||
* @param name Name
|
||||
* @return S32
|
||||
* @throws IOException
|
||||
*/
|
||||
public int readS32(String name) throws IOException {
|
||||
int i;
|
||||
long ret = 0;
|
||||
@@ -262,10 +371,20 @@ public class ABCInputStream implements AutoCloseable {
|
||||
return (int) ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets available bytes in the stream.
|
||||
* @return Available bytes
|
||||
* @throws IOException
|
||||
*/
|
||||
public int available() throws IOException {
|
||||
return is.available();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads long from the stream.
|
||||
* @return Long
|
||||
* @throws IOException
|
||||
*/
|
||||
private long readLong() throws IOException {
|
||||
safeRead(8, stringDataBuffer);
|
||||
byte[] readBuffer = stringDataBuffer;
|
||||
@@ -279,6 +398,12 @@ public class ABCInputStream implements AutoCloseable {
|
||||
+ ((readBuffer[0] & 255)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads double from the stream.
|
||||
* @param name Name
|
||||
* @return Double
|
||||
* @throws IOException
|
||||
*/
|
||||
public double readDouble(String name) throws IOException {
|
||||
newDumpLevel(name, "Double");
|
||||
long el = readLong();
|
||||
@@ -287,12 +412,24 @@ public class ABCInputStream implements AutoCloseable {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely reads bytes from the stream.
|
||||
* @param count Count
|
||||
* @param data Data
|
||||
* @throws IOException
|
||||
*/
|
||||
private void safeRead(int count, byte[] data) throws IOException {
|
||||
for (int i = 0; i < count; i++) {
|
||||
data[i] = (byte) readInternal();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads namespace from the stream.
|
||||
* @param name Name
|
||||
* @return Namespace
|
||||
* @throws IOException
|
||||
*/
|
||||
public Namespace readNamespace(String name) throws IOException {
|
||||
newDumpLevel(name, "Namespace");
|
||||
int kind = read("kind");
|
||||
@@ -307,6 +444,12 @@ public class ABCInputStream implements AutoCloseable {
|
||||
return new Namespace(kind, name_index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads multiname from the stream.
|
||||
* @param name Name
|
||||
* @return Multiname
|
||||
* @throws IOException
|
||||
*/
|
||||
public Multiname readMultiname(String name) throws IOException {
|
||||
int kind = readU8("kind");
|
||||
Multiname result = null;
|
||||
@@ -344,6 +487,12 @@ public class ABCInputStream implements AutoCloseable {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads method info from the stream.
|
||||
* @param name Name
|
||||
* @return Method info
|
||||
* @throws IOException
|
||||
*/
|
||||
public MethodInfo readMethodInfo(String name) throws IOException {
|
||||
newDumpLevel(name, "method_info");
|
||||
int param_count = readU30("param_count");
|
||||
@@ -376,6 +525,12 @@ public class ABCInputStream implements AutoCloseable {
|
||||
return new MethodInfo(param_types, ret_type, name_index, flags, optional, param_names);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads trait from the stream.
|
||||
* @param name Name
|
||||
* @return Trait
|
||||
* @throws IOException
|
||||
*/
|
||||
public Trait readTrait(String name) throws IOException {
|
||||
newDumpLevel(name, "Trait");
|
||||
long pos = getPosition();
|
||||
@@ -437,6 +592,12 @@ public class ABCInputStream implements AutoCloseable {
|
||||
return trait;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads traits from the stream.
|
||||
* @param name Name
|
||||
* @return Traits
|
||||
* @throws IOException
|
||||
*/
|
||||
public Traits readTraits(String name) throws IOException {
|
||||
newDumpLevel(name, "Traits");
|
||||
int count = readU30("count");
|
||||
@@ -448,6 +609,12 @@ public class ABCInputStream implements AutoCloseable {
|
||||
return traits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads bytes from the stream.
|
||||
* @param count Count
|
||||
* @return Bytes
|
||||
* @throws IOException
|
||||
*/
|
||||
private byte[] readBytesInternal(int count) throws IOException {
|
||||
byte[] ret = new byte[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
@@ -456,6 +623,14 @@ public class ABCInputStream implements AutoCloseable {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads bytes from the stream.
|
||||
* @param count Count
|
||||
* @param name Name
|
||||
* @param specialType Special type
|
||||
* @return Bytes
|
||||
* @throws IOException
|
||||
*/
|
||||
public byte[] readBytes(int count, String name, DumpInfoSpecialType specialType) throws IOException {
|
||||
newDumpLevel(name, "Bytes", specialType);
|
||||
byte[] ret = readBytesInternal(count);
|
||||
@@ -463,6 +638,12 @@ public class ABCInputStream implements AutoCloseable {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads decimal from the stream.
|
||||
* @param name Name
|
||||
* @return Decimal
|
||||
* @throws IOException
|
||||
*/
|
||||
public Decimal readDecimal(String name) throws IOException {
|
||||
newDumpLevel(name, "Decimal");
|
||||
byte[] data = readBytesInternal(16);
|
||||
@@ -470,6 +651,12 @@ public class ABCInputStream implements AutoCloseable {
|
||||
return new Decimal(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads float from the stream.
|
||||
* @param name Name
|
||||
* @return Float
|
||||
* @throws IOException
|
||||
*/
|
||||
public Float readFloat(String name) throws IOException {
|
||||
newDumpLevel(name, "Float");
|
||||
int intBits = (readInternal()) + (readInternal() << 8);
|
||||
@@ -478,6 +665,12 @@ public class ABCInputStream implements AutoCloseable {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads float4 from the stream.
|
||||
* @param name Name
|
||||
* @return Float4
|
||||
* @throws IOException
|
||||
*/
|
||||
public Float4 readFloat4(String name) throws IOException {
|
||||
newDumpLevel(name, "Float4");
|
||||
float f1 = readFloat("value1");
|
||||
@@ -489,6 +682,12 @@ public class ABCInputStream implements AutoCloseable {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads instance info from the stream.
|
||||
* @param name Name
|
||||
* @return Instance info
|
||||
* @throws IOException
|
||||
*/
|
||||
public InstanceInfo readInstanceInfo(String name) throws IOException {
|
||||
newDumpLevel(name, "instance_info");
|
||||
InstanceInfo ret = new InstanceInfo(null); // do not create Traits in constructor
|
||||
@@ -509,6 +708,12 @@ public class ABCInputStream implements AutoCloseable {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads string from the stream.
|
||||
* @param name Name
|
||||
* @return String
|
||||
* @throws IOException
|
||||
*/
|
||||
public String readString(String name) throws IOException {
|
||||
newDumpLevel(name, "String");
|
||||
int length = readU30Internal();
|
||||
@@ -529,14 +734,17 @@ public class ABCInputStream implements AutoCloseable {
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/*public void markStart(){
|
||||
bytesRead=0;
|
||||
}*/
|
||||
/**
|
||||
* Gets current position in the stream.
|
||||
* @return Position
|
||||
*/
|
||||
public long getPosition() {
|
||||
return is.getPos();
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the stream.
|
||||
*/
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
|
||||
@@ -20,31 +20,42 @@ import com.jpexs.decompiler.flash.abc.types.ClassInfo;
|
||||
import com.jpexs.decompiler.flash.abc.types.InstanceInfo;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.TraitClass;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.TraitFunction;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.TraitMethodGetterSetter;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.TraitSlotConst;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* ABC method indexing.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ABCMethodIndexing {
|
||||
|
||||
/**
|
||||
* ABC
|
||||
*/
|
||||
private final ABC abc;
|
||||
|
||||
/**
|
||||
* Method body index for method info
|
||||
*/
|
||||
private Map<MethodInfo, Integer> bodyIdxFromMethod = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Constructs ABC method indexing.
|
||||
* @param abc ABC
|
||||
*/
|
||||
public ABCMethodIndexing(ABC abc) {
|
||||
this.abc = abc;
|
||||
createBodyIdxFromMethodIdxMap(abc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates body index from method index map.
|
||||
* @param abc ABC
|
||||
*/
|
||||
public final void createBodyIdxFromMethodIdxMap(ABC abc) {
|
||||
List<MethodBody> bodies = abc.bodies;
|
||||
Map<MethodInfo, Integer> map = new HashMap<>(bodies.size());
|
||||
@@ -56,6 +67,11 @@ public class ABCMethodIndexing {
|
||||
bodyIdxFromMethod = map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds method body index for method info.
|
||||
* @param methodInfo Method info
|
||||
* @return Method body index or -1 if not found
|
||||
*/
|
||||
public int findMethodBodyIndex(MethodInfo methodInfo) {
|
||||
Integer bi = bodyIdxFromMethod.get(methodInfo);
|
||||
if (bi == null) {
|
||||
@@ -65,6 +81,11 @@ public class ABCMethodIndexing {
|
||||
return bi;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds method body index for method info.
|
||||
* @param methodInfo Method info index
|
||||
* @return Method body index or -1 if not found
|
||||
*/
|
||||
public int findMethodBodyIndex(int methodInfo) {
|
||||
if (methodInfo < 0 || methodInfo >= abc.method_info.size()) {
|
||||
return -1;
|
||||
@@ -74,6 +95,11 @@ public class ABCMethodIndexing {
|
||||
return findMethodBodyIndex(mi);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds method body for method info.
|
||||
* @param methodInfo Method info
|
||||
* @return Method body or null if not found
|
||||
*/
|
||||
public MethodBody findMethodBody(MethodInfo methodInfo) {
|
||||
int bi = findMethodBodyIndex(methodInfo);
|
||||
if (bi != -1) {
|
||||
@@ -83,6 +109,11 @@ public class ABCMethodIndexing {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds method body for method info.
|
||||
* @param methodInfo Method info index
|
||||
* @return Method body or null if not found
|
||||
*/
|
||||
public MethodBody findMethodBody(int methodInfo) {
|
||||
int bi = findMethodBodyIndex(methodInfo);
|
||||
if (bi != -1) {
|
||||
@@ -92,6 +123,12 @@ public class ABCMethodIndexing {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds method traits.
|
||||
* @param pack Script pack
|
||||
* @param bodyIndex Method body index
|
||||
* @return Method traits
|
||||
*/
|
||||
public List<Trait> findMethodTraits(ScriptPack pack, int bodyIndex) {
|
||||
int methodInfo = abc.bodies.get(bodyIndex).method_info;
|
||||
List<Trait> traits = abc.script_info.get(pack.scriptIndex).traits.traits;
|
||||
@@ -104,6 +141,13 @@ public class ABCMethodIndexing {
|
||||
return resultTraits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds traits.
|
||||
* @param abc ABC
|
||||
* @param trait Trait
|
||||
* @param methodInfo Method info index
|
||||
* @param result Result list
|
||||
*/
|
||||
private static void findTraits(ABC abc, Trait trait, int methodInfo, List<Trait> result) {
|
||||
if (trait instanceof TraitSlotConst) {
|
||||
TraitSlotConst tsc = (TraitSlotConst) trait;
|
||||
|
||||
@@ -19,15 +19,24 @@ package com.jpexs.decompiler.flash.abc;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
*
|
||||
* ABC open exception.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ABCOpenException extends IOException {
|
||||
|
||||
/**
|
||||
* Constructs a new ABCOpenException with the specified detail message.
|
||||
* @param message Detail message
|
||||
*/
|
||||
public ABCOpenException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new ABCOpenException with the specified detail message and cause.
|
||||
* @param message Detail message
|
||||
* @param cause Cause
|
||||
*/
|
||||
public ABCOpenException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
@@ -16,57 +16,85 @@
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.types.Decimal;
|
||||
import com.jpexs.decompiler.flash.abc.types.Float4;
|
||||
import com.jpexs.decompiler.flash.abc.types.InstanceInfo;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.flash.abc.types.Multiname;
|
||||
import com.jpexs.decompiler.flash.abc.types.Namespace;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.TraitClass;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.TraitFunction;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.TraitMethodGetterSetter;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.TraitSlotConst;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.Traits;
|
||||
import com.jpexs.decompiler.flash.abc.types.*;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.*;
|
||||
import com.jpexs.helpers.utf8.Utf8Helper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
*
|
||||
* ABC output stream.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ABCOutputStream extends OutputStream {
|
||||
|
||||
/**
|
||||
* Output stream
|
||||
*/
|
||||
private final OutputStream os;
|
||||
|
||||
/**
|
||||
* Current position
|
||||
*/
|
||||
private long position = 0L;
|
||||
|
||||
/**
|
||||
* Constructs ABC output stream.
|
||||
* @param os Output stream
|
||||
*/
|
||||
public ABCOutputStream(OutputStream os) {
|
||||
this.os = os;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns current position.
|
||||
* @return Current position
|
||||
*/
|
||||
public long getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a byte to the output stream.
|
||||
* @param b The byte to write.
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
os.write(b);
|
||||
position++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a byte array to the output stream.
|
||||
* @param data The data to write.
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
public void write(byte[] data) throws IOException {
|
||||
os.write(data);
|
||||
position += data.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a byte array to the output stream.
|
||||
* @param b The data to write.
|
||||
* @param off The start offset in the data.
|
||||
* @param len The number of bytes to write.
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
os.write(b, off, len);
|
||||
position += len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes U30 to the output stream.
|
||||
* @param value Value to write
|
||||
* @throws IOException
|
||||
*/
|
||||
public void writeU30(long value) throws IOException {
|
||||
writeS32(value);
|
||||
/*boolean loop = true;
|
||||
@@ -91,6 +119,11 @@ public class ABCOutputStream extends OutputStream {
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes U32 to the output stream.
|
||||
* @param value Value to write
|
||||
* @throws IOException
|
||||
*/
|
||||
public void writeU32(long value) throws IOException {
|
||||
boolean loop = true;
|
||||
value &= 0xFFFFFFFFL;
|
||||
@@ -107,6 +140,11 @@ public class ABCOutputStream extends OutputStream {
|
||||
} while (loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes S24 to the output stream.
|
||||
* @param value Value to write
|
||||
* @throws IOException
|
||||
*/
|
||||
public void writeS24(long value) throws IOException {
|
||||
int ret = (int) (value & 0xff);
|
||||
write(ret);
|
||||
@@ -118,6 +156,11 @@ public class ABCOutputStream extends OutputStream {
|
||||
write(ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes S32 to the output stream.
|
||||
* @param value Value to write
|
||||
* @throws IOException
|
||||
*/
|
||||
public void writeS32(long value) throws IOException {
|
||||
boolean belowZero = value < 0;
|
||||
/*if (belowZero) {
|
||||
@@ -150,6 +193,11 @@ public class ABCOutputStream extends OutputStream {
|
||||
} while (loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes long to the output stream.
|
||||
* @param value Value to write
|
||||
* @throws IOException
|
||||
*/
|
||||
public void writeLong(long value) throws IOException {
|
||||
byte[] writeBuffer = new byte[8];
|
||||
writeBuffer[7] = (byte) (value >>> 56);
|
||||
@@ -163,14 +211,29 @@ public class ABCOutputStream extends OutputStream {
|
||||
write(writeBuffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes double to the output stream.
|
||||
* @param value Value to write
|
||||
* @throws IOException
|
||||
*/
|
||||
public void writeDouble(double value) throws IOException {
|
||||
writeLong(Double.doubleToLongBits(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes float to the output stream.
|
||||
* @param value Value to write
|
||||
* @throws IOException
|
||||
*/
|
||||
public void writeFloat(float value) throws IOException {
|
||||
writeU16(Float.floatToIntBits(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes float4 to the output stream.
|
||||
* @param value Value to write
|
||||
* @throws IOException
|
||||
*/
|
||||
public void writeFloat4(Float4 value) throws IOException {
|
||||
writeFloat(value.values[0]);
|
||||
writeFloat(value.values[1]);
|
||||
@@ -178,21 +241,41 @@ public class ABCOutputStream extends OutputStream {
|
||||
writeFloat(value.values[3]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes U8 to the output stream.
|
||||
* @param value Value to write
|
||||
* @throws IOException
|
||||
*/
|
||||
public void writeU8(int value) throws IOException {
|
||||
write(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes U16 to the output stream.
|
||||
* @param value Value to write
|
||||
* @throws IOException
|
||||
*/
|
||||
public void writeU16(int value) throws IOException {
|
||||
write(value & 0xff);
|
||||
write((value >> 8) & 0xff);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes String to the output stream.
|
||||
* @param s String to write
|
||||
* @throws IOException
|
||||
*/
|
||||
public void writeString(String s) throws IOException {
|
||||
byte[] sbytes = Utf8Helper.getBytes(s);
|
||||
writeU30(sbytes.length);
|
||||
write(sbytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes Namespace to the output stream.
|
||||
* @param ns Namespace to write
|
||||
* @throws IOException
|
||||
*/
|
||||
public void writeNamespace(Namespace ns) throws IOException {
|
||||
write(ns.kind);
|
||||
boolean found = false;
|
||||
@@ -208,6 +291,11 @@ public class ABCOutputStream extends OutputStream {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes Multiname to the output stream.
|
||||
* @param m Multiname to write
|
||||
* @throws IOException
|
||||
*/
|
||||
public void writeMultiname(Multiname m) throws IOException {
|
||||
writeU8(m.kind);
|
||||
if ((m.kind == Multiname.QNAME) || (m.kind == Multiname.QNAMEA)) {
|
||||
@@ -230,6 +318,11 @@ public class ABCOutputStream extends OutputStream {
|
||||
// kind==0x11,0x12 nothing CONSTANT_RTQNameL and CONSTANT_RTQNameLA.
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes MethodInfo to the output stream.
|
||||
* @param mi MethodInfo to write
|
||||
* @throws IOException
|
||||
*/
|
||||
public void writeMethodInfo(MethodInfo mi) throws IOException {
|
||||
writeU30(mi.param_types.length);
|
||||
writeU30(mi.ret_type);
|
||||
@@ -253,6 +346,11 @@ public class ABCOutputStream extends OutputStream {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes Trait to the output stream.
|
||||
* @param t Trait to write
|
||||
* @throws IOException
|
||||
*/
|
||||
public void writeTrait(Trait t) throws IOException {
|
||||
writeU30(t.name_index);
|
||||
write((t.kindFlags << 4) + t.kindType);
|
||||
@@ -288,6 +386,11 @@ public class ABCOutputStream extends OutputStream {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes Traits to the output stream.
|
||||
* @param t Traits to write
|
||||
* @throws IOException
|
||||
*/
|
||||
public void writeTraits(Traits t) throws IOException {
|
||||
writeU30(t.traits.size());
|
||||
for (int i = 0; i < t.traits.size(); i++) {
|
||||
@@ -295,6 +398,11 @@ public class ABCOutputStream extends OutputStream {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes InstanceInfo to the output stream.
|
||||
* @param ii InstanceInfo to write
|
||||
* @throws IOException
|
||||
*/
|
||||
public void writeInstanceInfo(InstanceInfo ii) throws IOException {
|
||||
writeU30(ii.name_index);
|
||||
writeU30(ii.super_index);
|
||||
@@ -310,10 +418,20 @@ public class ABCOutputStream extends OutputStream {
|
||||
writeTraits(ii.instance_traits);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes Decimal to the output stream.
|
||||
* @param value Decimal to write
|
||||
* @throws IOException
|
||||
*/
|
||||
public void writeDecimal(Decimal value) throws IOException {
|
||||
write(value.data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets U30 byte length.
|
||||
* @param value Value
|
||||
* @return
|
||||
*/
|
||||
public static int getU30ByteLength(long value) {
|
||||
boolean belowZero = value < 0;
|
||||
int bitcount = 0;
|
||||
|
||||
@@ -16,20 +16,43 @@
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc;
|
||||
|
||||
/**
|
||||
* Represents ABC version
|
||||
*/
|
||||
public class ABCVersion implements Comparable<ABCVersion> {
|
||||
|
||||
/**
|
||||
* Major version
|
||||
*/
|
||||
public int major = 46;
|
||||
|
||||
/**
|
||||
* Minor version
|
||||
*/
|
||||
public int minor = 16;
|
||||
|
||||
/**
|
||||
* Constructs new ABCVersion
|
||||
*/
|
||||
public ABCVersion() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs new ABCVersion
|
||||
* @param major Major version
|
||||
* @param minor Minor version
|
||||
*/
|
||||
public ABCVersion(int major, int minor) {
|
||||
this.major = major;
|
||||
this.minor = minor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares ABCVersion with another ABCVersion
|
||||
* @param o the object to be compared.
|
||||
* @return Negative number if this version is lower, 0 if versions are equal, positive number if this version is higher
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(ABCVersion o) {
|
||||
if (major != o.major) {
|
||||
@@ -38,11 +61,19 @@ public class ABCVersion implements Comparable<ABCVersion> {
|
||||
return minor - o.minor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns string representation of ABCVersion
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "" + major + "." + minor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns hash code of ABCVersion
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 7;
|
||||
@@ -51,6 +82,11 @@ public class ABCVersion implements Comparable<ABCVersion> {
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Equals method
|
||||
* @param obj
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
|
||||
@@ -22,7 +22,7 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Target ABC version
|
||||
* Target ABC version.
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
@@ -30,13 +30,34 @@ import java.lang.annotation.Target;
|
||||
@Target({ElementType.FIELD, ElementType.TYPE})
|
||||
public @interface ABCVersionRequirements {
|
||||
|
||||
/**
|
||||
* Minimum minor version.
|
||||
* @return
|
||||
*/
|
||||
int minMinor() default 0;
|
||||
|
||||
/**
|
||||
* Maximum minor version.
|
||||
* @return
|
||||
*/
|
||||
|
||||
int maxMinor() default 0;
|
||||
|
||||
/**
|
||||
* Maximum major version.
|
||||
* @return
|
||||
*/
|
||||
int maxMajor() default 0;
|
||||
|
||||
/**
|
||||
* Minimum major version.
|
||||
* @return
|
||||
*/
|
||||
int minMajor() default 0;
|
||||
|
||||
/**
|
||||
* Exact minor version.
|
||||
* @return
|
||||
*/
|
||||
int exactMinor() default 0;
|
||||
}
|
||||
|
||||
@@ -21,56 +21,90 @@ import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.CodeStats;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.parser.script.AbcIndexing;
|
||||
import com.jpexs.decompiler.flash.abc.types.ABCException;
|
||||
import com.jpexs.decompiler.flash.abc.types.InstanceInfo;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.flash.abc.types.ScriptInfo;
|
||||
import com.jpexs.decompiler.flash.abc.types.*;
|
||||
import com.jpexs.decompiler.graph.DottedChain;
|
||||
import com.jpexs.decompiler.graph.GraphPart;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.ScopeStack;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* AVM2 local data.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class AVM2LocalData extends BaseLocalData {
|
||||
|
||||
/**
|
||||
* Whether the method is static
|
||||
*/
|
||||
public Boolean isStatic;
|
||||
|
||||
/**
|
||||
* Current class index
|
||||
*/
|
||||
public Integer classIndex;
|
||||
|
||||
/**
|
||||
* Local registers values
|
||||
*/
|
||||
public HashMap<Integer, GraphTargetItem> localRegs;
|
||||
|
||||
/**
|
||||
* Scope stack
|
||||
*/
|
||||
public ScopeStack scopeStack;
|
||||
|
||||
/**
|
||||
* Local scope stack
|
||||
*/
|
||||
public ScopeStack localScopeStack;
|
||||
|
||||
/**
|
||||
* Current method body
|
||||
*/
|
||||
public MethodBody methodBody;
|
||||
|
||||
/**
|
||||
* Current call stack
|
||||
*/
|
||||
public List<MethodBody> callStack;
|
||||
|
||||
/**
|
||||
* Current ABC file
|
||||
*/
|
||||
public ABC abc;
|
||||
|
||||
/**
|
||||
* ABCIndexing
|
||||
*/
|
||||
public AbcIndexing abcIndex;
|
||||
|
||||
/**
|
||||
* Local register names
|
||||
*/
|
||||
public HashMap<Integer, String> localRegNames;
|
||||
|
||||
/**
|
||||
* Local register types
|
||||
*/
|
||||
public HashMap<Integer, GraphTargetItem> localRegTypes;
|
||||
|
||||
/**
|
||||
* Fully qualified names
|
||||
*/
|
||||
public List<DottedChain> fullyQualifiedNames;
|
||||
|
||||
/**
|
||||
* Parsed exceptions
|
||||
*/
|
||||
public List<ABCException> parsedExceptions = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Parsed exception ids
|
||||
*/
|
||||
public List<Integer> parsedExceptionIds = new ArrayList<>();
|
||||
|
||||
//public Map<Integer, List<Integer>> finallyJumps;
|
||||
/**
|
||||
* Mapped jumps from pushbyte xx part to apropriate lookupswitch branch
|
||||
*/
|
||||
@@ -81,56 +115,114 @@ public class AVM2LocalData extends BaseLocalData {
|
||||
*/
|
||||
public Map<GraphPart, Integer> finallyJumpsToFinallyIndex = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Mapping from finally exception index to default part
|
||||
*/
|
||||
public Map<Integer, GraphPart> finallyIndexToDefaultGraphPart = new HashMap<>();
|
||||
|
||||
//exception index => switchPart
|
||||
/**
|
||||
* Mapping from exception index to switch part
|
||||
*/
|
||||
public Map<Integer, GraphPart> ignoredSwitches = new HashMap<>();
|
||||
|
||||
/**
|
||||
* exception index -> switch defaultPart
|
||||
* Mapping from exception index to switch defaultPart
|
||||
*/
|
||||
public Map<Integer, GraphPart> defaultParts = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Mapping from finally index to register index
|
||||
*/
|
||||
public Map<Integer, Integer> switchedRegs = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Mapping from finally index push default part
|
||||
*/
|
||||
public Map<Integer, GraphPart> pushDefaultPart = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Mapping from finally index to finally kind
|
||||
* See AVM2Graph.FINALLY_KIND_* constants.
|
||||
*/
|
||||
public Map<Integer, Integer> finallyKinds = new HashMap<>();
|
||||
|
||||
/**
|
||||
* exception index -> switch throw part
|
||||
* Mapping from finally exception index to switch throw part
|
||||
*/
|
||||
public Map<Integer, GraphPart> finallyThrowParts = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Mapping from finally exception index to target part
|
||||
*/
|
||||
public Map<Integer, GraphPart> finallyTargetParts = new HashMap<>();
|
||||
|
||||
//switchedPart -> index of nextpart
|
||||
/**
|
||||
* Mapping from switchedPart to index of nextpart
|
||||
*/
|
||||
public Map<GraphPart, Integer> defaultWays = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Current script index
|
||||
*/
|
||||
public Integer scriptIndex;
|
||||
|
||||
/**
|
||||
* Local registers assignment ips. Maps register index to ip where it was assigned.
|
||||
*/
|
||||
public HashMap<Integer, Integer> localRegAssignmentIps;
|
||||
|
||||
/**
|
||||
* Current instruction pointer
|
||||
*/
|
||||
public Integer ip;
|
||||
|
||||
/**
|
||||
* AVM2 code
|
||||
*/
|
||||
public AVM2Code code;
|
||||
|
||||
/**
|
||||
* Whether this has default to primitive
|
||||
*/
|
||||
public boolean thisHasDefaultToPrimitive;
|
||||
|
||||
/**
|
||||
* Mapping from setLocal position to getLocal positions
|
||||
*/
|
||||
public Map<Integer, Set<Integer>> setLocalPosToGetLocalPos = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Code stats
|
||||
*/
|
||||
public CodeStats codeStats;
|
||||
|
||||
/**
|
||||
* Indices of finally exceptions with double push
|
||||
*/
|
||||
public Set<Integer> finallyIndicesWithDoublePush = new HashSet<>();
|
||||
|
||||
/**
|
||||
* Whether we are in get loops
|
||||
*/
|
||||
public boolean inGetLoops = false;
|
||||
|
||||
/**
|
||||
* Set of seen methods
|
||||
*/
|
||||
public Set<Integer> seenMethods = new HashSet<>();
|
||||
|
||||
/**
|
||||
* Constructs a new AVM2LocalData
|
||||
*/
|
||||
public AVM2LocalData() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns set of getLocal positions for given setLocal position
|
||||
* @param setLocalPos SetLocal position
|
||||
* @return Set of getLocal positions
|
||||
*/
|
||||
public Set<Integer> getSetLocalUsages(int setLocalPos) {
|
||||
if (setLocalPosToGetLocalPos == null) {
|
||||
return new HashSet<>();
|
||||
@@ -141,6 +233,10 @@ public class AVM2LocalData extends BaseLocalData {
|
||||
return setLocalPosToGetLocalPos.get(setLocalPos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new AVM2LocalData from another AVM2LocalData
|
||||
* @param localData Another AVM2LocalData
|
||||
*/
|
||||
public AVM2LocalData(AVM2LocalData localData) {
|
||||
allSwitchParts = localData.allSwitchParts;
|
||||
isStatic = localData.isStatic;
|
||||
@@ -181,18 +277,34 @@ public class AVM2LocalData extends BaseLocalData {
|
||||
seenMethods = localData.seenMethods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns constant pool
|
||||
* @return Constant pool
|
||||
*/
|
||||
public AVM2ConstantPool getConstants() {
|
||||
return abc.constants;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns ABC method infos
|
||||
* @return List of MethodInfo
|
||||
*/
|
||||
public List<MethodInfo> getMethodInfo() {
|
||||
return abc.method_info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns ABC instance infos
|
||||
* @return List of InstanceInfo
|
||||
*/
|
||||
public List<InstanceInfo> getInstanceInfo() {
|
||||
return abc.instance_info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns ABC script infos
|
||||
* @return List of ScriptInfo
|
||||
*/
|
||||
public List<ScriptInfo> getScriptInfo() {
|
||||
return abc.script_info;
|
||||
}
|
||||
|
||||
@@ -17,36 +17,64 @@
|
||||
package com.jpexs.decompiler.flash.abc;
|
||||
|
||||
import com.jpexs.decompiler.graph.DottedChain;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
*
|
||||
* Class path
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ClassPath implements Serializable {
|
||||
|
||||
/**
|
||||
* Package name
|
||||
*/
|
||||
public final DottedChain packageStr;
|
||||
|
||||
/**
|
||||
* Class name
|
||||
*/
|
||||
public final String className;
|
||||
|
||||
/**
|
||||
* Namespace suffix
|
||||
*/
|
||||
public final String namespaceSuffix;
|
||||
|
||||
/**
|
||||
* Constructs a new class path
|
||||
* @param packageStr Package name
|
||||
* @param className Class name
|
||||
* @param namespaceSuffix Namespace suffix
|
||||
*/
|
||||
public ClassPath(DottedChain packageStr, String className, String namespaceSuffix) {
|
||||
this.packageStr = packageStr == null ? DottedChain.TOPLEVEL : packageStr;
|
||||
this.className = className;
|
||||
this.namespaceSuffix = namespaceSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* To string
|
||||
* @return String
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return packageStr.add(className, namespaceSuffix).toPrintableString(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* To raw string
|
||||
* @return Raw string
|
||||
*/
|
||||
public String toRawString() {
|
||||
return packageStr.add(className, namespaceSuffix).toRawString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash code
|
||||
* @return Hash code
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 3;
|
||||
@@ -56,6 +84,11 @@ public class ClassPath implements Serializable {
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Equals
|
||||
* @param obj
|
||||
* @return True if equals
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
|
||||
@@ -21,30 +21,61 @@ import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
*
|
||||
* Output stream that copies data to another output stream.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class CopyOutputStream extends OutputStream {
|
||||
|
||||
/**
|
||||
* Output stream to copy data to.
|
||||
*/
|
||||
private final OutputStream os;
|
||||
|
||||
/**
|
||||
* Input stream to compare data with.
|
||||
*/
|
||||
private final InputStream is;
|
||||
|
||||
/**
|
||||
* Position in the output stream.
|
||||
*/
|
||||
private long pos = 0;
|
||||
|
||||
/**
|
||||
* Size of the temporary buffer.
|
||||
*/
|
||||
private final int TEMPSIZE = 5;
|
||||
|
||||
/**
|
||||
* Temporary buffer.
|
||||
*/
|
||||
private final int[] temp = new int[TEMPSIZE];
|
||||
|
||||
/**
|
||||
* Position in the temporary buffer.
|
||||
*/
|
||||
private int tempPos = 0;
|
||||
|
||||
/**
|
||||
* Number of bytes to ignore at the beginning.
|
||||
*/
|
||||
public int ignoreFirst = 0;
|
||||
|
||||
/**
|
||||
* Constructs a new CopyOutputStream.
|
||||
* @param os Output stream to copy data to
|
||||
* @param is Input stream to compare data with
|
||||
*/
|
||||
public CopyOutputStream(OutputStream os, InputStream is) {
|
||||
this.os = os;
|
||||
this.is = is;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a byte to the output stream.
|
||||
* @param b Byte to write
|
||||
* @throws IOException If an I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
temp[tempPos] = b;
|
||||
|
||||
@@ -19,11 +19,15 @@ package com.jpexs.decompiler.flash.abc;
|
||||
import com.jpexs.helpers.Helper;
|
||||
|
||||
/**
|
||||
*
|
||||
* Streams are not the same exception.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class NotSameException extends RuntimeException {
|
||||
|
||||
/**
|
||||
* Constructs a new NotSameException with specified position.
|
||||
* @param pos Position
|
||||
*/
|
||||
public NotSameException(long pos) {
|
||||
super("Streams are not the same at pos " + Helper.formatHex((int) pos, 8));
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
package com.jpexs.decompiler.flash.abc;
|
||||
|
||||
/**
|
||||
*
|
||||
* Rename type enum.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public enum RenameType {
|
||||
|
||||
@@ -16,31 +16,20 @@
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc;
|
||||
|
||||
import com.jpexs.decompiler.flash.IdentifiersDeobfuscation;
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.ConvertException;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.OffsetUpdater;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instructions;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.IfTypeIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.debug.DebugFileIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.debug.DebugIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.debug.DebugLineIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.JumpIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.LookupSwitchIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.GlobalAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.parser.script.AbcIndexing;
|
||||
import com.jpexs.decompiler.flash.abc.types.ABCException;
|
||||
import com.jpexs.decompiler.flash.abc.types.ConvertData;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.Multiname;
|
||||
import com.jpexs.decompiler.flash.abc.types.Namespace;
|
||||
import com.jpexs.decompiler.flash.abc.types.ScriptInfo;
|
||||
import com.jpexs.decompiler.flash.abc.types.*;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.TraitClass;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.TraitFunction;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.TraitMethodGetterSetter;
|
||||
import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.settings.ScriptExportSettings;
|
||||
@@ -58,62 +47,91 @@ import com.jpexs.decompiler.graph.ScopeStack;
|
||||
import com.jpexs.helpers.CancellableWorker;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import com.jpexs.helpers.Path;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* Script pack class.
|
||||
* A script pack is a collection of traits that are in the same script.
|
||||
* It can be a simple script pack (contains only one externally visible definition)
|
||||
* or a compound script pack (contains more than one externally visible definitions).
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ScriptPack extends AS3ClassTreeItem {
|
||||
|
||||
/**
|
||||
* Logger
|
||||
*/
|
||||
private static final Logger logger = Logger.getLogger(ScriptPack.class.getName());
|
||||
|
||||
/**
|
||||
* ABC file
|
||||
*/
|
||||
public final ABC abc;
|
||||
|
||||
/**
|
||||
* All ABC files
|
||||
*/
|
||||
public List<ABC> allABCs;
|
||||
|
||||
/**
|
||||
* Script index
|
||||
*/
|
||||
public final int scriptIndex;
|
||||
|
||||
/**
|
||||
* Trait indices
|
||||
*/
|
||||
public final List<Integer> traitIndices;
|
||||
|
||||
/**
|
||||
* Class path
|
||||
*/
|
||||
private final ClassPath path;
|
||||
|
||||
/**
|
||||
* Is the scriptpack simple? ScriptPack can be either simple or compound.
|
||||
* Whether the scriptpack is simple. ScriptPack can be either simple or compound.
|
||||
* Compound = Contains more than one externally visible definitions.
|
||||
*/
|
||||
public boolean isSimple = false;
|
||||
|
||||
/**
|
||||
* Whether the script initializer is empty
|
||||
*/
|
||||
public boolean scriptInitializerIsEmpty = false;
|
||||
|
||||
/**
|
||||
* Gets openable.
|
||||
* @return Openable
|
||||
*/
|
||||
@Override
|
||||
public Openable getOpenable() {
|
||||
return abc.getOpenable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets class path.
|
||||
* @return Class path
|
||||
*/
|
||||
public ClassPath getClassPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new script pack.
|
||||
* @param path Class path
|
||||
* @param abc ABC file
|
||||
* @param allAbcs All ABC files
|
||||
* @param scriptIndex Script index
|
||||
* @param traitIndices Trait indices
|
||||
*/
|
||||
public ScriptPack(ClassPath path, ABC abc, List<ABC> allAbcs, int scriptIndex, List<Integer> traitIndices) {
|
||||
super(path.className, path.namespaceSuffix, path);
|
||||
this.abc = abc;
|
||||
@@ -123,6 +141,10 @@ public class ScriptPack extends AS3ClassTreeItem {
|
||||
this.allABCs = allAbcs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets path package.
|
||||
* @return Dotted chain
|
||||
*/
|
||||
public DottedChain getPathPackage() {
|
||||
DottedChain packageName = DottedChain.TOPLEVEL;
|
||||
for (int t : traitIndices) {
|
||||
@@ -135,6 +157,10 @@ public class ScriptPack extends AS3ClassTreeItem {
|
||||
return packageName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets public trait.
|
||||
* @return Trait or null if not found
|
||||
*/
|
||||
public Trait getPublicTrait() {
|
||||
for (int t : traitIndices) {
|
||||
Multiname name = abc.script_info.get(scriptIndex).traits.traits.get(t).getName(abc);
|
||||
@@ -146,6 +172,10 @@ public class ScriptPack extends AS3ClassTreeItem {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets path script name.
|
||||
* @return Script name
|
||||
*/
|
||||
public String getPathScriptName() {
|
||||
String scriptName = "script_" + scriptIndex;
|
||||
for (int t : traitIndices) {
|
||||
@@ -158,6 +188,12 @@ public class ScriptPack extends AS3ClassTreeItem {
|
||||
return scriptName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets export file.
|
||||
* @param directory Directory
|
||||
* @param extension Extension including dot
|
||||
* @return File
|
||||
*/
|
||||
public File getExportFile(String directory, String extension) {
|
||||
|
||||
String scriptName = getPathScriptName();
|
||||
@@ -167,6 +203,12 @@ public class ScriptPack extends AS3ClassTreeItem {
|
||||
return new File(fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets export file.
|
||||
* @param directory Directory
|
||||
* @param exportSettings Export settings
|
||||
* @return File
|
||||
*/
|
||||
public File getExportFile(String directory, ScriptExportSettings exportSettings) {
|
||||
if (exportSettings.singleFile) {
|
||||
return null;
|
||||
@@ -175,6 +217,16 @@ public class ScriptPack extends AS3ClassTreeItem {
|
||||
return getExportFile(directory, exportSettings.getFileExtension());
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the script pack.
|
||||
* @param abcIndex Abc indexing
|
||||
* @param writer Writer
|
||||
* @param traits Traits
|
||||
* @param convertData Convert data
|
||||
* @param exportMode Export mode
|
||||
* @param parallel Parallel
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public void convert(AbcIndexing abcIndex, final NulWriter writer, final List<Trait> traits, final ConvertData convertData, final ScriptExportMode exportMode, final boolean parallel) throws InterruptedException {
|
||||
|
||||
int sinit_index = abc.script_info.get(scriptIndex).init_index;
|
||||
@@ -208,6 +260,16 @@ public class ScriptPack extends AS3ClassTreeItem {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Append script to writer.
|
||||
* @param abcIndex Abc indexing
|
||||
* @param writer Writer
|
||||
* @param traits Traits
|
||||
* @param convertData Convert data
|
||||
* @param exportMode Export mode
|
||||
* @param parallel Parallel
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
private void appendTo(AbcIndexing abcIndex, GraphTextWriter writer, List<Trait> traits, ConvertData convertData, ScriptExportMode exportMode, boolean parallel) throws InterruptedException {
|
||||
boolean first = true;
|
||||
//script initializer
|
||||
@@ -269,6 +331,17 @@ public class ScriptPack extends AS3ClassTreeItem {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the script pack to source.
|
||||
* @param abcIndex Abc indexing
|
||||
* @param writer Writer
|
||||
* @param traits Traits
|
||||
* @param convertData Convert data
|
||||
* @param exportMode Export mode
|
||||
* @param parallel Parallel
|
||||
* @param ignoreFrameScripts Whether to ignore frame scripts
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public void toSource(AbcIndexing abcIndex, GraphTextWriter writer, final List<Trait> traits, final ConvertData convertData, final ScriptExportMode exportMode, final boolean parallel, boolean ignoreFrameScripts) throws InterruptedException {
|
||||
writer.suspendMeasure();
|
||||
int timeout = Configuration.decompilationTimeoutFile.get();
|
||||
@@ -310,6 +383,16 @@ public class ScriptPack extends AS3ClassTreeItem {
|
||||
appendTo(abcIndex, writer, traits, convertData, exportMode, parallel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Exports the script pack.
|
||||
* @param abcIndex Abc indexing
|
||||
* @param file File
|
||||
* @param exportSettings Export settings
|
||||
* @param parallel Parallel
|
||||
* @return File
|
||||
* @throws IOException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public File export(AbcIndexing abcIndex, File file, ScriptExportSettings exportSettings, boolean parallel) throws IOException, InterruptedException {
|
||||
if (!exportSettings.singleFile) {
|
||||
if (file.exists() && !Configuration.overwriteExistingFiles.get()) {
|
||||
@@ -336,6 +419,10 @@ public class ScriptPack extends AS3ClassTreeItem {
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash code.
|
||||
* @return Hash code
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 7;
|
||||
@@ -345,6 +432,11 @@ public class ScriptPack extends AS3ClassTreeItem {
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Equals.
|
||||
* @param obj Object
|
||||
* @return True if equals
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
@@ -363,6 +455,10 @@ public class ScriptPack extends AS3ClassTreeItem {
|
||||
return Objects.equals(path, other.path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets modified flag.
|
||||
* @return True if modified
|
||||
*/
|
||||
@Override
|
||||
public boolean isModified() {
|
||||
if (scriptIndex >= abc.script_info.size()) {
|
||||
@@ -371,6 +467,9 @@ public class ScriptPack extends AS3ClassTreeItem {
|
||||
return abc.script_info.get(scriptIndex).isModified();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears modified flag.
|
||||
*/
|
||||
public void clearModified() {
|
||||
if (scriptIndex >= abc.script_info.size()) {
|
||||
return;
|
||||
@@ -378,10 +477,21 @@ public class ScriptPack extends AS3ClassTreeItem {
|
||||
abc.script_info.get(scriptIndex).setModified(false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Label with address.
|
||||
*/
|
||||
private class Label {
|
||||
|
||||
/**
|
||||
* Address
|
||||
*/
|
||||
public long addr;
|
||||
|
||||
/**
|
||||
* Constructs a new label.
|
||||
* @param addr Address
|
||||
*/
|
||||
public Label(long addr) {
|
||||
this.addr = addr;
|
||||
}
|
||||
@@ -398,7 +508,12 @@ public class ScriptPack extends AS3ClassTreeItem {
|
||||
public void injectDebugInfo(File directoryPath) {
|
||||
injectDebugInfo(directoryPath, "main");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Injects debugfile, debugline instructions into the code.
|
||||
* @param directoryPath Directory path
|
||||
* @param swfHash SWF identifier
|
||||
*/
|
||||
public void injectDebugInfo(File directoryPath, String swfHash) {
|
||||
Map<Integer, Map<Integer, Integer>> bodyToPosToLine = new HashMap<>();
|
||||
Map<Integer, Map<Integer, Integer>> bodyLineToPos = new HashMap<>();
|
||||
@@ -694,6 +809,11 @@ public class ScriptPack extends AS3ClassTreeItem {
|
||||
((Tag) abc.parentTag).setModified(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Injects P-code debugfile, debugline instructions into the code.
|
||||
* @param abcIndex Abc indexing
|
||||
* @param swfHash SWF identifier
|
||||
*/
|
||||
public void injectPCodeDebugInfo(int abcIndex, String swfHash) {
|
||||
|
||||
Map<Integer, String> bodyToIdentifier = new HashMap<>();
|
||||
@@ -779,6 +899,10 @@ public class ScriptPack extends AS3ClassTreeItem {
|
||||
((Tag) abc.parentTag).setModified(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets method ids.
|
||||
* @param methodInfos Result list of MethodIds
|
||||
*/
|
||||
public void getMethodInfos(List<MethodId> methodInfos) {
|
||||
int script_init = abc.script_info.get(scriptIndex).init_index;
|
||||
methodInfos.add(new MethodId(GraphTextWriter.TRAIT_SCRIPT_INITIALIZER, -1, script_init));
|
||||
@@ -790,6 +914,11 @@ public class ScriptPack extends AS3ClassTreeItem {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the script pack.
|
||||
* @param abc ABC file
|
||||
* @param d Whether to delete
|
||||
*/
|
||||
public void delete(ABC abc, boolean d) {
|
||||
ScriptInfo si = abc.script_info.get(scriptIndex);
|
||||
if (isSimple) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -21,42 +21,76 @@ import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.abc.RenameType;
|
||||
import com.jpexs.decompiler.graph.DottedChain;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
*
|
||||
* AVM2 deobfuscation.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class AVM2Deobfuscation {
|
||||
|
||||
/**
|
||||
* Default size of random word.
|
||||
*/
|
||||
private static final int DEFAULT_FOO_SIZE = 10;
|
||||
|
||||
/**
|
||||
* Valid characters for first character of name.
|
||||
*/
|
||||
public static final String VALID_FIRST_CHARACTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$";
|
||||
|
||||
/**
|
||||
* Valid characters for next characters of name.
|
||||
*/
|
||||
public static final String VALID_NEXT_CHARACTERS = VALID_FIRST_CHARACTERS + "0123456789";
|
||||
|
||||
/**
|
||||
* Valid characters for namespace.
|
||||
*/
|
||||
public static final String VALID_NS_CHARACTERS = ".:";
|
||||
|
||||
/**
|
||||
* SWF file.
|
||||
*/
|
||||
private final SWF swf;
|
||||
|
||||
/**
|
||||
* AVM2 constant pool.
|
||||
*/
|
||||
private final AVM2ConstantPool constants;
|
||||
|
||||
/**
|
||||
* Usage types count.
|
||||
*/
|
||||
private final Map<String, Integer> usageTypesCount = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Flash proxy namespace.
|
||||
*/
|
||||
public static final DottedChain FLASH_PROXY = new DottedChain(new String[]{"flash", "utils", "flash_proxy"});
|
||||
|
||||
/**
|
||||
* Built-in namespace.
|
||||
*/
|
||||
public static final DottedChain BUILTIN = new DottedChain(new String[]{"-"});
|
||||
|
||||
/**
|
||||
* Constructs AVM2 deobfuscation.
|
||||
* @param swf SWF
|
||||
* @param constants AVM2 constant pool
|
||||
*/
|
||||
public AVM2Deobfuscation(SWF swf, AVM2ConstantPool constants) {
|
||||
this.swf = swf;
|
||||
this.constants = constants;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if string is valid namespace part.
|
||||
* @param s String
|
||||
* @return True if string is valid namespace part
|
||||
*/
|
||||
private boolean isValidNSPart(String s) {
|
||||
boolean isValid = true;
|
||||
if (IdentifiersDeobfuscation.isReservedWord2(s)) {
|
||||
@@ -80,6 +114,11 @@ public class AVM2Deobfuscation {
|
||||
return isValid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets built-in namespace.
|
||||
* @param ns Namespace
|
||||
* @return Built-in namespace
|
||||
*/
|
||||
public DottedChain builtInNs(String ns) {
|
||||
if (ns == null) {
|
||||
return null;
|
||||
@@ -93,6 +132,16 @@ public class AVM2Deobfuscation {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates random string.
|
||||
* @param deobfuscated Deobfuscated names
|
||||
* @param orig Original name
|
||||
* @param firstUppercase First uppercase
|
||||
* @param usageType Usage type
|
||||
* @param renameType Rename type
|
||||
* @param autoAdd Auto add
|
||||
* @return Random string
|
||||
*/
|
||||
private String fooString(HashMap<DottedChain, DottedChain> deobfuscated, String orig, boolean firstUppercase, String usageType, RenameType renameType, boolean autoAdd) {
|
||||
if (usageType == null) {
|
||||
usageType = "name";
|
||||
@@ -122,6 +171,15 @@ public class AVM2Deobfuscation {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deobfuscates package name.
|
||||
* @param stringUsageTypes String usage types
|
||||
* @param stringUsages String usages
|
||||
* @param namesMap Names map
|
||||
* @param strIndex String index
|
||||
* @param renameType Rename type
|
||||
* @return Deobfuscated package name
|
||||
*/
|
||||
public int deobfuscatePackageName(Map<Integer, String> stringUsageTypes, Set<Integer> stringUsages, HashMap<DottedChain, DottedChain> namesMap, int strIndex, RenameType renameType) {
|
||||
if (strIndex <= 0) {
|
||||
return strIndex;
|
||||
@@ -160,6 +218,17 @@ public class AVM2Deobfuscation {
|
||||
return strIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deobfuscates name.
|
||||
* @param stringUsageTypes String usage types
|
||||
* @param stringUsages String usages
|
||||
* @param namespaceUsages Namespace usages
|
||||
* @param namesMap Names map
|
||||
* @param strIndex String index
|
||||
* @param firstUppercase First uppercase
|
||||
* @param renameType Rename type
|
||||
* @return Deobfuscated name string index
|
||||
*/
|
||||
public int deobfuscateName(Map<Integer, String> stringUsageTypes, Set<Integer> stringUsages, Set<Integer> namespaceUsages, HashMap<DottedChain, DottedChain> namesMap, int strIndex, boolean firstUppercase, RenameType renameType) {
|
||||
if (strIndex <= 0) {
|
||||
return strIndex;
|
||||
|
||||
+21
-6
@@ -18,27 +18,42 @@ package com.jpexs.decompiler.flash.abc.avm2;
|
||||
|
||||
import com.jpexs.decompiler.flash.FinalProcessLocalData;
|
||||
import com.jpexs.decompiler.graph.Loop;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* AVM2 final process local data.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class AVM2FinalProcessLocalData extends FinalProcessLocalData {
|
||||
|
||||
/**
|
||||
* Local register names - register number to name mapping.
|
||||
*/
|
||||
public HashMap<Integer, String> localRegNames;
|
||||
|
||||
/**
|
||||
* Set local position to get local position mapping.
|
||||
*/
|
||||
public Map<Integer, Set<Integer>> setLocalPosToGetLocalPos = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Constructs AVM2 final process local data.
|
||||
* @param loops List of loops
|
||||
* @param localRegNames Local register names - register number to name mapping
|
||||
* @param setLocalPosToGetLocalPos Set local position to get local position mapping
|
||||
*/
|
||||
public AVM2FinalProcessLocalData(List<Loop> loops, HashMap<Integer, String> localRegNames, Map<Integer, Set<Integer>> setLocalPosToGetLocalPos) {
|
||||
super(loops);
|
||||
this.localRegNames = localRegNames;
|
||||
this.setLocalPosToGetLocalPos = setLocalPosToGetLocalPos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets getlocal positions for setlocal position.
|
||||
* @param setLocalPos Setlocal position
|
||||
* @return Set of getlocal positions
|
||||
*/
|
||||
public Set<Integer> getSetLocalUsages(int setLocalPos) {
|
||||
if (setLocalPosToGetLocalPos == null) {
|
||||
return new HashSet<>();
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
package com.jpexs.decompiler.flash.abc.avm2;
|
||||
|
||||
/**
|
||||
*
|
||||
* Type of AVM2 runtime enum.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public enum AVM2Runtime {
|
||||
|
||||
@@ -17,17 +17,32 @@
|
||||
package com.jpexs.decompiler.flash.abc.avm2;
|
||||
|
||||
/**
|
||||
*
|
||||
* Info of AVM2 runtime.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class AVM2RuntimeInfo {
|
||||
|
||||
/**
|
||||
* AVM2 runtime.
|
||||
*/
|
||||
public AVM2Runtime runtime;
|
||||
|
||||
/**
|
||||
* AVM2 version.
|
||||
*/
|
||||
public int version;
|
||||
|
||||
/**
|
||||
* Debug flag.
|
||||
*/
|
||||
public boolean debug;
|
||||
|
||||
/**
|
||||
* Constructs AVM2 runtime info.
|
||||
* @param runtime AVM2 runtime
|
||||
* @param version AVM2 version
|
||||
* @param debug Debug flag
|
||||
*/
|
||||
public AVM2RuntimeInfo(AVM2Runtime runtime, int version, boolean debug) {
|
||||
this.runtime = runtime;
|
||||
this.version = version;
|
||||
|
||||
@@ -20,30 +20,59 @@ import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
|
||||
import com.jpexs.decompiler.graph.DottedChain;
|
||||
import com.jpexs.decompiler.graph.model.LocalData;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* Code statistics.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class CodeStats {
|
||||
|
||||
/**
|
||||
* Maximum stack size
|
||||
*/
|
||||
public int maxstack = 0;
|
||||
|
||||
/**
|
||||
* Maximum scope size
|
||||
*/
|
||||
public int maxscope = 0;
|
||||
|
||||
/**
|
||||
* Number of local registers
|
||||
*/
|
||||
public int maxlocal = 1;
|
||||
|
||||
/**
|
||||
* Initial scope size
|
||||
*/
|
||||
public int initscope = 0;
|
||||
|
||||
/**
|
||||
* Has set_dxns instruction
|
||||
*/
|
||||
public boolean has_set_dxns = false;
|
||||
|
||||
/**
|
||||
* Has activation instruction
|
||||
*/
|
||||
public boolean has_activation = false;
|
||||
|
||||
/**
|
||||
* Instruction statistics
|
||||
*/
|
||||
public InstructionStats[] instructionStats;
|
||||
|
||||
/**
|
||||
* Converts statistics to string.
|
||||
* @param writer Writer
|
||||
* @param abc ABC
|
||||
* @param fullyQualifiedNames Fully qualified names
|
||||
* @return Writer
|
||||
*/
|
||||
public GraphTextWriter toString(GraphTextWriter writer, ABC abc, List<DottedChain> fullyQualifiedNames) {
|
||||
writer.appendNoHilight("Stats: maxstack=" + maxstack + ", maxscope=" + maxscope + ", maxlocal=" + maxlocal).newLine();
|
||||
int i = 0;
|
||||
@@ -59,9 +88,16 @@ public class CodeStats {
|
||||
return writer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs code statistics.
|
||||
*/
|
||||
public CodeStats() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs code statistics.
|
||||
* @param code AVM2 code
|
||||
*/
|
||||
public CodeStats(AVM2Code code) {
|
||||
instructionStats = new InstructionStats[code.code.size()];
|
||||
for (int i = 0; i < code.code.size(); i++) {
|
||||
|
||||
@@ -17,13 +17,22 @@
|
||||
package com.jpexs.decompiler.flash.abc.avm2;
|
||||
|
||||
/**
|
||||
*
|
||||
* Convert exception.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ConvertException extends RuntimeException {
|
||||
|
||||
/**
|
||||
* Line number
|
||||
*/
|
||||
public int line;
|
||||
|
||||
|
||||
/**
|
||||
* Constructs convert exception.
|
||||
* @param s Message
|
||||
* @param line Line number
|
||||
*/
|
||||
public ConvertException(String s, int line) {
|
||||
super(s + " on line " + line);
|
||||
this.line = line;
|
||||
|
||||
@@ -18,18 +18,30 @@ package com.jpexs.decompiler.flash.abc.avm2;
|
||||
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.TranslateStack;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* Conversion output.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ConvertOutput {
|
||||
|
||||
/**
|
||||
* Translate stack
|
||||
*/
|
||||
public TranslateStack stack;
|
||||
|
||||
/**
|
||||
* Output
|
||||
*/
|
||||
public List<GraphTargetItem> output;
|
||||
|
||||
/**
|
||||
* Constructs conversion output.
|
||||
* @param stack Translate stack
|
||||
* @param output Output
|
||||
*/
|
||||
public ConvertOutput(TranslateStack stack, List<GraphTargetItem> output) {
|
||||
this.stack = stack;
|
||||
this.output = output;
|
||||
|
||||
+25
-1
@@ -20,17 +20,28 @@ import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.TranslateStack;
|
||||
|
||||
/**
|
||||
*
|
||||
* Translate stack that counts the number of items pushed and not popped.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class FixItemCounterTranslateStack extends TranslateStack {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private int fixItemCount = Integer.MAX_VALUE;
|
||||
|
||||
/**
|
||||
* Constructs a new FixItemCounterTranslateStack
|
||||
* @param path Path
|
||||
*/
|
||||
public FixItemCounterTranslateStack(String path) {
|
||||
super(null); //null path => do not add PushItems
|
||||
}
|
||||
|
||||
/**
|
||||
* Pops an item from the stack
|
||||
* @return The popped item
|
||||
*/
|
||||
@Override
|
||||
public GraphTargetItem pop() {
|
||||
GraphTargetItem result = super.pop();
|
||||
@@ -41,6 +52,11 @@ public class FixItemCounterTranslateStack extends TranslateStack {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the element at the specified index
|
||||
* @param index the index of the element to be removed
|
||||
* @return The removed element
|
||||
*/
|
||||
@Override
|
||||
public synchronized GraphTargetItem remove(int index) {
|
||||
if (index < fixItemCount) {
|
||||
@@ -49,10 +65,18 @@ public class FixItemCounterTranslateStack extends TranslateStack {
|
||||
return super.remove(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* All items were never popped.
|
||||
* @return True if all items were never popped
|
||||
*/
|
||||
public boolean allItemsFixed() {
|
||||
return size() <= fixItemCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of items that were never popped
|
||||
* @return The number of items that were never popped
|
||||
*/
|
||||
public int getFixItemCount() {
|
||||
return fixItemCount;
|
||||
}
|
||||
|
||||
@@ -19,23 +19,45 @@ package com.jpexs.decompiler.flash.abc.avm2;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
|
||||
|
||||
/**
|
||||
*
|
||||
* Instruction statistics.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class InstructionStats {
|
||||
|
||||
/**
|
||||
* Whether the instruction has been seen while walking the instruction list
|
||||
*/
|
||||
public boolean seen = false;
|
||||
|
||||
/**
|
||||
* Stack position before the instruction
|
||||
*/
|
||||
public int stackpos = 0;
|
||||
|
||||
/**
|
||||
* Scope position before the instruction
|
||||
*/
|
||||
public int scopepos = 0;
|
||||
|
||||
/**
|
||||
* Stack position after the instruction
|
||||
*/
|
||||
public int stackpos_after = 0;
|
||||
|
||||
/**
|
||||
* Scope position after the instruction
|
||||
*/
|
||||
public int scopepos_after = 0;
|
||||
|
||||
/**
|
||||
* Instruction
|
||||
*/
|
||||
public AVM2Instruction ins;
|
||||
|
||||
/**
|
||||
* Constructs a new InstructionStats object
|
||||
* @param ins Instruction
|
||||
*/
|
||||
public InstructionStats(AVM2Instruction ins) {
|
||||
this.ins = ins;
|
||||
}
|
||||
|
||||
+6
-3
@@ -17,12 +17,15 @@
|
||||
package com.jpexs.decompiler.flash.abc.avm2;
|
||||
|
||||
/**
|
||||
*
|
||||
* Invalid instruction arguments exception.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class InvalidInstructionArguments extends RuntimeException {
|
||||
public class InvalidInstructionArgumentsException extends RuntimeException {
|
||||
|
||||
public InvalidInstructionArguments() {
|
||||
/**
|
||||
* Constructs new InvalidInstructionArgumentsException
|
||||
*/
|
||||
public InvalidInstructionArgumentsException() {
|
||||
super("Invalid method arguments");
|
||||
}
|
||||
}
|
||||
@@ -20,30 +20,61 @@ import java.util.HashMap;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
*
|
||||
* Local data area for AVM2 method execution.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class LocalDataArea {
|
||||
|
||||
/**
|
||||
* Name of the method that is currently being executed.
|
||||
*/
|
||||
public String methodName;
|
||||
|
||||
/**
|
||||
* Operand stack.
|
||||
*/
|
||||
public Stack<Object> operandStack = new Stack<>();
|
||||
|
||||
/**
|
||||
* Scope stack.
|
||||
*/
|
||||
public Stack<Object> scopeStack = new Stack<>();
|
||||
|
||||
/**
|
||||
* Local registers values - maps register index to value.
|
||||
*/
|
||||
public HashMap<Integer, Object> localRegisters = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Offset of jump
|
||||
*/
|
||||
public Long jump;
|
||||
|
||||
/**
|
||||
* Return value of the method.
|
||||
*/
|
||||
public Object returnValue;
|
||||
|
||||
/**
|
||||
* Runtime info.
|
||||
*/
|
||||
public AVM2RuntimeInfo runtimeInfo;
|
||||
|
||||
/**
|
||||
* Domain memory.
|
||||
*/
|
||||
private byte[] domainMemory;
|
||||
|
||||
/**
|
||||
* Constructs a new LocalDataArea.
|
||||
*/
|
||||
public LocalDataArea() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets domain memory.
|
||||
* @return Domain memory bytes.
|
||||
*/
|
||||
public byte[] getDomainMemory() {
|
||||
if (domainMemory == null) {
|
||||
domainMemory = new byte[1024]; // in flash player this is the default size
|
||||
@@ -52,14 +83,25 @@ public class LocalDataArea {
|
||||
return domainMemory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets runtime.
|
||||
* @return Runtime.
|
||||
*/
|
||||
public AVM2Runtime getRuntime() {
|
||||
return runtimeInfo == null ? AVM2Runtime.UNKNOWN : runtimeInfo.runtime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets debug flag.
|
||||
* @return True if debug flag is set.
|
||||
*/
|
||||
public boolean isDebug() {
|
||||
return runtimeInfo != null && runtimeInfo.debug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the local data area.
|
||||
*/
|
||||
public void clear() {
|
||||
operandStack.clear();
|
||||
scopeStack.clear();
|
||||
|
||||
@@ -16,8 +16,12 @@
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2;
|
||||
|
||||
/**
|
||||
* Number context.
|
||||
*/
|
||||
public class NumberContext {
|
||||
|
||||
//Rounding modes
|
||||
public static final int ROUND_CEILING = 0;
|
||||
public static final int ROUND_UP = 1;
|
||||
public static final int ROUND_HALF_UP = 2;
|
||||
@@ -26,28 +30,54 @@ public class NumberContext {
|
||||
public static final int ROUND_DOWN = 5;
|
||||
public static final int ROUND_FLOOR = 6;
|
||||
|
||||
//Usage modes
|
||||
public static final int USE_NUMBER = 0;
|
||||
public static final int USE_DECIMAL = 1;
|
||||
public static final int USE_DOUBLE = 2;
|
||||
public static final int USE_INT = 3;
|
||||
public static final int USE_UINT = 4;
|
||||
|
||||
/**
|
||||
* Usage of the number.
|
||||
*/
|
||||
private int usage = USE_NUMBER;
|
||||
/**
|
||||
* Precision of the number.
|
||||
*/
|
||||
private int precision = 34;
|
||||
/**
|
||||
* Rounding of the number.
|
||||
*/
|
||||
private int rounding = ROUND_HALF_EVEN;
|
||||
|
||||
/**
|
||||
* Creates a new number context.
|
||||
*
|
||||
* @param usage Usage of the number.
|
||||
* @param precision Precision of the number.
|
||||
* @param rounding Rounding of the number.
|
||||
*/
|
||||
public NumberContext(int usage, int precision, int rounding) {
|
||||
this.usage = usage;
|
||||
this.precision = precision;
|
||||
this.rounding = rounding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new number context.
|
||||
*
|
||||
* @param param Parameter.
|
||||
*/
|
||||
public NumberContext(int param) {
|
||||
this.usage = param & 7;
|
||||
this.rounding = (param >> 3) & 7;
|
||||
this.precision = param >> 6;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the usage of the number.
|
||||
* @param usage
|
||||
*/
|
||||
public void setUsage(int usage) {
|
||||
if (usage > 6 || usage < 0) {
|
||||
throw new IllegalArgumentException("Invalid usage value :" + usage);
|
||||
@@ -55,14 +85,26 @@ public class NumberContext {
|
||||
this.usage = usage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the usage of the number.
|
||||
* @return Usage of the number.
|
||||
*/
|
||||
public int getUsage() {
|
||||
return usage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the precision of the number.
|
||||
* @return Precision of the number.
|
||||
*/
|
||||
public int getPrecision() {
|
||||
return precision;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the precision of the number.
|
||||
* @param precision Precision of the number.
|
||||
*/
|
||||
public void setPrecision(int precision) {
|
||||
if (precision > 34) {
|
||||
throw new IllegalArgumentException("Maximum value of precision is 34");
|
||||
@@ -70,6 +112,10 @@ public class NumberContext {
|
||||
this.precision = precision;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the number context to a parameter.
|
||||
* @return Parameter.
|
||||
*/
|
||||
public int toParam() {
|
||||
int ret = usage;
|
||||
if (usage == USE_NUMBER || usage == USE_DECIMAL) {
|
||||
|
||||
@@ -17,12 +17,25 @@
|
||||
package com.jpexs.decompiler.flash.abc.avm2;
|
||||
|
||||
/**
|
||||
*
|
||||
* Offset updater interface.
|
||||
* Used to update offsets in instructions and operands.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public interface OffsetUpdater {
|
||||
|
||||
/**
|
||||
* Updates instruction offset.
|
||||
* @param addr Address of the instruction
|
||||
* @return New address of the instruction
|
||||
*/
|
||||
public long updateInstructionOffset(long addr);
|
||||
|
||||
/**
|
||||
* Updates operand offset.
|
||||
* @param jumpAddr Address of the jump instruction
|
||||
* @param targetAddress Address of the target instruction
|
||||
* @param offset Operand (offset) of the jump instruction
|
||||
* @return New operand offset
|
||||
*/
|
||||
public int updateOperandOffset(long jumpAddr, long targetAddress, int offset);
|
||||
}
|
||||
|
||||
+10
-3
@@ -17,14 +17,21 @@
|
||||
package com.jpexs.decompiler.flash.abc.avm2;
|
||||
|
||||
/**
|
||||
*
|
||||
* Exception thrown when unknown instruction code is found.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class UnknownInstructionCode extends RuntimeException {
|
||||
public class UnknownInstructionCodeException extends RuntimeException {
|
||||
|
||||
/**
|
||||
* Instruction code
|
||||
*/
|
||||
public int code;
|
||||
|
||||
public UnknownInstructionCode(int code) {
|
||||
/**
|
||||
* Constructs a new UnknownInstructionCodeException.
|
||||
* @param code Instruction code
|
||||
*/
|
||||
public UnknownInstructionCodeException(int code) {
|
||||
super("Unknown instruction code: 0x" + Integer.toHexString(code));
|
||||
this.code = code;
|
||||
}
|
||||
+66
-6
@@ -36,11 +36,8 @@ import com.jpexs.decompiler.flash.abc.avm2.model.UndefinedAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
|
||||
import com.jpexs.decompiler.flash.helpers.SWFDecompilerAdapter;
|
||||
import com.jpexs.decompiler.graph.Graph;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.NotCompileTimeItem;
|
||||
import com.jpexs.decompiler.graph.ScopeStack;
|
||||
import com.jpexs.decompiler.graph.TranslateException;
|
||||
import com.jpexs.decompiler.graph.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -48,7 +45,7 @@ import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* AVM2 Deobfuscator removing single get / set registers
|
||||
* AVM2 Deobfuscator removing single get / set registers.
|
||||
*
|
||||
* Example: getlocal_1, getlocal_2, (kill 1), (kill 2), setlocal_2, setlocal_1
|
||||
*
|
||||
@@ -56,12 +53,32 @@ import java.util.Map;
|
||||
*/
|
||||
public class AVM2DeobfuscatorGetSet extends SWFDecompilerAdapter {
|
||||
|
||||
/**
|
||||
* Undefined item
|
||||
*/
|
||||
private static final UndefinedAVM2Item UNDEFINED_ITEM = new UndefinedAVM2Item(null, null);
|
||||
|
||||
/**
|
||||
* Not compile time undefined item
|
||||
*/
|
||||
private static final NotCompileTimeItem NOT_COMPILE_TIME_UNDEFINED_ITEM = new NotCompileTimeItem(null, null, UNDEFINED_ITEM);
|
||||
|
||||
/**
|
||||
* Execution limit
|
||||
*/
|
||||
private final int executionLimit = 30000;
|
||||
|
||||
/**
|
||||
* Remove obfuscation get sets
|
||||
* @param classIndex Class index
|
||||
* @param isStatic Is static
|
||||
* @param scriptIndex Script index
|
||||
* @param abc ABC
|
||||
* @param body Method body
|
||||
* @param inlineIns Inline instructions
|
||||
* @return True if removed
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
protected boolean removeObfuscationGetSets(int classIndex, boolean isStatic, int scriptIndex, ABC abc, MethodBody body, List<AVM2Instruction> inlineIns) throws InterruptedException {
|
||||
AVM2Code code = body.getCode();
|
||||
if (code.code.isEmpty()) {
|
||||
@@ -99,10 +116,26 @@ public class AVM2DeobfuscatorGetSet extends SWFDecompilerAdapter {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove unreachable instructions.
|
||||
* @param code AVM2 code
|
||||
* @param body Method body
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
protected void removeUnreachableInstructions(AVM2Code code, MethodBody body) throws InterruptedException {
|
||||
code.removeDeadCode(body);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new local data.
|
||||
* @param scriptIndex Script index
|
||||
* @param abc ABC
|
||||
* @param cpool Constant pool
|
||||
* @param body Method body
|
||||
* @param isStatic Is static
|
||||
* @param classIndex Class index
|
||||
* @return AVM2 local data
|
||||
*/
|
||||
protected AVM2LocalData newLocalData(int scriptIndex, ABC abc, AVM2ConstantPool cpool, MethodBody body, boolean isStatic, int classIndex) {
|
||||
AVM2LocalData localData = new AVM2LocalData();
|
||||
localData.isStatic = isStatic;
|
||||
@@ -124,6 +157,12 @@ public class AVM2DeobfuscatorGetSet extends SWFDecompilerAdapter {
|
||||
return localData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize local registers.
|
||||
* @param localData AVM2 local data
|
||||
* @param localReservedCount Local reserved count
|
||||
* @param maxRegs Maximum registers
|
||||
*/
|
||||
protected void initLocalRegs(AVM2LocalData localData, int localReservedCount, int maxRegs) {
|
||||
for (int i = 0; i < localReservedCount; i++) {
|
||||
localData.localRegs.put(i, NOT_COMPILE_TIME_UNDEFINED_ITEM);
|
||||
@@ -133,6 +172,15 @@ public class AVM2DeobfuscatorGetSet extends SWFDecompilerAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute instructions.
|
||||
* @param body Method body
|
||||
* @param code AVM2 code
|
||||
* @param localData AVM2 local data
|
||||
* @param idx Index
|
||||
* @param endIdx End index
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
private void executeInstructions(MethodBody body, AVM2Code code, AVM2LocalData localData, int idx, int endIdx) throws InterruptedException {
|
||||
List<GraphTargetItem> output = new ArrayList<>();
|
||||
|
||||
@@ -217,6 +265,18 @@ public class AVM2DeobfuscatorGetSet extends SWFDecompilerAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* AVM2 code remove traps.
|
||||
* @param path Path
|
||||
* @param classIndex Class index
|
||||
* @param isStatic Is static
|
||||
* @param scriptIndex Script index
|
||||
* @param abc ABC
|
||||
* @param trait Trait
|
||||
* @param methodInfo Method info
|
||||
* @param body Method body
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Override
|
||||
public void avm2CodeRemoveTraps(String path, int classIndex, boolean isStatic, int scriptIndex, ABC abc, Trait trait, int methodInfo, MethodBody body) throws InterruptedException {
|
||||
AVM2Code code = body.getCode();
|
||||
|
||||
+21
-1
@@ -25,12 +25,13 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.LookupSwitchIns;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
|
||||
import com.jpexs.decompiler.flash.helpers.SWFDecompilerAdapter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Stub for deobfuscator merging jump parts
|
||||
* Stub for deobfuscator merging jump parts.
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
@@ -101,6 +102,19 @@ A: jump B
|
||||
C: blk_4
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
* Removes dead code and merges jump parts.
|
||||
* @param path Path
|
||||
* @param classIndex Class index
|
||||
* @param isStatic Is static
|
||||
* @param scriptIndex Script index
|
||||
* @param abc ABC
|
||||
* @param trait Trait
|
||||
* @param methodInfo Method info
|
||||
* @param body Method body
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Override
|
||||
public void avm2CodeRemoveTraps(String path, int classIndex, boolean isStatic, int scriptIndex, ABC abc, Trait trait, int methodInfo, MethodBody body) throws InterruptedException {
|
||||
AVM2Code code = body.getCode();
|
||||
@@ -165,6 +179,12 @@ C: blk_4
|
||||
new AVM2DeobfuscatorJumps().avm2CodeRemoveTraps(path, classIndex, isStatic, scriptIndex, abc, trait, methodInfo, body);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets real refs.
|
||||
* @param refs Refs
|
||||
* @param ip IP
|
||||
* @return Real refs
|
||||
*/
|
||||
private int realRefs(Map<Integer, List<Integer>> refs, int ip) {
|
||||
int refCount = 0;
|
||||
for (int r : refs.get(ip)) {
|
||||
|
||||
+13
@@ -25,6 +25,7 @@ import com.jpexs.decompiler.flash.abc.types.ABCException;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
|
||||
import com.jpexs.decompiler.flash.helpers.SWFDecompilerAdapter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -38,6 +39,18 @@ import java.util.Map;
|
||||
*/
|
||||
public class AVM2DeobfuscatorJumps extends SWFDecompilerAdapter {
|
||||
|
||||
/**
|
||||
* Removes jumps/ifs targeting other jumps.
|
||||
* @param path Path
|
||||
* @param classIndex Class index
|
||||
* @param isStatic Is static
|
||||
* @param scriptIndex Script index
|
||||
* @param abc ABC
|
||||
* @param trait Trait
|
||||
* @param methodInfo Method info
|
||||
* @param body Method body
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Override
|
||||
public void avm2CodeRemoveTraps(String path, int classIndex, boolean isStatic, int scriptIndex, ABC abc, Trait trait, int methodInfo, MethodBody body) throws InterruptedException {
|
||||
|
||||
|
||||
+59
-13
@@ -37,20 +37,10 @@ import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
|
||||
import com.jpexs.decompiler.flash.ecma.Null;
|
||||
import com.jpexs.decompiler.graph.Graph;
|
||||
import com.jpexs.decompiler.graph.GraphPart;
|
||||
import com.jpexs.decompiler.graph.GraphSource;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItem;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.TranslateException;
|
||||
import com.jpexs.decompiler.graph.TranslateStack;
|
||||
import com.jpexs.decompiler.graph.*;
|
||||
import com.jpexs.helpers.Reference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Stack;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@@ -64,6 +54,11 @@ import java.util.logging.Logger;
|
||||
*/
|
||||
public class AVM2DeobfuscatorRegisters extends AVM2DeobfuscatorSimple {
|
||||
|
||||
/**
|
||||
* Gets registers used in the code.
|
||||
* @param code AVM2 code
|
||||
* @return Set of registers
|
||||
*/
|
||||
private Set<Integer> getRegisters(AVM2Code code) {
|
||||
Set<Integer> regs = new HashSet<>();
|
||||
for (AVM2Instruction ins : code.code) {
|
||||
@@ -88,6 +83,18 @@ public class AVM2DeobfuscatorRegisters extends AVM2DeobfuscatorSimple {
|
||||
return regs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes single assigned local registers.
|
||||
* @param path Path
|
||||
* @param classIndex Class index
|
||||
* @param isStatic Is static
|
||||
* @param scriptIndex Script index
|
||||
* @param abc ABC
|
||||
* @param trait Trait
|
||||
* @param methodInfo Method info
|
||||
* @param body Method body
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Override
|
||||
public void avm2CodeRemoveTraps(String path, int classIndex, boolean isStatic, int scriptIndex, ABC abc, Trait trait, int methodInfo, MethodBody body) throws InterruptedException {
|
||||
//System.err.println("regdeo:" + path);
|
||||
@@ -155,6 +162,20 @@ public class AVM2DeobfuscatorRegisters extends AVM2DeobfuscatorSimple {
|
||||
//System.err.println("/deo");
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces single use registers.
|
||||
* @param singleRegisters Single registers
|
||||
* @param setInss Set instructions
|
||||
* @param classIndex Class index
|
||||
* @param isStatic Is static
|
||||
* @param scriptIndex Script index
|
||||
* @param abc ABC
|
||||
* @param cpool Constant pool
|
||||
* @param trait Trait
|
||||
* @param minfo Method info
|
||||
* @param body Method body
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
private void replaceSingleUseRegisters(Map<Integer, GraphTargetItem> singleRegisters, List<AVM2Instruction> setInss, int classIndex, boolean isStatic, int scriptIndex, ABC abc, AVM2ConstantPool cpool, Trait trait, MethodInfo minfo, MethodBody body) throws InterruptedException {
|
||||
AVM2Code code = body.getCode();
|
||||
|
||||
@@ -182,6 +203,16 @@ public class AVM2DeobfuscatorRegisters extends AVM2DeobfuscatorSimple {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets first register id which has setter.
|
||||
* @param assignment Assignment
|
||||
* @param body Method body
|
||||
* @param abc ABC
|
||||
* @param ignoredRegisters Ignored registers
|
||||
* @param ignoredGets Ignored gets
|
||||
* @return first register id
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
private int getFirstRegisterSetter(Reference<AVM2Instruction> assignment, MethodBody body, ABC abc, Set<Integer> ignoredRegisters, Set<Integer> ignoredGets) throws InterruptedException {
|
||||
AVM2Code code = body.getCode();
|
||||
|
||||
@@ -192,6 +223,21 @@ public class AVM2DeobfuscatorRegisters extends AVM2DeobfuscatorSimple {
|
||||
return visitCode(assignment, new HashSet<>(), new Stack<>(), body, abc, code, 0, code.code.size() - 1, ignoredRegisters, ignoredGets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits code.
|
||||
* @param assignment Assignment
|
||||
* @param visited Visited
|
||||
* @param stack Stack
|
||||
* @param body Method body
|
||||
* @param abc ABC
|
||||
* @param code AVM2 code
|
||||
* @param idx Index
|
||||
* @param endIdx End index
|
||||
* @param ignored Ignored
|
||||
* @param ignoredGets Ignored gets
|
||||
* @return Register id
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
private int visitCode(Reference<AVM2Instruction> assignment, Set<Integer> visited, Stack<Object> stack, MethodBody body, ABC abc, AVM2Code code, int idx, int endIdx, Set<Integer> ignored, Set<Integer> ignoredGets) throws InterruptedException {
|
||||
LocalDataArea localData = new LocalDataArea();
|
||||
initLocalRegs(localData, body.getLocalReservedCount(), body.max_regs, false);
|
||||
|
||||
+73
-14
@@ -35,21 +35,10 @@ import com.jpexs.decompiler.flash.abc.avm2.model.clauses.ExceptionAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.ABCException;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
|
||||
import com.jpexs.decompiler.graph.Graph;
|
||||
import com.jpexs.decompiler.graph.GraphPart;
|
||||
import com.jpexs.decompiler.graph.GraphSource;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItem;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.TranslateException;
|
||||
import com.jpexs.decompiler.graph.TranslateStack;
|
||||
import com.jpexs.decompiler.graph.*;
|
||||
import com.jpexs.helpers.Reference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -61,6 +50,11 @@ import java.util.Set;
|
||||
*/
|
||||
public class AVM2DeobfuscatorRegistersOld extends AVM2DeobfuscatorSimpleOld {
|
||||
|
||||
/**
|
||||
* Gets all register ids.
|
||||
* @param code AVM2 code
|
||||
* @return Set of register ids
|
||||
*/
|
||||
private Set<Integer> getRegisters(AVM2Code code) {
|
||||
Set<Integer> regs = new HashSet<>();
|
||||
for (AVM2Instruction ins : code.code) {
|
||||
@@ -85,6 +79,18 @@ public class AVM2DeobfuscatorRegistersOld extends AVM2DeobfuscatorSimpleOld {
|
||||
return regs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes single assigned local registers.
|
||||
* @param path Path
|
||||
* @param classIndex Class index
|
||||
* @param isStatic Is static
|
||||
* @param scriptIndex Script index
|
||||
* @param abc ABC
|
||||
* @param trait Trait
|
||||
* @param methodInfo Method info
|
||||
* @param body Method body
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Override
|
||||
public void avm2CodeRemoveTraps(String path, int classIndex, boolean isStatic, int scriptIndex, ABC abc, Trait trait, int methodInfo, MethodBody body) throws InterruptedException {
|
||||
//System.err.println("regdeo:" + path);
|
||||
@@ -152,6 +158,19 @@ public class AVM2DeobfuscatorRegistersOld extends AVM2DeobfuscatorSimpleOld {
|
||||
originalBody.setCode(body.getCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets first register with setter.
|
||||
* @param assignment Assignment
|
||||
* @param classIndex Class index
|
||||
* @param isStatic Is static
|
||||
* @param scriptIndex Script index
|
||||
* @param abc ABC
|
||||
* @param body Method body
|
||||
* @param ignoredRegisters Ignored registers
|
||||
* @param ignoredGets Ignored gets
|
||||
* @return Register id
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
private int getFirstRegisterSetter(Reference<AVM2Instruction> assignment, int classIndex, boolean isStatic, int scriptIndex, ABC abc, MethodBody body, Set<Integer> ignoredRegisters, Set<Integer> ignoredGets) throws InterruptedException {
|
||||
AVM2Code code = body.getCode();
|
||||
|
||||
@@ -163,26 +182,66 @@ public class AVM2DeobfuscatorRegistersOld extends AVM2DeobfuscatorSimpleOld {
|
||||
return visitCode(assignment, visited, new TranslateStack("deo"), classIndex, isStatic, body, scriptIndex, abc, code, 0, code.code.size() - 1, ignoredRegisters, ignoredGets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception target ip pair.
|
||||
*/
|
||||
private class ExceptionTargetIpPair {
|
||||
|
||||
/**
|
||||
* Exception.
|
||||
*/
|
||||
private final ABCException exception;
|
||||
/**
|
||||
* Target ip.
|
||||
*/
|
||||
private final int targetIp;
|
||||
|
||||
/**
|
||||
* Constructs a new instance of ExceptionTargetIpPair.
|
||||
* @param exception Exception
|
||||
* @param targetIp Target ip
|
||||
*/
|
||||
public ExceptionTargetIpPair(ABCException exception, int targetIp) {
|
||||
this.exception = exception;
|
||||
this.targetIp = targetIp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets exception.
|
||||
* @return Exception
|
||||
*/
|
||||
public ABCException getException() {
|
||||
return exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets target ip.
|
||||
* @return Target ip
|
||||
*/
|
||||
public int getTargetIp() {
|
||||
return targetIp;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits code.
|
||||
* @param assignment Assignment
|
||||
* @param visited Visited
|
||||
* @param stack Stack
|
||||
* @param classIndex Class index
|
||||
* @param isStatic Is static
|
||||
* @param body Method body
|
||||
* @param scriptIndex Script index
|
||||
* @param abc ABC
|
||||
* @param code AVM2 code
|
||||
* @param idx Index
|
||||
* @param endIdx End index
|
||||
* @param ignored Ignored
|
||||
* @param ignoredGets Ignored gets
|
||||
* @return Register id
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
private int visitCode(Reference<AVM2Instruction> assignment, Set<Integer> visited, TranslateStack stack, int classIndex, boolean isStatic, MethodBody body, int scriptIndex, ABC abc, AVM2Code code, int idx, int endIdx, Set<Integer> ignored, Set<Integer> ignoredGets) throws InterruptedException {
|
||||
|
||||
Map<Integer, List<ExceptionTargetIpPair>> exceptionStartToTargets = new HashMap<>();
|
||||
|
||||
+66
-45
@@ -20,38 +20,10 @@ import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.LocalDataArea;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.exceptions.AVM2ExecutionException;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instructions;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.DeobfuscatePopIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.IfTypeIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.AddIIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.AddIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.DecrementIIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.DecrementIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.DivideIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.IncrementIIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.IncrementIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.ModuloIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.MultiplyIIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.MultiplyIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.NegateIIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.NegateIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.NotIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.SubtractIIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.SubtractIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.BitAndIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.BitOrIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.BitXorIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.LShiftIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.RShiftIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.URShiftIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.EqualsIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.GreaterEqualsIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.GreaterThanIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.LessEqualsIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.LessThanIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.StrictEqualsIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.*;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.*;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.*;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.*;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.NewArrayIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.NewFunctionIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.NewObjectIns;
|
||||
@@ -59,18 +31,7 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.JumpIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.GetLocalTypeIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.SetLocalTypeIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.GetPropertyIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.DupIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PopIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushByteIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushDoubleIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushFalseIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushIntIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushNullIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushShortIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushStringIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushTrueIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushUndefinedIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.SwapIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.*;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.types.CoerceOrConvertTypeIns;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
|
||||
@@ -78,19 +39,34 @@ import com.jpexs.decompiler.flash.ecma.NotCompileTime;
|
||||
import com.jpexs.decompiler.flash.ecma.Undefined;
|
||||
import com.jpexs.decompiler.flash.helpers.collections.FixItemCounterStack;
|
||||
import com.jpexs.decompiler.graph.TranslateException;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
*
|
||||
* Simple AVM2 deobfuscator.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class AVM2DeobfuscatorSimple extends AVM2DeobfuscatorZeroJumpsNullPushes {
|
||||
|
||||
/**
|
||||
* Maximum number of instructions to execute in one pass
|
||||
*/
|
||||
private final int executionLimit = 30000;
|
||||
|
||||
/**
|
||||
* Removes obfuscation ifs.
|
||||
* @param classIndex Class index
|
||||
* @param isStatic Is static
|
||||
* @param scriptIndex Script index
|
||||
* @param abc ABC
|
||||
* @param body Method body
|
||||
* @param inlineIns Inline instruction
|
||||
* @return True if code was modified
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
protected boolean removeObfuscationIfs(int classIndex, boolean isStatic, int scriptIndex, ABC abc, MethodBody body, AVM2Instruction inlineIns) throws InterruptedException {
|
||||
AVM2Code code = body.getCode();
|
||||
if (code.code.isEmpty()) {
|
||||
@@ -128,6 +104,13 @@ public class AVM2DeobfuscatorSimple extends AVM2DeobfuscatorZeroJumpsNullPushes
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes local registers.
|
||||
* @param localData Local data
|
||||
* @param localReservedCount Count of reserved local registers
|
||||
* @param maxRegs Maximum registers
|
||||
* @param executeFromFirst Execute from first
|
||||
*/
|
||||
protected void initLocalRegs(LocalDataArea localData, int localReservedCount, int maxRegs, boolean executeFromFirst) {
|
||||
for (int i = 0; i < localReservedCount; i++) {
|
||||
localData.localRegisters.put(i, NotCompileTime.INSTANCE);
|
||||
@@ -137,6 +120,20 @@ public class AVM2DeobfuscatorSimple extends AVM2DeobfuscatorZeroJumpsNullPushes
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes instructions.
|
||||
* @param staticRegs Static registers
|
||||
* @param body Method body
|
||||
* @param abc ABC
|
||||
* @param code AVM2 code
|
||||
* @param localData Local data
|
||||
* @param idx Start index
|
||||
* @param endIdx End index
|
||||
* @param result Execution result
|
||||
* @param inlineIns Inline instruction
|
||||
* @return True if code was modified
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
private boolean executeInstructions(Map<Integer, Object> staticRegs, MethodBody body, ABC abc, AVM2Code code, LocalDataArea localData, int idx, int endIdx, ExecutionResult result, AVM2Instruction inlineIns) throws InterruptedException {
|
||||
int instructionsProcessed = 0;
|
||||
|
||||
@@ -348,6 +345,18 @@ public class AVM2DeobfuscatorSimple extends AVM2DeobfuscatorZeroJumpsNullPushes
|
||||
return modified;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple deobfuscation.
|
||||
* @param path Path
|
||||
* @param classIndex Class index
|
||||
* @param isStatic Is static
|
||||
* @param scriptIndex Script index
|
||||
* @param abc ABC
|
||||
* @param trait Trait
|
||||
* @param methodInfo Method info
|
||||
* @param body Method body
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Override
|
||||
public void avm2CodeRemoveTraps(String path, int classIndex, boolean isStatic, int scriptIndex, ABC abc, Trait trait, int methodInfo, MethodBody body) throws InterruptedException {
|
||||
AVM2Code code = body.getCode();
|
||||
@@ -357,12 +366,24 @@ public class AVM2DeobfuscatorSimple extends AVM2DeobfuscatorZeroJumpsNullPushes
|
||||
removeNullPushes(code, body);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execution result.
|
||||
*/
|
||||
class ExecutionResult {
|
||||
|
||||
/**
|
||||
* Ip
|
||||
*/
|
||||
public int idx = -1;
|
||||
|
||||
/**
|
||||
* Number of instructions processed
|
||||
*/
|
||||
public int instructionsProcessed = -1;
|
||||
|
||||
/**
|
||||
* Stack
|
||||
*/
|
||||
public Stack<Object> stack = new Stack<>();
|
||||
}
|
||||
}
|
||||
|
||||
+94
-66
@@ -21,39 +21,10 @@ import com.jpexs.decompiler.flash.abc.AVM2LocalData;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.FixItemCounterTranslateStack;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instructions;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.DeobfuscatePopIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.IfTypeIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.AddIIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.AddIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.DecrementIIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.DecrementIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.DivideIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.IncrementIIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.IncrementIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.ModuloIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.MultiplyIIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.MultiplyIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.NegateIIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.NegateIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.NotIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.SubtractIIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.SubtractIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.BitAndIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.BitNotIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.BitOrIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.BitXorIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.LShiftIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.RShiftIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.URShiftIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.EqualsIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.GreaterEqualsIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.GreaterThanIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.LessEqualsIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.LessThanIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.StrictEqualsIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.*;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.*;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.*;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.*;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.ConstructIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.NewArrayIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.NewFunctionIns;
|
||||
@@ -67,59 +38,48 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.GetLocalTypeIn
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.SetLocalTypeIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.GetPropertyIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.NopIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.DupIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PopIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushByteIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushDoubleIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushFalseIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushIntIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushNullIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushShortIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushStringIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushTrueIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushUndefinedIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.SwapIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.*;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.types.CoerceOrConvertTypeIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.types.TypeOfIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.FloatValueAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.GetPropertyAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.IntegerValueAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.NewArrayAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.NewFunctionAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.NullAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.StringAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.UndefinedAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.*;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
|
||||
import com.jpexs.decompiler.flash.ecma.Null;
|
||||
import com.jpexs.decompiler.flash.ecma.Undefined;
|
||||
import com.jpexs.decompiler.graph.Graph;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.NotCompileTimeItem;
|
||||
import com.jpexs.decompiler.graph.ScopeStack;
|
||||
import com.jpexs.decompiler.graph.TranslateException;
|
||||
import com.jpexs.decompiler.graph.TranslateStack;
|
||||
import com.jpexs.decompiler.graph.*;
|
||||
import com.jpexs.decompiler.graph.model.FalseItem;
|
||||
import com.jpexs.decompiler.graph.model.TrueItem;
|
||||
import com.jpexs.helpers.Reference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* Simple deobfuscator for AVM2 code. (Old version)
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class AVM2DeobfuscatorSimpleOld extends AVM2DeobfuscatorZeroJumpsNullPushes {
|
||||
|
||||
/**
|
||||
* Undefined item
|
||||
*/
|
||||
private static final UndefinedAVM2Item UNDEFINED_ITEM = new UndefinedAVM2Item(null, null);
|
||||
|
||||
/**
|
||||
* Not compile time undefined item
|
||||
*/
|
||||
private static final NotCompileTimeItem NOT_COMPILE_TIME_UNDEFINED_ITEM = new NotCompileTimeItem(null, null, UNDEFINED_ITEM);
|
||||
|
||||
/**
|
||||
* Execution limit
|
||||
*/
|
||||
private final int executionLimit = 30000;
|
||||
|
||||
/**
|
||||
* Creates a push instruction from a graph target item.
|
||||
* @param cpool Constant pool
|
||||
* @param graphTargetItem Graph target item
|
||||
* @return Push instruction
|
||||
*/
|
||||
protected AVM2Instruction makePush(AVM2ConstantPool cpool, GraphTargetItem graphTargetItem) {
|
||||
if (graphTargetItem instanceof IntegerValueAVM2Item) {
|
||||
IntegerValueAVM2Item iv = (IntegerValueAVM2Item) graphTargetItem;
|
||||
@@ -143,6 +103,17 @@ public class AVM2DeobfuscatorSimpleOld extends AVM2DeobfuscatorZeroJumpsNullPush
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes obfuscation ifs.
|
||||
* @param classIndex Class index
|
||||
* @param isStatic Is static
|
||||
* @param scriptIndex Script index
|
||||
* @param abc ABC
|
||||
* @param body Method body
|
||||
* @param inlineIns Inline instructions
|
||||
* @return True if removed, false otherwise
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
protected boolean removeObfuscationIfs(int classIndex, boolean isStatic, int scriptIndex, ABC abc, MethodBody body, List<AVM2Instruction> inlineIns) throws InterruptedException {
|
||||
AVM2Code code = body.getCode();
|
||||
if (code.code.isEmpty()) {
|
||||
@@ -196,6 +167,16 @@ public class AVM2DeobfuscatorSimpleOld extends AVM2DeobfuscatorZeroJumpsNullPush
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new local data.
|
||||
* @param scriptIndex Script index
|
||||
* @param abc ABC
|
||||
* @param cpool Constant pool
|
||||
* @param body Method body
|
||||
* @param isStatic Is static
|
||||
* @param classIndex Class index
|
||||
* @return New local data
|
||||
*/
|
||||
protected AVM2LocalData newLocalData(int scriptIndex, ABC abc, AVM2ConstantPool cpool, MethodBody body, boolean isStatic, int classIndex) {
|
||||
AVM2LocalData localData = new AVM2LocalData();
|
||||
localData.isStatic = isStatic;
|
||||
@@ -217,6 +198,12 @@ public class AVM2DeobfuscatorSimpleOld extends AVM2DeobfuscatorZeroJumpsNullPush
|
||||
return localData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes local registers.
|
||||
* @param localData Local data
|
||||
* @param localReservedCount Count of reserved local registers
|
||||
* @param maxRegs Maximal register id
|
||||
*/
|
||||
protected void initLocalRegs(AVM2LocalData localData, int localReservedCount, int maxRegs) {
|
||||
for (int i = 0; i < localReservedCount; i++) {
|
||||
localData.localRegs.put(i, NOT_COMPILE_TIME_UNDEFINED_ITEM);
|
||||
@@ -226,6 +213,23 @@ public class AVM2DeobfuscatorSimpleOld extends AVM2DeobfuscatorZeroJumpsNullPush
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes instructions.
|
||||
* @param importantOffsets Important offsets
|
||||
* @param staticRegs Static registers
|
||||
* @param body Method body
|
||||
* @param abc ABC
|
||||
* @param code AVM2 code
|
||||
* @param localData Local data
|
||||
* @param idx Index
|
||||
* @param endIdx End index
|
||||
* @param result Execution result
|
||||
* @param inlineIns Inline instructions
|
||||
* @param jumpTargets Jump targets
|
||||
* @param minChangedIpRef Minimal changed IP reference
|
||||
* @return True if executed, false otherwise
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
private boolean executeInstructions(Set<Long> importantOffsets, Map<Integer, GraphTargetItem> staticRegs, MethodBody body, ABC abc, AVM2Code code, AVM2LocalData localData, int idx, int endIdx, ExecutionResult result, List<AVM2Instruction> inlineIns, List<Integer> jumpTargets, Reference<Integer> minChangedIpRef) throws InterruptedException {
|
||||
List<GraphTargetItem> output = new ArrayList<>();
|
||||
|
||||
@@ -535,6 +539,18 @@ public class AVM2DeobfuscatorSimpleOld extends AVM2DeobfuscatorZeroJumpsNullPush
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple deobfuscates AVM2 code.
|
||||
* @param path Path
|
||||
* @param classIndex Class index
|
||||
* @param isStatic Is static
|
||||
* @param scriptIndex Script index
|
||||
* @param abc ABC
|
||||
* @param trait Trait
|
||||
* @param methodInfo Method info
|
||||
* @param body Method body
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Override
|
||||
public void avm2CodeRemoveTraps(String path, int classIndex, boolean isStatic, int scriptIndex, ABC abc, Trait trait, int methodInfo, MethodBody body) throws InterruptedException {
|
||||
AVM2Code code = body.getCode();
|
||||
@@ -544,12 +560,24 @@ public class AVM2DeobfuscatorSimpleOld extends AVM2DeobfuscatorZeroJumpsNullPush
|
||||
removeNullPushes(code, body);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execution result.
|
||||
*/
|
||||
class ExecutionResult {
|
||||
|
||||
/**
|
||||
* Ip
|
||||
*/
|
||||
public int idx = -1;
|
||||
|
||||
/**
|
||||
* Number of instructions processed
|
||||
*/
|
||||
public int instructionsProcessed = -1;
|
||||
|
||||
public TranslateStack stack = new TranslateStack("?");
|
||||
/**
|
||||
* Stack
|
||||
*/
|
||||
public Stack<Object> stack = new Stack<>();
|
||||
}
|
||||
}
|
||||
|
||||
+42
-13
@@ -22,34 +22,39 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.NotIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.JumpIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PopIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushByteIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushDoubleIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushFalseIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushIntIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushNanIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushNullIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushShortIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushStringIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushTrueIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushUIntIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushUndefinedIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.*;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
|
||||
import com.jpexs.decompiler.flash.helpers.SWFDecompilerAdapter;
|
||||
import com.jpexs.helpers.Reference;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* Deobfuscator for removing zero jumps and null pushes.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class AVM2DeobfuscatorZeroJumpsNullPushes extends SWFDecompilerAdapter {
|
||||
|
||||
/**
|
||||
* Removes zero jumps from the code.
|
||||
* @param code AVM2 code
|
||||
* @param body Method body
|
||||
* @return True if any zero jumps were removed
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
protected boolean removeZeroJumps(AVM2Code code, MethodBody body) throws InterruptedException {
|
||||
return removeZeroJumps(code, body, new Reference<>(-1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes zero jumps from the code.
|
||||
* @param code AVM2 code
|
||||
* @param body Method body
|
||||
* @param minChangedIpRef Reference to the minimum changed instruction pointer
|
||||
* @return True if any zero jumps were removed
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
protected boolean removeZeroJumps(AVM2Code code, MethodBody body, Reference<Integer> minChangedIpRef) throws InterruptedException {
|
||||
boolean result = false;
|
||||
int minChangedIp = -1;
|
||||
@@ -74,6 +79,11 @@ public class AVM2DeobfuscatorZeroJumpsNullPushes extends SWFDecompilerAdapter {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the instruction is a simple push.
|
||||
* @param def Instruction definition
|
||||
* @return True if the instruction is a simple push
|
||||
*/
|
||||
private boolean isSimplePush(InstructionDefinition def) {
|
||||
return (def instanceof PushByteIns
|
||||
|| def instanceof PushDoubleIns
|
||||
@@ -88,6 +98,13 @@ public class AVM2DeobfuscatorZeroJumpsNullPushes extends SWFDecompilerAdapter {
|
||||
|| def instanceof PushUndefinedIns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes null pushes from the code.
|
||||
* @param code AVM2 code
|
||||
* @param body Method body
|
||||
* @return True if any null pushes were removed
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
protected boolean removeNullPushes(AVM2Code code, MethodBody body) throws InterruptedException {
|
||||
boolean result = false;
|
||||
Set<Long> offsets = code.getImportantOffsets(body, true);
|
||||
@@ -136,6 +153,18 @@ public class AVM2DeobfuscatorZeroJumpsNullPushes extends SWFDecompilerAdapter {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes zero jumps and null pushes from the code.
|
||||
* @param path Path
|
||||
* @param classIndex Class index
|
||||
* @param isStatic Is static
|
||||
* @param scriptIndex Script index
|
||||
* @param abc ABC
|
||||
* @param trait Trait
|
||||
* @param methodInfo Method info
|
||||
* @param body Method body
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Override
|
||||
public void avm2CodeRemoveTraps(String path, int classIndex, boolean isStatic, int scriptIndex, ABC abc, Trait trait, int methodInfo, MethodBody body) throws InterruptedException {
|
||||
AVM2Code code = body.getCode();
|
||||
|
||||
+16
@@ -23,12 +23,22 @@ import com.jpexs.decompiler.flash.abc.types.NamespaceSet;
|
||||
import com.jpexs.decompiler.flash.abc.usages.multinames.MultinameUsage;
|
||||
import com.jpexs.decompiler.flash.tags.ABCContainerTag;
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Fixes collisions of multinames in ABC files.
|
||||
*/
|
||||
public class AbcMultiNameCollisionFixer {
|
||||
|
||||
/**
|
||||
* Fixes collisions of multinames in SWF file.
|
||||
*
|
||||
* @param swf SWF file
|
||||
* @return Number of fixed collisions
|
||||
*/
|
||||
public int fixCollisions(SWF swf) {
|
||||
int ret = 0;
|
||||
for (ABCContainerTag tag : swf.getAbcList()) {
|
||||
@@ -37,6 +47,12 @@ public class AbcMultiNameCollisionFixer {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixes collisions of multinames in ABC file.
|
||||
*
|
||||
* @param abc ABC file
|
||||
* @return Number of fixed collisions
|
||||
*/
|
||||
public int fixCollisions(ABC abc) {
|
||||
Set<MultinameUsage> collidingUsages = abc.getCollidingMultinameUsages();
|
||||
Set<Integer> collidingMultinameIndices = new HashSet<>();
|
||||
|
||||
+14
-1
@@ -17,19 +17,32 @@
|
||||
package com.jpexs.decompiler.flash.abc.avm2.deobfuscation;
|
||||
|
||||
/**
|
||||
*
|
||||
* Level of deobfuscation enum.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public enum DeobfuscationLevel {
|
||||
|
||||
LEVEL_REMOVE_DEAD_CODE(1),
|
||||
LEVEL_REMOVE_TRAPS(2);
|
||||
|
||||
/**
|
||||
* Level of deobfuscation as number
|
||||
*/
|
||||
private final int level;
|
||||
|
||||
/**
|
||||
* Get level of deobfuscation as number
|
||||
* @return
|
||||
*/
|
||||
public int getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get deobfuscation level by level number.
|
||||
* @param level Level number
|
||||
* @return Deobfuscation level or null if not found
|
||||
*/
|
||||
public static DeobfuscationLevel getByLevel(int level) {
|
||||
switch (level) {
|
||||
case 1:
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@
|
||||
package com.jpexs.decompiler.flash.abc.avm2.deobfuscation;
|
||||
|
||||
/**
|
||||
*
|
||||
* Deobfuscation scope enum.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public enum DeobfuscationScope {
|
||||
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Deobfuscating AVM2 bytecode.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.deobfuscation;
|
||||
+5
-1
@@ -17,11 +17,15 @@
|
||||
package com.jpexs.decompiler.flash.abc.avm2.exceptions;
|
||||
|
||||
/**
|
||||
*
|
||||
* Exception thrown when an error occurs during AVM2 execution.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class AVM2ExecutionException extends Exception {
|
||||
|
||||
/**
|
||||
* Constructs new AVM2ExecutionException with the specified detail message.
|
||||
* @param message
|
||||
*/
|
||||
public AVM2ExecutionException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
+19
-1
@@ -17,19 +17,37 @@
|
||||
package com.jpexs.decompiler.flash.abc.avm2.exceptions;
|
||||
|
||||
/**
|
||||
*
|
||||
* Range error exception.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class AVM2RangeErrorException extends AVM2ExecutionException {
|
||||
|
||||
/**
|
||||
* Constructs new AVM2RangeErrorException with the specified error code.
|
||||
* @param code Error code
|
||||
* @param debug If true, the error message will contain a description of the error
|
||||
*/
|
||||
public AVM2RangeErrorException(int code, boolean debug) {
|
||||
super(codeToMessage(code, debug, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs new AVM2RangeErrorException with the specified error code and parameters.
|
||||
* @param code Error code
|
||||
* @param debug If true, the error message will contain a description of the error
|
||||
* @param params Parameters for the error message
|
||||
*/
|
||||
public AVM2RangeErrorException(int code, boolean debug, Object[] params) {
|
||||
super(codeToMessage(code, debug, params));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts error code to error message.
|
||||
* @param code Error code
|
||||
* @param debug If true, the error message will contain a description of the error
|
||||
* @param params Parameters for the error message
|
||||
* @return Error message
|
||||
*/
|
||||
private static String codeToMessage(int code, boolean debug, Object[] params) {
|
||||
String msg = null;
|
||||
/*switch (code) {
|
||||
|
||||
+19
-1
@@ -17,19 +17,37 @@
|
||||
package com.jpexs.decompiler.flash.abc.avm2.exceptions;
|
||||
|
||||
/**
|
||||
*
|
||||
* AVM2 TypeError exception.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class AVM2TypeErrorException extends AVM2ExecutionException {
|
||||
|
||||
/**
|
||||
* Constructs new AVM2TypeErrorException with the specified error code.
|
||||
* @param code Error code
|
||||
* @param debug If true, the error message will contain a description of the error
|
||||
*/
|
||||
public AVM2TypeErrorException(int code, boolean debug) {
|
||||
super(codeToMessage(code, debug, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs new AVM2TypeErrorException with the specified error code and parameters.
|
||||
* @param code Error code
|
||||
* @param debug If true, the error message will contain a description of the error
|
||||
* @param params Parameters for the error message
|
||||
*/
|
||||
public AVM2TypeErrorException(int code, boolean debug, Object[] params) {
|
||||
super(codeToMessage(code, debug, params));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts error code to error message.
|
||||
* @param code Error code
|
||||
* @param debug If true, the error message will contain a description of the error
|
||||
* @param params Parameters for the error message
|
||||
* @return Error message
|
||||
*/
|
||||
private static String codeToMessage(int code, boolean debug, Object[] params) {
|
||||
String msg = null;
|
||||
/*switch (code) {
|
||||
|
||||
+28
-1
@@ -17,25 +17,52 @@
|
||||
package com.jpexs.decompiler.flash.abc.avm2.exceptions;
|
||||
|
||||
/**
|
||||
*
|
||||
* AVM2 VerifyError exception.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class AVM2VerifyErrorException extends AVM2ExecutionException {
|
||||
|
||||
/**
|
||||
* Illegal opcode error code.
|
||||
*/
|
||||
public static final int ILLEGAL_OPCODE = 1011;
|
||||
|
||||
/**
|
||||
* Branch target is not a valid instruction error code.
|
||||
*/
|
||||
public static final int BRANCH_TARGET_INVALID_INSTRUCTION = 1021;
|
||||
|
||||
/**
|
||||
* Cpool index out of range error code.
|
||||
*/
|
||||
public static final int CPOOL_INDEX_OUT_OF_RANGE = 1032;
|
||||
|
||||
/**
|
||||
* Constructs new AVM2VerifyErrorException with the specified error code.
|
||||
* @param code Error code
|
||||
* @param debug If true, the error message will contain a description of the error
|
||||
*/
|
||||
public AVM2VerifyErrorException(int code, boolean debug) {
|
||||
super(codeToMessage(code, debug, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs new AVM2VerifyErrorException with the specified error code and parameters.
|
||||
* @param code Error code
|
||||
* @param debug If true, the error message will contain a description of the error
|
||||
* @param params Parameters for the error message
|
||||
*/
|
||||
public AVM2VerifyErrorException(int code, boolean debug, Object[] params) {
|
||||
super(codeToMessage(code, debug, params));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts error code to error message.
|
||||
* @param code Error code
|
||||
* @param debug If true, the error message will contain a description of the error
|
||||
* @param params Parameters for the error message
|
||||
* @return Error message
|
||||
*/
|
||||
private static String codeToMessage(int code, boolean debug, Object[] params) {
|
||||
String msg = null;
|
||||
switch (code) {
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Exceptions for AVM2 execution.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.exceptions;
|
||||
+86
-2
@@ -17,51 +17,99 @@
|
||||
package com.jpexs.decompiler.flash.abc.avm2.fastavm2;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* Instruction item for fast AVM2 list.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class AVM2InstructionItem {
|
||||
|
||||
/**
|
||||
* Instruction
|
||||
*/
|
||||
public AVM2Instruction ins;
|
||||
|
||||
/**
|
||||
* Previous instruction
|
||||
*/
|
||||
public AVM2InstructionItem prev;
|
||||
|
||||
/**
|
||||
* Next instruction
|
||||
*/
|
||||
public AVM2InstructionItem next;
|
||||
|
||||
/**
|
||||
* Jump target
|
||||
*/
|
||||
private AVM2InstructionItem jumpTarget;
|
||||
|
||||
/**
|
||||
* Instructions that jump here
|
||||
*/
|
||||
public Set<AVM2InstructionItem> jumpsHere;
|
||||
|
||||
/**
|
||||
* Instructions that this instruction is the last instruction of
|
||||
*/
|
||||
public Set<AVM2InstructionItem> lastInsOf;
|
||||
|
||||
/**
|
||||
* Last instruction container
|
||||
*/
|
||||
private List<AVM2InstructionItem> containerLastInstructions;
|
||||
|
||||
// 1 means reachable, 2 means reachable and processed
|
||||
//
|
||||
/**
|
||||
* Whether this instruction is reachable.
|
||||
* 1 means reachable, 2 means reachable and processed.
|
||||
*/
|
||||
int reachable;
|
||||
|
||||
/**
|
||||
* Excluded
|
||||
*/
|
||||
public boolean excluded;
|
||||
|
||||
/**
|
||||
* Constructs a new AVM2InstructionItem
|
||||
* @param ins Instruction
|
||||
*/
|
||||
public AVM2InstructionItem(AVM2Instruction ins) {
|
||||
this.ins = ins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this instruction is a jump target.
|
||||
* @return Whether this instruction is a jump target
|
||||
*/
|
||||
public boolean isJumpTarget() {
|
||||
return jumpsHere != null && !jumpsHere.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of jumps to this instruction.
|
||||
* @return Number of jumps to this instruction
|
||||
*/
|
||||
public int jumpsHereSize() {
|
||||
return jumpsHere == null ? 0 : jumpsHere.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this instruction is the last instruction of a container.
|
||||
* @return Whether this instruction is the last instruction of a container
|
||||
*/
|
||||
public boolean isContainerLastInstruction() {
|
||||
return lastInsOf != null && !lastInsOf.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove jump target.
|
||||
*/
|
||||
public void removeJumpTarget() {
|
||||
if (jumpTarget == null) {
|
||||
return;
|
||||
@@ -74,14 +122,26 @@ public class AVM2InstructionItem {
|
||||
jumpTarget = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get jump target.
|
||||
* @return Instruction item
|
||||
*/
|
||||
public AVM2InstructionItem getJumpTarget() {
|
||||
return jumpTarget;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get jump target instruction.
|
||||
* @return Instruction
|
||||
*/
|
||||
public AVM2Instruction getJumpTargetInstruction() {
|
||||
return jumpTarget == null ? null : jumpTarget.ins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set jump target.
|
||||
* @param item Instruction item
|
||||
*/
|
||||
public void setJumpTarget(AVM2InstructionItem item) {
|
||||
removeJumpTarget();
|
||||
|
||||
@@ -97,10 +157,17 @@ public class AVM2InstructionItem {
|
||||
jumpTarget = item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get last instructions of container.
|
||||
* @return List of instruction items
|
||||
*/
|
||||
public List<AVM2InstructionItem> getContainerLastInstructions() {
|
||||
return containerLastInstructions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove last instructions of container.
|
||||
*/
|
||||
public void removeContainerLastInstructions() {
|
||||
if (containerLastInstructions == null) {
|
||||
return;
|
||||
@@ -115,6 +182,11 @@ public class AVM2InstructionItem {
|
||||
containerLastInstructions = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace container last instruction.
|
||||
* @param oldItem Old instruction item
|
||||
* @param newItem New instruction item
|
||||
*/
|
||||
public void replaceContainerLastInstruction(AVM2InstructionItem oldItem, AVM2InstructionItem newItem) {
|
||||
if (containerLastInstructions == null) {
|
||||
return;
|
||||
@@ -132,6 +204,10 @@ public class AVM2InstructionItem {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set container last instructions.
|
||||
* @param lastInstructions
|
||||
*/
|
||||
public void setContainerLastInstructions(List<AVM2InstructionItem> lastInstructions) {
|
||||
removeContainerLastInstructions();
|
||||
|
||||
@@ -142,6 +218,10 @@ public class AVM2InstructionItem {
|
||||
containerLastInstructions = lastInstructions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure last instruction is non-null.
|
||||
* @return Set of instruction items
|
||||
*/
|
||||
private Set<AVM2InstructionItem> ensureLastInstructionOf() {
|
||||
if (lastInsOf == null) {
|
||||
lastInsOf = new HashSet<>();
|
||||
@@ -150,6 +230,10 @@ public class AVM2InstructionItem {
|
||||
return lastInsOf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this instruction is excluded.
|
||||
* @return Whether this instruction is excluded
|
||||
*/
|
||||
public boolean isExcluded() {
|
||||
return excluded;
|
||||
}
|
||||
|
||||
+195
-8
@@ -24,28 +24,39 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.LookupSwitchIns;
|
||||
import com.jpexs.decompiler.flash.abc.types.ABCException;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItemContainer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* Fast AVM2 instruction list.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class FastAVM2List implements Collection<AVM2InstructionItem> {
|
||||
|
||||
/**
|
||||
* Size of the list
|
||||
*/
|
||||
private int size;
|
||||
|
||||
/**
|
||||
* First item
|
||||
*/
|
||||
private AVM2InstructionItem firstItem;
|
||||
|
||||
/**
|
||||
* Map of instructions to items
|
||||
*/
|
||||
private final Map<AVM2Instruction, AVM2InstructionItem> actionItemMap;
|
||||
|
||||
/**
|
||||
* Set of items
|
||||
*/
|
||||
private final Set<AVM2InstructionItem> actionItemSet;
|
||||
|
||||
/**
|
||||
* Constructs a new FastAVM2List from a method body
|
||||
* @param body Method body
|
||||
*/
|
||||
public FastAVM2List(MethodBody body) {
|
||||
// exceptions todo
|
||||
AVM2Code avm2code = body.getCode();
|
||||
@@ -60,11 +71,23 @@ public class FastAVM2List implements Collection<AVM2InstructionItem> {
|
||||
getJumps(avm2code, actionItemMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts item before another item
|
||||
* @param item Item to insert before
|
||||
* @param action Action to insert
|
||||
* @return
|
||||
*/
|
||||
public final AVM2InstructionItem insertItemBefore(AVM2InstructionItem item, AVM2Instruction action) {
|
||||
AVM2InstructionItem newItem = new AVM2InstructionItem(action);
|
||||
return insertItemBefore(item, newItem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts item before another item
|
||||
* @param item Item to insert before
|
||||
* @param newItem New item
|
||||
* @return New item
|
||||
*/
|
||||
public final AVM2InstructionItem insertItemBefore(AVM2InstructionItem item, AVM2InstructionItem newItem) {
|
||||
insertItemAfter(item.prev, newItem);
|
||||
if (item == firstItem) {
|
||||
@@ -74,11 +97,23 @@ public class FastAVM2List implements Collection<AVM2InstructionItem> {
|
||||
return newItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts item after another item
|
||||
* @param item Item to insert after
|
||||
* @param action Action to insert
|
||||
* @return
|
||||
*/
|
||||
public final AVM2InstructionItem insertItemAfter(AVM2InstructionItem item, AVM2Instruction action) {
|
||||
AVM2InstructionItem newItem = new AVM2InstructionItem(action);
|
||||
return insertItemAfter(item, newItem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts item after another item
|
||||
* @param item Item to insert after
|
||||
* @param newItem New item
|
||||
* @return New item
|
||||
*/
|
||||
public final AVM2InstructionItem insertItemAfter(AVM2InstructionItem item, AVM2InstructionItem newItem) {
|
||||
if (item == null && firstItem == null) {
|
||||
firstItem = newItem;
|
||||
@@ -103,6 +138,11 @@ public class FastAVM2List implements Collection<AVM2InstructionItem> {
|
||||
return newItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes item
|
||||
* @param item Item to remove
|
||||
* @return Next item
|
||||
*/
|
||||
public AVM2InstructionItem removeItem(AVM2InstructionItem item) {
|
||||
AVM2InstructionItem next = null;
|
||||
if (item == firstItem) {
|
||||
@@ -143,6 +183,11 @@ public class FastAVM2List implements Collection<AVM2InstructionItem> {
|
||||
return next;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes item.
|
||||
* @param index Index of item to remove
|
||||
* @param count Number of items to remove
|
||||
*/
|
||||
public void removeItem(int index, int count) {
|
||||
FastAVM2ListIterator iterator = new FastAVM2ListIterator(this, index);
|
||||
for (int i = 0; i < count; i++) {
|
||||
@@ -151,11 +196,21 @@ public class FastAVM2List implements Collection<AVM2InstructionItem> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets item at index
|
||||
* @param index Index
|
||||
* @return Item
|
||||
*/
|
||||
public AVM2InstructionItem get(int index) {
|
||||
FastAVM2ListIterator iterator = new FastAVM2ListIterator(this, index);
|
||||
return iterator.next();
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace jump targets.
|
||||
* @param target Target
|
||||
* @param newTarget New target
|
||||
*/
|
||||
public void replaceJumpTargets(AVM2InstructionItem target, AVM2InstructionItem newTarget) {
|
||||
if (target.jumpsHere != null) {
|
||||
for (AVM2InstructionItem item : new ArrayList<>(target.jumpsHere)) {
|
||||
@@ -164,6 +219,13 @@ public class FastAVM2List implements Collection<AVM2InstructionItem> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets nerby address.
|
||||
* @param instructions Instructions
|
||||
* @param address Address
|
||||
* @param next Next
|
||||
* @return
|
||||
*/
|
||||
private long getNearAddress(List<AVM2Instruction> instructions, long address, boolean next) {
|
||||
int min = 0;
|
||||
int max = instructions.size() - 1;
|
||||
@@ -185,6 +247,11 @@ public class FastAVM2List implements Collection<AVM2InstructionItem> {
|
||||
: (max >= 0 ? instructions.get(max).getAddress() : -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets jumps.
|
||||
* @param actions Actions
|
||||
* @param actionItemMap Action item map
|
||||
*/
|
||||
private void getJumps(AVM2Code actions, Map<AVM2Instruction, AVM2InstructionItem> actionItemMap) {
|
||||
AVM2InstructionItem item = firstItem;
|
||||
if (item == null) {
|
||||
@@ -208,6 +275,9 @@ public class FastAVM2List implements Collection<AVM2InstructionItem> {
|
||||
} while (item != firstItem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates action addresses and lengths.
|
||||
*/
|
||||
private void updateActionAddressesAndLengths() {
|
||||
AVM2InstructionItem item = firstItem;
|
||||
if (item == null) {
|
||||
@@ -223,6 +293,9 @@ public class FastAVM2List implements Collection<AVM2InstructionItem> {
|
||||
} while (item != firstItem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates jumps.
|
||||
*/
|
||||
private void updateJumps() {
|
||||
AVM2InstructionItem item = firstItem;
|
||||
if (item == null) {
|
||||
@@ -249,6 +322,10 @@ public class FastAVM2List implements Collection<AVM2InstructionItem> {
|
||||
} while (item != firstItem);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Updates container sizes.
|
||||
*/
|
||||
private void updateContainerSizes() {
|
||||
AVM2InstructionItem item = firstItem;
|
||||
if (item == null) {
|
||||
@@ -273,6 +350,11 @@ public class FastAVM2List implements Collection<AVM2InstructionItem> {
|
||||
} while (item != firstItem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets container.
|
||||
* @param item Item
|
||||
* @return Container
|
||||
*/
|
||||
public AVM2InstructionItem getContainer(AVM2InstructionItem item) {
|
||||
while (!(item.ins instanceof GraphSourceItemContainer) && item != firstItem) {
|
||||
item = item.prev;
|
||||
@@ -285,6 +367,9 @@ public class FastAVM2List implements Collection<AVM2InstructionItem> {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes zero jumps.
|
||||
*/
|
||||
public void removeZeroJumps() {
|
||||
AVM2InstructionItem item = firstItem;
|
||||
if (item == null) {
|
||||
@@ -304,6 +389,9 @@ public class FastAVM2List implements Collection<AVM2InstructionItem> {
|
||||
} while (item != firstItem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes unreachable actions.
|
||||
*/
|
||||
public void removeUnreachableActions() {
|
||||
AVM2InstructionItem item = firstItem;
|
||||
if (item == null) {
|
||||
@@ -322,6 +410,9 @@ public class FastAVM2List implements Collection<AVM2InstructionItem> {
|
||||
} while (item != firstItem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes included actions.
|
||||
*/
|
||||
public void removeIncludedActions() {
|
||||
AVM2InstructionItem item = firstItem;
|
||||
if (item == null) {
|
||||
@@ -338,6 +429,12 @@ public class FastAVM2List implements Collection<AVM2InstructionItem> {
|
||||
} while (item != firstItem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets unreachable action count.
|
||||
* @param jump Jump
|
||||
* @param jumpTarget Jump target
|
||||
* @return
|
||||
*/
|
||||
public int getUnreachableActionCount(AVM2InstructionItem jump, AVM2InstructionItem jumpTarget) {
|
||||
AVM2InstructionItem item = firstItem;
|
||||
if (item == null) {
|
||||
@@ -359,6 +456,9 @@ public class FastAVM2List implements Collection<AVM2InstructionItem> {
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears reachable flags.
|
||||
*/
|
||||
private void clearReachableFlags() {
|
||||
AVM2InstructionItem item = firstItem;
|
||||
if (item == null) {
|
||||
@@ -371,6 +471,10 @@ public class FastAVM2List implements Collection<AVM2InstructionItem> {
|
||||
} while (item != firstItem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets excluded flags.
|
||||
* @param value Value
|
||||
*/
|
||||
public void setExcludedFlags(boolean value) {
|
||||
AVM2InstructionItem item = firstItem;
|
||||
if (item == null) {
|
||||
@@ -383,6 +487,11 @@ public class FastAVM2List implements Collection<AVM2InstructionItem> {
|
||||
} while (item != firstItem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates reachable flags.
|
||||
* @param jump Jump
|
||||
* @param jumpTarget Jump target
|
||||
*/
|
||||
private void updateReachableFlags(AVM2InstructionItem jump, AVM2InstructionItem jumpTarget) {
|
||||
if (firstItem == null) {
|
||||
return;
|
||||
@@ -446,6 +555,10 @@ public class FastAVM2List implements Collection<AVM2InstructionItem> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates actions.
|
||||
* @param body Method body
|
||||
*/
|
||||
public void updateActions(MethodBody body) {
|
||||
AVM2Code result = new AVM2Code(size);
|
||||
AVM2InstructionItem item = firstItem;
|
||||
@@ -466,28 +579,53 @@ public class FastAVM2List implements Collection<AVM2InstructionItem> {
|
||||
updateContainerSizes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets first item.
|
||||
* @return First item
|
||||
*/
|
||||
public AVM2InstructionItem first() {
|
||||
return firstItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets last item.
|
||||
* @return Last item
|
||||
*/
|
||||
public AVM2InstructionItem last() {
|
||||
return firstItem == null ? null : firstItem.prev;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts to method body.
|
||||
* @param body Method body
|
||||
*/
|
||||
public void toMethodBody(MethodBody body) {
|
||||
updateActions(body);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets size.
|
||||
* @return Size
|
||||
*/
|
||||
@Override
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if empty.
|
||||
* @return Whether empty
|
||||
*/
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return size == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if contains.
|
||||
* @param o element whose presence in this collection is to be tested
|
||||
* @return Whether contains
|
||||
*/
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
if (o instanceof AVM2InstructionItem) {
|
||||
@@ -499,11 +637,19 @@ public class FastAVM2List implements Collection<AVM2InstructionItem> {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets iterator.
|
||||
* @return Iterator
|
||||
*/
|
||||
@Override
|
||||
public FastAVM2ListIterator iterator() {
|
||||
return new FastAVM2ListIterator(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts to array.
|
||||
* @return Array
|
||||
*/
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
Object[] result = new Object[size];
|
||||
@@ -522,6 +668,14 @@ public class FastAVM2List implements Collection<AVM2InstructionItem> {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts to array.
|
||||
* @param a the array into which the elements of this collection are to be
|
||||
* stored, if it is big enough; otherwise, a new array of the same
|
||||
* runtime type is allocated for this purpose.
|
||||
* @return Array
|
||||
* @param <T>
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T[] toArray(T[] a) {
|
||||
@@ -543,12 +697,22 @@ public class FastAVM2List implements Collection<AVM2InstructionItem> {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an element to this collection.
|
||||
* @param e element whose presence in this collection is to be ensured
|
||||
* @return Whether added
|
||||
*/
|
||||
@Override
|
||||
public boolean add(AVM2InstructionItem e) {
|
||||
insertItemAfter(null, e);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a single instance of the specified element from this collection,
|
||||
* @param o element to be removed from this collection, if present
|
||||
* @return Whether removed
|
||||
*/
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
AVM2InstructionItem item = null;
|
||||
@@ -566,6 +730,11 @@ public class FastAVM2List implements Collection<AVM2InstructionItem> {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this collection contains all of the elements in the specified collection.
|
||||
* @param c collection to be checked for containment in this collection
|
||||
* @return Whether contains all
|
||||
*/
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> c) {
|
||||
for (Object c1 : c) {
|
||||
@@ -577,6 +746,11 @@ public class FastAVM2List implements Collection<AVM2InstructionItem> {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds all of the elements in the specified collection to this collection.
|
||||
* @param c collection containing elements to be added to this collection
|
||||
* @return Whether added all
|
||||
*/
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends AVM2InstructionItem> c) {
|
||||
for (AVM2InstructionItem c1 : c) {
|
||||
@@ -586,6 +760,11 @@ public class FastAVM2List implements Collection<AVM2InstructionItem> {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all of this collection's elements that are also contained in the specified collection.
|
||||
* @param c collection containing elements to be removed from this collection
|
||||
* @return Whether removed all
|
||||
*/
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
boolean result = false;
|
||||
@@ -596,6 +775,11 @@ public class FastAVM2List implements Collection<AVM2InstructionItem> {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retains only the elements in this collection that are contained in the specified collection.
|
||||
* @param c collection containing elements to be retained in this collection
|
||||
* @return Whether retained all
|
||||
*/
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
AVM2InstructionItem item = firstItem;
|
||||
@@ -616,6 +800,9 @@ public class FastAVM2List implements Collection<AVM2InstructionItem> {
|
||||
return modified;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears this collection.
|
||||
*/
|
||||
@Override
|
||||
public void clear() {
|
||||
firstItem = null;
|
||||
|
||||
+56
-1
@@ -17,25 +17,44 @@
|
||||
package com.jpexs.decompiler.flash.abc.avm2.fastavm2;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
*
|
||||
* Iterator for FastAVM2List
|
||||
* @author JPEXS
|
||||
*/
|
||||
public final class FastAVM2ListIterator implements Iterator<AVM2InstructionItem> {
|
||||
|
||||
/**
|
||||
* Current item
|
||||
*/
|
||||
private AVM2InstructionItem item;
|
||||
|
||||
/**
|
||||
* List
|
||||
*/
|
||||
private final FastAVM2List list;
|
||||
|
||||
/**
|
||||
* If the iterator has been started
|
||||
*/
|
||||
private boolean started = false;
|
||||
|
||||
/**
|
||||
* Constructs a new iterator.
|
||||
* @param list List
|
||||
*/
|
||||
FastAVM2ListIterator(FastAVM2List list) {
|
||||
item = list.first();
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new iterator.
|
||||
* @param list List
|
||||
* @param index Index
|
||||
*/
|
||||
FastAVM2ListIterator(FastAVM2List list, int index) {
|
||||
item = list.first();
|
||||
this.list = list;
|
||||
@@ -48,11 +67,19 @@ public final class FastAVM2ListIterator implements Iterator<AVM2InstructionItem>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if there is a next item.
|
||||
* @return True if there is a next item
|
||||
*/
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return item != null && (!started || item != list.first());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the next item.
|
||||
* @return Next item
|
||||
*/
|
||||
@Override
|
||||
public AVM2InstructionItem next() {
|
||||
AVM2InstructionItem result = item;
|
||||
@@ -65,6 +92,10 @@ public final class FastAVM2ListIterator implements Iterator<AVM2InstructionItem>
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the previous item.
|
||||
* @return Previous item
|
||||
*/
|
||||
public AVM2InstructionItem prev() {
|
||||
item = item.prev;
|
||||
if (item == list.first()) {
|
||||
@@ -77,6 +108,10 @@ public final class FastAVM2ListIterator implements Iterator<AVM2InstructionItem>
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current item.
|
||||
* @param item Item
|
||||
*/
|
||||
public void setCurrent(AVM2InstructionItem item) {
|
||||
this.item = item;
|
||||
if (item == list.first()) {
|
||||
@@ -84,23 +119,43 @@ public final class FastAVM2ListIterator implements Iterator<AVM2InstructionItem>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the current item.
|
||||
*/
|
||||
@Override
|
||||
public void remove() {
|
||||
item = list.removeItem(item.prev);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an item.
|
||||
* @param ins Instruction
|
||||
*/
|
||||
public void add(AVM2Instruction ins) {
|
||||
item = list.insertItemAfter(item.prev, ins).next;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an item.
|
||||
* @param insItem Instruction item
|
||||
*/
|
||||
public void add(AVM2InstructionItem insItem) {
|
||||
item = list.insertItemAfter(item.prev, insItem).next;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an item before the current item.
|
||||
* @param insItem Instruction item
|
||||
*/
|
||||
public void addBefore(AVM2InstructionItem insItem) {
|
||||
list.insertItemBefore(item.prev, insItem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the item at the specified index.
|
||||
* @param index Index
|
||||
* @return Item
|
||||
*/
|
||||
public AVM2InstructionItem peek(int index) {
|
||||
AVM2InstructionItem item = this.item;
|
||||
for (int i = 0; i < index; i++) {
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Fast AVM2 instruction list implementation.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.fastavm2;
|
||||
@@ -30,13 +30,7 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.debug.DebugLineIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.IfStrictEqIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.JumpIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.LookupSwitchIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.DecLocalIIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.DecLocalIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.GetLocalTypeIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.IncLocalIIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.IncLocalIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.KillIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.SetLocalTypeIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.*;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.HasNext2Ins;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.LabelIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.NopIns;
|
||||
@@ -47,111 +41,70 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushByteIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushScopeIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.types.CoerceAIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.types.ConvertIIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.AVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.ConstructAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.FilteredCheckAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.FindPropertyAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.FullMultinameAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.GetLexAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.GetPropertyAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.HasNextAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.InAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.IntegerValueAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.LocalRegAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.NewActivationAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.NewFunctionAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.NextNameAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.NextValueAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.ReturnValueAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.ReturnVoidAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.SetLocalAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.SetPropertyAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.SetSlotAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.SetTypeAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.ThrowAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.WithAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.WithEndAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.WithObjectAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.clauses.ExceptionAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.clauses.FilterAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.clauses.ForEachInAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.clauses.ForInAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.clauses.TryAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.*;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.clauses.*;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.operations.StrictEqAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.parser.script.AbcIndexing;
|
||||
import com.jpexs.decompiler.flash.abc.types.ABCException;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.graph.AbstractGraphTargetVisitor;
|
||||
import com.jpexs.decompiler.graph.DottedChain;
|
||||
import com.jpexs.decompiler.graph.Graph;
|
||||
import com.jpexs.decompiler.graph.GraphException;
|
||||
import com.jpexs.decompiler.graph.GraphPart;
|
||||
import com.jpexs.decompiler.graph.GraphPartChangeException;
|
||||
import com.jpexs.decompiler.graph.GraphSource;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItem;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.Loop;
|
||||
import com.jpexs.decompiler.graph.ScopeStack;
|
||||
import com.jpexs.decompiler.graph.SecondPassData;
|
||||
import com.jpexs.decompiler.graph.StopPartKind;
|
||||
import com.jpexs.decompiler.graph.ThrowState;
|
||||
import com.jpexs.decompiler.graph.TranslateStack;
|
||||
import com.jpexs.decompiler.graph.TypeItem;
|
||||
import com.jpexs.decompiler.graph.model.AnyItem;
|
||||
import com.jpexs.decompiler.graph.model.BreakItem;
|
||||
import com.jpexs.decompiler.graph.model.CommaExpressionItem;
|
||||
import com.jpexs.decompiler.graph.model.ContinueItem;
|
||||
import com.jpexs.decompiler.graph.model.ExitItem;
|
||||
import com.jpexs.decompiler.graph.model.FalseItem;
|
||||
import com.jpexs.decompiler.graph.model.GotoItem;
|
||||
import com.jpexs.decompiler.graph.model.IfItem;
|
||||
import com.jpexs.decompiler.graph.model.LoopItem;
|
||||
import com.jpexs.decompiler.graph.model.NotItem;
|
||||
import com.jpexs.decompiler.graph.model.PushItem;
|
||||
import com.jpexs.decompiler.graph.model.SwitchItem;
|
||||
import com.jpexs.decompiler.graph.model.WhileItem;
|
||||
import com.jpexs.decompiler.graph.*;
|
||||
import com.jpexs.decompiler.graph.model.*;
|
||||
import com.jpexs.helpers.Reference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* AVM2 graph.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class AVM2Graph extends Graph {
|
||||
|
||||
/**
|
||||
* AVM2 code
|
||||
*/
|
||||
private final AVM2Code avm2code;
|
||||
|
||||
/**
|
||||
* ABC
|
||||
*/
|
||||
private final ABC abc;
|
||||
|
||||
/**
|
||||
* Method body
|
||||
*/
|
||||
private final MethodBody body;
|
||||
|
||||
/**
|
||||
* ABC indexing
|
||||
*/
|
||||
private final AbcIndexing abcIndex;
|
||||
|
||||
/**
|
||||
* Logger
|
||||
*/
|
||||
private final Logger logger = Logger.getLogger(AVM2Graph.class.getName());
|
||||
|
||||
//Kinds of finally blocks
|
||||
final int FINALLY_KIND_STACK_BASED = 0;
|
||||
final int FINALLY_KIND_REGISTER_BASED = 1;
|
||||
final int FINALLY_KIND_INLINED = 2;
|
||||
final int FINALLY_KIND_UNKNOWN = -1;
|
||||
|
||||
/**
|
||||
* Get AVM2 code
|
||||
* @return AVM2 code
|
||||
*/
|
||||
public AVM2Code getCode() {
|
||||
return avm2code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get exceptions
|
||||
* @param body Method body
|
||||
* @return Exceptions
|
||||
*/
|
||||
private static List<GraphException> getExceptionEntries(MethodBody body) {
|
||||
List<GraphException> ret = new ArrayList<>();
|
||||
AVM2Code code = body.getCode();
|
||||
@@ -161,29 +114,39 @@ public class AVM2Graph extends Graph {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs AVM2 graph
|
||||
* @param abcIndex ABC indexing
|
||||
* @param code AVM2 code
|
||||
* @param abc ABC
|
||||
* @param body Method body
|
||||
* @param isStatic Is static
|
||||
* @param scriptIndex Script index
|
||||
* @param classIndex Class index
|
||||
* @param localRegs Local registers
|
||||
* @param scopeStack Scope stack
|
||||
* @param localScopeStack Local scope stack
|
||||
* @param localRegNames Local register names
|
||||
* @param fullyQualifiedNames Fully qualified names
|
||||
* @param localRegAssigmentIps Local register assignment IPs
|
||||
*/
|
||||
public AVM2Graph(AbcIndexing abcIndex, AVM2Code code, ABC abc, MethodBody body, boolean isStatic, int scriptIndex, int classIndex, HashMap<Integer, GraphTargetItem> localRegs, ScopeStack scopeStack, ScopeStack localScopeStack, HashMap<Integer, String> localRegNames, List<DottedChain> fullyQualifiedNames, HashMap<Integer, Integer> localRegAssigmentIps) {
|
||||
super(new AVM2GraphSource(code, isStatic, scriptIndex, classIndex, localRegs, abc, body, localRegNames, fullyQualifiedNames, localRegAssigmentIps), getExceptionEntries(body));
|
||||
this.avm2code = code;
|
||||
this.abc = abc;
|
||||
this.body = body;
|
||||
this.abcIndex = abcIndex;
|
||||
/*heads = makeGraph(code, new ArrayList<GraphPart>(), body);
|
||||
this.code = code;
|
||||
this.abc = abc;
|
||||
this.body = body;
|
||||
for (GraphPart head : heads) {
|
||||
fixGraph(head);
|
||||
makeMulti(head, new ArrayList<GraphPart>());
|
||||
}*/
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether part can be break candidate
|
||||
* @param localData Local data
|
||||
* @param part Part
|
||||
* @param throwStates List of throw states
|
||||
* @return True if part can be break candidate, false otherwise
|
||||
*/
|
||||
@Override
|
||||
protected boolean canBeBreakCandidate(BaseLocalData localData, GraphPart part, List<ThrowState> throwStates) {
|
||||
/*AVM2LocalData aLocalData = (AVM2LocalData) localData;
|
||||
if (aLocalData.finallyTargetParts.containsValue(part)) {
|
||||
return false;
|
||||
}*/
|
||||
for (ThrowState ts : throwStates) {
|
||||
if (ts.targetPart == part) {
|
||||
return false;
|
||||
@@ -192,6 +155,14 @@ public class AVM2Graph extends Graph {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check before get loops
|
||||
* @param localData Local data
|
||||
* @param path Path
|
||||
* @param allParts All parts
|
||||
* @param throwStates Throw states
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Override
|
||||
protected void beforeGetLoops(BaseLocalData localData, String path, Set<GraphPart> allParts, List<ThrowState> throwStates) throws InterruptedException {
|
||||
AVM2LocalData avm2LocalData = ((AVM2LocalData) localData);
|
||||
@@ -221,11 +192,24 @@ public class AVM2Graph extends Graph {
|
||||
avm2LocalData.inGetLoops = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check after get loops
|
||||
* @param localData Local data
|
||||
* @param path Path
|
||||
* @param allParts All parts
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Override
|
||||
protected void afterGetLoops(BaseLocalData localData, String path, Set<GraphPart> allParts) throws InterruptedException {
|
||||
((AVM2LocalData) localData).inGetLoops = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets ignored switches
|
||||
* @param localData Local data
|
||||
* @param allParts All parts
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
private void getIgnoredSwitches(AVM2LocalData localData, Set<GraphPart> allParts) throws InterruptedException {
|
||||
|
||||
for (int e = 0; e < body.exceptions.length; e++) {
|
||||
@@ -494,6 +478,17 @@ public class AVM2Graph extends Graph {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walk local registers usage
|
||||
* @param throwStates List of throw states
|
||||
* @param localData Local data
|
||||
* @param getLocalPos Get local position
|
||||
* @param startPart Start part
|
||||
* @param part Part
|
||||
* @param visited Visited
|
||||
* @param ip IP
|
||||
* @param searchRegId Search register ID
|
||||
*/
|
||||
private void walkLocalRegsUsage(List<ThrowState> throwStates, AVM2LocalData localData, Set<Integer> getLocalPos, GraphPart startPart, GraphPart part, Set<GraphPart> visited, int ip, int searchRegId) {
|
||||
if (visited.contains(part) && part != startPart) {
|
||||
return;
|
||||
@@ -584,7 +579,17 @@ public class AVM2Graph extends Graph {
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: optimize this to make it faster!!!
|
||||
/**
|
||||
* Calculates local registers usage.
|
||||
*
|
||||
* TODO: optimize this to make it faster!!!
|
||||
* @param throwStates List of throw states
|
||||
* @param localData Local data
|
||||
* @param ignoredSwitches Ignored switches
|
||||
* @param path Path
|
||||
* @param allParts All parts
|
||||
* @return Map of getLocal to setLocal set
|
||||
*/
|
||||
public Map<Integer, Set<Integer>> calculateLocalRegsUsage(List<ThrowState> throwStates, AVM2LocalData localData, Set<Integer> ignoredSwitches, String path, Set<GraphPart> allParts) {
|
||||
logger.log(Level.FINE, "--- {0} ---", path);
|
||||
Map<Integer, Set<Integer>> setLocalPosToGetLocalPos = new TreeMap<>();
|
||||
@@ -627,6 +632,29 @@ public class AVM2Graph extends Graph {
|
||||
return setLocalPosToGetLocalPos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates via Graph - decompiles.
|
||||
* @param secondPassData Second pass data
|
||||
* @param callStack Call stack
|
||||
* @param abcIndex ABC indexing
|
||||
* @param path Path
|
||||
* @param code AVM2 code
|
||||
* @param abc ABC
|
||||
* @param body Method body
|
||||
* @param isStatic Is static
|
||||
* @param scriptIndex Script index
|
||||
* @param classIndex Class index
|
||||
* @param localRegs Local registers
|
||||
* @param scopeStack Scope stack
|
||||
* @param localRegNames Local register names
|
||||
* @param localRegTypes Local register types
|
||||
* @param fullyQualifiedNames Fully qualified names
|
||||
* @param staticOperation Unused
|
||||
* @param localRegAssigmentIps Local register assignment IPs
|
||||
* @param thisHasDefaultToPrimitive This has default to primitive
|
||||
* @return List of graph target items
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public static List<GraphTargetItem> translateViaGraph(SecondPassData secondPassData, List<MethodBody> callStack, AbcIndexing abcIndex, String path, AVM2Code code, ABC abc, MethodBody body, boolean isStatic, int scriptIndex, int classIndex, HashMap<Integer, GraphTargetItem> localRegs, ScopeStack scopeStack, HashMap<Integer, String> localRegNames, HashMap<Integer, GraphTargetItem> localRegTypes, List<DottedChain> fullyQualifiedNames, int staticOperation, HashMap<Integer, Integer> localRegAssigmentIps, boolean thisHasDefaultToPrimitive) throws InterruptedException {
|
||||
ScopeStack localScopeStack = new ScopeStack();
|
||||
AVM2Graph g = new AVM2Graph(abcIndex, code, abc, body, isStatic, scriptIndex, classIndex, localRegs, scopeStack, localScopeStack, localRegNames, fullyQualifiedNames, localRegAssigmentIps);
|
||||
@@ -657,6 +685,10 @@ public class AVM2Graph extends Graph {
|
||||
return g.translate(localData, staticOperation, path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check graph.
|
||||
* @param allBlocks All blocks
|
||||
*/
|
||||
@Override
|
||||
protected void checkGraph(List<GraphPart> allBlocks) {
|
||||
for (ABCException ex : body.exceptions) {
|
||||
@@ -674,41 +706,13 @@ public class AVM2Graph extends Graph {
|
||||
}
|
||||
}
|
||||
|
||||
private void findNearestPartOutsideTry(AVM2LocalData localData, GraphPart part, int tryEndIp, Set<GraphPart> visited, Set<GraphPart> result) {
|
||||
if (visited.contains(part)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (part.start >= tryEndIp || part.end >= tryEndIp) {
|
||||
result.add(part);
|
||||
return;
|
||||
}
|
||||
|
||||
if (localData.finallyJumps.containsKey(part)) {
|
||||
GraphPart afterSwitchPart = localData.finallyJumps.get(part);
|
||||
GraphPart switchPart = null;
|
||||
for (GraphPart r : afterSwitchPart.refs) {
|
||||
if (localData.ignoredSwitches.containsValue(r)) {
|
||||
switchPart = r;
|
||||
}
|
||||
}
|
||||
|
||||
if (switchPart != null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (GraphPart n : part.nextParts) {
|
||||
findNearestPartOutsideTry(localData, n, tryEndIp, visited, result);
|
||||
}
|
||||
}
|
||||
|
||||
private Set<GraphPart> findNearestPartOutsideTry(AVM2LocalData localData, GraphPart start, int tryEndIp) {
|
||||
Set<GraphPart> result = new HashSet<>();
|
||||
findNearestPartOutsideTry(localData, start, tryEndIp, new HashSet<>(), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds lookup switch with get local.
|
||||
* @param registerId Register ID
|
||||
* @param part Part
|
||||
* @param visited Visited
|
||||
* @return Graph part
|
||||
*/
|
||||
private GraphPart findLookupSwitchWithGetLocal(int registerId, GraphPart part, Set<GraphPart> visited) {
|
||||
if (visited.contains(part)) {
|
||||
return null;
|
||||
@@ -735,10 +739,25 @@ public class AVM2Graph extends Graph {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds lookup switch with get local.
|
||||
* @param registerId Register ID
|
||||
* @param part Part
|
||||
* @return Graph part
|
||||
*/
|
||||
private GraphPart findLookupSwitchWithGetLocal(int registerId, GraphPart part) {
|
||||
return findLookupSwitchWithGetLocal(registerId, part, new HashSet<>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all pops.
|
||||
* @param localData Local data
|
||||
* @param stackLevel Stack level
|
||||
* @param part Part
|
||||
* @param foundIps Found IPs
|
||||
* @param foundParts Found parts
|
||||
* @param visited Visited
|
||||
*/
|
||||
private void findAllPops(AVM2LocalData localData, int stackLevel, GraphPart part, List<Integer> foundIps, List<GraphPart> foundParts, Set<GraphPart> visited) {
|
||||
if (visited.contains(part)) {
|
||||
return;
|
||||
@@ -758,6 +777,12 @@ public class AVM2Graph extends Graph {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets real references.
|
||||
* Real = start >= 0
|
||||
* @param part
|
||||
* @return
|
||||
*/
|
||||
private List<GraphPart> getRealRefs(GraphPart part) {
|
||||
List<GraphPart> ret = new ArrayList<>();
|
||||
for (GraphPart r : part.refs) {
|
||||
@@ -768,31 +793,14 @@ public class AVM2Graph extends Graph {
|
||||
return ret;
|
||||
}
|
||||
|
||||
private GraphPart firstPartOutsideWalk(GraphPart part, int startIp, int endIp, Set<GraphPart> visited) {
|
||||
if (visited.contains(part)) {
|
||||
return null;
|
||||
}
|
||||
visited.add(part);
|
||||
if (part.start < startIp || part.start >= endIp) {
|
||||
return part;
|
||||
}
|
||||
for (GraphPart n : part.nextParts) {
|
||||
GraphPart r = firstPartOutsideWalk(n, startIp, endIp, visited);
|
||||
if (r != null) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private GraphPart searchFirstPartOutSideTryCatchSimple(ABCException ex, Collection<? extends GraphPart> allParts) {
|
||||
int startIp = code.adr2pos(ex.start, true);
|
||||
int endIp = code.adr2pos(ex.end, true);
|
||||
|
||||
GraphPart startPart = searchPart(startIp, allParts);
|
||||
return firstPartOutsideWalk(startPart, startIp, endIp, new HashSet<>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Search first part outside try-catch.
|
||||
* @param localData Local data
|
||||
* @param ex Exception
|
||||
* @param loops Loops
|
||||
* @param allParts All parts
|
||||
* @return Graph part
|
||||
*/
|
||||
private GraphPart searchFirstPartOutSideTryCatch(AVM2LocalData localData, ABCException ex, List<Loop> loops, Collection<? extends GraphPart> allParts) {
|
||||
LinkedHashSet<GraphPart> reachable = new LinkedHashSet<>();
|
||||
int startIp = localData.code.adr2pos(ex.start, true);
|
||||
@@ -820,6 +828,11 @@ public class AVM2Graph extends Graph {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets nearest non-empty part.
|
||||
* @param part Part
|
||||
* @return Graph part
|
||||
*/
|
||||
private GraphPart nearestNonEmptyPart(GraphPart part) {
|
||||
while (isPartEmpty(part)) {
|
||||
part = part.nextParts.get(0);
|
||||
@@ -827,6 +840,16 @@ public class AVM2Graph extends Graph {
|
||||
return part;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets catched exception IDs.
|
||||
* @param part Part
|
||||
* @param previouslyCatchedExceptionIds Previously catched exception IDs
|
||||
* @param catchedExceptionIds Catched exception IDs
|
||||
* @param finallyIndex Finally index
|
||||
* @param allParts All parts
|
||||
* @param loops Loops
|
||||
* @param localData Local data
|
||||
*/
|
||||
private void getCatchedExceptionIds(GraphPart part, List<Integer> previouslyCatchedExceptionIds, List<Integer> catchedExceptionIds, Reference<Integer> finallyIndex, Collection<? extends GraphPart> allParts,
|
||||
List<Loop> loops, AVM2LocalData localData) {
|
||||
|
||||
@@ -935,6 +958,12 @@ public class AVM2Graph extends Graph {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds nearest part outside catch.
|
||||
* @param tryTarget Try target
|
||||
* @param catchParts Catch parts
|
||||
* @return Graph part
|
||||
*/
|
||||
private GraphPart findNearestPartOutsideCatch(GraphPart tryTarget, Set<GraphPart> catchParts) {
|
||||
for (GraphPart p : catchParts) {
|
||||
for (GraphPart n : p.nextParts) {
|
||||
@@ -946,6 +975,27 @@ public class AVM2Graph extends Graph {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks try.
|
||||
* @param currentRet Current return
|
||||
* @param foundGotos Found gotos
|
||||
* @param partCodes Part codes
|
||||
* @param partCodePos Part code position
|
||||
* @param visited Visited
|
||||
* @param localData Local data
|
||||
* @param part Part
|
||||
* @param stopPart Stop part
|
||||
* @param stopPartKind Stop part kind
|
||||
* @param loops Loops
|
||||
* @param throwStates Throw states
|
||||
* @param allParts All parts
|
||||
* @param stack Stack
|
||||
* @param staticOperation Unused
|
||||
* @param path Path
|
||||
* @param recursionLevel Recursion level
|
||||
* @return True if try is found
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
private boolean checkTry(List<GraphTargetItem> currentRet, List<GotoItem> foundGotos, Map<GraphPart, List<GraphTargetItem>> partCodes, Map<GraphPart, Integer> partCodePos, Set<GraphPart> visited, AVM2LocalData localData, GraphPart part, List<GraphPart> stopPart, List<StopPartKind> stopPartKind, List<Loop> loops, List<ThrowState> throwStates, Set<GraphPart> allParts, TranslateStack stack, int staticOperation, String path, int recursionLevel) throws InterruptedException {
|
||||
if (localData.parsedExceptions == null) {
|
||||
localData.parsedExceptions = new ArrayList<>();
|
||||
@@ -1413,6 +1463,12 @@ public class AVM2Graph extends Graph {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the part can handle visited.
|
||||
* @param localData Local data
|
||||
* @param part Graph part
|
||||
* @return True if the part can handle visited
|
||||
*/
|
||||
@Override
|
||||
protected boolean canHandleVisited(BaseLocalData localData, GraphPart part) {
|
||||
AVM2LocalData aLocalData = (AVM2LocalData) localData;
|
||||
@@ -1428,6 +1484,14 @@ public class AVM2Graph extends Graph {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the part can handle loop.
|
||||
* @param localData Local data
|
||||
* @param part Graph part
|
||||
* @param loops List of loops
|
||||
* @param throwStates List of throw states
|
||||
* @return True if the part can handle loop
|
||||
*/
|
||||
@Override
|
||||
protected boolean canHandleLoop(BaseLocalData localData, GraphPart part, List<Loop> loops, List<ThrowState> throwStates) {
|
||||
Loop toBeLoop = null;
|
||||
@@ -1466,6 +1530,30 @@ public class AVM2Graph extends Graph {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check part output.
|
||||
* @param currentRet Current return
|
||||
* @param foundGotos Found gotos
|
||||
* @param partCodes Part codes
|
||||
* @param partCodePos Part code position
|
||||
* @param visited Visited
|
||||
* @param code Code
|
||||
* @param localData Local data
|
||||
* @param allParts All parts
|
||||
* @param stack Stack
|
||||
* @param parent Parent part
|
||||
* @param part Part
|
||||
* @param stopPart Stop part
|
||||
* @param stopPartKind Stop part kind
|
||||
* @param loops Loops
|
||||
* @param throwStates Throw states
|
||||
* @param currentLoop Current loop
|
||||
* @param staticOperation Unused
|
||||
* @param path Path
|
||||
* @param recursionLevel Recursion level
|
||||
* @return True to stop processing. False to continue.
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Override
|
||||
protected boolean checkPartOutput(List<GraphTargetItem> currentRet, List<GotoItem> foundGotos,
|
||||
Map<GraphPart, List<GraphTargetItem>> partCodes, Map<GraphPart, Integer> partCodePos,
|
||||
@@ -1481,6 +1569,31 @@ public class AVM2Graph extends Graph {
|
||||
return checkTry(currentRet, foundGotos, partCodes, partCodePos, visited, aLocalData, part, stopPart, stopPartKind, loops, throwStates, allParts, stack, staticOperation, path, recursionLevel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check before decompiling next section.
|
||||
* Override this method to provide custom behavior.
|
||||
* @param currentRet Current return
|
||||
* @param foundGotos Found gotos
|
||||
* @param partCodes Part codes
|
||||
* @param partCodePos Part code position
|
||||
* @param visited Visited
|
||||
* @param code Code
|
||||
* @param localData Local data
|
||||
* @param allParts All parts
|
||||
* @param stack Stack
|
||||
* @param parent Parent part
|
||||
* @param part Part
|
||||
* @param stopPart Stop part
|
||||
* @param stopPartKind Stop part kind
|
||||
* @param loops Loops
|
||||
* @param throwStates Throw states
|
||||
* @param output Output
|
||||
* @param currentLoop Current loop
|
||||
* @param staticOperation Unused
|
||||
* @param path Path
|
||||
* @return List of GraphTargetItems to replace current output and stop further processing. Null to continue.
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Override
|
||||
protected List<GraphTargetItem> check(List<GraphTargetItem> currentRet, List<GotoItem> foundGotos,
|
||||
Map<GraphPart, List<GraphTargetItem>> partCodes, Map<GraphPart, Integer> partCodePos,
|
||||
@@ -1607,6 +1720,13 @@ public class AVM2Graph extends Graph {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get next parts of a part.
|
||||
* Can be overriden to provide custom behavior.
|
||||
* @param localData Local data
|
||||
* @param part Part
|
||||
* @return List of GraphParts
|
||||
*/
|
||||
@Override
|
||||
protected List<GraphPart> getNextParts(BaseLocalData localData, GraphPart part) {
|
||||
AVM2LocalData aLocalData = (AVM2LocalData) localData;
|
||||
@@ -1618,6 +1738,17 @@ public class AVM2Graph extends Graph {
|
||||
return super.getNextParts(localData, part);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check of Part passing output.
|
||||
*
|
||||
* @param output List of GraphTargetItems
|
||||
* @param stack Translate stack
|
||||
* @param localData Local data
|
||||
* @param prev Previous part
|
||||
* @param part Part
|
||||
* @param allParts All parts
|
||||
* @return Return same part to continue processing or return another part to continue to other part. Or return null to stop.
|
||||
*/
|
||||
@Override
|
||||
protected GraphPart checkPartWithOutput(List<GraphTargetItem> output, TranslateStack stack,
|
||||
BaseLocalData localData, GraphPart prev,
|
||||
@@ -1693,11 +1824,26 @@ public class AVM2Graph extends Graph {
|
||||
return part;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check of part.
|
||||
* @param stack Translate stack
|
||||
* @param localData Local data
|
||||
* @param prev Previous part
|
||||
* @param part Part
|
||||
* @param allParts All parts
|
||||
* @return Return same part to continue processing or return another part to continue to other part. Or return null to stop.
|
||||
*/
|
||||
@Override
|
||||
protected GraphPart checkPart(TranslateStack stack, BaseLocalData localData, GraphPart prev, GraphPart part, Set<GraphPart> allParts) {
|
||||
return checkPartWithOutput(null, stack, localData, prev, part, allParts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether part is empty.
|
||||
* @param part Part
|
||||
* @return True if part is empty
|
||||
*/
|
||||
@Override
|
||||
protected boolean isPartEmpty(GraphPart part) {
|
||||
if (part.nextParts.size() > 1) {
|
||||
@@ -1715,6 +1861,16 @@ public class AVM2Graph extends Graph {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check loop.
|
||||
* @param output List of GraphTargetItems
|
||||
* @param loopItem Loop item
|
||||
* @param localData Local data
|
||||
* @param loops Loops
|
||||
* @param throwStates Throw states
|
||||
* @param stack Translate stack
|
||||
* @return Return loopItem to replace current loop. Return null to continue.
|
||||
*/
|
||||
@Override
|
||||
protected GraphTargetItem checkLoop(List<GraphTargetItem> output, LoopItem loopItem, BaseLocalData localData, List<Loop> loops, List<ThrowState> throwStates, TranslateStack stack) {
|
||||
if (debugDoNotProcess) {
|
||||
@@ -2047,6 +2203,11 @@ public class AVM2Graph extends Graph {
|
||||
return loopItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process various items.
|
||||
* @param list List of GraphTargetItems
|
||||
* @param lastLoopId Last loop id
|
||||
*/
|
||||
@Override
|
||||
protected void processOther(List<GraphTargetItem> list, long lastLoopId) {
|
||||
if (list.isEmpty()) {
|
||||
@@ -2097,6 +2258,13 @@ public class AVM2Graph extends Graph {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Final process after.
|
||||
* @param list List of GraphTargetItems
|
||||
* @param level Level
|
||||
* @param localData Local data
|
||||
* @param path Path
|
||||
*/
|
||||
@Override
|
||||
protected void finalProcessAfter(List<GraphTargetItem> list, int level, FinalProcessLocalData localData, String path) {
|
||||
super.finalProcessAfter(list, level, localData, path);
|
||||
@@ -2127,6 +2295,11 @@ public class AVM2Graph extends Graph {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if item is integer or pop integer.
|
||||
* @param item GraphTargetItem
|
||||
* @return True if item is integer or pop integer
|
||||
*/
|
||||
private boolean isIntegerOrPopInteger(GraphTargetItem item) {
|
||||
if (item instanceof IntegerValueAVM2Item) {
|
||||
return true;
|
||||
@@ -2137,6 +2310,14 @@ public class AVM2Graph extends Graph {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Final process.
|
||||
* @param list List of GraphTargetItems
|
||||
* @param level Level
|
||||
* @param localData Local data
|
||||
* @param path Path
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Override
|
||||
protected void finalProcess(List<GraphTargetItem> list, int level, FinalProcessLocalData localData, String path) throws InterruptedException {
|
||||
if (debugDoNotProcess) {
|
||||
@@ -2489,6 +2670,13 @@ public class AVM2Graph extends Graph {
|
||||
super.finalProcess(list, level, localData, path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets data for final process.
|
||||
* @param localData
|
||||
* @param loops
|
||||
* @param throwStates
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
protected FinalProcessLocalData getFinalData(BaseLocalData localData, List<Loop> loops, List<ThrowState> throwStates) {
|
||||
FinalProcessLocalData finalProcess = new AVM2FinalProcessLocalData(loops, ((AVM2LocalData) localData).localRegNames, ((AVM2LocalData) localData).setLocalPosToGetLocalPos);
|
||||
@@ -2496,6 +2684,11 @@ public class AVM2Graph extends Graph {
|
||||
return finalProcess;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares local data for branch.
|
||||
* @param localData Local data
|
||||
* @return Local data for a branch
|
||||
*/
|
||||
@Override
|
||||
public AVM2LocalData prepareBranchLocalData(BaseLocalData localData) {
|
||||
AVM2LocalData aLocalData = (AVM2LocalData) localData;
|
||||
@@ -2506,6 +2699,13 @@ public class AVM2Graph extends Graph {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks switch statement.
|
||||
* @param localData Local data
|
||||
* @param switchItem Switch item
|
||||
* @param otherSides Other sides
|
||||
* @param output Output
|
||||
*/
|
||||
@Override
|
||||
protected void checkSwitch(BaseLocalData localData, SwitchItem switchItem, Collection<? extends GraphTargetItem> otherSides, List<GraphTargetItem> output) {
|
||||
if (output.isEmpty()) {
|
||||
@@ -2539,6 +2739,11 @@ public class AVM2Graph extends Graph {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if part is a switch.
|
||||
* @param part Part
|
||||
* @return True if part is a switch
|
||||
*/
|
||||
@Override
|
||||
protected boolean partIsSwitch(GraphPart part) {
|
||||
if (part.end < 0) {
|
||||
@@ -2547,6 +2752,12 @@ public class AVM2Graph extends Graph {
|
||||
return avm2code.code.get(part.end).definition instanceof LookupSwitchIns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets throw states.
|
||||
* @param localData Local data
|
||||
* @param allParts All parts
|
||||
* @return List of ThrowStates
|
||||
*/
|
||||
@Override
|
||||
protected List<ThrowState> getThrowStates(BaseLocalData localData, Set<GraphPart> allParts) {
|
||||
|
||||
@@ -2628,6 +2839,15 @@ public class AVM2Graph extends Graph {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Walk catch parts register.
|
||||
* @param registerId Register id
|
||||
* @param part Part
|
||||
* @param startIp Start ip
|
||||
* @param catchParts Catch parts
|
||||
* @param path Path
|
||||
* @param visited Visited
|
||||
*/
|
||||
private void walkCatchPartsReg(int registerId, GraphPart part, int startIp, Set<GraphPart> catchParts, List<GraphPart> path, Set<GraphPart> visited) {
|
||||
if (visited.contains(part)) {
|
||||
return;
|
||||
@@ -2661,6 +2881,16 @@ public class AVM2Graph extends Graph {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walk catch parts.
|
||||
* @param stats Code stats
|
||||
* @param part Part
|
||||
* @param startIp Start ip
|
||||
* @param catchParts Catch parts
|
||||
* @param scopePos Scope position
|
||||
* @param allParts All parts
|
||||
* @param isFinally True if the catch is finally
|
||||
*/
|
||||
private void walkCatchParts(CodeStats stats, GraphPart part, int startIp, Set<GraphPart> catchParts, int scopePos, Set<GraphPart> allParts, boolean isFinally) {
|
||||
if (catchParts.contains(part)) {
|
||||
return;
|
||||
@@ -2704,19 +2934,13 @@ public class AVM2Graph extends Graph {
|
||||
part.nextParts.add(secondPart);
|
||||
secondPart.refs.add(part);
|
||||
|
||||
secondPart.type = GraphPart.TYPE_NONE;
|
||||
secondPart.discoveredTime = part.discoveredTime;
|
||||
secondPart.closedTime = part.closedTime;
|
||||
secondPart.finishedTime = part.finishedTime;
|
||||
secondPart.iloop_header = part.iloop_header;
|
||||
secondPart.irreducible = part.irreducible;
|
||||
secondPart.level = part.level;
|
||||
secondPart.numBlocks = part.numBlocks;
|
||||
secondPart.order = part.order;
|
||||
secondPart.path = part.path;
|
||||
secondPart.posX = part.posX;
|
||||
secondPart.posY = part.posY;
|
||||
secondPart.traversed = true;
|
||||
allParts.add(secondPart);
|
||||
}
|
||||
catchParts.add(part);
|
||||
@@ -2729,6 +2953,12 @@ public class AVM2Graph extends Graph {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves all stack items to commands.
|
||||
* (If it's not a branch stack resistant or other special case)
|
||||
* @param commands Commands
|
||||
* @param stack Stack
|
||||
*/
|
||||
public void makeAllCommands(List<GraphTargetItem> commands, TranslateStack stack) {
|
||||
for (int i = 0; i < stack.size(); i++) {
|
||||
//These are often obfuscated, so ignore them
|
||||
@@ -2740,6 +2970,12 @@ public class AVM2Graph extends Graph {
|
||||
super.makeAllCommands(commands, stack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares second pass data.
|
||||
* Can return null when no second pass will happen.
|
||||
* @param list List of GraphTargetItems
|
||||
* @return Second pass data or null
|
||||
*/
|
||||
@Override
|
||||
protected SecondPassData prepareSecondPass(List<GraphTargetItem> list) {
|
||||
return new SecondPassData();
|
||||
|
||||
+101
-8
@@ -23,49 +23,91 @@ import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.ConvertOutput;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.graph.DottedChain;
|
||||
import com.jpexs.decompiler.graph.Graph;
|
||||
import com.jpexs.decompiler.graph.GraphPart;
|
||||
import com.jpexs.decompiler.graph.GraphSource;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItem;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.TranslateStack;
|
||||
import com.jpexs.decompiler.graph.*;
|
||||
import com.jpexs.helpers.Reference;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* AVM2 graph source.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class AVM2GraphSource extends GraphSource {
|
||||
|
||||
/**
|
||||
* AVM2 code
|
||||
*/
|
||||
private final AVM2Code code;
|
||||
|
||||
/**
|
||||
* Is static
|
||||
*/
|
||||
boolean isStatic;
|
||||
|
||||
/**
|
||||
* Class index
|
||||
*/
|
||||
int classIndex;
|
||||
|
||||
/**
|
||||
* Script index
|
||||
*/
|
||||
int scriptIndex;
|
||||
|
||||
/**
|
||||
* Local registers - map of register index to value item
|
||||
*/
|
||||
HashMap<Integer, GraphTargetItem> localRegs;
|
||||
|
||||
/**
|
||||
* ABC
|
||||
*/
|
||||
ABC abc;
|
||||
|
||||
/**
|
||||
* Method body
|
||||
*/
|
||||
MethodBody body;
|
||||
|
||||
/**
|
||||
* Local register names - map of register index to name
|
||||
*/
|
||||
HashMap<Integer, String> localRegNames;
|
||||
|
||||
/**
|
||||
* Fully qualified names
|
||||
*/
|
||||
List<DottedChain> fullyQualifiedNames;
|
||||
|
||||
/**
|
||||
* Local register assignment IPs - map of register index to IP
|
||||
*/
|
||||
HashMap<Integer, Integer> localRegAssigmentIps;
|
||||
|
||||
/**
|
||||
* Get AVM2 code
|
||||
* @return AVM2 code
|
||||
*/
|
||||
public AVM2Code getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new AVM2 graph source
|
||||
* @param code AVM2 code
|
||||
* @param isStatic Is static
|
||||
* @param scriptIndex Script index
|
||||
* @param classIndex Class index
|
||||
* @param localRegs Local registers
|
||||
* @param abc ABC
|
||||
* @param body Method body
|
||||
* @param localRegNames Local register names
|
||||
* @param fullyQualifiedNames Fully qualified names
|
||||
* @param localRegAssigmentIp Local register assignment IPs
|
||||
*/
|
||||
public AVM2GraphSource(AVM2Code code, boolean isStatic, int scriptIndex, int classIndex, HashMap<Integer, GraphTargetItem> localRegs, ABC abc, MethodBody body, HashMap<Integer, String> localRegNames, List<DottedChain> fullyQualifiedNames, HashMap<Integer, Integer> localRegAssigmentIp) {
|
||||
this.code = code;
|
||||
this.isStatic = isStatic;
|
||||
@@ -80,11 +122,20 @@ public class AVM2GraphSource extends GraphSource {
|
||||
code.calculateDebugFileLine(abc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets important addresses
|
||||
* @return Important addresses
|
||||
*/
|
||||
@Override
|
||||
public Set<Long> getImportantAddresses() {
|
||||
return code.getImportantOffsets(body, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts instruction at the specified position to string
|
||||
* @param pos Position of the instruction
|
||||
* @return Instruction as string
|
||||
*/
|
||||
@Override
|
||||
public String insToString(int pos) {
|
||||
if (pos < code.code.size()) {
|
||||
@@ -93,21 +144,47 @@ public class AVM2GraphSource extends GraphSource {
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the size of the graph source
|
||||
* @return The size of the graph source
|
||||
*/
|
||||
@Override
|
||||
public int size() {
|
||||
return code.code.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the graph source item at the specified position
|
||||
* @param pos Position of the graph source item
|
||||
* @return The graph source item at the specified position
|
||||
*/
|
||||
@Override
|
||||
public AVM2Instruction get(int pos) {
|
||||
return code.code.get(pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the graph source is empty
|
||||
* @return True if the graph source is empty, false otherwise
|
||||
*/
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return code.code.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates the part of the graph source
|
||||
* @param graph Graph
|
||||
* @param part Graph part
|
||||
* @param localData Local data
|
||||
* @param stack Translate stack
|
||||
* @param start Start position
|
||||
* @param end End position
|
||||
* @param staticOperation Unused
|
||||
* @param path Path
|
||||
* @return List of graph target items
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Override
|
||||
public List<GraphTargetItem> translatePart(Graph graph, GraphPart part, BaseLocalData localData, TranslateStack stack, int start, int end, int staticOperation, String path) throws InterruptedException {
|
||||
List<GraphTargetItem> ret = new ArrayList<>();
|
||||
@@ -118,16 +195,32 @@ public class AVM2GraphSource extends GraphSource {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts address to position
|
||||
* @param adr Address
|
||||
* @return Position
|
||||
*/
|
||||
@Override
|
||||
public int adr2pos(long adr) {
|
||||
return code.adr2pos(adr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts address to position
|
||||
* @param adr Address
|
||||
* @param nearest Nearest
|
||||
* @return Position
|
||||
*/
|
||||
@Override
|
||||
public int adr2pos(long adr, boolean nearest) {
|
||||
return code.adr2pos(adr, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts position to address
|
||||
* @param pos Position
|
||||
* @return Address
|
||||
*/
|
||||
@Override
|
||||
public long pos2adr(int pos) {
|
||||
return code.pos2adr(pos);
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* AVM2 control flow graph.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.graph;
|
||||
+228
-22
@@ -32,43 +32,63 @@ import com.jpexs.decompiler.flash.abc.types.Multiname;
|
||||
import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import com.jpexs.decompiler.flash.ecma.EcmaScript;
|
||||
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
|
||||
import com.jpexs.decompiler.graph.DottedChain;
|
||||
import com.jpexs.decompiler.graph.GraphSource;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItem;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.TranslateStack;
|
||||
import com.jpexs.decompiler.graph.*;
|
||||
import com.jpexs.decompiler.graph.model.LocalData;
|
||||
import com.jpexs.helpers.Helper;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* AVM2 instruction.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class AVM2Instruction implements Cloneable, GraphSourceItem {
|
||||
|
||||
/**
|
||||
* Definition
|
||||
*/
|
||||
public InstructionDefinition definition;
|
||||
|
||||
/**
|
||||
* Operands
|
||||
*/
|
||||
public int[] operands;
|
||||
|
||||
/**
|
||||
* Address
|
||||
*/
|
||||
private long address;
|
||||
|
||||
/**
|
||||
* Comment
|
||||
*/
|
||||
public String comment;
|
||||
|
||||
/**
|
||||
* Ignored
|
||||
*/
|
||||
private boolean ignored = false;
|
||||
|
||||
/**
|
||||
* Line
|
||||
*/
|
||||
private int line;
|
||||
|
||||
/**
|
||||
* File
|
||||
*/
|
||||
private String file;
|
||||
|
||||
/**
|
||||
* Virtual address - used for deobfuscation
|
||||
*/
|
||||
private long virtualAddress = -1;
|
||||
|
||||
/**
|
||||
* Old style names for getlocal and setlocal
|
||||
*/
|
||||
private static final Map<String, String> oldStyleNames = new HashMap<>();
|
||||
|
||||
static {
|
||||
@@ -78,11 +98,19 @@ public class AVM2Instruction implements Cloneable, GraphSourceItem {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets file offset.
|
||||
* @return File offset
|
||||
*/
|
||||
@Override
|
||||
public long getFileOffset() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the line offset.
|
||||
* @return Line offset
|
||||
*/
|
||||
@Override
|
||||
public long getLineOffset() {
|
||||
if (virtualAddress > -1) {
|
||||
@@ -91,21 +119,42 @@ public class AVM2Instruction implements Cloneable, GraphSourceItem {
|
||||
return getAddress();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets file and line.
|
||||
* @param file File
|
||||
* @param line Line
|
||||
*/
|
||||
public void setFileLine(String file, int line) {
|
||||
this.file = file;
|
||||
this.line = line;
|
||||
}
|
||||
|
||||
public AVM2Instruction(long offset, int insructionCode, int[] operands) {
|
||||
this(offset, AVM2Code.instructionSet[insructionCode], operands);
|
||||
/**
|
||||
* Constructs a new AVM2 instruction.
|
||||
* @param offset Offset
|
||||
* @param instructionCode Instruction code
|
||||
* @param operands Operands
|
||||
*/
|
||||
public AVM2Instruction(long offset, int instructionCode, int[] operands) {
|
||||
this(offset, AVM2Code.instructionSet[instructionCode], operands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new AVM2 instruction.
|
||||
* @param address Address
|
||||
* @param definition Definition
|
||||
* @param operands Operands
|
||||
*/
|
||||
public AVM2Instruction(long address, InstructionDefinition definition, int[] operands) {
|
||||
this.definition = definition;
|
||||
this.operands = operands != null && operands.length > 0 ? operands : null;
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the bytes.
|
||||
* @return Bytes
|
||||
*/
|
||||
public byte[] getBytes() {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
try {
|
||||
@@ -142,6 +191,10 @@ public class AVM2Instruction implements Cloneable, GraphSourceItem {
|
||||
return bos.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the length of the bytes.
|
||||
* @return Length of the bytes
|
||||
*/
|
||||
@Override
|
||||
public int getBytesLength() {
|
||||
int cnt = 1;
|
||||
@@ -174,6 +227,10 @@ public class AVM2Instruction implements Cloneable, GraphSourceItem {
|
||||
return cnt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the offsets.
|
||||
* @return Offsets
|
||||
*/
|
||||
public List<Long> getOffsets() {
|
||||
List<Long> ret = new ArrayList<>();
|
||||
String s = "";
|
||||
@@ -196,6 +253,12 @@ public class AVM2Instruction implements Cloneable, GraphSourceItem {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the parameter.
|
||||
* @param constants Constants
|
||||
* @param idx Index of operand
|
||||
* @return Parameter
|
||||
*/
|
||||
public Object getParam(AVM2ConstantPool constants, int idx) {
|
||||
//if (idx < 0 || idx >= definition.operands.length) {
|
||||
// return null;
|
||||
@@ -223,10 +286,22 @@ public class AVM2Instruction implements Cloneable, GraphSourceItem {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the parameter as a long.
|
||||
* @param constants Constants
|
||||
* @param idx Index of operand
|
||||
* @return Parameter as a long
|
||||
*/
|
||||
public Long getParamAsLong(AVM2ConstantPool constants, int idx) {
|
||||
return (Long) getParam(constants, idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all parameters as string.
|
||||
* @param constants Constants
|
||||
* @param fullyQualifiedNames Fully qualified names
|
||||
* @return All parameters as string
|
||||
*/
|
||||
public String getParams(AVM2ConstantPool constants, List<DottedChain> fullyQualifiedNames) {
|
||||
StringBuilder s = new StringBuilder();
|
||||
for (int i = 0; i < definition.operands.length; i++) {
|
||||
@@ -398,6 +473,10 @@ public class AVM2Instruction implements Cloneable, GraphSourceItem {
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the comment.
|
||||
* @return Comment
|
||||
*/
|
||||
public String getComment() {
|
||||
if (isIgnored()) {
|
||||
return " ;ignored";
|
||||
@@ -408,11 +487,19 @@ public class AVM2Instruction implements Cloneable, GraphSourceItem {
|
||||
return " ;" + comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this item is ignored.
|
||||
* @return True if this item is ignored, false otherwise
|
||||
*/
|
||||
@Override
|
||||
public boolean isIgnored() {
|
||||
return ignored;
|
||||
}
|
||||
|
||||
/**
|
||||
* To string.
|
||||
* @return String
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder s = new StringBuilder();
|
||||
@@ -426,12 +513,22 @@ public class AVM2Instruction implements Cloneable, GraphSourceItem {
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* To string.
|
||||
* @param writer Writer
|
||||
* @param localData Local data
|
||||
* @return Writer
|
||||
*/
|
||||
public GraphTextWriter toString(GraphTextWriter writer, LocalData localData) {
|
||||
writer.appendNoHilight(Helper.formatAddress(address) + " " + String.format("%-30s", Helper.byteArrToString(getBytes())) + getCustomizedInstructionName());
|
||||
writer.appendNoHilight(getParams(localData.constantsAvm2, localData.fullyQualifiedNames) + getComment());
|
||||
return writer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the customized instruction name.
|
||||
* @return Customized instruction name
|
||||
*/
|
||||
private String getCustomizedInstructionName() {
|
||||
if (Configuration.useOldStyleGetSetLocalsAs3PCode.get() && oldStyleNames.containsKey(definition.instructionName)) {
|
||||
return oldStyleNames.get(definition.instructionName);
|
||||
@@ -439,6 +536,12 @@ public class AVM2Instruction implements Cloneable, GraphSourceItem {
|
||||
return definition.instructionName;
|
||||
}
|
||||
|
||||
/**
|
||||
* To string without address.
|
||||
* @param constants Constants
|
||||
* @param fullyQualifiedNames Fully qualified names
|
||||
* @return String without address
|
||||
*/
|
||||
public String toStringNoAddress(AVM2ConstantPool constants, List<DottedChain> fullyQualifiedNames) {
|
||||
String s = getCustomizedInstructionName();
|
||||
if (Configuration.padAs3PCodeInstructionName.get()) {
|
||||
@@ -450,6 +553,15 @@ public class AVM2Instruction implements Cloneable, GraphSourceItem {
|
||||
return s.trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate the item to target items.
|
||||
* @param localData Local data
|
||||
* @param stack Stack
|
||||
* @param output Output list
|
||||
* @param staticOperation Unused
|
||||
* @param path Path
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Override
|
||||
public void translate(BaseLocalData localData, TranslateStack stack, List<GraphTargetItem> output, int staticOperation, String path) throws InterruptedException {
|
||||
AVM2LocalData aLocalData = (AVM2LocalData) localData;
|
||||
@@ -460,58 +572,114 @@ public class AVM2Instruction implements Cloneable, GraphSourceItem {
|
||||
}*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of stack items that are popped by this item.
|
||||
* @param localData Local data
|
||||
* @param stack Stack
|
||||
* @return Number of stack items that are popped by this item
|
||||
*/
|
||||
@Override
|
||||
public int getStackPopCount(BaseLocalData localData, TranslateStack stack) {
|
||||
AVM2LocalData aLocalData = (AVM2LocalData) localData;
|
||||
return getStackPopCount(aLocalData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of stack items that are popped by this item.
|
||||
* @param aLocalData Local data
|
||||
* @return Number of stack items that are popped by this item
|
||||
*/
|
||||
public int getStackPopCount(AVM2LocalData aLocalData) {
|
||||
return definition.getStackPopCount(this, aLocalData.abc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of stack items that are pushed by this item.
|
||||
* @param localData Local data
|
||||
* @param stack Stack
|
||||
* @return Number of stack items that are pushed by this item
|
||||
*/
|
||||
@Override
|
||||
public int getStackPushCount(BaseLocalData localData, TranslateStack stack) {
|
||||
AVM2LocalData aLocalData = (AVM2LocalData) localData;
|
||||
return getStackPushCount(aLocalData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of stack items that are pushed by this item.
|
||||
* @param aLocalData Local data
|
||||
* @return Number of stack items that are pushed by this item
|
||||
*/
|
||||
public int getStackPushCount(AVM2LocalData aLocalData) {
|
||||
return definition.getStackPushCount(this, aLocalData.abc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this item is a jump.
|
||||
* @return True if this item is a jump, false otherwise
|
||||
*/
|
||||
@Override
|
||||
public boolean isJump() {
|
||||
return definition instanceof JumpIns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this item is a branch.
|
||||
* @return True if this item is a branch, false otherwise
|
||||
*/
|
||||
@Override
|
||||
public boolean isBranch() {
|
||||
return (definition instanceof IfTypeIns) || (definition instanceof LookupSwitchIns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this item is an exit (throw, return, etc.).
|
||||
* @return True if this item is an exit, false otherwise
|
||||
*/
|
||||
@Override
|
||||
public boolean isExit() {
|
||||
return (definition instanceof ReturnValueIns) || (definition instanceof ReturnVoidIns) || (definition instanceof ThrowIns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the address.
|
||||
* @return Address
|
||||
*/
|
||||
@Override
|
||||
public long getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the address.
|
||||
* @param address Address
|
||||
*/
|
||||
public void setAddress(long address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the target address of jump.
|
||||
* @return Target address.
|
||||
*/
|
||||
public long getTargetAddress() {
|
||||
return address + 4 /*getBytesLength()*/ + operands[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the target offset of jump.
|
||||
* @param offset Offset
|
||||
*/
|
||||
public void setTargetOffset(int offset) {
|
||||
operands[0] = offset;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets branches
|
||||
* @param code Code
|
||||
* @return List of IPs to branch to
|
||||
*/
|
||||
@Override
|
||||
public List<Integer> getBranches(GraphSource code) {
|
||||
List<Integer> ret = new ArrayList<>();
|
||||
@@ -531,21 +699,39 @@ public class AVM2Instruction implements Cloneable, GraphSourceItem {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the loops are ignored.
|
||||
* @return True if the loops are ignored, false otherwise
|
||||
*/
|
||||
@Override
|
||||
public boolean ignoredLoops() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this item is ignored.
|
||||
* @param ignored True if this item is ignored, false otherwise
|
||||
* @param pos Sub position
|
||||
*/
|
||||
@Override
|
||||
public void setIgnored(boolean ignored, int pos) {
|
||||
this.ignored = ignored;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this item is a DeobfuscatePop instruction.
|
||||
* It is a special instruction for deobfuscation.
|
||||
* @return True if this item is a DeobfuscatePop instruction, false otherwise
|
||||
*/
|
||||
@Override
|
||||
public boolean isDeobfuscatePop() {
|
||||
return definition instanceof DeobfuscatePopIns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone the instruction.
|
||||
* @return Cloned instruction
|
||||
*/
|
||||
@Override
|
||||
public AVM2Instruction clone() {
|
||||
try {
|
||||
@@ -559,11 +745,19 @@ public class AVM2Instruction implements Cloneable, GraphSourceItem {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the line in the high level source code.
|
||||
* @return Line
|
||||
*/
|
||||
@Override
|
||||
public int getLine() {
|
||||
return line;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the high level source code file name.
|
||||
* @return File name
|
||||
*/
|
||||
@Override
|
||||
public String getFile() {
|
||||
return file;
|
||||
@@ -571,12 +765,12 @@ public class AVM2Instruction implements Cloneable, GraphSourceItem {
|
||||
|
||||
/**
|
||||
* Set operand value the right way - update offsets neccessarily. Because
|
||||
* some operand types are variable length (like U30)
|
||||
* some operand types are variable length (like U30).
|
||||
*
|
||||
* @param operandIndex
|
||||
* @param newValue
|
||||
* @param code
|
||||
* @param body
|
||||
* @param operandIndex Index of operand
|
||||
* @param newValue New value
|
||||
* @param code Code
|
||||
* @param body Method body
|
||||
*/
|
||||
public void setOperand(int operandIndex, int newValue, AVM2Code code, MethodBody body) {
|
||||
int oldByteCount = getBytesLength();
|
||||
@@ -591,11 +785,11 @@ public class AVM2Instruction implements Cloneable, GraphSourceItem {
|
||||
|
||||
/**
|
||||
* Set operand values the right way - update offsets neccessarily. Because
|
||||
* some operand types are variable length (like U30)
|
||||
* some operand types are variable length (like U30).
|
||||
*
|
||||
* @param operands
|
||||
* @param code
|
||||
* @param body
|
||||
* @param operands Operands
|
||||
* @param code Code
|
||||
* @param body Method body
|
||||
*/
|
||||
public void setOperands(int[] operands, AVM2Code code, MethodBody body) {
|
||||
int oldByteCount = getBytesLength();
|
||||
@@ -608,11 +802,23 @@ public class AVM2Instruction implements Cloneable, GraphSourceItem {
|
||||
body.setModified();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets virtual address. A virtual address can be used for storing original
|
||||
* address before applying deobfuscation.
|
||||
*
|
||||
* @return Virtual address
|
||||
*/
|
||||
@Override
|
||||
public long getVirtualAddress() {
|
||||
return virtualAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets virtual address. A virtual address can be used for storing original
|
||||
* address before applying deobfuscation.
|
||||
*
|
||||
* @param virtualAddress Virtual address
|
||||
*/
|
||||
@Override
|
||||
public void setVirtualAddress(long virtualAddress) {
|
||||
this.virtualAddress = virtualAddress;
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions;
|
||||
|
||||
/**
|
||||
*
|
||||
* Flags for AVM2 instructions.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public enum AVM2InstructionFlag {
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions;
|
||||
|
||||
/**
|
||||
*
|
||||
* Set of AVM2 instructions.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class AVM2Instructions {
|
||||
|
||||
+31
-1
@@ -21,31 +21,61 @@ import com.jpexs.decompiler.flash.abc.AVM2LocalData;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PopIns;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.TranslateStack;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* DeobfuscatePop instruction.
|
||||
* Special pop pused for deobfuscation purposes.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class DeobfuscatePopIns extends PopIns {
|
||||
|
||||
/**
|
||||
* Instruction name
|
||||
*/
|
||||
public static final String NAME = "ffdec_deobfuscatepop";
|
||||
|
||||
/**
|
||||
* Singleton instance
|
||||
*/
|
||||
private static final DeobfuscatePopIns instance = new DeobfuscatePopIns();
|
||||
|
||||
/**
|
||||
* Returns singleton instance
|
||||
* @return Singleton instance
|
||||
*/
|
||||
public static final DeobfuscatePopIns getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs new instance
|
||||
*/
|
||||
private DeobfuscatePopIns() {
|
||||
instructionName = NAME;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Translates instruction to high level code.
|
||||
* @param localData Local data area
|
||||
* @param stack Translate stack
|
||||
* @param ins Instruction
|
||||
* @param output Output
|
||||
* @param path Path
|
||||
*/
|
||||
@Override
|
||||
public void translate(AVM2LocalData localData, TranslateStack stack, AVM2Instruction ins, List<GraphTargetItem> output, String path) {
|
||||
stack.pop(); //Just ignore the value
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets number of pops from stack.
|
||||
* @param ins Instruction
|
||||
* @param abc ABC
|
||||
* @return Number of pops from stack
|
||||
*/
|
||||
@Override
|
||||
public int getStackPopCount(AVM2Instruction ins, ABC abc) {
|
||||
return 1;
|
||||
|
||||
+10
-2
@@ -19,13 +19,21 @@ package com.jpexs.decompiler.flash.abc.avm2.instructions;
|
||||
import com.jpexs.decompiler.flash.abc.AVM2LocalData;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.TranslateStack;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
*
|
||||
* IfType instruction interface.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public interface IfTypeIns {
|
||||
|
||||
public abstract void translateInverted(AVM2LocalData localData, HashMap<Integer, GraphTargetItem> localRegs, TranslateStack stack, AVM2Instruction ins);
|
||||
/**
|
||||
* Translates the instruction as inverted.
|
||||
* @param localData Local data
|
||||
* @param localRegs Local registers
|
||||
* @param stack Stack
|
||||
* @param ins Instruction
|
||||
*/
|
||||
public void translateInverted(AVM2LocalData localData, HashMap<Integer, GraphTargetItem> localRegs, TranslateStack stack, AVM2Instruction ins);
|
||||
}
|
||||
|
||||
+196
-103
@@ -23,35 +23,9 @@ import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.LocalDataArea;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.exceptions.AVM2ExecutionException;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.exceptions.AVM2VerifyErrorException;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.DecLocalIIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.DecLocalIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.IncLocalIIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.IncLocalIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.SetLocalTypeIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.GetPropertyIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.SetPropertyIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.AVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.ApplyTypeAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.ClassAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.ConstructAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.ConvertAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.DecrementAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.FindPropertyAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.FullMultinameAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.GetLexAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.GetPropertyAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.GlobalAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.IncrementAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.InitPropertyAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.InitVectorAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.LocalRegAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.NewActivationAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.PostDecrementAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.PostIncrementAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.SetLocalAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.SetPropertyAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.SetTypeAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.ThisAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.*;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.clauses.ExceptionAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.operations.PreDecrementAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.operations.PreIncrementAVM2Item;
|
||||
@@ -61,43 +35,57 @@ import com.jpexs.decompiler.flash.abc.types.Multiname;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.TraitWithSlot;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.Traits;
|
||||
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
|
||||
import com.jpexs.decompiler.graph.DottedChain;
|
||||
import com.jpexs.decompiler.graph.GraphPart;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItem;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.ScopeStack;
|
||||
import com.jpexs.decompiler.graph.TranslateStack;
|
||||
import com.jpexs.decompiler.graph.*;
|
||||
import com.jpexs.decompiler.graph.model.DuplicateItem;
|
||||
import com.jpexs.helpers.Reference;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.Stack;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* AVM2 Instruction definition.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public abstract class InstructionDefinition implements Serializable {
|
||||
|
||||
/**
|
||||
* Serial version UID
|
||||
*/
|
||||
public static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Operands
|
||||
*/
|
||||
public int[] operands;
|
||||
|
||||
/**
|
||||
* Instruction name
|
||||
*/
|
||||
public String instructionName = "";
|
||||
|
||||
/**
|
||||
* Instruction code
|
||||
*/
|
||||
public int instructionCode = 0;
|
||||
|
||||
/**
|
||||
* Can throw exception
|
||||
*/
|
||||
public boolean canThrow;
|
||||
|
||||
/**
|
||||
* Flags
|
||||
*/
|
||||
public AVM2InstructionFlag[] flags;
|
||||
|
||||
/**
|
||||
* Constructs new instance
|
||||
* @param instructionCode Instruction code
|
||||
* @param instructionName Instruction name
|
||||
* @param operands Operands
|
||||
* @param canThrow Can throw exception
|
||||
* @param flags Flags
|
||||
*/
|
||||
public InstructionDefinition(int instructionCode, String instructionName, int[] operands, boolean canThrow, AVM2InstructionFlag... flags) {
|
||||
this.instructionCode = instructionCode;
|
||||
this.instructionName = instructionName;
|
||||
@@ -106,6 +94,11 @@ public abstract class InstructionDefinition implements Serializable {
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if instruction has flag
|
||||
* @param flag Flag
|
||||
* @return True if instruction has flag
|
||||
*/
|
||||
public boolean hasFlag(AVM2InstructionFlag flag) {
|
||||
for (AVM2InstructionFlag f : flags) {
|
||||
if (f == flag) {
|
||||
@@ -115,6 +108,10 @@ public abstract class InstructionDefinition implements Serializable {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* To string
|
||||
* @return String representation
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder s = new StringBuilder();
|
||||
@@ -125,6 +122,13 @@ public abstract class InstructionDefinition implements Serializable {
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify instruction
|
||||
* @param lda Local data area
|
||||
* @param constants Constant pool
|
||||
* @param ins Instruction
|
||||
* @throws AVM2VerifyErrorException
|
||||
*/
|
||||
public void verify(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instruction ins) throws AVM2VerifyErrorException {
|
||||
for (int i = 0; i < operands.length; i++) {
|
||||
int operand = operands[i];
|
||||
@@ -177,22 +181,77 @@ public abstract class InstructionDefinition implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if instruction cannot be statically computed.
|
||||
* @return True = cannot be statically computed, false = can be statically computed
|
||||
*/
|
||||
public boolean isNotCompileTimeSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes instruction.
|
||||
* @param lda Local data area
|
||||
* @param constants Constant pool
|
||||
* @param ins Instruction
|
||||
* @return True if instruction was executed, false if not
|
||||
* @throws AVM2ExecutionException
|
||||
*/
|
||||
public boolean execute(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instruction ins) throws AVM2ExecutionException {
|
||||
//throw new UnsupportedOperationException("Instruction " + instructionName + " not implemented");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws illegal opcode exception.
|
||||
* @param lda Local data area
|
||||
* @param ins Instruction
|
||||
* @throws AVM2VerifyErrorException
|
||||
*/
|
||||
protected void illegalOpCode(LocalDataArea lda, AVM2Instruction ins) throws AVM2VerifyErrorException {
|
||||
throw new AVM2VerifyErrorException(AVM2VerifyErrorException.ILLEGAL_OPCODE, lda.isDebug(), new Object[]{lda.methodName, instructionCode, ins.getAddress()});
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates instruction to high level code.
|
||||
* @param localData Local data area
|
||||
* @param stack Translate stack
|
||||
* @param ins Instruction
|
||||
* @param output Output
|
||||
* @param path Path
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public void translate(AVM2LocalData localData, TranslateStack stack, AVM2Instruction ins, List<GraphTargetItem> output, String path) throws InterruptedException {
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates instruction to high level code.
|
||||
* @param switchParts Switch parts
|
||||
* @param callStack Call stack
|
||||
* @param abcIndex ABC indexing
|
||||
* @param setLocalPosToGetLocalPos Set local position to get local position
|
||||
* @param lineStartItem Line start item
|
||||
* @param isStatic Is static
|
||||
* @param scriptIndex Script index
|
||||
* @param classIndex Class index
|
||||
* @param localRegs Local registers
|
||||
* @param stack Translate stack
|
||||
* @param scopeStack Scope stack
|
||||
* @param localScopeStack Local scope stack
|
||||
* @param ins Instruction
|
||||
* @param output Output
|
||||
* @param body Method body
|
||||
* @param abc ABC
|
||||
* @param localRegNames Local register names
|
||||
* @param localRegTypes Local register types
|
||||
* @param fullyQualifiedNames Fully qualified names
|
||||
* @param path Path
|
||||
* @param localRegsAssignmentIps Local registers assignment IPs
|
||||
* @param ip IP
|
||||
* @param code AVM2 code
|
||||
* @param thisHasDefaultToPrimitive This has default to primitive
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public void translate(Set<GraphPart> switchParts, List<MethodBody> callStack, AbcIndexing abcIndex, Map<Integer, Set<Integer>> setLocalPosToGetLocalPos, Reference<GraphSourceItem> lineStartItem, boolean isStatic, int scriptIndex, int classIndex, HashMap<Integer, GraphTargetItem> localRegs, TranslateStack stack, ScopeStack scopeStack, ScopeStack localScopeStack, AVM2Instruction ins, List<GraphTargetItem> output, MethodBody body, ABC abc, HashMap<Integer, String> localRegNames, HashMap<Integer, GraphTargetItem> localRegTypes, List<DottedChain> fullyQualifiedNames, String path, HashMap<Integer, Integer> localRegsAssignmentIps, int ip, AVM2Code code, boolean thisHasDefaultToPrimitive) throws InterruptedException {
|
||||
AVM2LocalData localData = new AVM2LocalData();
|
||||
localData.allSwitchParts = switchParts;
|
||||
@@ -219,14 +278,32 @@ public abstract class InstructionDefinition implements Serializable {
|
||||
lineStartItem.setVal(localData.lineStartInstruction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets number of pops from stack.
|
||||
* @param ins Instruction
|
||||
* @param abc ABC
|
||||
* @return Number of pops from stack
|
||||
*/
|
||||
public int getStackPopCount(AVM2Instruction ins, ABC abc) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets number of pushes to stack.
|
||||
* @param ins Instruction
|
||||
* @param abc ABC
|
||||
* @return Number of pushes to stack
|
||||
*/
|
||||
public int getStackPushCount(AVM2Instruction ins, ABC abc) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves multiname.
|
||||
* @param localData Local data area
|
||||
* @param constants Constant pool
|
||||
* @param multinameIndex Multiname index
|
||||
*/
|
||||
protected void resolveMultiname(LocalDataArea localData, AVM2ConstantPool constants, int multinameIndex) {
|
||||
if (multinameIndex > 0 && multinameIndex < constants.getMultinameCount()) {
|
||||
Multiname multiname = constants.getMultiname(multinameIndex);
|
||||
@@ -239,6 +316,16 @@ public abstract class InstructionDefinition implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves multiname.
|
||||
* @param localData Local data area
|
||||
* @param property Property
|
||||
* @param stack Translate stack
|
||||
* @param constants Constant pool
|
||||
* @param multinameIndex Multiname index
|
||||
* @param ins Instruction
|
||||
* @return Resolved multiname
|
||||
*/
|
||||
protected FullMultinameAVM2Item resolveMultiname(AVM2LocalData localData, boolean property, TranslateStack stack, AVM2ConstantPool constants, int multinameIndex, AVM2Instruction ins) {
|
||||
GraphTargetItem ns = null;
|
||||
GraphTargetItem name = null;
|
||||
@@ -255,6 +342,12 @@ public abstract class InstructionDefinition implements Serializable {
|
||||
return new FullMultinameAVM2Item(property, ins, localData.lineStartInstruction, multinameIndex, localData.abc.constants.getMultiname(multinameIndex).getName(localData.getConstants(), new ArrayList<>(), true, true), name, ns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets required stack size for multiname.
|
||||
* @param constants Constant pool
|
||||
* @param multinameIndex Multiname index
|
||||
* @return Required stack size
|
||||
*/
|
||||
protected int getMultinameRequiredStackSize(AVM2ConstantPool constants, int multinameIndex) {
|
||||
int res = 0;
|
||||
if (multinameIndex > 0 && multinameIndex < constants.getMultinameCount()) {
|
||||
@@ -274,78 +367,40 @@ public abstract class InstructionDefinition implements Serializable {
|
||||
return res;
|
||||
}
|
||||
|
||||
protected int resolvedCount(AVM2ConstantPool constants, int multinameIndex) {
|
||||
int pos = 0;
|
||||
if (constants.getMultiname(multinameIndex).needsNs()) {
|
||||
pos++;
|
||||
}
|
||||
if (constants.getMultiname(multinameIndex).needsName()) {
|
||||
pos++;
|
||||
}
|
||||
return pos;
|
||||
|
||||
}
|
||||
|
||||
protected String resolveMultinameNoPop(int pos, Stack<AVM2Item> stack, AVM2ConstantPool constants, int multinameIndex, AVM2Instruction ins, List<DottedChain> fullyQualifiedNames) {
|
||||
String ns = "";
|
||||
String name;
|
||||
if (constants.getMultiname(multinameIndex).needsNs()) {
|
||||
ns = "[" + stack.get(pos) + "]";
|
||||
pos++;
|
||||
}
|
||||
if (constants.getMultiname(multinameIndex).needsName()) {
|
||||
name = stack.get(pos).toString();
|
||||
} else {
|
||||
name = GraphTextWriter.hilighOffset(constants.getMultiname(multinameIndex).getName(constants, fullyQualifiedNames, false, true), ins.getAddress());
|
||||
}
|
||||
return name + ns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets stack delta. Stack push count - stack pop count.
|
||||
* @param ins Instruction
|
||||
* @param abc ABC
|
||||
* @return Stack delta
|
||||
*/
|
||||
public int getStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return getStackPushCount(ins, abc) - getStackPopCount(ins, abc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets scope stack delta. Scope stack push count - scope stack pop count.
|
||||
* @param ins Instruction
|
||||
* @param abc ABC
|
||||
* @return Scope stack delta
|
||||
*/
|
||||
public int getScopeStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected boolean isRegisterCompileTime(int regId, int ip, HashMap<Integer, List<Integer>> refs, AVM2Code code) {
|
||||
Set<Integer> previous = new HashSet<>();
|
||||
AVM2Code.getPreviousReachableIps(ip, refs, previous, new HashSet<>());
|
||||
for (int p : previous) {
|
||||
if (p < 0) {
|
||||
continue;
|
||||
}
|
||||
if (p >= code.code.size()) {
|
||||
continue;
|
||||
}
|
||||
AVM2Instruction sins = code.code.get(p);
|
||||
if (code.code.get(p).definition instanceof SetLocalTypeIns) {
|
||||
SetLocalTypeIns sl = (SetLocalTypeIns) sins.definition;
|
||||
if (sl.getRegisterId(sins) == regId) {
|
||||
if (!AVM2Code.isDirectAncestor(ip, p, refs)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((code.code.get(p).definition instanceof IncLocalIns)
|
||||
|| (code.code.get(p).definition instanceof IncLocalIIns)
|
||||
|| (code.code.get(p).definition instanceof DecLocalIns)
|
||||
|| (code.code.get(p).definition instanceof DecLocalIIns)) {
|
||||
if (sins.operands[0] == regId) {
|
||||
if (!AVM2Code.isDirectAncestor(ip, p, refs)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if instruction is exit instruction. (e.g. return, throw)
|
||||
* @return True if instruction is exit instruction
|
||||
*/
|
||||
public boolean isExitInstruction() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets item IP.
|
||||
* @param localData Local data
|
||||
* @param item Item
|
||||
* @return Item IP or -1 if not found
|
||||
*/
|
||||
public static int getItemIp(AVM2LocalData localData, GraphTargetItem item) {
|
||||
GraphSourceItem src = item.getSrc();
|
||||
if (src == null) {
|
||||
@@ -354,10 +409,27 @@ public abstract class InstructionDefinition implements Serializable {
|
||||
return localData.code.adr2pos(src.getAddress());
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for slot name.
|
||||
* @param slotIndex Slot index
|
||||
* @param localData Local data
|
||||
* @param obj Object
|
||||
* @param realObj Real object
|
||||
* @return Slot multiname or null if not found
|
||||
*/
|
||||
protected static Multiname searchSlotName(int slotIndex, AVM2LocalData localData, GraphTargetItem obj, Reference<GraphTargetItem> realObj) {
|
||||
return searchSlotName(slotIndex, localData, obj, -1, realObj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for slot name.
|
||||
* @param slotIndex Slot index
|
||||
* @param localData Local data
|
||||
* @param obj Object
|
||||
* @param multiNameIndex Multiname index
|
||||
* @param realObj Real object
|
||||
* @return Slot multiname or null if not found
|
||||
*/
|
||||
private static Multiname searchSlotName(int slotIndex, AVM2LocalData localData, GraphTargetItem obj, int multiNameIndex, Reference<GraphTargetItem> realObj) {
|
||||
if ((obj instanceof ExceptionAVM2Item) && (multiNameIndex == -1 || ((ExceptionAVM2Item) obj).exception.name_index == multiNameIndex)) {
|
||||
return localData.getConstants().getMultiname(((ExceptionAVM2Item) obj).exception.name_index);
|
||||
@@ -402,6 +474,15 @@ public abstract class InstructionDefinition implements Serializable {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles set property.
|
||||
* @param init Init
|
||||
* @param localData Local data
|
||||
* @param stack Translate stack
|
||||
* @param ins Instruction
|
||||
* @param output Output
|
||||
* @param path Path
|
||||
*/
|
||||
public void handleSetProperty(boolean init, AVM2LocalData localData, TranslateStack stack, AVM2Instruction ins, List<GraphTargetItem> output, String path) {
|
||||
int multinameIndex = ins.operands[0];
|
||||
GraphTargetItem value = stack.pop();
|
||||
@@ -649,6 +730,18 @@ public abstract class InstructionDefinition implements Serializable {
|
||||
SetTypeIns.handleResult(value, stack, output, localData, (GraphTargetItem) result, -1, type.getVal());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if increment or decrement.
|
||||
* @param standalone Standalone
|
||||
* @param multinameIndex Multiname index
|
||||
* @param ins Instruction
|
||||
* @param localData Local data
|
||||
* @param item Item
|
||||
* @param valueLocalReg Value local register
|
||||
* @param nameLocalReg Name local register
|
||||
* @param objLocalReg Object local register
|
||||
* @return Increment or decrement item or null if not found
|
||||
*/
|
||||
private GraphTargetItem checkIncDec(boolean standalone, int multinameIndex, AVM2Instruction ins, AVM2LocalData localData, GraphTargetItem item,
|
||||
LocalRegAVM2Item valueLocalReg, LocalRegAVM2Item nameLocalReg, LocalRegAVM2Item objLocalReg) {
|
||||
if (item instanceof SetLocalAVM2Item) {
|
||||
|
||||
+19
-6
@@ -17,23 +17,26 @@
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.AVM2LocalData;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.AVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.CoerceAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.ConvertAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.LocalRegAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.SetLocalAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.*;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.TranslateStack;
|
||||
import com.jpexs.decompiler.graph.TypeItem;
|
||||
import com.jpexs.decompiler.graph.model.DuplicateItem;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* SetType instruction interface.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public interface SetTypeIns {
|
||||
|
||||
/**
|
||||
* Handles number to int conversion.
|
||||
* @param value Value to convert
|
||||
* @param type Type to convert to
|
||||
* @return Value
|
||||
*/
|
||||
public static GraphTargetItem handleNumberToInt(GraphTargetItem value, GraphTargetItem type) {
|
||||
if ((value instanceof ConvertAVM2Item) || (value instanceof CoerceAVM2Item)) {
|
||||
if (type != null && (type.equals(TypeItem.INT) || type.equals(TypeItem.UINT))) {
|
||||
@@ -45,6 +48,16 @@ public interface SetTypeIns {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles result.
|
||||
* @param value Value
|
||||
* @param stack Stack
|
||||
* @param output Output
|
||||
* @param localData Local data
|
||||
* @param result Result
|
||||
* @param regId Register ID
|
||||
* @param type Type
|
||||
*/
|
||||
public static void handleResult(GraphTargetItem value, TranslateStack stack, List<GraphTargetItem> output, AVM2LocalData localData, GraphTargetItem result, int regId, GraphTargetItem type) {
|
||||
GraphTargetItem notCoercedValue = value;
|
||||
if ((value instanceof CoerceAVM2Item) || (value instanceof ConvertAVM2Item)) {
|
||||
|
||||
+20
-1
@@ -22,20 +22,39 @@ import com.jpexs.decompiler.flash.abc.avm2.exceptions.AVM2ExecutionException;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.exceptions.AVM2VerifyErrorException;
|
||||
|
||||
/**
|
||||
*
|
||||
* Unknown instruction definition.
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class UnknownInstruction extends InstructionDefinition {
|
||||
|
||||
/**
|
||||
* Constructs a new UnknownInstruction object.
|
||||
* @param instructionCode Instruction code
|
||||
*/
|
||||
public UnknownInstruction(int instructionCode) {
|
||||
super(instructionCode, "instruction_" + Integer.toString(instructionCode), new int[0], false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify instruction
|
||||
* @param lda Local data area
|
||||
* @param constants Constant pool
|
||||
* @param ins Instruction
|
||||
* @throws AVM2VerifyErrorException
|
||||
*/
|
||||
@Override
|
||||
public void verify(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instruction ins) throws AVM2VerifyErrorException {
|
||||
illegalOpCode(lda, ins);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes instruction.
|
||||
* @param lda Local data area
|
||||
* @param constants Constant pool
|
||||
* @param ins Instruction
|
||||
* @return True if instruction was executed, false if not
|
||||
* @throws AVM2ExecutionException
|
||||
*/
|
||||
@Override
|
||||
public boolean execute(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instruction ins) throws AVM2ExecutionException {
|
||||
return false;
|
||||
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Alchemy (domain memory) AVM2 instructions
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy;
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Arithmetic AVM2 instructions.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic;
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Bitwise AVM2 instructions.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise;
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Comparison AVM2 instructions.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions.comparison;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user