mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-06-11 11:33:34 +00:00
trunk contents moved to root
This commit is contained in:
111
src/com/jpexs/browsers/cache/CacheEntry.java
vendored
Normal file
111
src/com/jpexs/browsers/cache/CacheEntry.java
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.browsers.cache;
|
||||
|
||||
import com.jpexs.helpers.LimitedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Map;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.InflaterInputStream;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public abstract class CacheEntry {
|
||||
|
||||
public abstract String getRequestURL();
|
||||
|
||||
public abstract Map<String, String> getResponseHeaders();
|
||||
|
||||
public abstract String getStatusLine();
|
||||
|
||||
public abstract String getRequestMethod();
|
||||
|
||||
public abstract InputStream getResponseRawDataStream();
|
||||
|
||||
public InputStream getResponseDataStream() {
|
||||
String contentLengthStr = getHeader("Content-Length");
|
||||
int contentLength = -1;
|
||||
if (contentLengthStr != null) {
|
||||
try {
|
||||
contentLength = Integer.parseInt(contentLengthStr);
|
||||
} catch (NumberFormatException nex) {
|
||||
}
|
||||
}
|
||||
final InputStream rawIs = getResponseRawDataStream();
|
||||
InputStream is = rawIs;
|
||||
if (contentLength > -1) {
|
||||
is = new LimitedInputStream(is, contentLength);
|
||||
}
|
||||
|
||||
String encoding = getHeader("Content-Encoding");
|
||||
if (encoding != null) {
|
||||
switch (encoding) {
|
||||
case "gzip":
|
||||
try {
|
||||
is = new GZIPInputStream(is);
|
||||
} catch (IOException ex) {
|
||||
is = null;
|
||||
//ignore
|
||||
}
|
||||
break;
|
||||
case "deflate":
|
||||
is = new InflaterInputStream(is);
|
||||
break;
|
||||
default: //unknown
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if ("chunked".equals(getHeader("Transfer-Encoding"))) {
|
||||
is = new ChunkedInputStream(is);
|
||||
}
|
||||
return is;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getRequestURL();
|
||||
}
|
||||
|
||||
public int getStatusCode() {
|
||||
String st = getStatusLine();
|
||||
if (st == null) {
|
||||
return 0;
|
||||
}
|
||||
String parts[] = st.split(" ");
|
||||
try {
|
||||
return Integer.parseInt(parts[1]);
|
||||
} catch (NumberFormatException nfe) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public String getHeader(String header) {
|
||||
Map<String, String> m = getResponseHeaders();
|
||||
if (m == null) {
|
||||
return null;
|
||||
}
|
||||
for (String k : m.keySet()) {
|
||||
if (k.toLowerCase().equals(header.toLowerCase())) {
|
||||
return m.get(k);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
30
src/com/jpexs/browsers/cache/CacheImplementation.java
vendored
Normal file
30
src/com/jpexs/browsers/cache/CacheImplementation.java
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.browsers.cache;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public interface CacheImplementation {
|
||||
|
||||
public List<CacheEntry> getEntries();
|
||||
|
||||
public void refresh();
|
||||
}
|
||||
45
src/com/jpexs/browsers/cache/CacheReader.java
vendored
Normal file
45
src/com/jpexs/browsers/cache/CacheReader.java
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.browsers.cache;
|
||||
|
||||
import com.jpexs.browsers.cache.chrome.ChromeCache;
|
||||
import com.jpexs.browsers.cache.firefox.FirefoxCache;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class CacheReader {
|
||||
|
||||
public static final String BROWSER_FIREFOX = "firefox";
|
||||
public static final String BROWSER_CHROME = "chrome";
|
||||
|
||||
public static String[] availableBrowsers() {
|
||||
return new String[]{BROWSER_FIREFOX, BROWSER_CHROME};
|
||||
}
|
||||
|
||||
public static CacheImplementation getBrowserCache(String browser) {
|
||||
switch (browser) {
|
||||
case BROWSER_CHROME:
|
||||
return ChromeCache.getInstance();
|
||||
case BROWSER_FIREFOX:
|
||||
return FirefoxCache.getInstance();
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid browser:" + browser);
|
||||
}
|
||||
}
|
||||
}
|
||||
96
src/com/jpexs/browsers/cache/ChunkedInputStream.java
vendored
Normal file
96
src/com/jpexs/browsers/cache/ChunkedInputStream.java
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.browsers.cache;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ChunkedInputStream extends InputStream {
|
||||
|
||||
private final InputStream is;
|
||||
private int chunkPos = 0;
|
||||
private int chunkLen = 0;
|
||||
private boolean end = false;
|
||||
private boolean first = true;
|
||||
|
||||
public ChunkedInputStream(InputStream is) {
|
||||
this.is = is;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
if (end) {
|
||||
return -1;
|
||||
}
|
||||
if (chunkPos >= chunkLen) {
|
||||
if (!first) {
|
||||
if (is.read() != '\r') {
|
||||
throw new IOException("Invalid chunk");
|
||||
}
|
||||
if (is.read() != '\n') {
|
||||
throw new IOException("Invalid chunk");
|
||||
}
|
||||
}
|
||||
String lenStr = readLine();
|
||||
try {
|
||||
chunkLen = Integer.parseInt(lenStr);
|
||||
} catch (NumberFormatException nfe) {
|
||||
throw new IOException("Invalid chunk");
|
||||
}
|
||||
if (chunkLen == 0) {
|
||||
is.read(); // \r
|
||||
is.read(); // \n
|
||||
end = true;
|
||||
return -1;
|
||||
}
|
||||
chunkPos = 0;
|
||||
first = false;
|
||||
}
|
||||
|
||||
chunkPos++;
|
||||
return is.read();
|
||||
}
|
||||
|
||||
private String readLine() throws IOException {
|
||||
int i;
|
||||
boolean inr = false;
|
||||
String ret = "";
|
||||
while ((i = is.read()) > -1) {
|
||||
if (inr) {
|
||||
inr = false;
|
||||
if (i == '\n') {
|
||||
break;
|
||||
} else {
|
||||
ret += "\r";
|
||||
}
|
||||
}
|
||||
if (i == '\r') {
|
||||
inr = true;
|
||||
continue;
|
||||
}
|
||||
ret += (char) i;
|
||||
}
|
||||
if (inr) {
|
||||
ret += "\r";
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
48
src/com/jpexs/browsers/cache/RafInputStream.java
vendored
Normal file
48
src/com/jpexs/browsers/cache/RafInputStream.java
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.browsers.cache;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class RafInputStream extends InputStream {
|
||||
|
||||
private final RandomAccessFile raf;
|
||||
private long pos = 0;
|
||||
|
||||
public RafInputStream(RandomAccessFile raf) {
|
||||
this.raf = raf;
|
||||
try {
|
||||
pos = raf.getFilePointer();
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(RafInputStream.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
raf.seek(pos++);
|
||||
return raf.read();
|
||||
}
|
||||
}
|
||||
69
src/com/jpexs/browsers/cache/chrome/BlockFileHeader.java
vendored
Normal file
69
src/com/jpexs/browsers/cache/chrome/BlockFileHeader.java
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.browsers.cache.chrome;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class BlockFileHeader {
|
||||
|
||||
static final int kBlockHeaderSize = 8192; // Two pages: almost 64k entries
|
||||
static final int kMaxBlocks = (kBlockHeaderSize - 80) * 8;
|
||||
long magic; // c3 ca 04 c1
|
||||
long version; // 00 00 02 00
|
||||
int this_file;
|
||||
int next_file;
|
||||
int entry_size;
|
||||
int num_entries;
|
||||
int max_entries;
|
||||
int empty[] = new int[4];
|
||||
int hints[] = new int[4];
|
||||
int updating;
|
||||
int user[] = new int[5];
|
||||
long allocation_map[] = new long[kMaxBlocks / 32];
|
||||
|
||||
public BlockFileHeader(InputStream is) throws IOException {
|
||||
IndexInputStream iis = new IndexInputStream(is);
|
||||
magic = iis.readUInt32();
|
||||
version = iis.readUInt32();
|
||||
this_file = iis.readInt16();
|
||||
next_file = iis.readInt16();
|
||||
entry_size = iis.readInt32();
|
||||
num_entries = iis.readInt32();
|
||||
max_entries = iis.readInt32();
|
||||
empty = new int[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
empty[i] = iis.readInt32();
|
||||
}
|
||||
hints = new int[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
hints[i] = iis.readInt32();
|
||||
}
|
||||
updating = iis.readInt32();
|
||||
user = new int[5];
|
||||
for (int i = 0; i < 5; i++) {
|
||||
user[i] = iis.readInt32();
|
||||
}
|
||||
for (int i = 0; i < allocation_map.length; i++) {
|
||||
allocation_map[i] = iis.readUInt32();
|
||||
}
|
||||
}
|
||||
}
|
||||
122
src/com/jpexs/browsers/cache/chrome/CacheAddr.java
vendored
Normal file
122
src/com/jpexs/browsers/cache/chrome/CacheAddr.java
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.browsers.cache.chrome;
|
||||
|
||||
import com.jpexs.browsers.cache.RafInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class CacheAddr {
|
||||
|
||||
public static final int EXTERNAL = 0;
|
||||
public static final int RANKINGS = 1;
|
||||
public static final int BLOCK_256 = 2;
|
||||
public static final int BLOCK_1K = 3;
|
||||
public static final int BLOCK_4K = 4;
|
||||
public static final int BLOCK_FILES = 5;
|
||||
public static final int BLOCK_ENTRIES = 6;
|
||||
public static final int BLOCK_EVICTED = 7;
|
||||
public static final String blockNames[] = new String[]{"EXTERNAL", "RANKINGS", "BLOCK_256", "BLOCK_1K", "BLOCK_4K", "BLOCK_FILES", "BLOCK_ENTRIES", "BLOCK_EVICTED"};
|
||||
public static final int blockSizes[] = new int[]{0, 36, 256, 1024, 4096, 8, 104, 48};
|
||||
public static final long kInitializedMask = 0x80000000L;
|
||||
public static final long kFileTypeMask = 0x70000000L;
|
||||
public static final int kFileTypeOffset = 28;
|
||||
public static final long kReservedBitsMask = 0x0c000000L;
|
||||
public static final long kNumBlocksMask = 0x03000000L;
|
||||
public static final int kNumBlocksOffset = 24;
|
||||
public static final long kFileSelectorMask = 0x00ff0000L;
|
||||
public static final int FileSelectorOffset = 16;
|
||||
public static final long kStartBlockMask = 0x0000FFFFL;
|
||||
public static final long kFileNameMask = 0x0FFFFFFFL;
|
||||
public boolean initialized;
|
||||
public int fileType;
|
||||
public int numBlocks;
|
||||
public int fileSelector;
|
||||
public int startBlock;
|
||||
public int fileName;
|
||||
public long val;
|
||||
public File rootPath;
|
||||
private final Map<Integer, RandomAccessFile> dataFiles;
|
||||
private final File externalFilesDir;
|
||||
|
||||
public CacheAddr(InputStream is, File rootPath, Map<Integer, RandomAccessFile> dataFiles, File externalFilesDir) throws IOException {
|
||||
this.dataFiles = dataFiles;
|
||||
this.rootPath = rootPath;
|
||||
this.externalFilesDir = externalFilesDir;
|
||||
IndexInputStream iis = new IndexInputStream(is);
|
||||
val = iis.readUInt32();
|
||||
initialized = (val & kInitializedMask) == kInitializedMask;
|
||||
fileType = (int) ((val & kFileTypeMask) >> kFileTypeOffset);
|
||||
if (fileType == EXTERNAL) {
|
||||
fileName = (int) (val & kFileNameMask);
|
||||
} else {
|
||||
numBlocks = (int) ((val & kNumBlocksMask) >> kNumBlocksOffset);
|
||||
fileSelector = (int) ((val & kFileSelectorMask) >> FileSelectorOffset);
|
||||
startBlock = (int) (val & kStartBlockMask);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
String ft = blockNames[fileType];
|
||||
if (fileType == EXTERNAL) {
|
||||
return ft + ":" + fileName;
|
||||
}
|
||||
if (!initialized) {
|
||||
return "uninitialized";
|
||||
}
|
||||
return ft + ": numBlocks " + numBlocks + " fileSelector " + fileSelector + " startBlock " + startBlock;
|
||||
}
|
||||
|
||||
public InputStream getInputStream() throws IOException {
|
||||
if (!initialized) {
|
||||
return null;
|
||||
}
|
||||
switch (fileType) {
|
||||
case EXTERNAL:
|
||||
String fileNameStr = Long.toHexString(fileName);
|
||||
while (fileNameStr.length() < 6) {
|
||||
fileNameStr = "0" + fileNameStr;
|
||||
}
|
||||
fileNameStr = "f_" + fileNameStr;
|
||||
return new RafInputStream(new RandomAccessFile(new File(externalFilesDir, fileNameStr), "r"));
|
||||
case BLOCK_1K:
|
||||
case BLOCK_256:
|
||||
case BLOCK_4K:
|
||||
|
||||
RandomAccessFile raf;
|
||||
|
||||
if (dataFiles.containsKey(fileSelector)) {
|
||||
raf = dataFiles.get(fileSelector);
|
||||
} else {
|
||||
raf = new RandomAccessFile(rootPath + "\\data_" + fileSelector, "r");
|
||||
dataFiles.put(fileSelector, raf);
|
||||
}
|
||||
raf.seek(BlockFileHeader.kBlockHeaderSize + startBlock * blockSizes[fileType]);
|
||||
return new RafInputStream(raf);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
194
src/com/jpexs/browsers/cache/chrome/ChromeCache.java
vendored
Normal file
194
src/com/jpexs/browsers/cache/chrome/ChromeCache.java
vendored
Normal file
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.browsers.cache.chrome;
|
||||
|
||||
import com.jpexs.browsers.cache.CacheEntry;
|
||||
import com.jpexs.browsers.cache.CacheImplementation;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ChromeCache implements CacheImplementation {
|
||||
|
||||
private static ChromeCache instance;
|
||||
private File tempDir;
|
||||
private List<File> dataFiles;
|
||||
private File indexFile;
|
||||
|
||||
private ChromeCache() {
|
||||
Runtime.getRuntime().addShutdownHook(new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
free();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static ChromeCache getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new ChromeCache();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
private boolean loaded = false;
|
||||
private Index index;
|
||||
|
||||
@Override
|
||||
public List<CacheEntry> getEntries() {
|
||||
if (!loaded) {
|
||||
refresh();
|
||||
}
|
||||
if (!loaded) {
|
||||
return null;
|
||||
}
|
||||
List<CacheEntry> ret = new ArrayList<>();
|
||||
try {
|
||||
List<EntryStore> entries = index.getEntries();
|
||||
for (EntryStore en : entries) {
|
||||
if (en.state == EntryStore.ENTRY_NORMAL) {
|
||||
String key = en.getKey();
|
||||
if (key != null && !key.trim().isEmpty()) {
|
||||
ret.add(en);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(ChromeCache.class.getName()).log(Level.SEVERE, null, ex);
|
||||
return null;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
free();
|
||||
File cacheDir = null;
|
||||
try {
|
||||
cacheDir = getCacheDirectory();
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(ChromeCache.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
if (cacheDir == null) {
|
||||
return;
|
||||
}
|
||||
File systemTempDir = new File(System.getProperty("java.io.tmpdir"));
|
||||
File originalIndexFile = new File(cacheDir + File.separator + "index");
|
||||
tempDir = new File(systemTempDir, "cacheView" + System.identityHashCode(this));
|
||||
tempDir.mkdir();
|
||||
indexFile = new File(tempDir, "index");
|
||||
try {
|
||||
Files.copy(originalIndexFile.toPath(), indexFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(ChromeCache.class.getName()).log(Level.SEVERE, null, ex);
|
||||
return;
|
||||
}
|
||||
File originalDataFile;
|
||||
dataFiles = new ArrayList<>();
|
||||
for (int i = 0; (originalDataFile = new File(cacheDir, "data_" + i)).exists(); i++) {
|
||||
File dataFile = new File(tempDir, "data_" + i);
|
||||
dataFiles.add(dataFile);
|
||||
try {
|
||||
Files.copy(originalDataFile.toPath(), dataFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(ChromeCache.class.getName()).log(Level.SEVERE, null, ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
try {
|
||||
index = new Index(indexFile, cacheDir);
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(ChromeCache.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
loaded = true;
|
||||
}
|
||||
|
||||
private enum OSId {
|
||||
|
||||
WINDOWS, OSX, UNIX
|
||||
}
|
||||
|
||||
private static OSId getOSId() {
|
||||
PrivilegedAction<String> doGetOSName = new PrivilegedAction<String>() {
|
||||
@Override
|
||||
public String run() {
|
||||
return System.getProperty("os.name");
|
||||
}
|
||||
};
|
||||
OSId id = OSId.UNIX;
|
||||
String osName = AccessController.doPrivileged(doGetOSName);
|
||||
if (osName != null) {
|
||||
if (osName.toLowerCase().startsWith("mac os x")) {
|
||||
id = OSId.OSX;
|
||||
} else if (osName.contains("Windows")) {
|
||||
id = OSId.WINDOWS;
|
||||
}
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
public static File getCacheDirectory() throws IOException {
|
||||
String userHome = null;
|
||||
File ret = null;
|
||||
try {
|
||||
userHome = System.getProperty("user.home");
|
||||
} catch (SecurityException ignore) {
|
||||
}
|
||||
if (userHome != null) {
|
||||
OSId osId = getOSId();
|
||||
if (osId == OSId.WINDOWS) {
|
||||
ret = new File(userHome + "\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Cache\\");
|
||||
if (!ret.exists()) {
|
||||
ret = new File(userHome + "\\Local Settings\\Application Data\\Google\\Chrome\\User Data\\Default\\Cache");
|
||||
}
|
||||
} else if (osId == OSId.OSX) {
|
||||
ret = new File(userHome + "/Library/Caches/Google/Chrome/Default/Cache");
|
||||
} else {
|
||||
ret = new File(userHome + "/.config/google-chrome/Default/Application Cache/Cache/");
|
||||
if (!ret.exists()) {
|
||||
ret = new File(userHome + "/.cache/chromium/Default/Cache");
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((ret != null) && !ret.exists()) {
|
||||
return null;
|
||||
}
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
private void free() {
|
||||
if (loaded) {
|
||||
index.free();
|
||||
indexFile.delete();
|
||||
for (File d : dataFiles) {
|
||||
d.delete();
|
||||
}
|
||||
tempDir.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
27
src/com/jpexs/browsers/cache/chrome/EntryFlags.java
vendored
Normal file
27
src/com/jpexs/browsers/cache/chrome/EntryFlags.java
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.browsers.cache.chrome;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class EntryFlags {
|
||||
|
||||
public static final int PARENT_ENTRY = 1;
|
||||
public static final int CHILD_ENTRY = 1 << 1;
|
||||
}
|
||||
28
src/com/jpexs/browsers/cache/chrome/EntryState.java
vendored
Normal file
28
src/com/jpexs/browsers/cache/chrome/EntryState.java
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.browsers.cache.chrome;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class EntryState {
|
||||
|
||||
public static final int ENTRY_NORMAL = 0;
|
||||
public static final int ENTRY_EVICTED = 1;
|
||||
public static final int ENTRY_DOOMED = 2;
|
||||
}
|
||||
153
src/com/jpexs/browsers/cache/chrome/EntryStore.java
vendored
Normal file
153
src/com/jpexs/browsers/cache/chrome/EntryStore.java
vendored
Normal file
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.browsers.cache.chrome;
|
||||
|
||||
import com.jpexs.browsers.cache.CacheEntry;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class EntryStore extends CacheEntry {
|
||||
|
||||
public static final int ENTRY_NORMAL = 0;
|
||||
public static final int ENTRY_EVICTED = 1; // The entry was recently evicted from the cache.
|
||||
public static final int ENTRY_DOOMED = 2; // The entry was doomed
|
||||
public static final int PARENT_ENTRY = 1; // This entry has children (sparse) entries.
|
||||
public static final int CHILD_ENTRY = 1 << 1;
|
||||
public long hash; // Full hash of the key.
|
||||
public CacheAddr next; // Next entry with the same hash or bucket.
|
||||
public CacheAddr rankings_node; // Rankings node for this entry.
|
||||
public int reuse_count; // How often is this entry used.
|
||||
public int refetch_count; // How often is this fetched from the net.
|
||||
public int state; // Current state.
|
||||
public long creation_time;
|
||||
public int key_len;
|
||||
public CacheAddr long_key; // Optional address of a long key.
|
||||
public int data_size[] = new int[4]; // We can store up to 4 data streams for each
|
||||
public CacheAddr data_addr[] = new CacheAddr[4]; // entry.
|
||||
public long flags; // Any combination of EntryFlags.
|
||||
public int pad[] = new int[4];
|
||||
public long self_hash; // The hash of EntryStore up to this point.
|
||||
public byte key[] = new byte[256 - 24 * 4]; // null terminated
|
||||
|
||||
public EntryStore(InputStream is, File rootDir, Map<Integer, RandomAccessFile> dataFiles, File externalFilesDir) throws IOException {
|
||||
IndexInputStream iis = new IndexInputStream(is);
|
||||
hash = iis.readUInt32();
|
||||
next = new CacheAddr(is, rootDir, dataFiles, externalFilesDir);
|
||||
rankings_node = new CacheAddr(is, rootDir, dataFiles, externalFilesDir);
|
||||
reuse_count = iis.readInt32();
|
||||
refetch_count = iis.readInt32();
|
||||
state = iis.readInt32();
|
||||
creation_time = iis.readUInt64();
|
||||
key_len = iis.readInt32();
|
||||
long_key = new CacheAddr(is, rootDir, dataFiles, externalFilesDir);
|
||||
data_size = new int[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
data_size[i] = iis.readInt32();
|
||||
}
|
||||
data_addr = new CacheAddr[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
data_addr[i] = new CacheAddr(is, rootDir, dataFiles, externalFilesDir);
|
||||
}
|
||||
flags = iis.readUInt32();
|
||||
pad = new int[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
pad[i] = iis.readInt32();
|
||||
}
|
||||
self_hash = iis.readUInt32();
|
||||
key = new byte[256 - 24 * 4];
|
||||
iis.read(key);
|
||||
}
|
||||
|
||||
public HttpResponseInfo getResponseInfo() {
|
||||
try {
|
||||
InputStream is = data_addr[0].getInputStream();
|
||||
if (is == null) {
|
||||
return null;
|
||||
}
|
||||
return new HttpResponseInfo(is);
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(EntryStore.class.getName()).log(Level.SEVERE, null, ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public int getResponseDataSize() {
|
||||
return data_size[1];
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getResponseRawDataStream() {
|
||||
try {
|
||||
return data_addr[1].getInputStream();
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(EntryStore.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
if (key_len < 0) {
|
||||
return null;
|
||||
}
|
||||
return new String(key, 0, key_len > key.length || key_len < 0 ? key.length : key_len);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRequestURL() {
|
||||
return getKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getResponseHeaders() {
|
||||
HttpResponseInfo ri = getResponseInfo();
|
||||
if (ri == null) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
List<String> headers = ri.headers;
|
||||
Map<String, String> ret = new HashMap<>();
|
||||
for (int h = 1; h < headers.size(); h++) {
|
||||
String hs = headers.get(h);
|
||||
if (hs.contains(":")) {
|
||||
String hp[] = hs.split(":");
|
||||
ret.put(hp[0].trim(), hp[1].trim());
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStatusLine() {
|
||||
HttpResponseInfo ri = getResponseInfo();
|
||||
return ri.headers.get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRequestMethod() {
|
||||
return "GET";
|
||||
}
|
||||
}
|
||||
107
src/com/jpexs/browsers/cache/chrome/HttpResponseInfo.java
vendored
Normal file
107
src/com/jpexs/browsers/cache/chrome/HttpResponseInfo.java
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.browsers.cache.chrome;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class HttpResponseInfo {
|
||||
|
||||
public long flags;
|
||||
public int version;
|
||||
public long request_time;
|
||||
public long response_time;
|
||||
public long payload_size;
|
||||
public List<String> headers;
|
||||
// The version of the response info used when persisting response info.
|
||||
public static final int RESPONSE_INFO_VERSION = 3;
|
||||
// The minimum version supported for deserializing response info.
|
||||
public static final int RESPONSE_INFO_MINIMUM_VERSION = 1;
|
||||
// We reserve up to 8 bits for the version number.
|
||||
public static final int RESPONSE_INFO_VERSION_MASK = 0xFF;
|
||||
// This bit is set if the response info has a cert at the end.
|
||||
// Version 1 serialized only the end-entity certificate, while subsequent
|
||||
// versions include the available certificate chain.
|
||||
public static final int RESPONSE_INFO_HAS_CERT = 1 << 8;
|
||||
// This bit is set if the response info has a security-bits field (security
|
||||
// strength, in bits, of the SSL connection) at the end.
|
||||
public static final int RESPONSE_INFO_HAS_SECURITY_BITS = 1 << 9;
|
||||
// This bit is set if the response info has a cert status at the end.
|
||||
public static final int RESPONSE_INFO_HAS_CERT_STATUS = 1 << 10;
|
||||
// This bit is set if the response info has vary header data.
|
||||
public static final int RESPONSE_INFO_HAS_VARY_DATA = 1 << 11;
|
||||
// This bit is set if the request was cancelled before completion.
|
||||
public static final int RESPONSE_INFO_TRUNCATED = 1 << 12;
|
||||
// This bit is set if the response was received via SPDY.
|
||||
public static final int RESPONSE_INFO_WAS_SPDY = 1 << 13;
|
||||
// This bit is set if the request has NPN negotiated.
|
||||
public static final int RESPONSE_INFO_WAS_NPN = 1 << 14;
|
||||
// This bit is set if the request was fetched via an explicit proxy.
|
||||
public static final int RESPONSE_INFO_WAS_PROXY = 1 << 15;
|
||||
// This bit is set if the response info has an SSL connection status field.
|
||||
// This contains the ciphersuite used to fetch the resource as well as the
|
||||
// protocol version, compression method and whether SSLv3 fallback was used.
|
||||
public static final int RESPONSE_INFO_HAS_SSL_CONNECTION_STATUS = 1 << 16;
|
||||
// This bit is set if the response info has protocol version.
|
||||
public static final int RESPONSE_INFO_HAS_NPN_NEGOTIATED_PROTOCOL = 1 << 17;
|
||||
// This bit is set if the response info has connection info.
|
||||
public static final int RESPONSE_INFO_HAS_CONNECTION_INFO = 1 << 18;
|
||||
// This bit is set if the request has http authentication.
|
||||
public static final int RESPONSE_INFO_USE_HTTP_AUTHENTICATION = 1 << 19;
|
||||
|
||||
public String getHeaderValue(String header) {
|
||||
for (String h : headers) {
|
||||
if (h.contains(":")) {
|
||||
String keyval[] = h.split(":");
|
||||
String key = keyval[0].trim().toLowerCase();
|
||||
String val = keyval[1].trim();
|
||||
if (header.toLowerCase().equals(key)) {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public HttpResponseInfo(InputStream is) throws IOException {
|
||||
IndexInputStream iis = new IndexInputStream(is);
|
||||
payload_size = iis.readUInt32();
|
||||
flags = iis.readInt();
|
||||
version = (int) (flags & RESPONSE_INFO_VERSION_MASK);
|
||||
if (version < RESPONSE_INFO_MINIMUM_VERSION || version > RESPONSE_INFO_VERSION) {
|
||||
throw new RuntimeException("unexpected response info version: " + version);
|
||||
}
|
||||
request_time = iis.readInt64();
|
||||
response_time = iis.readInt64();
|
||||
String headersStr = iis.readString();
|
||||
headers = new ArrayList<>();
|
||||
int nulpos;
|
||||
while ((nulpos = headersStr.indexOf(0)) > 0) {
|
||||
String h = headersStr.substring(0, nulpos);
|
||||
headersStr = headersStr.substring(nulpos + 1);
|
||||
headers.add(h);
|
||||
}
|
||||
|
||||
//TODO: Read SSL info
|
||||
}
|
||||
}
|
||||
79
src/com/jpexs/browsers/cache/chrome/Index.java
vendored
Normal file
79
src/com/jpexs/browsers/cache/chrome/Index.java
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.browsers.cache.chrome;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class Index {
|
||||
|
||||
IndexHeader header;
|
||||
CacheAddr table[];
|
||||
public static final int kIndexTablesize = 0x10000;
|
||||
public File rootDir;
|
||||
private final Map<Integer, RandomAccessFile> dataFiles;
|
||||
private final File externalFilesDir;
|
||||
|
||||
public void free() {
|
||||
for (RandomAccessFile r : dataFiles.values()) {
|
||||
try {
|
||||
r.close();
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<EntryStore> getEntries() throws IOException {
|
||||
List<EntryStore> ret = new ArrayList<>();
|
||||
for (CacheAddr ca : table) {
|
||||
InputStream is = ca.getInputStream();
|
||||
if (is != null) {
|
||||
EntryStore es = new EntryStore(is, rootDir, dataFiles, externalFilesDir);
|
||||
ret.add(es);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public Index(File file, File externalFilesDir) throws IOException {
|
||||
dataFiles = new HashMap<>();
|
||||
this.externalFilesDir = externalFilesDir;
|
||||
try (FileInputStream is = new FileInputStream(file)) {
|
||||
rootDir = file.getParentFile();
|
||||
header = new IndexHeader(is, rootDir, dataFiles, externalFilesDir);
|
||||
int tsize = kIndexTablesize;
|
||||
if (header.table_len > 0) {
|
||||
tsize = header.table_len;
|
||||
}
|
||||
table = new CacheAddr[tsize];
|
||||
for (int i = 0; i < tsize; i++) {
|
||||
table[i] = new CacheAddr(is, rootDir, dataFiles, externalFilesDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
64
src/com/jpexs/browsers/cache/chrome/IndexHeader.java
vendored
Normal file
64
src/com/jpexs/browsers/cache/chrome/IndexHeader.java
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.browsers.cache.chrome;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class IndexHeader {
|
||||
|
||||
long magic; //c3 ca 03 c1
|
||||
long version; //01 00 02 00
|
||||
int num_entries;
|
||||
int num_bytes;
|
||||
int last_file;
|
||||
int this_id;
|
||||
CacheAddr stats;
|
||||
int table_len;
|
||||
int crash;
|
||||
int experiment;
|
||||
long create_time;
|
||||
int pad[] = new int[52];
|
||||
LruData lru;
|
||||
|
||||
public IndexHeader(InputStream is, File rootDir, Map<Integer, RandomAccessFile> dataFiles, File externalFilesDir) throws IOException {
|
||||
IndexInputStream iis = new IndexInputStream(is);
|
||||
magic = iis.readUInt32();
|
||||
version = iis.readUInt32();
|
||||
num_entries = iis.readInt32();
|
||||
num_bytes = iis.readInt32();
|
||||
last_file = iis.readInt32();
|
||||
this_id = iis.readInt32();
|
||||
stats = new CacheAddr(iis, rootDir, dataFiles, externalFilesDir);
|
||||
table_len = iis.readInt32();
|
||||
crash = iis.readInt32();
|
||||
experiment = iis.readInt32();
|
||||
create_time = iis.readUInt64();
|
||||
pad = new int[52];
|
||||
for (int i = 0; i < 52; i++) {
|
||||
pad[i] = iis.readInt32();
|
||||
}
|
||||
lru = new LruData(is, rootDir, dataFiles, externalFilesDir);
|
||||
}
|
||||
}
|
||||
79
src/com/jpexs/browsers/cache/chrome/IndexInputStream.java
vendored
Normal file
79
src/com/jpexs/browsers/cache/chrome/IndexInputStream.java
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.browsers.cache.chrome;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class IndexInputStream extends InputStream {
|
||||
|
||||
private final InputStream is;
|
||||
public long pos = 0;
|
||||
|
||||
public long getPos() {
|
||||
return pos;
|
||||
}
|
||||
|
||||
public IndexInputStream(InputStream is) {
|
||||
this.is = is;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
int r = is.read();
|
||||
//System.out.print("$"+Integer.toHexString(r));
|
||||
pos++;
|
||||
return r;
|
||||
}
|
||||
|
||||
public long readUInt32() throws IOException {
|
||||
long r = (((long) read()) + ((long) (read() << 8)) + ((long) (read() << 16)) + ((long) (read() << 24))) & 0xffffffffL;
|
||||
//System.out.println("");
|
||||
return r;
|
||||
}
|
||||
|
||||
public long readUInt64() throws IOException {
|
||||
return readUInt32() + (readUInt32() << 32);
|
||||
}
|
||||
|
||||
public long readInt64() throws IOException {
|
||||
return readUInt64(); //FIXME
|
||||
}
|
||||
|
||||
public int readInt32() throws IOException {
|
||||
return (int) readUInt32();
|
||||
}
|
||||
|
||||
public int readInt16() throws IOException {
|
||||
return (short) ((int) read() + (int) (read() << 8));
|
||||
}
|
||||
|
||||
public long readInt() throws IOException {
|
||||
return readInt32();
|
||||
}
|
||||
|
||||
public String readString() throws IOException {
|
||||
int len = (int) readInt();
|
||||
byte data[] = new byte[len];
|
||||
read(data);
|
||||
return new String(data);
|
||||
}
|
||||
}
|
||||
71
src/com/jpexs/browsers/cache/chrome/LruData.java
vendored
Normal file
71
src/com/jpexs/browsers/cache/chrome/LruData.java
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.browsers.cache.chrome;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class LruData {
|
||||
|
||||
int pad1[] = new int[2];
|
||||
int filled;
|
||||
int sizes[] = new int[5];
|
||||
CacheAddr heads[] = new CacheAddr[5];
|
||||
CacheAddr tails[] = new CacheAddr[5];
|
||||
CacheAddr transaction;
|
||||
int operation;
|
||||
int operation_list;
|
||||
int pad2[] = new int[7];
|
||||
|
||||
public LruData(InputStream is, File rootDir, Map<Integer, RandomAccessFile> dataFiles, File externalFilesDir) throws IOException {
|
||||
IndexInputStream iis = new IndexInputStream(is);
|
||||
pad1 = new int[2];
|
||||
pad1[0] = iis.readInt32();
|
||||
pad1[1] = iis.readInt32();
|
||||
filled = iis.readInt32();
|
||||
sizes = new int[5];
|
||||
for (int i = 0; i < 5; i++) {
|
||||
sizes[i] = iis.readInt32();
|
||||
}
|
||||
sizes = new int[5];
|
||||
for (int i = 0; i < 5; i++) {
|
||||
sizes[i] = iis.readInt32();
|
||||
}
|
||||
heads = new CacheAddr[5];
|
||||
for (int i = 0; i < 5; i++) {
|
||||
heads[i] = new CacheAddr(is, rootDir, dataFiles, externalFilesDir);
|
||||
}
|
||||
tails = new CacheAddr[5];
|
||||
for (int i = 0; i < 5; i++) {
|
||||
tails[i] = new CacheAddr(is, rootDir, dataFiles, externalFilesDir);
|
||||
}
|
||||
transaction = new CacheAddr(is, rootDir, dataFiles, externalFilesDir);
|
||||
operation = iis.readInt32();
|
||||
operation_list = iis.readInt32();
|
||||
pad2 = new int[7];
|
||||
for (int i = 0; i < 7; i++) {
|
||||
pad2[i] = iis.readInt32();
|
||||
}
|
||||
}
|
||||
}
|
||||
32
src/com/jpexs/browsers/cache/chrome/RankingsNode.java
vendored
Normal file
32
src/com/jpexs/browsers/cache/chrome/RankingsNode.java
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.browsers.cache.chrome;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class RankingsNode {
|
||||
|
||||
public long last_used;
|
||||
public long last_modified;
|
||||
CacheAddr next;
|
||||
CacheAddr prev;
|
||||
CacheAddr contents;
|
||||
int dirty;
|
||||
long self_hash;
|
||||
}
|
||||
51
src/com/jpexs/browsers/cache/firefox/CacheInputStream.java
vendored
Normal file
51
src/com/jpexs/browsers/cache/firefox/CacheInputStream.java
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.browsers.cache.firefox;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class CacheInputStream extends InputStream {
|
||||
|
||||
private final InputStream is;
|
||||
|
||||
@Override
|
||||
public int available() throws IOException {
|
||||
return is.available();
|
||||
}
|
||||
|
||||
public CacheInputStream(InputStream is) {
|
||||
this.is = is;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
return is.read();
|
||||
}
|
||||
|
||||
public long readInt32() throws IOException {
|
||||
return (read() << 24) + (read() << 16) + (read() << 8) + read();
|
||||
}
|
||||
|
||||
public int readInt16() throws IOException {
|
||||
return (read() << 8) + read();
|
||||
}
|
||||
}
|
||||
72
src/com/jpexs/browsers/cache/firefox/CacheMap.java
vendored
Normal file
72
src/com/jpexs/browsers/cache/firefox/CacheMap.java
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.browsers.cache.firefox;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class CacheMap {
|
||||
|
||||
public long version;
|
||||
public long datasize;
|
||||
public long entryCount;
|
||||
public long dirtyFlag;
|
||||
public long recordCount;
|
||||
public long evictionRank[];
|
||||
public long bucketUsage[];
|
||||
public List<MapBucket> mapBuckets;
|
||||
|
||||
public CacheMap(File file) throws IOException {
|
||||
File cacheDir = file.getParentFile();
|
||||
CacheInputStream cis = new CacheInputStream(new FileInputStream(file));
|
||||
version = cis.readInt32();
|
||||
datasize = cis.readInt32();
|
||||
entryCount = cis.readInt32();
|
||||
dirtyFlag = cis.readInt32();
|
||||
recordCount = cis.readInt32();
|
||||
evictionRank = new long[32];
|
||||
for (int i = 0; i < evictionRank.length; i++) {
|
||||
evictionRank[i] = cis.readInt32();
|
||||
}
|
||||
bucketUsage = new long[32];
|
||||
for (int i = 0; i < bucketUsage.length; i++) {
|
||||
bucketUsage[i] = cis.readInt32();
|
||||
}
|
||||
mapBuckets = new ArrayList<>();
|
||||
Map<Integer, RandomAccessFile> cacheFiles = new HashMap<>();
|
||||
for (int i = 1; i <= 3; i++) {
|
||||
cacheFiles.put(i, new RandomAccessFile(new File(cacheDir, "_CACHE_00" + i + "_"), "r"));
|
||||
}
|
||||
while (cis.available() > 0) {
|
||||
MapBucket mb = new MapBucket(cis, cacheDir, cacheFiles);
|
||||
if (mb.hash == 0) {
|
||||
continue;
|
||||
}
|
||||
mapBuckets.add(mb);
|
||||
}
|
||||
}
|
||||
}
|
||||
161
src/com/jpexs/browsers/cache/firefox/FirefoxCache.java
vendored
Normal file
161
src/com/jpexs/browsers/cache/firefox/FirefoxCache.java
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.browsers.cache.firefox;
|
||||
|
||||
import com.jpexs.browsers.cache.CacheEntry;
|
||||
import com.jpexs.browsers.cache.CacheImplementation;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class FirefoxCache implements CacheImplementation {
|
||||
|
||||
private static FirefoxCache instance;
|
||||
|
||||
private FirefoxCache() {
|
||||
}
|
||||
|
||||
public static FirefoxCache getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new FirefoxCache();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
private boolean loaded = false;
|
||||
private CacheMap map;
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
File dir = getCacheDirectory();
|
||||
if (dir == null) {
|
||||
return;
|
||||
}
|
||||
File cacheMapFile = new File(dir, "_CACHE_MAP_");
|
||||
try {
|
||||
map = new CacheMap(cacheMapFile);
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(FirefoxCache.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
loaded = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CacheEntry> getEntries() {
|
||||
if (!loaded) {
|
||||
refresh();
|
||||
}
|
||||
if (map == null) {
|
||||
return null;
|
||||
}
|
||||
List<CacheEntry> ret = new ArrayList<>();
|
||||
|
||||
ret.addAll(map.mapBuckets);
|
||||
return ret;
|
||||
}
|
||||
|
||||
private enum OSId {
|
||||
|
||||
WINDOWS, OSX, UNIX
|
||||
}
|
||||
|
||||
private static OSId getOSId() {
|
||||
PrivilegedAction<String> doGetOSName = new PrivilegedAction<String>() {
|
||||
@Override
|
||||
public String run() {
|
||||
return System.getProperty("os.name");
|
||||
}
|
||||
};
|
||||
OSId id = OSId.UNIX;
|
||||
String osName = AccessController.doPrivileged(doGetOSName);
|
||||
if (osName != null) {
|
||||
if (osName.toLowerCase().startsWith("mac os x")) {
|
||||
id = OSId.OSX;
|
||||
} else if (osName.contains("Windows")) {
|
||||
id = OSId.WINDOWS;
|
||||
}
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
public static File getProfileDirectory() {
|
||||
File profilesDir = getProfilesDirectory();
|
||||
if (profilesDir == null) {
|
||||
return null;
|
||||
}
|
||||
File profiles[] = profilesDir.listFiles();
|
||||
File profileDir = null;
|
||||
for (File f : profiles) {
|
||||
if (f.isDirectory()) {
|
||||
if (f.getName().matches("[a-z0-9]+\\.default")) {
|
||||
profileDir = f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return profileDir;
|
||||
}
|
||||
|
||||
public static File getCacheDirectory() {
|
||||
File profileDir = getProfileDirectory();
|
||||
File cacheDir = null;
|
||||
if (profileDir != null) {
|
||||
cacheDir = new File(profileDir, "Cache");
|
||||
}
|
||||
if (cacheDir == null) {
|
||||
return null;
|
||||
}
|
||||
if (!cacheDir.exists()) {
|
||||
return null;
|
||||
}
|
||||
return cacheDir;
|
||||
}
|
||||
|
||||
public static File getProfilesDirectory() {
|
||||
String userHome = null;
|
||||
File profilesDir = null;
|
||||
try {
|
||||
userHome = System.getProperty("user.home");
|
||||
} catch (SecurityException ignore) {
|
||||
}
|
||||
if (userHome != null) {
|
||||
OSId osId = getOSId();
|
||||
if (osId == OSId.WINDOWS) {
|
||||
profilesDir = new File(userHome + "\\AppData\\Local\\Mozilla\\Firefox\\Profiles");
|
||||
if (!profilesDir.exists()) {
|
||||
profilesDir = new File(userHome + "\\Local Settings\\Application Data\\Mozilla\\Firefox\\Profiles");
|
||||
}
|
||||
} else if (osId == OSId.OSX) {
|
||||
profilesDir = new File(userHome + "/Library/Caches/Firefox/Profiles");
|
||||
} else {
|
||||
profilesDir = new File(userHome + "/.mozilla/firefox");
|
||||
}
|
||||
}
|
||||
if ((profilesDir == null) || !profilesDir.exists()) {
|
||||
return null;
|
||||
}
|
||||
return profilesDir;
|
||||
}
|
||||
}
|
||||
28
src/com/jpexs/browsers/cache/firefox/IncompatibleVersionException.java
vendored
Normal file
28
src/com/jpexs/browsers/cache/firefox/IncompatibleVersionException.java
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 etrik
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.browsers.cache.firefox;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author petrik
|
||||
*/
|
||||
public class IncompatibleVersionException extends Exception {
|
||||
|
||||
public IncompatibleVersionException(int version) {
|
||||
super("Incompatible version: " + version);
|
||||
}
|
||||
}
|
||||
116
src/com/jpexs/browsers/cache/firefox/Location.java
vendored
Normal file
116
src/com/jpexs/browsers/cache/firefox/Location.java
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.browsers.cache.firefox;
|
||||
|
||||
import com.jpexs.browsers.cache.RafInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class Location {
|
||||
|
||||
public int locationSelector;
|
||||
public int extraBlocks;
|
||||
public long blockNumber;
|
||||
public int fileGeneration;
|
||||
public int fileSize;
|
||||
public boolean isMetadata;
|
||||
public long hash;
|
||||
private final File rootDir;
|
||||
public static final long eReservedMask = 0x4C000000L;
|
||||
public static final long eLocationSelectorMask = 0x30000000L;
|
||||
public static final int eLocationSelectorOffset = 28;
|
||||
public static final long eExtraBlocksMask = 0x03000000L;
|
||||
public static final int eExtraBlocksOffset = 24;
|
||||
public static final long eBlockNumberMask = 0x00FFFFFFL;
|
||||
public static final long eFileGenerationMask = 0x000000FFL;
|
||||
public static final long eFileSizeMask = 0x00FFFF00L;
|
||||
public static final int eFileSizeOffset = 8;
|
||||
public static final long eFileReservedMask = 0x4F000000L;
|
||||
|
||||
public static int size_shift(int idx) {
|
||||
return (2 * ((idx) - 1));
|
||||
}
|
||||
|
||||
public static int bitmapSizeForIndex(int idx) {
|
||||
return ((idx > 0) ? (131072 >> size_shift(idx)) : 0);
|
||||
}
|
||||
|
||||
public static int blockSizeForIndex(int idx) {
|
||||
return ((idx > 0) ? (256 << size_shift(idx)) : 0);
|
||||
}
|
||||
/*
|
||||
#define BLOCK_SIZE_FOR_INDEX(idx) ((idx) ? (256 << SIZE_SHIFT(idx)) : 0)
|
||||
#define BITMAP_SIZE_FOR_INDEX(idx) ((idx) ? (131072 >> SIZE_SHIFT(idx)) : 0)
|
||||
*/
|
||||
private final Map<Integer, RandomAccessFile> dataFiles;
|
||||
|
||||
public InputStream getInputStream() throws IOException {
|
||||
String fileName = getFileName();
|
||||
if (locationSelector > 0) {
|
||||
RandomAccessFile raf = dataFiles.get(locationSelector);
|
||||
raf.seek(bitmapSizeForIndex(locationSelector) / 8 + blockSizeForIndex(locationSelector) * blockNumber);
|
||||
return new RafInputStream(raf);
|
||||
}
|
||||
return new FileInputStream(new File(rootDir, fileName));
|
||||
}
|
||||
|
||||
public Location(long val, boolean isMetadata, long hash, File rootDir, Map<Integer, RandomAccessFile> dataFiles) {
|
||||
this.hash = hash;
|
||||
this.dataFiles = dataFiles;
|
||||
this.rootDir = rootDir;
|
||||
this.isMetadata = isMetadata;
|
||||
locationSelector = (int) ((val & eLocationSelectorMask) >> eLocationSelectorOffset);
|
||||
if (locationSelector > 0) {
|
||||
extraBlocks = (int) ((val & eExtraBlocksMask) >> eExtraBlocksOffset);
|
||||
blockNumber = (int) (val & eBlockNumberMask);
|
||||
} else {
|
||||
fileSize = (int) ((val & eFileSizeMask) >> eFileSizeOffset);
|
||||
fileGeneration = (int) (val & eFileGenerationMask);
|
||||
}
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
if (locationSelector > 0) {
|
||||
return "_CACHE_00" + locationSelector + "_";
|
||||
}
|
||||
String hashHex = Long.toHexString(hash & 0xffffffffL).toUpperCase();
|
||||
while (hashHex.length() < 8) {
|
||||
hashHex = "0" + hashHex;
|
||||
}
|
||||
String genHex = Integer.toHexString(fileGeneration);
|
||||
while (genHex.length() < 2) {
|
||||
genHex = "0" + genHex;
|
||||
}
|
||||
return hashHex.charAt(0) + File.separator + hashHex.substring(1, 1 + 2) + File.separator + hashHex.substring(3) + (isMetadata ? "m" : "d") + genHex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (locationSelector > 0) {
|
||||
return getFileName() + " block " + blockNumber + " extraBlocks " + extraBlocks;
|
||||
}
|
||||
return getFileName();
|
||||
}
|
||||
}
|
||||
129
src/com/jpexs/browsers/cache/firefox/MapBucket.java
vendored
Normal file
129
src/com/jpexs/browsers/cache/firefox/MapBucket.java
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.browsers.cache.firefox;
|
||||
|
||||
import com.jpexs.browsers.cache.CacheEntry;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class MapBucket extends CacheEntry {
|
||||
|
||||
public long hash;
|
||||
public long enviction;
|
||||
public Location dataLocation;
|
||||
public Location metadataLocation;
|
||||
private MetaData metadata;
|
||||
|
||||
public MapBucket(InputStream is, File rootDir, Map<Integer, RandomAccessFile> dataFiles) throws IOException {
|
||||
CacheInputStream cis = new CacheInputStream(is);
|
||||
hash = cis.readInt32();
|
||||
enviction = cis.readInt32();
|
||||
dataLocation = new Location(cis.readInt32(), false, hash, rootDir, dataFiles);
|
||||
metadataLocation = new Location(cis.readInt32(), true, hash, rootDir, dataFiles);
|
||||
}
|
||||
|
||||
public InputStream getMetaDataStream() throws IOException {
|
||||
return metadataLocation.getInputStream();
|
||||
}
|
||||
|
||||
public MetaData getMetaData() {
|
||||
if (metadata == null) {
|
||||
try {
|
||||
metadata = new MetaData(getMetaDataStream());
|
||||
} catch (IncompatibleVersionException ie) {
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(MapBucket.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
return metadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRequestURL() {
|
||||
String req = null;
|
||||
MetaData m = getMetaData();
|
||||
if (m == null) {
|
||||
return null;
|
||||
}
|
||||
req = m.request;
|
||||
if (req == null) {
|
||||
return null;
|
||||
}
|
||||
if (req.startsWith("HTTP:")) {
|
||||
req = req.substring("HTTP:".length());
|
||||
}
|
||||
return req;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getResponseHeaders() {
|
||||
MetaData m = getMetaData();
|
||||
if (m == null) {
|
||||
return null;
|
||||
}
|
||||
String responseHead = m.response.get("response-head");
|
||||
if (responseHead == null) {
|
||||
return null;
|
||||
}
|
||||
String headers[] = responseHead.split("\r\n");
|
||||
Map<String, String> ret = new HashMap<>();
|
||||
for (int h = 1; h < headers.length; h++) {
|
||||
String hs = headers[h];
|
||||
if (hs.contains(":")) {
|
||||
String hp[] = hs.split(":");
|
||||
ret.put(hp[0].trim(), hp[1].trim());
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStatusLine() {
|
||||
MetaData m = getMetaData();
|
||||
if (m == null) {
|
||||
return null;
|
||||
}
|
||||
String responseHead = m.response.get("response-head");
|
||||
String headers[] = responseHead.split("\r\n");
|
||||
return headers[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRequestMethod() {
|
||||
return "GET"; //No POST caching in Firefox
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getResponseRawDataStream() {
|
||||
try {
|
||||
return dataLocation.getInputStream();
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(MapBucket.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
79
src/com/jpexs/browsers/cache/firefox/MetaData.java
vendored
Normal file
79
src/com/jpexs/browsers/cache/firefox/MetaData.java
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.browsers.cache.firefox;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class MetaData {
|
||||
|
||||
public int majorVersion;
|
||||
public int minorVersion;
|
||||
public long location;
|
||||
public long fetchCount;
|
||||
public long firstFetchTime;
|
||||
public long lastFetchTime;
|
||||
public long expireTime;
|
||||
public long dataSize;
|
||||
public long requestSize;
|
||||
public long infoSize;
|
||||
public String request;
|
||||
public Map<String, String> response;
|
||||
|
||||
public MetaData(InputStream is) throws IOException, IncompatibleVersionException {
|
||||
CacheInputStream cis = new CacheInputStream(is);
|
||||
majorVersion = cis.readInt16();
|
||||
if (majorVersion != 1) {
|
||||
throw new IncompatibleVersionException(majorVersion);
|
||||
}
|
||||
minorVersion = cis.readInt16();
|
||||
location = cis.readInt32();
|
||||
fetchCount = cis.readInt32();
|
||||
firstFetchTime = cis.readInt32();
|
||||
lastFetchTime = cis.readInt32();
|
||||
expireTime = cis.readInt32();
|
||||
dataSize = cis.readInt32();
|
||||
requestSize = cis.readInt32();
|
||||
infoSize = cis.readInt32();
|
||||
byte req[] = new byte[(int) requestSize];
|
||||
cis.read(req);
|
||||
request = new String(req, 0, (int) requestSize - 1/*Ends with char 0*/);
|
||||
byte res[] = new byte[(int) infoSize];
|
||||
cis.read(res);
|
||||
String responseStr = new String(res);
|
||||
int nulpos;
|
||||
boolean inKey = true;
|
||||
String key = null;
|
||||
response = new HashMap<>();
|
||||
while ((nulpos = responseStr.indexOf(0)) > 0) {
|
||||
String v = responseStr.substring(0, nulpos);
|
||||
responseStr = responseStr.substring(nulpos + 1);
|
||||
if (inKey) {
|
||||
key = v;
|
||||
} else {
|
||||
response.put(key, v);
|
||||
}
|
||||
inKey = !inKey;
|
||||
}
|
||||
}
|
||||
}
|
||||
33
src/com/jpexs/decompiler/flash/AbortRetryIgnoreHandler.java
Normal file
33
src/com/jpexs/decompiler/flash/AbortRetryIgnoreHandler.java
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public interface AbortRetryIgnoreHandler {
|
||||
|
||||
public static int UNDEFINED = -1;
|
||||
public static int ABORT = 0;
|
||||
public static int RETRY = 1;
|
||||
public static int IGNORE = 2;
|
||||
|
||||
public int handle(Throwable thrown);
|
||||
|
||||
public AbortRetryIgnoreHandler getNewInstance();
|
||||
}
|
||||
56
src/com/jpexs/decompiler/flash/AppStrings.java
Normal file
56
src/com/jpexs/decompiler/flash/AppStrings.java
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class AppStrings {
|
||||
|
||||
private static Class resourceClass;
|
||||
private static ResourceBundle resourceBundle;
|
||||
|
||||
public static void setResourceClass(Class cls) {
|
||||
resourceClass = cls;
|
||||
updateLanguage();
|
||||
}
|
||||
|
||||
public static String getResourcePath(Class cls) {
|
||||
String name = cls.getName();
|
||||
if (name.startsWith("com.jpexs.decompiler.flash.gui.")) {
|
||||
name = name.substring("com.jpexs.decompiler.flash.gui.".length());
|
||||
name = "com.jpexs.decompiler.flash.gui.locales." + name;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
public static String translate(String key) {
|
||||
return resourceBundle.getString(key);
|
||||
}
|
||||
|
||||
public static String translate(String bundle, String key) {
|
||||
ResourceBundle b = ResourceBundle.getBundle(bundle);
|
||||
return b.getString(key);
|
||||
}
|
||||
|
||||
public static void updateLanguage() {
|
||||
resourceBundle = ResourceBundle.getBundle(getResourcePath(resourceClass));
|
||||
}
|
||||
}
|
||||
64
src/com/jpexs/decompiler/flash/ApplicationInfo.java
Normal file
64
src/com/jpexs/decompiler/flash/ApplicationInfo.java
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ApplicationInfo {
|
||||
|
||||
public static final String APPLICATION_NAME = "JPEXS Free Flash Decompiler";
|
||||
public static final String SHORT_APPLICATION_NAME = "FFDec";
|
||||
public static final String VENDOR = "JPEXS";
|
||||
public static String version = "";
|
||||
public static String build = "";
|
||||
public static boolean nightly = false;
|
||||
public static String applicationVerName;
|
||||
public static String shortApplicationVerName;
|
||||
public static final String PROJECT_PAGE = "http://www.free-decompiler.com/flash";
|
||||
public static String updatePageStub = "http://www.free-decompiler.com/flash/update.html?currentVersion=";
|
||||
public static String updatePage;
|
||||
|
||||
static {
|
||||
loadProperties();
|
||||
}
|
||||
|
||||
private static void loadProperties() {
|
||||
Properties prop = new Properties();
|
||||
try {
|
||||
prop.load(ApplicationInfo.class.getResourceAsStream("/project.properties"));
|
||||
version = prop.getProperty("version");
|
||||
build = prop.getProperty("build");
|
||||
nightly = prop.getProperty("nightly").equals("true");
|
||||
if (nightly) {
|
||||
version = version + " nightly build " + build;
|
||||
}
|
||||
} catch (IOException | NullPointerException ex) {
|
||||
//ignore
|
||||
version = "unknown";
|
||||
}
|
||||
|
||||
applicationVerName = APPLICATION_NAME + " v." + version;
|
||||
updatePage = updatePageStub + version;
|
||||
shortApplicationVerName = SHORT_APPLICATION_NAME + " v." + version;
|
||||
}
|
||||
|
||||
}
|
||||
25
src/com/jpexs/decompiler/flash/BaseLocalData.java
Normal file
25
src/com/jpexs/decompiler/flash/BaseLocalData.java
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public abstract class BaseLocalData {
|
||||
|
||||
}
|
||||
85
src/com/jpexs/decompiler/flash/BinarySWFBundle.java
Normal file
85
src/com/jpexs/decompiler/flash/BinarySWFBundle.java
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) 2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class BinarySWFBundle implements SWFBundle {
|
||||
|
||||
private final SWFSearch search;
|
||||
|
||||
public BinarySWFBundle(InputStream is, boolean noCheck, SearchMode searchMode) {
|
||||
search = new SWFSearch(new SwfHeaderStreamSearch(is), noCheck, searchMode);
|
||||
search.process();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int length() {
|
||||
return search.length();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getKeys() {
|
||||
Set<String> ret = new HashSet<>();
|
||||
for (Long address : search.getAddresses()) {
|
||||
ret.add("[" + address + "]");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SeekableInputStream getSWF(String key) {
|
||||
if (!key.startsWith("[")) {
|
||||
return null;
|
||||
}
|
||||
if (!key.endsWith("]")) {
|
||||
return null;
|
||||
}
|
||||
key = key.substring(1, key.length() - 1);
|
||||
try {
|
||||
int address = Integer.parseInt(key);
|
||||
return search.get(null, address);
|
||||
} catch (IOException | NumberFormatException iex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, SeekableInputStream> getAll() {
|
||||
Map<String, SeekableInputStream> ret = new HashMap<>();
|
||||
for (String key : getKeys()) {
|
||||
ret.put(key, getSWF(key));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExtension() {
|
||||
return "bin";
|
||||
}
|
||||
}
|
||||
26
src/com/jpexs/decompiler/flash/DisassemblyListener.java
Normal file
26
src/com/jpexs/decompiler/flash/DisassemblyListener.java
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public interface DisassemblyListener {
|
||||
|
||||
public void progress(String phase, long pos, long total);
|
||||
}
|
||||
28
src/com/jpexs/decompiler/flash/EndOfStreamException.java
Normal file
28
src/com/jpexs/decompiler/flash/EndOfStreamException.java
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class EndOfStreamException extends RuntimeException {
|
||||
|
||||
public EndOfStreamException() {
|
||||
super("Premature end of the stream reached");
|
||||
}
|
||||
}
|
||||
26
src/com/jpexs/decompiler/flash/EventListener.java
Normal file
26
src/com/jpexs/decompiler/flash/EventListener.java
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public interface EventListener {
|
||||
|
||||
public void handleEvent(String event, Object data);
|
||||
}
|
||||
32
src/com/jpexs/decompiler/flash/FinalProcessLocalData.java
Normal file
32
src/com/jpexs/decompiler/flash/FinalProcessLocalData.java
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class FinalProcessLocalData {
|
||||
|
||||
public final HashSet<Integer> temporaryRegisters;
|
||||
|
||||
public FinalProcessLocalData() {
|
||||
temporaryRegisters = new HashSet<>();
|
||||
}
|
||||
}
|
||||
55
src/com/jpexs/decompiler/flash/RetryTask.java
Normal file
55
src/com/jpexs/decompiler/flash/RetryTask.java
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class RetryTask {
|
||||
|
||||
private final RunnableIOEx r;
|
||||
private final AbortRetryIgnoreHandler handler;
|
||||
public Object result;
|
||||
|
||||
public RetryTask(RunnableIOEx r, AbortRetryIgnoreHandler handler) {
|
||||
this.r = r;
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
public void run() throws IOException {
|
||||
boolean retry;
|
||||
do {
|
||||
retry = false;
|
||||
try {
|
||||
r.run();
|
||||
} catch (Exception ex) {
|
||||
switch (handler.handle(ex)) {
|
||||
case AbortRetryIgnoreHandler.ABORT:
|
||||
throw ex;
|
||||
case AbortRetryIgnoreHandler.RETRY:
|
||||
retry = true;
|
||||
break;
|
||||
case AbortRetryIgnoreHandler.IGNORE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (retry);
|
||||
}
|
||||
}
|
||||
28
src/com/jpexs/decompiler/flash/RunnableIOEx.java
Normal file
28
src/com/jpexs/decompiler/flash/RunnableIOEx.java
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public interface RunnableIOEx {
|
||||
|
||||
public void run() throws IOException;
|
||||
}
|
||||
27
src/com/jpexs/decompiler/flash/RunnableIOExResult.java
Normal file
27
src/com/jpexs/decompiler/flash/RunnableIOExResult.java
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param <T>
|
||||
* @author JPEXS
|
||||
*/
|
||||
public abstract class RunnableIOExResult<T> implements RunnableIOEx {
|
||||
|
||||
public T result;
|
||||
}
|
||||
79
src/com/jpexs/decompiler/flash/SWC.java
Normal file
79
src/com/jpexs/decompiler/flash/SWC.java
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
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;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class SWC extends ZippedSWFBundle {
|
||||
|
||||
public SWC(InputStream is) throws IOException {
|
||||
super(is);
|
||||
keySet.clear();
|
||||
this.is.reset();
|
||||
ZipInputStream zip = new ZipInputStream(this.is);
|
||||
ZipEntry entry;
|
||||
try {
|
||||
while ((entry = zip.getNextEntry()) != null) {
|
||||
if (entry.getName().equals("catalog.xml")) {
|
||||
try {
|
||||
SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||
SAXParser saxParser = factory.newSAXParser();
|
||||
DefaultHandler handler = new DefaultHandler() {
|
||||
|
||||
@Override
|
||||
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
|
||||
if (qName.equalsIgnoreCase("library")) {
|
||||
String path = attributes.getValue("path");
|
||||
if (path != null) {
|
||||
keySet.add(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
saxParser.parse(zip, handler);
|
||||
} catch (Exception ex) {
|
||||
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(ZippedSWFBundle.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExtension() {
|
||||
return "swc";
|
||||
}
|
||||
|
||||
}
|
||||
2952
src/com/jpexs/decompiler/flash/SWF.java
Normal file
2952
src/com/jpexs/decompiler/flash/SWF.java
Normal file
File diff suppressed because it is too large
Load Diff
39
src/com/jpexs/decompiler/flash/SWFBundle.java
Normal file
39
src/com/jpexs/decompiler/flash/SWFBundle.java
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
import com.jpexs.helpers.streams.SeekableInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public interface SWFBundle {
|
||||
|
||||
public int length();
|
||||
|
||||
public Set<String> getKeys();
|
||||
|
||||
public SeekableInputStream getSWF(String key) throws IOException;
|
||||
|
||||
public Map<String, SeekableInputStream> getAll() throws IOException;
|
||||
|
||||
public String getExtension();
|
||||
}
|
||||
2930
src/com/jpexs/decompiler/flash/SWFInputStream.java
Normal file
2930
src/com/jpexs/decompiler/flash/SWFInputStream.java
Normal file
File diff suppressed because it is too large
Load Diff
1756
src/com/jpexs/decompiler/flash/SWFOutputStream.java
Normal file
1756
src/com/jpexs/decompiler/flash/SWFOutputStream.java
Normal file
File diff suppressed because it is too large
Load Diff
151
src/com/jpexs/decompiler/flash/SWFSearch.java
Normal file
151
src/com/jpexs/decompiler/flash/SWFSearch.java
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright (C) 2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
import com.jpexs.helpers.MemoryInputStream;
|
||||
import com.jpexs.helpers.PosMarkedInputStream;
|
||||
import com.jpexs.helpers.ProgressListener;
|
||||
import com.jpexs.helpers.Searchable;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class SWFSearch {
|
||||
|
||||
protected Searchable s;
|
||||
private final boolean noCheck;
|
||||
private final SearchMode searchMode;
|
||||
private boolean processed = false;
|
||||
private final Set<ProgressListener> listeners = new HashSet<>();
|
||||
private final Map<Long, MemoryInputStream> swfStreams = new HashMap<>();
|
||||
|
||||
public SWFSearch(Searchable s, boolean noCheck, SearchMode searchMode) {
|
||||
this.s = s;
|
||||
this.noCheck = noCheck;
|
||||
this.searchMode = searchMode;
|
||||
}
|
||||
|
||||
public void addProgressListener(ProgressListener l) {
|
||||
listeners.add(l);
|
||||
}
|
||||
|
||||
public void removeProgressListener(ProgressListener l) {
|
||||
listeners.remove(l);
|
||||
}
|
||||
|
||||
private void setProgress(int p) {
|
||||
for (ProgressListener l : listeners) {
|
||||
l.progress(p);
|
||||
}
|
||||
}
|
||||
|
||||
public void process() {
|
||||
Map<Long, InputStream> ret = new HashMap<>();
|
||||
ret = s.search(new ProgressListener() {
|
||||
@Override
|
||||
public void progress(int p) {
|
||||
setProgress(p);
|
||||
}
|
||||
},
|
||||
"FWS".getBytes(), //Uncompressed Flash
|
||||
"CWS".getBytes(), //ZLib compressed Flash
|
||||
"ZWS".getBytes(), //LZMA compressed Flash
|
||||
"GFX".getBytes(), //Uncompressed ScaleForm GFx
|
||||
"CFX".getBytes()); //Compressed ScaleForm GFx
|
||||
int pos = 0;
|
||||
long biggestSize = 0;
|
||||
long smallestSize = Long.MAX_VALUE;
|
||||
addressLoop:
|
||||
for (Long addr : ret.keySet()) {
|
||||
setProgress(pos * 100 / ret.size());
|
||||
pos++;
|
||||
try {
|
||||
MemoryInputStream mis = (MemoryInputStream) ret.get(addr);
|
||||
mis.reset();
|
||||
PosMarkedInputStream pmi = new PosMarkedInputStream(mis);
|
||||
SWF swf = noCheck ? new SWF(pmi) : new SWF(pmi, null, false, true);
|
||||
boolean valid = swf.fileSize > 0
|
||||
&& swf.version > 0
|
||||
&& (!swf.tags.isEmpty() || noCheck)
|
||||
&& swf.version < 25; // Needs to be fixed when SWF versions reaches this value
|
||||
if (valid) {
|
||||
long limit = pmi.getPos();
|
||||
MemoryInputStream is = new MemoryInputStream(mis.getAllRead(), (int) (long) addr, (int) limit);
|
||||
switch (searchMode) {
|
||||
case ALL:
|
||||
swfStreams.put(addr, is);
|
||||
break;
|
||||
case BIGGEST:
|
||||
if (limit > biggestSize) {
|
||||
biggestSize = limit;
|
||||
swfStreams.clear();
|
||||
swfStreams.put(addr, is);
|
||||
}
|
||||
break;
|
||||
case SMALLEST:
|
||||
if (limit < smallestSize) {
|
||||
smallestSize = limit;
|
||||
swfStreams.clear();
|
||||
swfStreams.put(addr, is);
|
||||
}
|
||||
break;
|
||||
case FIRST:
|
||||
swfStreams.put(addr, is);
|
||||
break addressLoop;
|
||||
case LAST:
|
||||
swfStreams.clear();
|
||||
swfStreams.put(addr, is);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (OutOfMemoryError ome) {
|
||||
System.gc();
|
||||
} catch (Exception | Error ex) {
|
||||
}
|
||||
}
|
||||
setProgress(100);
|
||||
processed = true;
|
||||
}
|
||||
|
||||
public MemoryInputStream get(ProgressListener listener, long address) throws IOException {
|
||||
if (!processed) {
|
||||
return null;
|
||||
}
|
||||
if (!swfStreams.containsKey(address)) {
|
||||
return null;
|
||||
}
|
||||
return swfStreams.get(address);
|
||||
}
|
||||
|
||||
public Set<Long> getAddresses() {
|
||||
return swfStreams.keySet();
|
||||
}
|
||||
|
||||
public int length() {
|
||||
if (!processed) {
|
||||
return 0;
|
||||
}
|
||||
return swfStreams.size();
|
||||
}
|
||||
}
|
||||
95
src/com/jpexs/decompiler/flash/SWFSourceInfo.java
Normal file
95
src/com/jpexs/decompiler/flash/SWFSourceInfo.java
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class SWFSourceInfo {
|
||||
|
||||
private final InputStream inputStream;
|
||||
private final String file;
|
||||
private final String fileTitle;
|
||||
|
||||
public SWFSourceInfo(InputStream inputStream, String file, String fileTitle) {
|
||||
this.inputStream = inputStream;
|
||||
this.file = file;
|
||||
this.fileTitle = fileTitle;
|
||||
}
|
||||
|
||||
public InputStream getInputStream() {
|
||||
return inputStream;
|
||||
}
|
||||
|
||||
public String getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
public String getFileTitle() {
|
||||
return fileTitle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get title of the file
|
||||
*
|
||||
* @return file title
|
||||
*/
|
||||
public String getFileTitleOrName() {
|
||||
if (fileTitle != null) {
|
||||
return fileTitle;
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
public boolean isBundle() {
|
||||
if (inputStream == null) {
|
||||
File fileObj = new File(file);
|
||||
String fileName = fileObj.getName();
|
||||
if (fileName.startsWith("asdec_") && fileName.endsWith(".tmp")) {
|
||||
return false;
|
||||
}
|
||||
String extension = Path.getExtension(fileObj);
|
||||
return !(extension.equals(".swf") || extension.equals(".gfx"));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public SWFBundle getBundle(boolean noCheck, SearchMode searchMode) throws IOException {
|
||||
if (!isBundle()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String extension = Path.getExtension(new File(file));
|
||||
InputStream is = new BufferedInputStream(new FileInputStream(file));
|
||||
switch (extension) {
|
||||
case ".swc":
|
||||
return new SWC(is);
|
||||
case ".zip":
|
||||
return new ZippedSWFBundle(is);
|
||||
default:
|
||||
return new BinarySWFBundle(is, noCheck, searchMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
26
src/com/jpexs/decompiler/flash/SearchMode.java
Normal file
26
src/com/jpexs/decompiler/flash/SearchMode.java
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public enum SearchMode {
|
||||
|
||||
ALL, BIGGEST, SMALLEST, FIRST, LAST
|
||||
}
|
||||
60
src/com/jpexs/decompiler/flash/SourceGeneratorLocalData.java
Normal file
60
src/com/jpexs/decompiler/flash/SourceGeneratorLocalData.java
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.types.ABCException;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.ScriptInfo;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class SourceGeneratorLocalData implements Serializable {
|
||||
|
||||
public HashMap<String, Integer> registerVars;
|
||||
public Integer inFunction;
|
||||
public Boolean inMethod;
|
||||
public Integer forInLevel;
|
||||
|
||||
//TODO: handle AVM2 separately
|
||||
public List<ABCException> exceptions = new ArrayList<>();
|
||||
public List<Integer> finallyCatches = new ArrayList<Integer>();
|
||||
public Map<Integer, Integer> finallyCounter = new HashMap<>();
|
||||
public int finallyRegister = -1;
|
||||
public String currentClass;
|
||||
public int activationReg = 0;
|
||||
public List<MethodBody> callStack = new ArrayList<>();
|
||||
public Map<MethodBody, List<Integer>> traitUsages = new HashMap<>();
|
||||
public String pkg = "";
|
||||
public List<GraphTargetItem> scopeStack = new ArrayList<GraphTargetItem>();
|
||||
public boolean documentClass;
|
||||
public ScriptInfo currentScript;
|
||||
|
||||
public SourceGeneratorLocalData(HashMap<String, Integer> registerVars, Integer inFunction, Boolean inMethod, Integer forInLevel) {
|
||||
this.registerVars = registerVars;
|
||||
this.inFunction = inFunction;
|
||||
this.inMethod = inMethod;
|
||||
this.forInLevel = forInLevel;
|
||||
}
|
||||
}
|
||||
39
src/com/jpexs/decompiler/flash/Version.java
Normal file
39
src/com/jpexs/decompiler/flash/Version.java
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class Version {
|
||||
|
||||
public int versionId;
|
||||
public String revision;
|
||||
public String versionName;
|
||||
public String longVersionName;
|
||||
public String releaseDate;
|
||||
public String appName;
|
||||
public String appFullName;
|
||||
public String updateLink;
|
||||
public boolean nightly;
|
||||
public Map<String, List<String>> changes = new HashMap<>();
|
||||
}
|
||||
110
src/com/jpexs/decompiler/flash/ZippedSWFBundle.java
Normal file
110
src/com/jpexs/decompiler/flash/ZippedSWFBundle.java
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (C) 2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
import com.jpexs.helpers.Helper;
|
||||
import com.jpexs.helpers.MemoryInputStream;
|
||||
import com.jpexs.helpers.ReReadableInputStream;
|
||||
import com.jpexs.helpers.streams.SeekableInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ZippedSWFBundle implements SWFBundle {
|
||||
|
||||
protected Set<String> keySet = new HashSet<>();
|
||||
private final Map<String, SeekableInputStream> cachedSWFs = new HashMap<>();
|
||||
protected ReReadableInputStream is;
|
||||
|
||||
public ZippedSWFBundle(InputStream is) {
|
||||
this.is = new ReReadableInputStream(is);
|
||||
ZipInputStream zip = new ZipInputStream(this.is);
|
||||
ZipEntry entry;
|
||||
try {
|
||||
while ((entry = zip.getNextEntry()) != null) {
|
||||
if (entry.getName().toLowerCase().endsWith(".swf")
|
||||
|| entry.getName().toLowerCase().endsWith(".gfx")) {
|
||||
keySet.add(entry.getName());
|
||||
}
|
||||
//streamMap.put(, is)
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(ZippedSWFBundle.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int length() {
|
||||
return keySet.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getKeys() {
|
||||
return keySet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SeekableInputStream getSWF(String key) throws IOException {
|
||||
if (!keySet.contains(key)) {
|
||||
return null;
|
||||
}
|
||||
if (!cachedSWFs.containsKey(key)) {
|
||||
|
||||
this.is.reset();
|
||||
ZipInputStream zip = new ZipInputStream(this.is);
|
||||
ZipEntry entry;
|
||||
try {
|
||||
while ((entry = zip.getNextEntry()) != null) {
|
||||
if (entry.getName().equals(key)) {
|
||||
MemoryInputStream mis = new MemoryInputStream(Helper.readStream(zip));
|
||||
cachedSWFs.put(key, mis);
|
||||
break;
|
||||
}
|
||||
zip.closeEntry();
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(ZippedSWFBundle.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
|
||||
}
|
||||
return cachedSWFs.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, SeekableInputStream> getAll() throws IOException {
|
||||
for (String key : getKeys()) { //cache everything first
|
||||
getSWF(key);
|
||||
}
|
||||
return cachedSWFs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExtension() {
|
||||
return "zip";
|
||||
}
|
||||
}
|
||||
948
src/com/jpexs/decompiler/flash/abc/ABC.java
Normal file
948
src/com/jpexs/decompiler/flash/abc/ABC.java
Normal file
@@ -0,0 +1,948 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc;
|
||||
|
||||
import com.jpexs.decompiler.flash.EventListener;
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Deobfuscation;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.ConstantPool;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.UnknownInstructionCode;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.executing.CallPropertyIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushStringIns;
|
||||
import com.jpexs.decompiler.flash.abc.types.ABCException;
|
||||
import com.jpexs.decompiler.flash.abc.types.ClassInfo;
|
||||
import com.jpexs.decompiler.flash.abc.types.InstanceInfo;
|
||||
import com.jpexs.decompiler.flash.abc.types.MetadataInfo;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
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.NamespaceSet;
|
||||
import com.jpexs.decompiler.flash.abc.types.ScriptInfo;
|
||||
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.usages.ClassNameMultinameUsage;
|
||||
import com.jpexs.decompiler.flash.abc.usages.ConstVarNameMultinameUsage;
|
||||
import com.jpexs.decompiler.flash.abc.usages.ConstVarTypeMultinameUsage;
|
||||
import com.jpexs.decompiler.flash.abc.usages.ExtendsMultinameUsage;
|
||||
import com.jpexs.decompiler.flash.abc.usages.ImplementsMultinameUsage;
|
||||
import com.jpexs.decompiler.flash.abc.usages.MethodBodyMultinameUsage;
|
||||
import com.jpexs.decompiler.flash.abc.usages.MethodNameMultinameUsage;
|
||||
import com.jpexs.decompiler.flash.abc.usages.MethodParamsMultinameUsage;
|
||||
import com.jpexs.decompiler.flash.abc.usages.MethodReturnTypeMultinameUsage;
|
||||
import com.jpexs.decompiler.flash.abc.usages.MultinameUsage;
|
||||
import com.jpexs.decompiler.flash.abc.usages.TypeNameMultinameUsage;
|
||||
import com.jpexs.decompiler.flash.helpers.collections.MyEntry;
|
||||
import com.jpexs.decompiler.flash.tags.ABCContainerTag;
|
||||
import com.jpexs.helpers.utf8.Utf8PrintWriter;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
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.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class ABC {
|
||||
|
||||
public int major_version = 46;
|
||||
public int minor_version = 16;
|
||||
public ConstantPool constants = new ConstantPool();
|
||||
public List<MethodInfo> method_info = new ArrayList<>();
|
||||
public List<MetadataInfo> metadata_info = new ArrayList<>();
|
||||
public List<InstanceInfo> instance_info = new ArrayList<>();
|
||||
public List<ClassInfo> class_info = new ArrayList<>();
|
||||
public List<ScriptInfo> script_info = new ArrayList<>();
|
||||
public List<MethodBody> bodies = new ArrayList<>();
|
||||
private List<Integer> bodyIdxFromMethodIdx = new ArrayList<>();
|
||||
public long[] stringOffsets;
|
||||
public static final int MINORwithDECIMAL = 17;
|
||||
protected Set<EventListener> listeners = new HashSet<>();
|
||||
private static final Logger logger = Logger.getLogger(ABC.class.getName());
|
||||
private final AVM2Deobfuscation deobfuscation;
|
||||
public SWF swf;
|
||||
public ABCContainerTag parentTag;
|
||||
|
||||
public ABC(SWF swf) {
|
||||
this.deobfuscation = null;
|
||||
this.swf = swf;
|
||||
constants.constant_double.add(null);
|
||||
constants.constant_int.add(null);
|
||||
constants.constant_uint.add(null);
|
||||
constants.constant_string.add(null);
|
||||
constants.constant_multiname.add(null);
|
||||
constants.constant_namespace.add(null);
|
||||
constants.constant_namespace_set.add(null);
|
||||
}
|
||||
|
||||
public int addMethodBody(MethodBody body) {
|
||||
bodies.add(body);
|
||||
if (body.method_info >= bodyIdxFromMethodIdx.size()) {
|
||||
int newlen = body.method_info + 1;
|
||||
int oldlen = bodyIdxFromMethodIdx.size();
|
||||
for (int i = oldlen; i < newlen; i++) {
|
||||
bodyIdxFromMethodIdx.add(-1);
|
||||
}
|
||||
bodyIdxFromMethodIdx.set(body.method_info, bodies.size() - 1);
|
||||
}
|
||||
return bodies.size() - 1;
|
||||
}
|
||||
|
||||
public int addMethodInfo(MethodInfo mi) {
|
||||
method_info.add(mi);
|
||||
return method_info.size() - 1;
|
||||
}
|
||||
|
||||
public void addEventListener(EventListener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeEventListener(EventListener listener) {
|
||||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
protected void informListeners(String event, Object data) {
|
||||
for (EventListener listener : listeners) {
|
||||
listener.handleEvent(event, data);
|
||||
}
|
||||
}
|
||||
|
||||
public int removeTraps() throws InterruptedException {
|
||||
int rem = 0;
|
||||
for (int s = 0; s < script_info.size(); s++) {
|
||||
rem += script_info.get(s).removeTraps(s, this, "");
|
||||
}
|
||||
return rem;
|
||||
}
|
||||
|
||||
public int removeDeadCode() throws InterruptedException {
|
||||
int rem = 0;
|
||||
for (MethodBody body : bodies) {
|
||||
rem += body.removeDeadCode(constants, null/*FIXME*/, method_info.get(body.method_info));
|
||||
}
|
||||
return rem;
|
||||
}
|
||||
|
||||
public void restoreControlFlow() throws InterruptedException {
|
||||
for (MethodBody body : bodies) {
|
||||
body.restoreControlFlow(constants, null/*FIXME*/, method_info.get(body.method_info));
|
||||
}
|
||||
}
|
||||
|
||||
public Set<Integer> getNsStringUsages() {
|
||||
Set<Integer> ret = new HashSet<>();
|
||||
for (int n = 1; n < constants.getNamespaceCount(); n++) {
|
||||
ret.add(constants.getNamespace(n).name_index);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public Set<Integer> getStringUsages() {
|
||||
Set<Integer> ret = new HashSet<>();
|
||||
for (MethodBody body : bodies) {
|
||||
for (AVM2Instruction ins : body.code.code) {
|
||||
for (int i = 0; i < ins.definition.operands.length; i++) {
|
||||
if (ins.definition.operands[i] == AVM2Code.DAT_STRING_INDEX) {
|
||||
ret.add(ins.operands[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private void setStringUsageType(Map<Integer, String> ret, int strIndex, String usageType) {
|
||||
if (ret.containsKey(strIndex)) {
|
||||
if (!"name".equals(usageType)) {
|
||||
if (!ret.get(strIndex).equals(usageType)) {
|
||||
ret.put(strIndex, "name");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ret.put(strIndex, usageType);
|
||||
}
|
||||
}
|
||||
|
||||
private void getStringUsageTypes(Map<Integer, String> ret, Traits traits, boolean classesOnly) {
|
||||
for (Trait t : traits.traits) {
|
||||
int strIndex = constants.getMultiname(t.name_index).name_index;
|
||||
String usageType = "";
|
||||
if (t instanceof TraitClass) {
|
||||
TraitClass tc = (TraitClass) t;
|
||||
getStringUsageTypes(ret, class_info.get(tc.class_info).static_traits, classesOnly);
|
||||
getStringUsageTypes(ret, instance_info.get(tc.class_info).instance_traits, classesOnly);
|
||||
|
||||
if (instance_info.get(tc.class_info).name_index != 0) {
|
||||
setStringUsageType(ret, constants.getMultiname(instance_info.get(tc.class_info).name_index).name_index, "class");
|
||||
}
|
||||
if (instance_info.get(tc.class_info).super_index != 0) {
|
||||
setStringUsageType(ret, constants.getMultiname(instance_info.get(tc.class_info).super_index).name_index, "class");
|
||||
}
|
||||
|
||||
usageType = "class";
|
||||
}
|
||||
if (t instanceof TraitMethodGetterSetter) {
|
||||
TraitMethodGetterSetter tm = (TraitMethodGetterSetter) t;
|
||||
usageType = "method";
|
||||
MethodBody body = findBody(tm.method_info);
|
||||
if (body != null) {
|
||||
getStringUsageTypes(ret, body.traits, classesOnly);
|
||||
}
|
||||
}
|
||||
if (t instanceof TraitFunction) {
|
||||
TraitFunction tf = (TraitFunction) t;
|
||||
MethodBody body = findBody(tf.method_info);
|
||||
if (body != null) {
|
||||
getStringUsageTypes(ret, body.traits, classesOnly);
|
||||
}
|
||||
usageType = "function";
|
||||
}
|
||||
if (t instanceof TraitSlotConst) {
|
||||
TraitSlotConst ts = (TraitSlotConst) t;
|
||||
if (ts.isVar()) {
|
||||
usageType = "var";
|
||||
}
|
||||
if (ts.isConst()) {
|
||||
usageType = "const";
|
||||
}
|
||||
}
|
||||
if (usageType.equals("class") || (!classesOnly)) {
|
||||
setStringUsageType(ret, strIndex, usageType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void getStringUsageTypes(Map<Integer, String> ret, boolean classesOnly) {
|
||||
for (ScriptInfo script : script_info) {
|
||||
getStringUsageTypes(ret, script.traits, classesOnly);
|
||||
}
|
||||
}
|
||||
|
||||
public void renameMultiname(int multinameIndex, String newname) {
|
||||
if (multinameIndex <= 0 || multinameIndex >= constants.getMultinameCount()) {
|
||||
throw new IllegalArgumentException("Multiname with index " + multinameIndex + " does not exist");
|
||||
}
|
||||
Set<Integer> stringUsages = getStringUsages();
|
||||
Set<Integer> namespaceUsages = getNsStringUsages();
|
||||
int strIndex = constants.getMultiname(multinameIndex).name_index;
|
||||
if (stringUsages.contains(strIndex) || namespaceUsages.contains(strIndex)) { //name is used elsewhere as string literal
|
||||
strIndex = constants.getStringId(newname, true);
|
||||
constants.getMultiname(multinameIndex).name_index = strIndex;
|
||||
} else {
|
||||
constants.setString(strIndex, newname);
|
||||
}
|
||||
}
|
||||
|
||||
public void deobfuscateIdentifiers(HashMap<String, String> namesMap, RenameType renameType, boolean classesOnly) {
|
||||
Set<Integer> stringUsages = getStringUsages();
|
||||
Set<Integer> namespaceUsages = getNsStringUsages();
|
||||
Map<Integer, String> stringUsageTypes = new HashMap<>();
|
||||
informListeners("deobfuscate", "Getting usage types...");
|
||||
getStringUsageTypes(stringUsageTypes, classesOnly);
|
||||
for (int i = 0; i < instance_info.size(); i++) {
|
||||
informListeners("deobfuscate", "class " + i + "/" + instance_info.size());
|
||||
InstanceInfo insti = instance_info.get(i);
|
||||
if (insti.name_index != 0) {
|
||||
constants.getMultiname(insti.name_index).name_index = deobfuscation.deobfuscateName(stringUsageTypes, stringUsages, namespaceUsages, namesMap, constants.getMultiname(insti.name_index).name_index, true, renameType);
|
||||
if (constants.getMultiname(insti.name_index).namespace_index != 0) {
|
||||
constants.getNamespace(constants.getMultiname(insti.name_index).namespace_index).name_index
|
||||
= deobfuscation.deobfuscatePackageName(stringUsageTypes, stringUsages, namesMap, constants.getNamespace(constants.getMultiname(insti.name_index).namespace_index).name_index, renameType);
|
||||
}
|
||||
}
|
||||
if (insti.super_index != 0) {
|
||||
constants.getMultiname(insti.super_index).name_index = deobfuscation.deobfuscateName(stringUsageTypes, stringUsages, namespaceUsages, namesMap, constants.getMultiname(insti.super_index).name_index, true, renameType);
|
||||
}
|
||||
}
|
||||
if (classesOnly) {
|
||||
return;
|
||||
}
|
||||
for (int i = 1; i < constants.getMultinameCount(); i++) {
|
||||
informListeners("deobfuscate", "name " + i + "/" + constants.getMultinameCount());
|
||||
constants.getMultiname(i).name_index = deobfuscation.deobfuscateName(stringUsageTypes, stringUsages, namespaceUsages, namesMap, constants.getMultiname(i).name_index, false, renameType);
|
||||
}
|
||||
for (int i = 1; i < constants.getNamespaceCount(); i++) {
|
||||
informListeners("deobfuscate", "namespace " + i + "/" + constants.getNamespaceCount());
|
||||
if (constants.getNamespace(i).kind != Namespace.KIND_PACKAGE) { //only packages
|
||||
continue;
|
||||
}
|
||||
constants.getNamespace(i).name_index = deobfuscation.deobfuscatePackageName(stringUsageTypes, stringUsages, namesMap, constants.getNamespace(i).name_index, renameType);
|
||||
}
|
||||
|
||||
//process reflection using getDefinitionByName too
|
||||
for (MethodBody body : bodies) {
|
||||
for (int ip = 0; ip < body.code.code.size(); ip++) {
|
||||
if (body.code.code.get(ip).definition instanceof CallPropertyIns) {
|
||||
int mIndex = body.code.code.get(ip).operands[0];
|
||||
if (mIndex > 0) {
|
||||
Multiname m = constants.getMultiname(mIndex);
|
||||
if (m.getNameWithNamespace(constants).equals("flash.utils.getDefinitionByName")) {
|
||||
if (ip > 0) {
|
||||
if (body.code.code.get(ip - 1).definition instanceof PushStringIns) {
|
||||
int strIndex = body.code.code.get(ip - 1).operands[0];
|
||||
String fullname = constants.getString(strIndex);
|
||||
String pkg = "";
|
||||
String name = fullname;
|
||||
if (fullname.contains(".")) {
|
||||
pkg = fullname.substring(0, fullname.lastIndexOf('.'));
|
||||
name = fullname.substring(fullname.lastIndexOf('.') + 1);
|
||||
}
|
||||
if (!pkg.isEmpty()) {
|
||||
int pkgStrIndex = constants.getStringId(pkg, true);
|
||||
pkgStrIndex = deobfuscation.deobfuscatePackageName(stringUsageTypes, stringUsages, namesMap, pkgStrIndex, renameType);
|
||||
pkg = constants.getString(pkgStrIndex);
|
||||
}
|
||||
int nameStrIndex = constants.getStringId(name, true);
|
||||
nameStrIndex = deobfuscation.deobfuscateName(stringUsageTypes, stringUsages, namespaceUsages, namesMap, nameStrIndex, true, renameType);
|
||||
name = constants.getString(nameStrIndex);
|
||||
String fullChanged = "";
|
||||
if (!pkg.isEmpty()) {
|
||||
fullChanged = pkg + ".";
|
||||
}
|
||||
fullChanged += name;
|
||||
strIndex = constants.getStringId(fullChanged, true);
|
||||
body.code.code.get(ip - 1).operands[0] = strIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ABC(InputStream is, SWF swf, ABCContainerTag tag) throws IOException {
|
||||
this.swf = swf;
|
||||
this.parentTag = tag;
|
||||
ABCInputStream ais = new ABCInputStream(is);
|
||||
minor_version = ais.readU16();
|
||||
major_version = ais.readU16();
|
||||
logger.log(Level.FINE, "ABC minor_version: {0}, major_version: {1}", new Object[]{minor_version, major_version});
|
||||
constants = new ConstantPool();
|
||||
deobfuscation = new AVM2Deobfuscation(constants);
|
||||
//constant integers
|
||||
int constant_int_pool_count = ais.readU30();
|
||||
constants.constant_int = new ArrayList<>(constant_int_pool_count);
|
||||
if (constant_int_pool_count > 0) {
|
||||
constants.addInt(0);
|
||||
}
|
||||
for (int i = 1; i < constant_int_pool_count; i++) { //index 0 not used. Values 1..n-1
|
||||
constants.addInt(ais.readS32());
|
||||
}
|
||||
|
||||
//constant unsigned integers
|
||||
int constant_uint_pool_count = ais.readU30();
|
||||
constants.constant_uint = new ArrayList<>(constant_uint_pool_count);
|
||||
if (constant_uint_pool_count > 0) {
|
||||
constants.addUInt(0);
|
||||
}
|
||||
for (int i = 1; i < constant_uint_pool_count; i++) { //index 0 not used. Values 1..n-1
|
||||
constants.addUInt(ais.readU32());
|
||||
}
|
||||
|
||||
//constant double
|
||||
int constant_double_pool_count = ais.readU30();
|
||||
constants.constant_double = new ArrayList<>(constant_double_pool_count);
|
||||
if (constant_double_pool_count > 0) {
|
||||
constants.addDouble(0);
|
||||
}
|
||||
for (int i = 1; i < constant_double_pool_count; i++) { //index 0 not used. Values 1..n-1
|
||||
constants.addDouble(ais.readDouble());
|
||||
}
|
||||
|
||||
//constant decimal
|
||||
if (minor_version >= MINORwithDECIMAL) {
|
||||
int constant_decimal_pool_count = ais.readU30();
|
||||
constants.constant_decimal = new ArrayList<>(constant_decimal_pool_count);
|
||||
if (constant_decimal_pool_count > 0) {
|
||||
constants.addDecimal(null);
|
||||
}
|
||||
for (int i = 1; i < constant_decimal_pool_count; i++) { //index 0 not used. Values 1..n-1
|
||||
constants.addDecimal(ais.readDecimal());
|
||||
}
|
||||
} else {
|
||||
constants.constant_decimal = new ArrayList<>(0);
|
||||
}
|
||||
|
||||
//constant string
|
||||
int constant_string_pool_count = ais.readU30();
|
||||
constants.constant_string = new ArrayList<>(constant_string_pool_count);
|
||||
stringOffsets = new long[constant_string_pool_count];
|
||||
if (constant_string_pool_count > 0) {
|
||||
constants.addString("");
|
||||
}
|
||||
for (int i = 1; i < constant_string_pool_count; i++) { //index 0 not used. Values 1..n-1
|
||||
long pos = ais.getPosition();
|
||||
constants.addString(ais.readString());
|
||||
stringOffsets[i] = pos;
|
||||
}
|
||||
|
||||
//constant namespace
|
||||
int constant_namespace_pool_count = ais.readU30();
|
||||
constants.constant_namespace = new ArrayList<>(constant_namespace_pool_count);
|
||||
if (constant_namespace_pool_count > 0) {
|
||||
constants.addNamespace(null);
|
||||
}
|
||||
for (int i = 1; i < constant_namespace_pool_count; i++) { //index 0 not used. Values 1..n-1
|
||||
constants.addNamespace(ais.readNamespace());
|
||||
}
|
||||
|
||||
//constant namespace set
|
||||
int constant_namespace_set_pool_count = ais.readU30();
|
||||
constants.constant_namespace_set = new ArrayList<>(constant_namespace_set_pool_count);
|
||||
if (constant_namespace_set_pool_count > 0) {
|
||||
constants.addNamespaceSet(null);
|
||||
}
|
||||
for (int i = 1; i < constant_namespace_set_pool_count; i++) { //index 0 not used. Values 1..n-1
|
||||
constants.addNamespaceSet(new NamespaceSet());
|
||||
int namespace_count = ais.readU30();
|
||||
constants.getNamespaceSet(i).namespaces = new int[namespace_count];
|
||||
for (int j = 0; j < namespace_count; j++) {
|
||||
constants.getNamespaceSet(i).namespaces[j] = ais.readU30();
|
||||
}
|
||||
}
|
||||
|
||||
//constant multiname
|
||||
int constant_multiname_pool_count = ais.readU30();
|
||||
constants.constant_multiname = new ArrayList<>(constant_multiname_pool_count);
|
||||
if (constant_multiname_pool_count > 0) {
|
||||
constants.addMultiname(null);
|
||||
}
|
||||
for (int i = 1; i < constant_multiname_pool_count; i++) { //index 0 not used. Values 1..n-1
|
||||
constants.addMultiname(ais.readMultiname());
|
||||
}
|
||||
|
||||
//method info
|
||||
int methods_count = ais.readU30();
|
||||
method_info = new ArrayList<>();//MethodInfo[methods_count];
|
||||
bodyIdxFromMethodIdx = new ArrayList<>(); //[methods_count];
|
||||
for (int i = 0; i < methods_count; i++) {
|
||||
method_info.add(ais.readMethodInfo());
|
||||
bodyIdxFromMethodIdx.add(-1);
|
||||
}
|
||||
|
||||
//metadata info
|
||||
int metadata_count = ais.readU30();
|
||||
metadata_info = new ArrayList<>();
|
||||
for (int i = 0; i < metadata_count; i++) {
|
||||
int name_index = ais.readU30();
|
||||
int values_count = ais.readU30();
|
||||
int[] keys = new int[values_count];
|
||||
for (int v = 0; v < values_count; v++) {
|
||||
keys[v] = ais.readU30();
|
||||
}
|
||||
int[] values = new int[values_count];
|
||||
for (int v = 0; v < values_count; v++) {
|
||||
values[v] = ais.readU30();
|
||||
}
|
||||
metadata_info.add(new MetadataInfo(name_index, keys, values));
|
||||
}
|
||||
|
||||
int class_count = ais.readU30();
|
||||
instance_info = new ArrayList<>(); //InstanceInfo[class_count];
|
||||
for (int i = 0; i < class_count; i++) {
|
||||
instance_info.add(ais.readInstanceInfo());
|
||||
}
|
||||
class_info = new ArrayList<>(); //ClassInfo[class_count];
|
||||
for (int i = 0; i < class_count; i++) {
|
||||
ClassInfo ci = new ClassInfo();
|
||||
ci.cinit_index = ais.readU30();
|
||||
ci.static_traits = ais.readTraits();
|
||||
class_info.add(ci);
|
||||
}
|
||||
int script_count = ais.readU30();
|
||||
script_info = new ArrayList<>(); //ScriptInfo[script_count];
|
||||
for (int i = 0; i < script_count; i++) {
|
||||
ScriptInfo si = new ScriptInfo();
|
||||
si.init_index = ais.readU30();
|
||||
si.traits = ais.readTraits();
|
||||
script_info.add(si);
|
||||
}
|
||||
|
||||
int bodies_count = ais.readU30();
|
||||
bodies = new ArrayList<>(); //MethodBody[bodies_count];
|
||||
for (int i = 0; i < bodies_count; i++) {
|
||||
MethodBody mb = new MethodBody();
|
||||
mb.method_info = ais.readU30();
|
||||
mb.max_stack = ais.readU30();
|
||||
mb.max_regs = ais.readU30();
|
||||
mb.init_scope_depth = ais.readU30();
|
||||
mb.max_scope_depth = ais.readU30();
|
||||
int code_length = ais.readU30();
|
||||
mb.codeBytes = ais.readBytes(code_length);
|
||||
try {
|
||||
mb.code = new AVM2Code(new ByteArrayInputStream(mb.codeBytes));
|
||||
} catch (UnknownInstructionCode re) {
|
||||
mb.code = new AVM2Code();
|
||||
Logger.getLogger(ABC.class.getName()).log(Level.SEVERE, null, re);
|
||||
}
|
||||
mb.code.compact();
|
||||
int ex_count = ais.readU30();
|
||||
mb.exceptions = new ABCException[ex_count];
|
||||
for (int j = 0; j < ex_count; j++) {
|
||||
ABCException abce = new ABCException();
|
||||
abce.start = ais.readU30();
|
||||
abce.end = ais.readU30();
|
||||
abce.target = ais.readU30();
|
||||
abce.type_index = ais.readU30();
|
||||
abce.name_index = ais.readU30();
|
||||
mb.exceptions[j] = abce;
|
||||
}
|
||||
mb.traits = ais.readTraits();
|
||||
bodies.add(mb);
|
||||
method_info.get(mb.method_info).setBody(mb);
|
||||
bodyIdxFromMethodIdx.set(mb.method_info, i);
|
||||
}
|
||||
loadNamespaceMap();
|
||||
/*for(int i=0;i<script_count;i++){
|
||||
MethodBody bod=bodies.get(bodyIdxFromMethodIdx.get(script_info.get(i).init_index));
|
||||
GraphTextWriter t=new HilightedTextWriter(Configuration.getCodeFormatting(),false);
|
||||
try {
|
||||
bod.toString("script", ScriptExportMode.PCODE, false,i, 0, this, null, constants, method_info, new Stack<GraphTargetItem>(), false, t ,new ArrayList<String>(), null);
|
||||
} catch (InterruptedException ex) {
|
||||
Logger.getLogger(ABC.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
System.out.println(""+t.toString());
|
||||
}
|
||||
System.exit(0);*/
|
||||
}
|
||||
|
||||
public void saveToStream(OutputStream os) throws IOException {
|
||||
ABCOutputStream aos = new ABCOutputStream(os);
|
||||
aos.writeU16(minor_version);
|
||||
aos.writeU16(major_version);
|
||||
|
||||
aos.writeU30(constants.getIntCount());
|
||||
for (int i = 1; i < constants.getIntCount(); i++) {
|
||||
aos.writeS32(constants.getInt(i));
|
||||
}
|
||||
aos.writeU30(constants.getUIntCount());
|
||||
for (int i = 1; i < constants.getUIntCount(); i++) {
|
||||
aos.writeU32(constants.getUInt(i));
|
||||
}
|
||||
|
||||
aos.writeU30(constants.getDoubleCount());
|
||||
for (int i = 1; i < constants.getDoubleCount(); i++) {
|
||||
aos.writeDouble(constants.getDouble(i));
|
||||
}
|
||||
|
||||
if (minor_version >= MINORwithDECIMAL) {
|
||||
aos.writeU30(constants.getDecimalCount());
|
||||
for (int i = 1; i < constants.getDecimalCount(); i++) {
|
||||
aos.writeDecimal(constants.getDecimal(i));
|
||||
}
|
||||
}
|
||||
|
||||
aos.writeU30(constants.getStringCount());
|
||||
for (int i = 1; i < constants.getStringCount(); i++) {
|
||||
aos.writeString(constants.getString(i));
|
||||
}
|
||||
|
||||
aos.writeU30(constants.getNamespaceCount());
|
||||
for (int i = 1; i < constants.getNamespaceCount(); i++) {
|
||||
aos.writeNamespace(constants.getNamespace(i));
|
||||
}
|
||||
|
||||
aos.writeU30(constants.getNamespaceSetCount());
|
||||
for (int i = 1; i < constants.getNamespaceSetCount(); i++) {
|
||||
aos.writeU30(constants.getNamespaceSet(i).namespaces.length);
|
||||
for (int j = 0; j < constants.getNamespaceSet(i).namespaces.length; j++) {
|
||||
aos.writeU30(constants.getNamespaceSet(i).namespaces[j]);
|
||||
}
|
||||
}
|
||||
|
||||
aos.writeU30(constants.getMultinameCount());
|
||||
for (int i = 1; i < constants.getMultinameCount(); i++) {
|
||||
aos.writeMultiname(constants.getMultiname(i));
|
||||
}
|
||||
|
||||
aos.writeU30(method_info.size());
|
||||
for (MethodInfo mi : method_info) {
|
||||
aos.writeMethodInfo(mi);
|
||||
}
|
||||
|
||||
aos.writeU30(metadata_info.size());
|
||||
for (MetadataInfo mi : metadata_info) {
|
||||
aos.writeU30(mi.name_index);
|
||||
aos.writeU30(mi.values.length);
|
||||
for (int j = 0; j < mi.values.length; j++) {
|
||||
aos.writeU30(mi.keys[j]);
|
||||
}
|
||||
for (int j = 0; j < mi.values.length; j++) {
|
||||
aos.writeU30(mi.values[j]);
|
||||
}
|
||||
}
|
||||
|
||||
aos.writeU30(class_info.size());
|
||||
for (InstanceInfo ii : instance_info) {
|
||||
aos.writeInstanceInfo(ii);
|
||||
}
|
||||
for (ClassInfo ci : class_info) {
|
||||
aos.writeU30(ci.cinit_index);
|
||||
aos.writeTraits(ci.static_traits);
|
||||
}
|
||||
aos.writeU30(script_info.size());
|
||||
for (ScriptInfo si : script_info) {
|
||||
aos.writeU30(si.init_index);
|
||||
aos.writeTraits(si.traits);
|
||||
}
|
||||
|
||||
aos.writeU30(bodies.size());
|
||||
for (MethodBody mb : bodies) {
|
||||
aos.writeU30(mb.method_info);
|
||||
aos.writeU30(mb.max_stack);
|
||||
aos.writeU30(mb.max_regs);
|
||||
aos.writeU30(mb.init_scope_depth);
|
||||
aos.writeU30(mb.max_scope_depth);
|
||||
byte[] codeBytes = mb.code.getBytes();
|
||||
aos.writeU30(codeBytes.length);
|
||||
aos.write(codeBytes);
|
||||
aos.writeU30(mb.exceptions.length);
|
||||
for (int j = 0; j < mb.exceptions.length; j++) {
|
||||
aos.writeU30(mb.exceptions[j].start);
|
||||
aos.writeU30(mb.exceptions[j].end);
|
||||
aos.writeU30(mb.exceptions[j].target);
|
||||
aos.writeU30(mb.exceptions[j].type_index);
|
||||
aos.writeU30(mb.exceptions[j].name_index);
|
||||
}
|
||||
aos.writeTraits(mb.traits);
|
||||
}
|
||||
}
|
||||
|
||||
public MethodBody findBody(int methodInfo) {
|
||||
if (methodInfo < 0) {
|
||||
return null;
|
||||
}
|
||||
return method_info.get(methodInfo).getBody();
|
||||
}
|
||||
|
||||
public int findBodyIndex(int methodInfo) {
|
||||
if (methodInfo == -1) {
|
||||
return -1;
|
||||
}
|
||||
return bodyIdxFromMethodIdx.get(methodInfo);
|
||||
}
|
||||
|
||||
public MethodBody findBodyByClassAndName(String className, String methodName) {
|
||||
for (int i = 0; i < instance_info.size(); i++) {
|
||||
if (className.equals(constants.getMultiname(instance_info.get(i).name_index).getName(constants, new ArrayList<String>()))) {
|
||||
for (Trait t : instance_info.get(i).instance_traits.traits) {
|
||||
if (t instanceof TraitMethodGetterSetter) {
|
||||
TraitMethodGetterSetter t2 = (TraitMethodGetterSetter) t;
|
||||
if (methodName.equals(t2.getName(this).getName(constants, new ArrayList<String>()))) {
|
||||
for (MethodBody body : bodies) {
|
||||
if (body.method_info == t2.method_info) {
|
||||
return body;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//break;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < class_info.size(); i++) {
|
||||
if (className.equals(constants.getMultiname(instance_info.get(i).name_index).getName(constants, new ArrayList<String>()))) {
|
||||
for (Trait t : class_info.get(i).static_traits.traits) {
|
||||
if (t instanceof TraitMethodGetterSetter) {
|
||||
TraitMethodGetterSetter t2 = (TraitMethodGetterSetter) t;
|
||||
if (methodName.equals(t2.getName(this).getName(constants, new ArrayList<String>()))) {
|
||||
for (MethodBody body : bodies) {
|
||||
if (body.method_info == t2.method_info) {
|
||||
return body;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//break;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isStaticTraitId(int classIndex, int traitId) {
|
||||
if (traitId < class_info.get(classIndex).static_traits.traits.size()) {
|
||||
return true;
|
||||
} else if (traitId < class_info.get(classIndex).static_traits.traits.size() + instance_info.get(classIndex).instance_traits.traits.size()) {
|
||||
return false;
|
||||
} else {
|
||||
return true; //Can be class or instance initializer
|
||||
}
|
||||
}
|
||||
|
||||
public Trait findTraitByTraitId(int classIndex, int traitId) {
|
||||
if (classIndex == -1) {
|
||||
return null;
|
||||
}
|
||||
if (traitId < class_info.get(classIndex).static_traits.traits.size()) {
|
||||
return class_info.get(classIndex).static_traits.traits.get(traitId);
|
||||
} else if (traitId < class_info.get(classIndex).static_traits.traits.size() + instance_info.get(classIndex).instance_traits.traits.size()) {
|
||||
traitId -= class_info.get(classIndex).static_traits.traits.size();
|
||||
return instance_info.get(classIndex).instance_traits.traits.get(traitId);
|
||||
} else {
|
||||
return null; //Can be class or instance initializer
|
||||
}
|
||||
}
|
||||
|
||||
public int findMethodIdByTraitId(int classIndex, int traitId) {
|
||||
if (classIndex == -1) {
|
||||
return -1;
|
||||
}
|
||||
if (traitId < class_info.get(classIndex).static_traits.traits.size()) {
|
||||
if (class_info.get(classIndex).static_traits.traits.get(traitId) instanceof TraitMethodGetterSetter) {
|
||||
return ((TraitMethodGetterSetter) class_info.get(classIndex).static_traits.traits.get(traitId)).method_info;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} else if (traitId < class_info.get(classIndex).static_traits.traits.size() + instance_info.get(classIndex).instance_traits.traits.size()) {
|
||||
traitId -= class_info.get(classIndex).static_traits.traits.size();
|
||||
if (instance_info.get(classIndex).instance_traits.traits.get(traitId) instanceof TraitMethodGetterSetter) {
|
||||
return ((TraitMethodGetterSetter) instance_info.get(classIndex).instance_traits.traits.get(traitId)).method_info;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
traitId -= class_info.get(classIndex).static_traits.traits.size() + instance_info.get(classIndex).instance_traits.traits.size();
|
||||
if (traitId == 0) {
|
||||
return instance_info.get(classIndex).iinit_index;
|
||||
} else if (traitId == 1) {
|
||||
return class_info.get(classIndex).cinit_index;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Map from multiname index of namespace value to namespace name**/
|
||||
private HashMap<String, String> namespaceMap;
|
||||
|
||||
private void loadNamespaceMap() {
|
||||
namespaceMap = new HashMap<>();
|
||||
for (ScriptInfo si : script_info) {
|
||||
for (Trait t : si.traits.traits) {
|
||||
if (t instanceof TraitSlotConst) {
|
||||
TraitSlotConst s = ((TraitSlotConst) t);
|
||||
if (s.isNamespace()) {
|
||||
String key = constants.getNamespace(s.value_index).getName(constants); //assume not null
|
||||
String val = constants.getMultiname(s.name_index).getNameWithNamespace(constants);
|
||||
namespaceMap.put(key, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String nsValueToName(String value) {
|
||||
if (namespaceMap.containsKey(value)) {
|
||||
return namespaceMap.get(value);
|
||||
} else {
|
||||
String ns = deobfuscation.builtInNs(value);
|
||||
if (ns == null) {
|
||||
return "";
|
||||
} else {
|
||||
return ns;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<MyEntry<ClassPath, ScriptPack>> getScriptPacks() {
|
||||
List<MyEntry<ClassPath, ScriptPack>> ret = new ArrayList<>();
|
||||
for (int i = 0; i < script_info.size(); i++) {
|
||||
ret.addAll(script_info.get(i).getPacks(this, i));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void dump(OutputStream os) {
|
||||
Utf8PrintWriter output;
|
||||
output = new Utf8PrintWriter(os);
|
||||
constants.dump(output);
|
||||
for (int i = 0; i < method_info.size(); i++) {
|
||||
output.println("MethodInfo[" + i + "]:" + method_info.get(i).toString(constants, new ArrayList<String>()));
|
||||
}
|
||||
for (int i = 0; i < metadata_info.size(); i++) {
|
||||
output.println("MetadataInfo[" + i + "]:" + metadata_info.get(i).toString(constants));
|
||||
}
|
||||
for (int i = 0; i < instance_info.size(); i++) {
|
||||
output.println("InstanceInfo[" + i + "]:" + instance_info.get(i).toString(this, new ArrayList<String>()));
|
||||
}
|
||||
for (int i = 0; i < class_info.size(); i++) {
|
||||
output.println("ClassInfo[" + i + "]:" + class_info.get(i).toString(this, new ArrayList<String>()));
|
||||
}
|
||||
for (int i = 0; i < script_info.size(); i++) {
|
||||
output.println("ScriptInfo[" + i + "]:" + script_info.get(i).toString(this, new ArrayList<String>()));
|
||||
}
|
||||
for (int i = 0; i < bodies.size(); i++) {
|
||||
output.println("MethodBody[" + i + "]:"); //+ bodies[i].toString(this, constants, method_info));
|
||||
}
|
||||
}
|
||||
|
||||
private void checkMultinameUsedInMethod(int multinameIndex, int methodInfo, List<MultinameUsage> ret, int classIndex, int traitIndex, boolean isStatic, boolean isInitializer, Traits traits, int parentTraitIndex) {
|
||||
for (int p = 0; p < method_info.get(methodInfo).param_types.length; p++) {
|
||||
if (method_info.get(methodInfo).param_types[p] == multinameIndex) {
|
||||
ret.add(new MethodParamsMultinameUsage(multinameIndex, classIndex, traitIndex, isStatic, isInitializer, traits, parentTraitIndex));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (method_info.get(methodInfo).ret_type == multinameIndex) {
|
||||
ret.add(new MethodReturnTypeMultinameUsage(multinameIndex, classIndex, traitIndex, isStatic, isInitializer, traits, parentTraitIndex));
|
||||
}
|
||||
MethodBody body = findBody(methodInfo);
|
||||
if (body != null) {
|
||||
findMultinameUsageInTraits(body.traits, multinameIndex, isStatic, classIndex, ret, traitIndex);
|
||||
for (ABCException e : body.exceptions) {
|
||||
if ((e.name_index == multinameIndex) || (e.type_index == multinameIndex)) {
|
||||
ret.add(new MethodBodyMultinameUsage(multinameIndex, classIndex, traitIndex, isStatic, isInitializer, traits, parentTraitIndex));
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (AVM2Instruction ins : body.code.code) {
|
||||
for (int o = 0; o < ins.definition.operands.length; o++) {
|
||||
if (ins.definition.operands[o] == AVM2Code.DAT_MULTINAME_INDEX) {
|
||||
if (ins.operands[o] == multinameIndex) {
|
||||
ret.add(new MethodBodyMultinameUsage(multinameIndex, classIndex, traitIndex, isStatic, isInitializer, traits, parentTraitIndex));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void findMultinameUsageInTraits(Traits traits, int multinameIndex, boolean isStatic, int classIndex, List<MultinameUsage> ret, int parentTraitIndex) {
|
||||
for (int t = 0; t < traits.traits.size(); t++) {
|
||||
if (traits.traits.get(t) instanceof TraitSlotConst) {
|
||||
TraitSlotConst tsc = (TraitSlotConst) traits.traits.get(t);
|
||||
if (tsc.name_index == multinameIndex) {
|
||||
ret.add(new ConstVarNameMultinameUsage(multinameIndex, classIndex, t, isStatic, traits, parentTraitIndex));
|
||||
}
|
||||
if (tsc.type_index == multinameIndex) {
|
||||
ret.add(new ConstVarTypeMultinameUsage(multinameIndex, classIndex, t, isStatic, traits, parentTraitIndex));
|
||||
}
|
||||
}
|
||||
if (traits.traits.get(t) instanceof TraitMethodGetterSetter) {
|
||||
TraitMethodGetterSetter tmgs = (TraitMethodGetterSetter) traits.traits.get(t);
|
||||
if (tmgs.name_index == multinameIndex) {
|
||||
ret.add(new MethodNameMultinameUsage(multinameIndex, classIndex, t, isStatic, false, traits, parentTraitIndex));
|
||||
}
|
||||
checkMultinameUsedInMethod(multinameIndex, tmgs.method_info, ret, classIndex, t, isStatic, false, traits, parentTraitIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<MultinameUsage> findMultinameUsage(int multinameIndex) {
|
||||
List<MultinameUsage> ret = new ArrayList<>();
|
||||
if (multinameIndex == 0) {
|
||||
return ret;
|
||||
}
|
||||
for (int c = 0; c < instance_info.size(); c++) {
|
||||
if (instance_info.get(c).name_index == multinameIndex) {
|
||||
ret.add(new ClassNameMultinameUsage(multinameIndex, c));
|
||||
}
|
||||
if (instance_info.get(c).super_index == multinameIndex) {
|
||||
ret.add(new ExtendsMultinameUsage(multinameIndex, c));
|
||||
}
|
||||
for (int i = 0; i < instance_info.get(c).interfaces.length; i++) {
|
||||
if (instance_info.get(c).interfaces[i] == multinameIndex) {
|
||||
ret.add(new ImplementsMultinameUsage(multinameIndex, c));
|
||||
}
|
||||
}
|
||||
checkMultinameUsedInMethod(multinameIndex, instance_info.get(c).iinit_index, ret, c, 0, false, true, null, -1);
|
||||
checkMultinameUsedInMethod(multinameIndex, class_info.get(c).cinit_index, ret, c, 0, true, true, null, -1);
|
||||
findMultinameUsageInTraits(instance_info.get(c).instance_traits, multinameIndex, false, c, ret, -1);
|
||||
findMultinameUsageInTraits(class_info.get(c).static_traits, multinameIndex, true, c, ret, -1);
|
||||
}
|
||||
loopm:
|
||||
for (int m = 1; m < constants.getMultinameCount(); m++) {
|
||||
if (constants.getMultiname(m).kind == Multiname.TYPENAME) {
|
||||
if (constants.getMultiname(m).qname_index == multinameIndex) {
|
||||
ret.add(new TypeNameMultinameUsage(m));
|
||||
continue;
|
||||
}
|
||||
for (int mp : constants.getMultiname(m).params) {
|
||||
if (mp == multinameIndex) {
|
||||
ret.add(new TypeNameMultinameUsage(m));
|
||||
continue loopm;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public int findMethodInfoByName(int classId, String methodName) {
|
||||
if (classId > -1) {
|
||||
for (Trait t : instance_info.get(classId).instance_traits.traits) {
|
||||
if (t instanceof TraitMethodGetterSetter) {
|
||||
if (t.getName(this).getName(constants, new ArrayList<String>()).equals(methodName)) {
|
||||
return ((TraitMethodGetterSetter) t).method_info;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int findMethodBodyByName(int classId, String methodName) {
|
||||
if (classId > -1) {
|
||||
for (Trait t : instance_info.get(classId).instance_traits.traits) {
|
||||
if (t instanceof TraitMethodGetterSetter) {
|
||||
if (t.getName(this).getName(constants, new ArrayList<String>()).equals(methodName)) {
|
||||
return findBodyIndex(((TraitMethodGetterSetter) t).method_info);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int findMethodBodyByName(String className, String methodName) {
|
||||
int classId = findClassByName(className);
|
||||
return findMethodBodyByName(classId, methodName);
|
||||
}
|
||||
|
||||
public int findClassByName(String name) {
|
||||
for (int c = 0; c < instance_info.size(); c++) {
|
||||
String s = constants.getMultiname(instance_info.get(c).name_index).getNameWithNamespace(constants);
|
||||
if (name.equals(s)) {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public ScriptPack findScriptPackByPath(String name) {
|
||||
List<MyEntry<ClassPath, ScriptPack>> packs = getScriptPacks();
|
||||
for (MyEntry<ClassPath, ScriptPack> en : packs) {
|
||||
if (en.key.toString().equals(name)) {
|
||||
return en.value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
391
src/com/jpexs/decompiler/flash/abc/ABCInputStream.java
Normal file
391
src/com/jpexs/decompiler/flash/abc/ABCInputStream.java
Normal file
@@ -0,0 +1,391 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.types.Decimal;
|
||||
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.helpers.utf8.Utf8Helper;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ABCInputStream extends InputStream {
|
||||
|
||||
private static final int CLASS_PROTECTED_NS = 8;
|
||||
private static final int ATTR_METADATA = 4;
|
||||
private final InputStream is;
|
||||
private long bytesRead = 0;
|
||||
private ByteArrayOutputStream bufferOs = null;
|
||||
public static final boolean DEBUG_READ = false;
|
||||
|
||||
public void startBuffer() {
|
||||
if (bufferOs == null) {
|
||||
bufferOs = new ByteArrayOutputStream();
|
||||
} else {
|
||||
bufferOs.reset();
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] stopBuffer() {
|
||||
if (bufferOs == null) {
|
||||
return new byte[0];
|
||||
}
|
||||
byte[] ret = bufferOs.toByteArray();
|
||||
bufferOs.reset();
|
||||
return ret;
|
||||
}
|
||||
|
||||
public ABCInputStream(InputStream is) {
|
||||
this.is = is;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
bytesRead++;
|
||||
int i = is.read();
|
||||
if (DEBUG_READ) {
|
||||
System.out.println("Read:0x" + Integer.toHexString(i));
|
||||
}
|
||||
if (bufferOs != null) {
|
||||
if (i != -1) {
|
||||
bufferOs.write(i);
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] b) throws IOException {
|
||||
int currBytesRead = is.read(b);
|
||||
bytesRead += currBytesRead;
|
||||
if (DEBUG_READ) {
|
||||
StringBuilder sb = new StringBuilder("Read[");
|
||||
sb.append(currBytesRead);
|
||||
sb.append('/');
|
||||
sb.append(b.length);
|
||||
sb.append("]: ");
|
||||
for (int jj = 0; jj < currBytesRead; jj++) {
|
||||
sb.append("0x");
|
||||
sb.append(Integer.toHexString(b[jj]));
|
||||
sb.append(' ');
|
||||
}
|
||||
System.out.println(sb.toString());
|
||||
}
|
||||
if (bufferOs != null) {
|
||||
if (currBytesRead > 0) {
|
||||
bufferOs.write(b, 0, currBytesRead);
|
||||
}
|
||||
}
|
||||
return currBytesRead;
|
||||
}
|
||||
|
||||
;
|
||||
|
||||
public int readU8() throws IOException {
|
||||
return read();
|
||||
}
|
||||
|
||||
public long readU32() throws IOException {
|
||||
int i;
|
||||
long ret = 0;
|
||||
int bytePos = 0;
|
||||
int byteCount = 0;
|
||||
boolean nextByte;
|
||||
do {
|
||||
i = read();
|
||||
nextByte = (i >> 7) == 1;
|
||||
i &= 0x7f;
|
||||
ret += (((long) i) << bytePos);
|
||||
byteCount++;
|
||||
bytePos += 7;
|
||||
} while (nextByte);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public int readU30() throws IOException {
|
||||
return (int) readU32();
|
||||
}
|
||||
|
||||
public int readS24() throws IOException {
|
||||
int ret = (read()) + (read() << 8) + (read() << 16);
|
||||
|
||||
if ((ret >> 23) == 1) {
|
||||
ret |= 0xff000000;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public int readU16() throws IOException {
|
||||
return (read()) + (read() << 8);
|
||||
}
|
||||
|
||||
public long readS32() throws IOException {
|
||||
int i;
|
||||
long ret = 0;
|
||||
int bytePos = 0;
|
||||
int byteCount = 0;
|
||||
boolean nextByte;
|
||||
do {
|
||||
i = read();
|
||||
nextByte = (i >> 7) == 1;
|
||||
i &= 0x7f;
|
||||
ret += (i << bytePos);
|
||||
byteCount++;
|
||||
bytePos += 7;
|
||||
if (bytePos == 35) {
|
||||
if ((ret >> 31) == 1) {
|
||||
ret = -(ret & 0x7fffffff);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} while (nextByte);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int available() throws IOException {
|
||||
return is.available();
|
||||
}
|
||||
|
||||
public final long readLong() throws IOException {
|
||||
byte[] readBuffer = safeRead(8);
|
||||
return (((long) readBuffer[7] << 56)
|
||||
+ ((long) (readBuffer[6] & 255) << 48)
|
||||
+ ((long) (readBuffer[5] & 255) << 40)
|
||||
+ ((long) (readBuffer[4] & 255) << 32)
|
||||
+ ((long) (readBuffer[3] & 255) << 24)
|
||||
+ ((readBuffer[2] & 255) << 16)
|
||||
+ ((readBuffer[1] & 255) << 8)
|
||||
+ ((readBuffer[0] & 255)));
|
||||
}
|
||||
|
||||
public double readDouble() throws IOException {
|
||||
long el = readLong();
|
||||
double ret = Double.longBitsToDouble(el);
|
||||
return ret;
|
||||
}
|
||||
|
||||
private byte[] safeRead(int count) throws IOException {
|
||||
byte[] ret = new byte[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
ret[i] = (byte) read();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public Namespace readNamespace() throws IOException {
|
||||
int kind = read();
|
||||
int name_index = 0;
|
||||
for (int k = 0; k < Namespace.nameSpaceKinds.length; k++) {
|
||||
if (Namespace.nameSpaceKinds[k] == kind) {
|
||||
name_index = readU30();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return new Namespace(kind, name_index);
|
||||
}
|
||||
|
||||
public Multiname readMultiname() throws IOException {
|
||||
int kind = readU8();
|
||||
int namespace_index = 0;
|
||||
int name_index = 0;
|
||||
int namespace_set_index = 0;
|
||||
int qname_index = 0;
|
||||
List<Integer> params = new ArrayList<>();
|
||||
|
||||
if ((kind == Multiname.QNAME) || (kind == Multiname.QNAMEA)) {
|
||||
namespace_index = readU30();
|
||||
name_index = readU30();
|
||||
} else if ((kind == Multiname.RTQNAME) || (kind == Multiname.RTQNAMEA)) {
|
||||
name_index = readU30();
|
||||
} else if ((kind == Multiname.RTQNAMEL) || (kind == Multiname.RTQNAMELA)) {
|
||||
|
||||
} else if ((kind == Multiname.MULTINAME) || (kind == Multiname.MULTINAMEA)) {
|
||||
name_index = readU30();
|
||||
namespace_set_index = readU30();
|
||||
} else if ((kind == Multiname.MULTINAMEL) || (kind == Multiname.MULTINAMELA)) {
|
||||
namespace_set_index = readU30();
|
||||
} else if (kind == Multiname.TYPENAME) {
|
||||
qname_index = readU30(); //Multiname index!!!
|
||||
int paramsLength = readU30();
|
||||
for (int i = 0; i < paramsLength; i++) {
|
||||
params.add(readU30()); //multiname indices!
|
||||
}
|
||||
} else {
|
||||
throw new IOException("Unknown kind of Multiname:0x" + Integer.toHexString(kind));
|
||||
}
|
||||
|
||||
return new Multiname(kind, name_index, namespace_index, namespace_set_index, qname_index, params);
|
||||
}
|
||||
|
||||
public MethodInfo readMethodInfo() throws IOException {
|
||||
int param_count = readU30();
|
||||
int ret_type = readU30();
|
||||
int[] param_types = new int[param_count];
|
||||
for (int i = 0; i < param_count; i++) {
|
||||
param_types[i] = readU30();
|
||||
}
|
||||
int name_index = readU30();
|
||||
int flags = read();
|
||||
|
||||
//// 1=need_arguments, 2=need_activation, 4=need_rest 8=has_optional (16=ignore_rest, 32=explicit,) 64=setsdxns, 128=has_paramnames
|
||||
ValueKind[] optional = new ValueKind[0];
|
||||
if ((flags & 8) == 8) { //if has_optional
|
||||
int optional_count = readU30();
|
||||
optional = new ValueKind[optional_count];
|
||||
for (int i = 0; i < optional_count; i++) {
|
||||
optional[i] = new ValueKind(readU30(), read());
|
||||
}
|
||||
}
|
||||
|
||||
int[] param_names = new int[param_count];
|
||||
if ((flags & 128) == 128) { //if has_paramnames
|
||||
for (int i = 0; i < param_count; i++) {
|
||||
param_names[i] = readU30();
|
||||
}
|
||||
}
|
||||
return new MethodInfo(param_types, ret_type, name_index, flags, optional, param_names);
|
||||
}
|
||||
|
||||
public Trait readTrait() throws IOException {
|
||||
long pos = getPosition();
|
||||
startBuffer();
|
||||
int name_index = readU30();
|
||||
int kind = read();
|
||||
int kindType = 0xf & kind;
|
||||
int kindFlags = kind >> 4;
|
||||
Trait trait;
|
||||
|
||||
switch (kindType) {
|
||||
case 0: //slot
|
||||
case 6: //const
|
||||
TraitSlotConst t1 = new TraitSlotConst();
|
||||
t1.slot_id = readU30();
|
||||
t1.type_index = readU30();
|
||||
t1.value_index = readU30();
|
||||
if (t1.value_index != 0) {
|
||||
t1.value_kind = read();
|
||||
}
|
||||
trait = t1;
|
||||
break;
|
||||
case 1: //method
|
||||
case 2: //getter
|
||||
case 3: //setter
|
||||
TraitMethodGetterSetter t2 = new TraitMethodGetterSetter();
|
||||
t2.disp_id = readU30();
|
||||
t2.method_info = readU30();
|
||||
trait = t2;
|
||||
break;
|
||||
case 4: //class
|
||||
TraitClass t3 = new TraitClass();
|
||||
t3.slot_id = readU30();
|
||||
t3.class_info = readU30();
|
||||
trait = t3;
|
||||
break;
|
||||
case 5: //function
|
||||
TraitFunction t4 = new TraitFunction();
|
||||
t4.slot_id = readU30();
|
||||
t4.method_info = readU30();
|
||||
trait = t4;
|
||||
break;
|
||||
default:
|
||||
throw new IOException("Unknown trait kind:" + kind);
|
||||
}
|
||||
trait.fileOffset = pos;
|
||||
trait.kindType = kindType;
|
||||
trait.kindFlags = kindFlags;
|
||||
trait.name_index = name_index;
|
||||
if ((kindFlags & ATTR_METADATA) != 0) {
|
||||
int metadata_count = readU30();
|
||||
trait.metadata = new int[metadata_count];
|
||||
for (int i = 0; i < metadata_count; i++) {
|
||||
trait.metadata[i] = readU30();
|
||||
}
|
||||
}
|
||||
trait.bytes = stopBuffer();
|
||||
return trait;
|
||||
}
|
||||
|
||||
public Traits readTraits() throws IOException {
|
||||
int count = readU30();
|
||||
Traits traits = new Traits();
|
||||
traits.traits = new ArrayList<>();
|
||||
for (int i = 0; i < count; i++) {
|
||||
traits.traits.add(readTrait());
|
||||
}
|
||||
return traits;
|
||||
}
|
||||
|
||||
public byte[] readBytes(int count) throws IOException {
|
||||
byte[] ret = new byte[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
ret[i] = (byte) read();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public Decimal readDecimal() throws IOException {
|
||||
byte[] data = readBytes(16);
|
||||
return new Decimal(data);
|
||||
}
|
||||
|
||||
public InstanceInfo readInstanceInfo() throws IOException {
|
||||
InstanceInfo ret = new InstanceInfo();
|
||||
ret.name_index = readU30();
|
||||
ret.super_index = readU30();
|
||||
ret.flags = read();
|
||||
if ((ret.flags & CLASS_PROTECTED_NS) != 0) {
|
||||
ret.protectedNS = readU30();
|
||||
}
|
||||
int interfaces_count = readU30();
|
||||
ret.interfaces = new int[interfaces_count];
|
||||
for (int i = 0; i < interfaces_count; i++) {
|
||||
ret.interfaces[i] = readU30();
|
||||
}
|
||||
ret.iinit_index = readU30();
|
||||
ret.instance_traits = readTraits();
|
||||
return ret;
|
||||
}
|
||||
|
||||
public String readString() throws IOException {
|
||||
int length = readU30();
|
||||
byte[] b = safeRead(length);
|
||||
String r = new String(b, Utf8Helper.charset);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/*public void markStart(){
|
||||
bytesRead=0;
|
||||
}*/
|
||||
public long getPosition() {
|
||||
return bytesRead;
|
||||
}
|
||||
}
|
||||
286
src/com/jpexs/decompiler/flash/abc/ABCOutputStream.java
Normal file
286
src/com/jpexs/decompiler/flash/abc/ABCOutputStream.java
Normal file
@@ -0,0 +1,286 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.types.Decimal;
|
||||
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.helpers.utf8.Utf8Helper;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class ABCOutputStream extends OutputStream {
|
||||
|
||||
private final OutputStream os;
|
||||
|
||||
public ABCOutputStream(OutputStream os) {
|
||||
this.os = os;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
os.write(b);
|
||||
}
|
||||
|
||||
public void writeU30(long value) throws IOException {
|
||||
writeS32(value);
|
||||
/*boolean loop = true;
|
||||
boolean underZero=value<0;
|
||||
|
||||
if(underZero){
|
||||
value = value & 0xFFFFFFFF;
|
||||
}else{
|
||||
value = value & 0x7FFFFFFF;
|
||||
}
|
||||
do {
|
||||
int ret = (int) (value & 0x7F);
|
||||
if (value < 0x80) {
|
||||
loop = false;
|
||||
}
|
||||
if (value > 0x7F) {
|
||||
ret += 0x80;
|
||||
}
|
||||
write(ret);
|
||||
value = value >> 7;
|
||||
} while (loop);
|
||||
*/
|
||||
}
|
||||
|
||||
public void writeU32(long value) throws IOException {
|
||||
boolean loop = true;
|
||||
value &= 0xFFFFFFFF;
|
||||
do {
|
||||
int ret = (int) (value & 0x7F);
|
||||
if (value < 0x80) {
|
||||
loop = false;
|
||||
}
|
||||
if (value > 0x7F) {
|
||||
ret += 0x80;
|
||||
}
|
||||
write(ret);
|
||||
value >>= 7;
|
||||
} while (loop);
|
||||
}
|
||||
|
||||
public void writeS24(long value) throws IOException {
|
||||
int ret = (int) (value & 0xff);
|
||||
write(ret);
|
||||
value >>= 8;
|
||||
ret = (int) (value & 0xff);
|
||||
write(ret);
|
||||
value >>= 8;
|
||||
ret = (int) (value & 0xff);
|
||||
write(ret);
|
||||
}
|
||||
|
||||
public void writeS32(long value) throws IOException {
|
||||
boolean belowZero = value < 0;
|
||||
/*if (belowZero) {
|
||||
value = -value;
|
||||
}*/
|
||||
int bitcount = 0;
|
||||
boolean loop = true;
|
||||
//value = value & 0xFFFFFFFF;
|
||||
do {
|
||||
bitcount += 7;
|
||||
int ret = (int) (value & 0x7F);
|
||||
if (value < 0x80) {
|
||||
if (belowZero) { //&& bitcount < 35
|
||||
ret += 0x80;
|
||||
} else {
|
||||
loop = false;
|
||||
}
|
||||
} else {
|
||||
ret += 0x80;
|
||||
}
|
||||
|
||||
if (bitcount == 35) {
|
||||
ret &= 0xf;
|
||||
}
|
||||
write(ret);
|
||||
if (bitcount == 35) {
|
||||
break;
|
||||
}
|
||||
value >>= 7;
|
||||
} while (loop);
|
||||
}
|
||||
|
||||
public void writeLong(long value) throws IOException {
|
||||
byte[] writeBuffer = new byte[8];
|
||||
writeBuffer[7] = (byte) (value >>> 56);
|
||||
writeBuffer[6] = (byte) (value >>> 48);
|
||||
writeBuffer[5] = (byte) (value >>> 40);
|
||||
writeBuffer[4] = (byte) (value >>> 32);
|
||||
writeBuffer[3] = (byte) (value >>> 24);
|
||||
writeBuffer[2] = (byte) (value >>> 16);
|
||||
writeBuffer[1] = (byte) (value >>> 8);
|
||||
writeBuffer[0] = (byte) (value);
|
||||
write(writeBuffer);
|
||||
}
|
||||
|
||||
public void writeDouble(double value) throws IOException {
|
||||
writeLong(Double.doubleToLongBits(value));
|
||||
}
|
||||
|
||||
public void writeU8(int value) throws IOException {
|
||||
write(value);
|
||||
}
|
||||
|
||||
public void writeU16(int value) throws IOException {
|
||||
write(value & 0xff);
|
||||
write((value >> 8) & 0xff);
|
||||
}
|
||||
|
||||
public void writeString(String s) throws IOException {
|
||||
byte[] sbytes = Utf8Helper.getBytes(s);
|
||||
writeU30(sbytes.length);
|
||||
write(sbytes);
|
||||
}
|
||||
|
||||
public void writeNamespace(Namespace ns) throws IOException {
|
||||
write(ns.kind);
|
||||
boolean found = false;
|
||||
for (int k = 0; k < Namespace.nameSpaceKinds.length; k++) {
|
||||
if (Namespace.nameSpaceKinds[k] == ns.kind) {
|
||||
writeU30(ns.name_index);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
throw new RuntimeException("Invalid ns kind:" + ns.kind);
|
||||
}
|
||||
}
|
||||
|
||||
public void writeMultiname(Multiname m) throws IOException {
|
||||
writeU8(m.kind);
|
||||
if ((m.kind == 7) || (m.kind == 0xd)) { // CONSTANT_QName and CONSTANT_QNameA.
|
||||
writeU30(m.namespace_index);
|
||||
writeU30(m.name_index);
|
||||
}
|
||||
if ((m.kind == 9) || (m.kind == 0xe)) { // CONSTANT_Multiname and CONSTANT_MultinameA.
|
||||
writeU30(m.name_index);
|
||||
writeU30(m.namespace_set_index);
|
||||
}
|
||||
if ((m.kind == 0xf) || (m.kind == 0x10)) { //CONSTANT_RTQName and CONSTANT_RTQNameA
|
||||
writeU30(m.name_index);
|
||||
}
|
||||
if ((m.kind == 0x1B) || (m.kind == 0x1C)) { //CONSTANT_MultinameL and CONSTANT_MultinameLA
|
||||
writeU30(m.namespace_set_index);
|
||||
}
|
||||
if (m.kind == 0x1D) {
|
||||
writeU30(m.qname_index);
|
||||
writeU30(m.params.size());
|
||||
for (int i = 0; i < m.params.size(); i++) {
|
||||
writeU30(m.params.get(i));
|
||||
}
|
||||
}
|
||||
//kind==0x11,0x12 nothing CONSTANT_RTQNameL and CONSTANT_RTQNameLA.
|
||||
}
|
||||
|
||||
public void writeMethodInfo(MethodInfo mi) throws IOException {
|
||||
writeU30(mi.param_types.length);
|
||||
writeU30(mi.ret_type);
|
||||
for (int i = 0; i < mi.param_types.length; i++) {
|
||||
writeU30(mi.param_types[i]);
|
||||
}
|
||||
writeU30(mi.name_index);
|
||||
write(mi.flags);
|
||||
if ((mi.flags & 8) == 8) {
|
||||
writeU30(mi.optional.length);
|
||||
for (int i = 0; i < mi.optional.length; i++) {
|
||||
writeU30(mi.optional[i].value_index);
|
||||
write(mi.optional[i].value_kind);
|
||||
}
|
||||
}
|
||||
|
||||
if ((mi.flags & 128) == 128) { //if has_paramnames
|
||||
for (int i = 0; i < mi.paramNames.length; i++) {
|
||||
writeU30(mi.paramNames[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void writeTrait(Trait t) throws IOException {
|
||||
writeU30(t.name_index);
|
||||
write((t.kindFlags << 4) + t.kindType);
|
||||
if (t instanceof TraitSlotConst) {
|
||||
TraitSlotConst t1 = (TraitSlotConst) t;
|
||||
writeU30(t1.slot_id);
|
||||
writeU30(t1.type_index);
|
||||
writeU30(t1.value_index);
|
||||
if (t1.value_index != 0) {
|
||||
write(t1.value_kind);
|
||||
}
|
||||
}
|
||||
if (t instanceof TraitMethodGetterSetter) {
|
||||
TraitMethodGetterSetter t2 = (TraitMethodGetterSetter) t;
|
||||
writeU30(t2.disp_id);
|
||||
writeU30(t2.method_info);
|
||||
}
|
||||
if (t instanceof TraitClass) {
|
||||
TraitClass t3 = (TraitClass) t;
|
||||
writeU30(t3.slot_id);
|
||||
writeU30(t3.class_info);
|
||||
}
|
||||
if (t instanceof TraitFunction) {
|
||||
TraitFunction t4 = (TraitFunction) t;
|
||||
writeU30(t4.slot_id);
|
||||
writeU30(t4.method_info);
|
||||
}
|
||||
if ((t.kindFlags & 4) == 4) {
|
||||
writeU30(t.metadata.length);
|
||||
for (int i = 0; i < t.metadata.length; i++) {
|
||||
writeU30(t.metadata[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void writeTraits(Traits t) throws IOException {
|
||||
writeU30(t.traits.size());
|
||||
for (int i = 0; i < t.traits.size(); i++) {
|
||||
writeTrait(t.traits.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
public void writeInstanceInfo(InstanceInfo ii) throws IOException {
|
||||
writeU30(ii.name_index);
|
||||
writeU30(ii.super_index);
|
||||
write(ii.flags);
|
||||
if ((ii.flags & 8) == 8) {
|
||||
writeU30(ii.protectedNS);
|
||||
}
|
||||
writeU30(ii.interfaces.length);
|
||||
for (int i = 0; i < ii.interfaces.length; i++) {
|
||||
writeU30(ii.interfaces[i]);
|
||||
}
|
||||
writeU30(ii.iinit_index);
|
||||
writeTraits(ii.instance_traits);
|
||||
}
|
||||
|
||||
public void writeDecimal(Decimal value) throws IOException {
|
||||
write(value.data);
|
||||
}
|
||||
}
|
||||
80
src/com/jpexs/decompiler/flash/abc/AVM2LocalData.java
Normal file
80
src/com/jpexs/decompiler/flash/abc/AVM2LocalData.java
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc;
|
||||
|
||||
import com.jpexs.decompiler.flash.BaseLocalData;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.ConstantPool;
|
||||
import com.jpexs.decompiler.flash.abc.types.ABCException;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class AVM2LocalData extends BaseLocalData {
|
||||
|
||||
public Boolean isStatic;
|
||||
public Integer classIndex;
|
||||
public HashMap<Integer, GraphTargetItem> localRegs;
|
||||
public Stack<GraphTargetItem> scopeStack;
|
||||
public ConstantPool constants;
|
||||
public List<MethodInfo> methodInfo;
|
||||
public MethodBody methodBody;
|
||||
public ABC abc;
|
||||
public HashMap<Integer, String> localRegNames;
|
||||
public List<String> fullyQualifiedNames;
|
||||
public ArrayList<ABCException> parsedExceptions;
|
||||
public ArrayList<Integer> finallyJumps;
|
||||
public ArrayList<Integer> ignoredSwitches;
|
||||
public Integer scriptIndex;
|
||||
public HashMap<Integer, Integer> localRegAssignmentIps;
|
||||
public Integer ip;
|
||||
public HashMap<Integer, List<Integer>> refs;
|
||||
public AVM2Code code;
|
||||
|
||||
public AVM2LocalData() {
|
||||
|
||||
}
|
||||
|
||||
public AVM2LocalData(AVM2LocalData localData) {
|
||||
isStatic = localData.isStatic;
|
||||
classIndex = localData.classIndex;
|
||||
localRegs = localData.localRegs;
|
||||
scopeStack = localData.scopeStack;
|
||||
constants = localData.constants;
|
||||
methodInfo = localData.methodInfo;
|
||||
methodBody = localData.methodBody;
|
||||
abc = localData.abc;
|
||||
localRegNames = localData.localRegNames;
|
||||
fullyQualifiedNames = localData.fullyQualifiedNames;
|
||||
parsedExceptions = localData.parsedExceptions;
|
||||
finallyJumps = localData.finallyJumps;
|
||||
ignoredSwitches = localData.ignoredSwitches;
|
||||
scriptIndex = localData.scriptIndex;
|
||||
localRegAssignmentIps = localData.localRegAssignmentIps;
|
||||
ip = localData.ip;
|
||||
refs = localData.refs;
|
||||
code = localData.code;
|
||||
}
|
||||
}
|
||||
65
src/com/jpexs/decompiler/flash/abc/ClassPath.java
Normal file
65
src/com/jpexs/decompiler/flash/abc/ClassPath.java
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ClassPath {
|
||||
|
||||
public String packageStr;
|
||||
public String className;
|
||||
|
||||
public ClassPath(String packageStr, String className) {
|
||||
this.packageStr = packageStr;
|
||||
this.className = className;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return (packageStr == null || packageStr.isEmpty()) ? className : packageStr + "." + className;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 7;
|
||||
hash = 37 * hash + Objects.hashCode(this.packageStr);
|
||||
hash = 37 * hash + Objects.hashCode(this.className);
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final ClassPath other = (ClassPath) obj;
|
||||
if (!Objects.equals(this.packageStr, other.packageStr)) {
|
||||
return false;
|
||||
}
|
||||
if (!Objects.equals(this.className, other.className)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
73
src/com/jpexs/decompiler/flash/abc/CopyOutputStream.java
Normal file
73
src/com/jpexs/decompiler/flash/abc/CopyOutputStream.java
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class CopyOutputStream extends OutputStream {
|
||||
|
||||
private final OutputStream os;
|
||||
private final InputStream is;
|
||||
private long pos = 0;
|
||||
private final int TEMPSIZE = 5;
|
||||
private final int[] temp = new int[TEMPSIZE];
|
||||
private int tempPos = 0;
|
||||
public int ignoreFirst = 0;
|
||||
|
||||
public CopyOutputStream(OutputStream os, InputStream is) {
|
||||
this.os = os;
|
||||
this.is = is;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
temp[tempPos] = b;
|
||||
tempPos = (tempPos + 1) % TEMPSIZE;
|
||||
|
||||
pos++;
|
||||
int r = is.read();
|
||||
if ((b & 0xff) != r) {
|
||||
if (ignoreFirst <= 0) {
|
||||
os.flush();
|
||||
|
||||
boolean output = true;
|
||||
|
||||
if (output) {
|
||||
System.out.println("Position: " + pos);
|
||||
System.out.print("Last written:");
|
||||
for (int i = 0; i < TEMPSIZE; i++) {
|
||||
System.out.print("" + Integer.toHexString(temp[(tempPos + i) % TEMPSIZE]) + " ");
|
||||
}
|
||||
System.out.println("");
|
||||
System.out.println("More expected:");
|
||||
for (int i = 0; i < TEMPSIZE; i++) {
|
||||
System.out.println("" + Integer.toHexString(is.read()));
|
||||
}
|
||||
|
||||
System.out.println("");
|
||||
System.out.println(Integer.toHexString(r) + " expected but " + Integer.toHexString(b) + " found");
|
||||
}
|
||||
throw new NotSameException(pos);
|
||||
} else {
|
||||
ignoreFirst--;
|
||||
}
|
||||
}
|
||||
os.write(b);
|
||||
}
|
||||
}
|
||||
26
src/com/jpexs/decompiler/flash/abc/NotSameException.java
Normal file
26
src/com/jpexs/decompiler/flash/abc/NotSameException.java
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc;
|
||||
|
||||
import com.jpexs.helpers.Helper;
|
||||
|
||||
public class NotSameException extends RuntimeException {
|
||||
|
||||
public NotSameException(long pos) {
|
||||
super("Streams are not the same at pos " + Helper.formatHex((int) pos, 8));
|
||||
}
|
||||
}
|
||||
27
src/com/jpexs/decompiler/flash/abc/RenameType.java
Normal file
27
src/com/jpexs/decompiler/flash/abc/RenameType.java
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public enum RenameType {
|
||||
|
||||
TYPENUMBER,
|
||||
RANDOMWORD
|
||||
}
|
||||
201
src/com/jpexs/decompiler/flash/abc/ScriptPack.java
Normal file
201
src/com/jpexs/decompiler/flash/abc/ScriptPack.java
Normal file
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2013 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
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.traits.Trait;
|
||||
import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
|
||||
import com.jpexs.decompiler.flash.helpers.FileTextWriter;
|
||||
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
|
||||
import com.jpexs.decompiler.flash.helpers.NulWriter;
|
||||
import com.jpexs.decompiler.flash.tags.ABCContainerTag;
|
||||
import com.jpexs.decompiler.flash.treeitems.TreeElementItem;
|
||||
import com.jpexs.helpers.CancellableWorker;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ScriptPack implements TreeElementItem {
|
||||
|
||||
public ABC abc;
|
||||
public int scriptIndex;
|
||||
public List<Integer> traitIndices;
|
||||
private final ClassPath path;
|
||||
|
||||
@Override
|
||||
public SWF getSwf() {
|
||||
return abc.swf;
|
||||
}
|
||||
|
||||
public ClassPath getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public ScriptPack(ClassPath path, ABC abc, int scriptIndex, List<Integer> traitIndices) {
|
||||
this.abc = abc;
|
||||
this.scriptIndex = scriptIndex;
|
||||
this.traitIndices = traitIndices;
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public String getPathPackage() {
|
||||
String packageName = "";
|
||||
for (int t : traitIndices) {
|
||||
Multiname name = abc.script_info.get(scriptIndex).traits.traits.get(t).getName(abc);
|
||||
Namespace ns = name.getNamespace(abc.constants);
|
||||
if ((ns.kind == Namespace.KIND_PACKAGE) || (ns.kind == Namespace.KIND_PACKAGE_INTERNAL)) {
|
||||
packageName = ns.getName(abc.constants); //assume not null
|
||||
}
|
||||
}
|
||||
return packageName;
|
||||
}
|
||||
|
||||
public String getPathScriptName() {
|
||||
String scriptName = "";
|
||||
for (int t : traitIndices) {
|
||||
Multiname name = abc.script_info.get(scriptIndex).traits.traits.get(t).getName(abc);
|
||||
Namespace ns = name.getNamespace(abc.constants);
|
||||
if ((ns.kind == Namespace.KIND_PACKAGE) || (ns.kind == Namespace.KIND_PACKAGE_INTERNAL)) {
|
||||
scriptName = name.getName(abc.constants, new ArrayList<String>());
|
||||
}
|
||||
}
|
||||
return scriptName;
|
||||
}
|
||||
|
||||
/*public String getPath() {
|
||||
String packageName = "";
|
||||
String scriptName = "";
|
||||
for (int t : traitIndices) {
|
||||
Multiname name = abc.script_info[scriptIndex].traits.traits.get(t).getName(abc);
|
||||
Namespace ns = name.getNamespace(abc.constants);
|
||||
if ((ns.kind == Namespace.KIND_PACKAGE) || (ns.kind == Namespace.KIND_PACKAGE_INTERNAL)) {
|
||||
packageName = ns.getName(abc.constants);
|
||||
scriptName = name.getName(abc.constants, new ArrayList<String>());
|
||||
}
|
||||
}
|
||||
return packageName.equals("") ? scriptName : packageName + "." + scriptName;
|
||||
}*/
|
||||
private static String makeDirPath(String packageName) {
|
||||
if (packageName.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
String[] pathParts;
|
||||
if (packageName.contains(".")) {
|
||||
pathParts = packageName.split("\\.");
|
||||
} else {
|
||||
pathParts = new String[]{packageName};
|
||||
}
|
||||
for (int i = 0; i < pathParts.length; i++) {
|
||||
pathParts[i] = Helper.makeFileName(pathParts[i]);
|
||||
}
|
||||
return Helper.joinStrings(pathParts, File.separator);
|
||||
}
|
||||
|
||||
public void convert(final NulWriter writer, final List<ABCContainerTag> abcList, final List<Trait> traits, final ScriptExportMode exportMode, final boolean parallel) throws InterruptedException {
|
||||
for (int t : traitIndices) {
|
||||
Trait trait = traits.get(t);
|
||||
Multiname name = trait.getName(abc);
|
||||
Namespace ns = name.getNamespace(abc.constants);
|
||||
if ((ns.kind == Namespace.KIND_PACKAGE) || (ns.kind == Namespace.KIND_PACKAGE_INTERNAL)) {
|
||||
trait.convertPackaged(null, "", abcList, abc, false, exportMode, scriptIndex, -1, writer, new ArrayList<String>(), parallel);
|
||||
} else {
|
||||
trait.convert(null, "", abcList, abc, false, exportMode, scriptIndex, -1, writer, new ArrayList<String>(), parallel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void appendTo(GraphTextWriter writer, List<ABCContainerTag> abcList, List<Trait> traits, ScriptExportMode exportMode, boolean parallel) throws InterruptedException {
|
||||
for (int t : traitIndices) {
|
||||
Trait trait = traits.get(t);
|
||||
Multiname name = trait.getName(abc);
|
||||
Namespace ns = name.getNamespace(abc.constants);
|
||||
if ((ns.kind == Namespace.KIND_PACKAGE) || (ns.kind == Namespace.KIND_PACKAGE_INTERNAL)) {
|
||||
trait.toStringPackaged(null, "", abcList, abc, false, exportMode, scriptIndex, -1, writer, new ArrayList<String>(), parallel);
|
||||
} else {
|
||||
trait.toString(null, "", abcList, abc, false, exportMode, scriptIndex, -1, writer, new ArrayList<String>(), parallel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void toSource(GraphTextWriter writer, final List<ABCContainerTag> abcList, final List<Trait> traits, final ScriptExportMode exportMode, final boolean parallel) throws InterruptedException {
|
||||
writer.suspendMeasure();
|
||||
int timeout = Configuration.decompilationTimeoutFile.get();
|
||||
try {
|
||||
CancellableWorker.call(new Callable<Void>() {
|
||||
@Override
|
||||
public Void call() throws Exception {
|
||||
convert(new NulWriter(), abcList, traits, exportMode, parallel);
|
||||
return null;
|
||||
}
|
||||
}, timeout, TimeUnit.SECONDS);
|
||||
} catch (TimeoutException ex) {
|
||||
writer.continueMeasure();
|
||||
Logger.getLogger(MethodBody.class.getName()).log(Level.SEVERE, "Decompilation error", ex);
|
||||
Helper.appendTimeoutComment(writer, timeout);
|
||||
return;
|
||||
} catch (ExecutionException ex) {
|
||||
writer.continueMeasure();
|
||||
Logger.getLogger(MethodBody.class.getName()).log(Level.SEVERE, "Decompilation error", ex);
|
||||
Helper.appendErrorComment(writer, ex);
|
||||
return;
|
||||
}
|
||||
writer.continueMeasure();
|
||||
|
||||
appendTo(writer, abcList, traits, exportMode, parallel);
|
||||
}
|
||||
|
||||
public File export(String directory, List<ABCContainerTag> abcList, ScriptExportMode exportMode, boolean parallel) throws IOException {
|
||||
String scriptName = getPathScriptName();
|
||||
String packageName = getPathPackage();
|
||||
File outDir = new File(directory + File.separatorChar + makeDirPath(packageName));
|
||||
if (!outDir.exists()) {
|
||||
if (!outDir.mkdirs()) {
|
||||
if (!outDir.exists()) {
|
||||
throw new IOException("cannot create directory " + outDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
String fileName = outDir.toString() + File.separator + Helper.makeFileName(scriptName) + ".as";
|
||||
|
||||
File file = new File(fileName);
|
||||
try (FileTextWriter writer = new FileTextWriter(Configuration.getCodeFormatting(), new FileOutputStream(file))) {
|
||||
try {
|
||||
toSource(writer, abcList, abc.script_info.get(scriptIndex).traits.traits, exportMode, parallel);
|
||||
} catch (InterruptedException ex) {
|
||||
Logger.getLogger(ScriptPack.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
return file;
|
||||
}
|
||||
}
|
||||
2894
src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java
Normal file
2894
src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java
Normal file
File diff suppressed because it is too large
Load Diff
246
src/com/jpexs/decompiler/flash/abc/avm2/AVM2Deobfuscation.java
Normal file
246
src/com/jpexs/decompiler/flash/abc/avm2/AVM2Deobfuscation.java
Normal file
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.RenameType;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class AVM2Deobfuscation {
|
||||
|
||||
private static final Random rnd = new Random();
|
||||
private static final int DEFAULT_FOO_SIZE = 10;
|
||||
|
||||
public static final String[] reservedWords = {
|
||||
"as", "break", "case", "catch", "class", "const", "continue", "default", "delete", "do", "each", "else",
|
||||
"extends", "false", "finally", "for", "function", "get", "if", "implements", "import", "in", "instanceof",
|
||||
"interface", "internal", "is", "native", "new", "null", "override", "package", "private", "protected", "public",
|
||||
"return", "set", "super", "switch", "this", "throw", "true", "try", "typeof", "use", "var", /*"void",*/ "while",
|
||||
"with", "dynamic", "default", "final", "in", "static"};
|
||||
public static final String VALID_FIRST_CHARACTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_";
|
||||
public static final String VALID_NEXT_CHARACTERS = VALID_FIRST_CHARACTERS + "0123456789";
|
||||
public static final String VALID_NS_CHARACTERS = ".:$";
|
||||
public static final String FOO_CHARACTERS = "bcdfghjklmnpqrstvwz";
|
||||
public static final String FOO_JOIN_CHARACTERS = "aeiouy";
|
||||
|
||||
private final ConstantPool constants;
|
||||
private final Map<String, Integer> usageTypesCount = new HashMap<>();
|
||||
|
||||
public AVM2Deobfuscation(ConstantPool constants) {
|
||||
this.constants = constants;
|
||||
}
|
||||
|
||||
private static boolean isReserved(String s) {
|
||||
for (String rw : reservedWords) {
|
||||
if (rw.equals(s.trim())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isValidNSPart(String s) {
|
||||
boolean isValid = true;
|
||||
if (isReserved(s)) {
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
if (isValid) {
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
if (s.charAt(i) > 127) {
|
||||
isValid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isValid) {
|
||||
Pattern pat = Pattern.compile("^([" + Pattern.quote(VALID_FIRST_CHARACTERS) + "]" + "[" + Pattern.quote(VALID_FIRST_CHARACTERS + VALID_NEXT_CHARACTERS + VALID_NS_CHARACTERS) + "]*)*$");
|
||||
if (!pat.matcher(s).matches()) {
|
||||
isValid = false;
|
||||
}
|
||||
}
|
||||
return isValid;
|
||||
}
|
||||
|
||||
public String builtInNs(String ns) {
|
||||
if (ns == null) {
|
||||
return null;
|
||||
}
|
||||
if (ns.equals("http://www.adobe.com/2006/actionscript/flash/proxy")) {
|
||||
return "flash.utils.flash_proxy";
|
||||
}
|
||||
if (ns.equals("http://adobe.com/AS3/2006/builtin")) {
|
||||
return "-";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String fooString(HashMap<String, String> deobfuscated, String orig, boolean firstUppercase, int rndSize, String usageType, RenameType renameType) {
|
||||
boolean exists;
|
||||
String ret;
|
||||
int pos = 0;
|
||||
|
||||
if (usageType == null) {
|
||||
usageType = "name";
|
||||
}
|
||||
if (usageTypesCount.containsKey(usageType)) {
|
||||
pos = usageTypesCount.get(usageType);
|
||||
}
|
||||
|
||||
loopfoo:
|
||||
do {
|
||||
exists = false;
|
||||
ret = "";
|
||||
if (renameType == RenameType.TYPENUMBER) {
|
||||
pos++;
|
||||
ret = usageType + "_" + pos;
|
||||
} else if (renameType == RenameType.RANDOMWORD) {
|
||||
int len = 3 + rnd.nextInt(rndSize - 3);
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
String c = "";
|
||||
if ((i % 2) == 0) {
|
||||
c = "" + FOO_CHARACTERS.charAt(rnd.nextInt(FOO_CHARACTERS.length()));
|
||||
} else {
|
||||
c = "" + FOO_JOIN_CHARACTERS.charAt(rnd.nextInt(FOO_JOIN_CHARACTERS.length()));
|
||||
}
|
||||
if (i == 0 && firstUppercase) {
|
||||
c = c.toUpperCase(Locale.ENGLISH);
|
||||
}
|
||||
ret += c;
|
||||
}
|
||||
}
|
||||
for (int i = 1; i < constants.getStringCount(); i++) {
|
||||
if (constants.getString(i).equals(ret)) {
|
||||
exists = true;
|
||||
rndSize += 1;
|
||||
continue loopfoo;
|
||||
}
|
||||
}
|
||||
if (isReserved(ret)) {
|
||||
exists = true;
|
||||
rndSize += 1;
|
||||
continue;
|
||||
}
|
||||
if (deobfuscated.containsValue(ret)) {
|
||||
exists = true;
|
||||
rndSize += 1;
|
||||
continue;
|
||||
}
|
||||
} while (exists);
|
||||
usageTypesCount.put(usageType, pos);
|
||||
deobfuscated.put(orig, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public int deobfuscatePackageName(Map<Integer, String> stringUsageTypes, Set<Integer> stringUsages, HashMap<String, String> namesMap, int strIndex, RenameType renameType) {
|
||||
if (strIndex <= 0) {
|
||||
return strIndex;
|
||||
}
|
||||
String s = constants.getString(strIndex);
|
||||
if (builtInNs(s) != null) {
|
||||
return strIndex;
|
||||
}
|
||||
boolean isValid = isValidNSPart(s);
|
||||
if (!isValid) {
|
||||
String newName;
|
||||
if (namesMap.containsKey(s)) {
|
||||
newName = constants.setString(strIndex, namesMap.get(s));
|
||||
} else {
|
||||
String[] parts = null;
|
||||
if (s.contains(".")) {
|
||||
parts = s.split("\\.");
|
||||
} else {
|
||||
parts = new String[]{s};
|
||||
}
|
||||
String ret = "";
|
||||
for (int p = 0; p < parts.length; p++) {
|
||||
if (p > 0) {
|
||||
ret += ".";
|
||||
}
|
||||
if (!isValidNSPart(parts[p])) {
|
||||
ret += fooString(namesMap, parts[p], false, DEFAULT_FOO_SIZE, "package", renameType);
|
||||
} else {
|
||||
ret += parts[p];
|
||||
}
|
||||
}
|
||||
newName = ret;
|
||||
namesMap.put(s, newName);
|
||||
}
|
||||
if (stringUsages.contains(strIndex)) {
|
||||
strIndex = constants.addString(newName);
|
||||
} else {
|
||||
constants.setString(strIndex, newName);
|
||||
}
|
||||
|
||||
}
|
||||
return strIndex;
|
||||
}
|
||||
|
||||
public int deobfuscateName(Map<Integer, String> stringUsageTypes, Set<Integer> stringUsages, Set<Integer> namespaceUsages, HashMap<String, String> namesMap, int strIndex, boolean firstUppercase, RenameType renameType) {
|
||||
if (strIndex <= 0) {
|
||||
return strIndex;
|
||||
}
|
||||
String s = constants.getString(strIndex);
|
||||
boolean isValid = true;
|
||||
if (isReserved(s)) {
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
if (isValid) {
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
if (s.charAt(i) > 127) {
|
||||
isValid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isValid) {
|
||||
Pattern pat = Pattern.compile("^[" + Pattern.quote(VALID_FIRST_CHARACTERS) + "]" + "[" + Pattern.quote(VALID_FIRST_CHARACTERS + VALID_NEXT_CHARACTERS) + "]*$");
|
||||
if (!pat.matcher(s).matches()) {
|
||||
isValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isValid) {
|
||||
String newname;
|
||||
if (namesMap.containsKey(s)) {
|
||||
newname = namesMap.get(s);
|
||||
} else {
|
||||
newname = fooString(namesMap, constants.getString(strIndex), firstUppercase, DEFAULT_FOO_SIZE, stringUsageTypes.get(strIndex), renameType);
|
||||
}
|
||||
if (stringUsages.contains(strIndex) || namespaceUsages.contains(strIndex)) { //this name is already referenced as String
|
||||
strIndex = constants.addString(s); //add new index
|
||||
}
|
||||
constants.setString(strIndex, newname);
|
||||
if (!namesMap.containsKey(s)) {
|
||||
namesMap.put(s, constants.getString(strIndex));
|
||||
}
|
||||
}
|
||||
return strIndex;
|
||||
}
|
||||
|
||||
}
|
||||
59
src/com/jpexs/decompiler/flash/abc/avm2/CodeStats.java
Normal file
59
src/com/jpexs/decompiler/flash/abc/avm2/CodeStats.java
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
|
||||
import com.jpexs.decompiler.graph.model.LocalData;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class CodeStats {
|
||||
|
||||
public int maxstack = 0;
|
||||
public int maxscope = 0;
|
||||
public int maxlocal = 1;
|
||||
public int initscope = 0;
|
||||
public boolean has_set_dxns = false;
|
||||
public boolean has_activation = false;
|
||||
public InstructionStats[] instructionStats;
|
||||
|
||||
public GraphTextWriter toString(GraphTextWriter writer, ABC abc, List<String> fullyQualifiedNames) {
|
||||
writer.appendNoHilight("Stats: maxstack=" + maxstack + ", maxscope=" + maxscope + ", maxlocal=" + maxlocal).newLine();
|
||||
int i = 0;
|
||||
int ms = 0;
|
||||
for (InstructionStats stats : instructionStats) {
|
||||
int deltastack = stats.ins.definition.getStackDelta(stats.ins, abc);
|
||||
if (stats.stackpos > ms) {
|
||||
ms = stats.stackpos;
|
||||
}
|
||||
writer.appendNoHilight(i + ":" + stats.stackpos + (deltastack >= 0 ? "+" + deltastack : deltastack) + "," + stats.scopepos + " " + stats.ins.toString(writer, LocalData.create(abc.constants, null, fullyQualifiedNames))).newLine();
|
||||
i++;
|
||||
}
|
||||
return writer;
|
||||
}
|
||||
|
||||
public CodeStats(AVM2Code code) {
|
||||
instructionStats = new InstructionStats[code.code.size()];
|
||||
for (int i = 0; i < code.code.size(); i++) {
|
||||
instructionStats[i] = new InstructionStats(code.code.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
391
src/com/jpexs/decompiler/flash/abc/avm2/ConstantPool.java
Normal file
391
src/com/jpexs/decompiler/flash/abc/avm2/ConstantPool.java
Normal file
@@ -0,0 +1,391 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.types.Decimal;
|
||||
import com.jpexs.decompiler.flash.abc.types.Multiname;
|
||||
import com.jpexs.decompiler.flash.abc.types.Namespace;
|
||||
import com.jpexs.decompiler.flash.abc.types.NamespaceSet;
|
||||
import com.jpexs.helpers.utf8.Utf8PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ConstantPool {
|
||||
|
||||
public List<Long> constant_int = new ArrayList<>();
|
||||
public List<Long> constant_uint = new ArrayList<>();
|
||||
public List<Double> constant_double = new ArrayList<>();
|
||||
/* Only for some minor versions */
|
||||
public List<Decimal> constant_decimal = new ArrayList<>();
|
||||
public List<String> constant_string = new ArrayList<>();
|
||||
public List<Namespace> constant_namespace = new ArrayList<>();
|
||||
public List<NamespaceSet> constant_namespace_set = new ArrayList<>();
|
||||
public List<Multiname> constant_multiname = new ArrayList<>();
|
||||
|
||||
public synchronized int addInt(long value) {
|
||||
constant_int.add(value);
|
||||
return constant_int.size() - 1;
|
||||
}
|
||||
|
||||
public synchronized int addNamespace(Namespace ns) {
|
||||
constant_namespace.add(ns);
|
||||
return constant_namespace.size() - 1;
|
||||
}
|
||||
|
||||
public synchronized int addNamespaceSet(NamespaceSet nss) {
|
||||
constant_namespace_set.add(nss);
|
||||
return constant_namespace_set.size() - 1;
|
||||
}
|
||||
|
||||
public synchronized int addMultiname(Multiname m) {
|
||||
constant_multiname.add(m);
|
||||
return constant_multiname.size() - 1;
|
||||
}
|
||||
|
||||
public synchronized int addUInt(long value) {
|
||||
constant_uint.add(value);
|
||||
return constant_uint.size() - 1;
|
||||
}
|
||||
|
||||
public synchronized int addDouble(double value) {
|
||||
constant_double.add(value);
|
||||
return constant_double.size() - 1;
|
||||
}
|
||||
|
||||
public synchronized int addDecimal(Decimal value) {
|
||||
constant_decimal.add(value);
|
||||
return constant_decimal.size() - 1;
|
||||
}
|
||||
|
||||
public synchronized int addString(String value) {
|
||||
constant_string.add(value);
|
||||
return constant_string.size() - 1;
|
||||
}
|
||||
|
||||
public long setInt(int index, long value) {
|
||||
constant_int.set(index, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
public Namespace setNamespace(int index, Namespace ns) {
|
||||
constant_namespace.set(index, ns);
|
||||
return ns;
|
||||
}
|
||||
|
||||
public NamespaceSet setNamespaceSet(int index, NamespaceSet nss) {
|
||||
constant_namespace_set.set(index, nss);
|
||||
return nss;
|
||||
}
|
||||
|
||||
public Multiname setMultiname(int index, Multiname m) {
|
||||
constant_multiname.set(index, m);
|
||||
return m;
|
||||
}
|
||||
|
||||
public long setUInt(int index, long value) {
|
||||
constant_uint.set(index, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
public double setDouble(int index, double value) {
|
||||
constant_double.set(index, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
public Decimal setDecimal(int index, Decimal value) {
|
||||
constant_decimal.set(index, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
public String setString(int index, String value) {
|
||||
constant_string.set(index, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
public long getInt(int index) {
|
||||
return constant_int.get(index);
|
||||
}
|
||||
|
||||
public Namespace getNamespace(int index) {
|
||||
return constant_namespace.get(index);
|
||||
}
|
||||
|
||||
public NamespaceSet getNamespaceSet(int index) {
|
||||
return constant_namespace_set.get(index);
|
||||
}
|
||||
|
||||
public Multiname getMultiname(int index) {
|
||||
return constant_multiname.get(index);
|
||||
}
|
||||
|
||||
public long getUInt(int index) {
|
||||
return constant_uint.get(index);
|
||||
}
|
||||
|
||||
public double getDouble(int index) {
|
||||
return constant_double.get(index);
|
||||
}
|
||||
|
||||
public Decimal getDecimal(int index) {
|
||||
return constant_decimal.get(index);
|
||||
}
|
||||
|
||||
public String getString(int index) {
|
||||
return constant_string.get(index);
|
||||
}
|
||||
|
||||
public int getIntCount() {
|
||||
return constant_int.size();
|
||||
}
|
||||
|
||||
public int getNamespaceCount() {
|
||||
return constant_namespace.size();
|
||||
}
|
||||
|
||||
public int getNamespaceSetCount() {
|
||||
return constant_namespace_set.size();
|
||||
}
|
||||
|
||||
public int getMultinameCount() {
|
||||
return constant_multiname.size();
|
||||
}
|
||||
|
||||
public int getUIntCount() {
|
||||
return constant_uint.size();
|
||||
}
|
||||
|
||||
public int getDoubleCount() {
|
||||
return constant_double.size();
|
||||
}
|
||||
|
||||
public int getDecimalCount() {
|
||||
return constant_decimal.size();
|
||||
}
|
||||
|
||||
public int getStringCount() {
|
||||
return constant_string.size();
|
||||
}
|
||||
|
||||
public int getNamespaceId(Namespace val, int index) {
|
||||
for (int n = 1; n < constant_namespace.size(); n++) {
|
||||
Namespace ns = constant_namespace.get(n);
|
||||
if (ns.name_index == val.name_index && (ns.kind == val.kind)) {
|
||||
if (index == 0) {
|
||||
return n;
|
||||
}
|
||||
index--;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getIntId(long value) {
|
||||
for (int i = 1; i < constant_int.size(); i++) {
|
||||
if (constant_int.get(i) == value) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getUIntId(long value) {
|
||||
for (int i = 1; i < constant_uint.size(); i++) {
|
||||
if (constant_uint.get(i) == value) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getDoubleId(double value) {
|
||||
for (int i = 1; i < constant_double.size(); i++) {
|
||||
if(Double.isNaN(value) && Double.isNaN(constant_double.get(i))){
|
||||
return i;
|
||||
}
|
||||
if (Double.compare(constant_double.get(i), value) == 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getStringId(String val) {
|
||||
if (val == null) {
|
||||
return 0;
|
||||
}
|
||||
for (int i = 1; i < constant_string.size(); i++) {
|
||||
if (constant_string.get(i).equals(val)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getMultinameId(Multiname val) {
|
||||
loopm:
|
||||
for (int m = 1; m < constant_multiname.size(); m++) {
|
||||
Multiname mul = constant_multiname.get(m);
|
||||
if (mul.kind == val.kind && mul.name_index == val.name_index && mul.namespace_index == val.namespace_index && mul.namespace_set_index == val.namespace_set_index && mul.qname_index == val.qname_index && mul.params.size() == val.params.size()) {
|
||||
for (int p = 0; p < mul.params.size(); p++) {
|
||||
if (mul.params.get(p) != val.params.get(p)) {
|
||||
continue loopm;
|
||||
}
|
||||
}
|
||||
return m;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getQnameId(String name, int namespaceKind, String namespaceName, boolean add) {
|
||||
return getMultinameId(new Multiname(Multiname.QNAME, getStringId(name, add), getNamespaceId(new Namespace(namespaceKind, getStringId(namespaceName, add)), 0, add), -1, -1, new ArrayList<Integer>()), add);
|
||||
}
|
||||
|
||||
public int getPublicQnameId(String name, boolean add) {
|
||||
return getQnameId(name, Namespace.KIND_PACKAGE, "", add);
|
||||
}
|
||||
|
||||
public int getMultinameId(Multiname val, boolean add) {
|
||||
int id = getMultinameId(val);
|
||||
if (add && id == 0) {
|
||||
id = addMultiname(val);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
public int getStringId(String val, boolean add) {
|
||||
if (val == null) {
|
||||
return 0;
|
||||
}
|
||||
int id = getStringId(val);
|
||||
if (add && id == 0) {
|
||||
id = addString(val);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
public int getIntId(long val, boolean add) {
|
||||
int id = getIntId(val);
|
||||
if (add && id == 0) {
|
||||
id = addInt(val);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
public int getNamespaceId(Namespace val, int index, boolean add) {
|
||||
int id = getNamespaceId(val, index);
|
||||
if (add && id == 0) {
|
||||
id = addNamespace(val);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
public int getNamespaceSetId(NamespaceSet val) {
|
||||
loopi:
|
||||
for (int i = 1; i < constant_namespace_set.size(); i++) {
|
||||
NamespaceSet ts = constant_namespace_set.get(i);
|
||||
if (ts.namespaces.length != val.namespaces.length) {
|
||||
continue;
|
||||
}
|
||||
for (int j = 0; j < val.namespaces.length; j++) {
|
||||
boolean found = false;
|
||||
for (int k = 0; k < val.namespaces.length; k++) {
|
||||
if (ts.namespaces[j] == val.namespaces[k]) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
continue loopi;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getNamespaceSetId(NamespaceSet val, boolean add) {
|
||||
int id = getNamespaceSetId(val);
|
||||
if (add && id == 0) {
|
||||
id = addNamespaceSet(val);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
public int getUIntId(long val, boolean add) {
|
||||
int id = getUIntId(val);
|
||||
if (add && id == 0) {
|
||||
id = addUInt(val);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
public int getDoubleId(double val, boolean add) {
|
||||
int id = getDoubleId(val);
|
||||
if (add && id == 0) {
|
||||
id = addDouble(val);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
public void dump(Utf8PrintWriter writer) {
|
||||
String s = "";
|
||||
for (int i = 1; i < constant_int.size(); i++) {
|
||||
writer.println("INT[" + i + "]=" + constant_int.get(i));
|
||||
}
|
||||
for (int i = 1; i < constant_uint.size(); i++) {
|
||||
writer.println("UINT[" + i + "]=" + constant_uint.get(i));
|
||||
}
|
||||
for (int i = 1; i < constant_double.size(); i++) {
|
||||
writer.println("Double[" + i + "]=" + constant_double.get(i));
|
||||
}
|
||||
for (int i = 1; i < constant_string.size(); i++) {
|
||||
writer.println("String[" + i + "]=" + constant_string.get(i));
|
||||
}
|
||||
for (int i = 1; i < constant_namespace.size(); i++) {
|
||||
writer.println("Namespace[" + i + "]=" + constant_namespace.get(i).toString(this));
|
||||
}
|
||||
for (int i = 1; i < constant_namespace_set.size(); i++) {
|
||||
writer.println("NamespaceSet[" + i + "]=" + constant_namespace_set.get(i).toString(this));
|
||||
}
|
||||
|
||||
for (int i = 1; i < constant_multiname.size(); i++) {
|
||||
writer.println("Multiname[" + i + "]=" + constant_multiname.get(i).toString(this, new ArrayList<String>()));
|
||||
}
|
||||
}
|
||||
|
||||
public String multinameToString(int index) {
|
||||
if (index == 0) {
|
||||
return "null";
|
||||
}
|
||||
return constant_multiname.get(index).toString(this, new ArrayList<String>());
|
||||
}
|
||||
|
||||
public String namespaceToString(int index) {
|
||||
if (index == 0) {
|
||||
return "null";
|
||||
}
|
||||
return constant_namespace.get(index).toString(this);
|
||||
}
|
||||
|
||||
public String namespaceSetToString(int index) {
|
||||
if (index == 0) {
|
||||
return "null";
|
||||
}
|
||||
return constant_namespace_set.get(index).toString(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2;
|
||||
|
||||
public class ConvertException extends RuntimeException {
|
||||
|
||||
public int line;
|
||||
|
||||
public ConvertException(String s, int line) {
|
||||
super(s + " on line " + line);
|
||||
this.line = line;
|
||||
}
|
||||
}
|
||||
36
src/com/jpexs/decompiler/flash/abc/avm2/ConvertOutput.java
Normal file
36
src/com/jpexs/decompiler/flash/abc/avm2/ConvertOutput.java
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2;
|
||||
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ConvertOutput {
|
||||
|
||||
public Stack<GraphTargetItem> stack;
|
||||
public List<GraphTargetItem> output;
|
||||
|
||||
public ConvertOutput(Stack<GraphTargetItem> stack, List<GraphTargetItem> output) {
|
||||
this.stack = stack;
|
||||
this.output = output;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class InstructionStats {
|
||||
|
||||
public boolean seen = false;
|
||||
public int stackpos = 0;
|
||||
public int scopepos = 0;
|
||||
public int stackpos_after = 0;
|
||||
public int scopepos_after = 0;
|
||||
public AVM2Instruction ins;
|
||||
|
||||
public InstructionStats(AVM2Instruction ins) {
|
||||
this.ins = ins;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2;
|
||||
|
||||
public class InvalidInstructionArguments extends RuntimeException {
|
||||
|
||||
public InvalidInstructionArguments() {
|
||||
super("Invalid method arguments");
|
||||
}
|
||||
}
|
||||
27
src/com/jpexs/decompiler/flash/abc/avm2/LocalDataArea.java
Normal file
27
src/com/jpexs/decompiler/flash/abc/avm2/LocalDataArea.java
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Stack;
|
||||
|
||||
public class LocalDataArea {
|
||||
|
||||
public Stack<Object> operandStack = new Stack<>();
|
||||
public Stack<Object> scopeStack = new Stack<>();
|
||||
public HashMap<Integer, Object> localRegisters = new HashMap<>();
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2;
|
||||
|
||||
public class UnknownInstructionCode extends RuntimeException {
|
||||
|
||||
public int code;
|
||||
|
||||
public UnknownInstructionCode(int code) {
|
||||
super("Unknown instruction code: 0x" + Integer.toHexString(code));
|
||||
this.code = code;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2;
|
||||
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
public class UnknownJumpException extends RuntimeException {
|
||||
|
||||
public Stack stack;
|
||||
public int ip;
|
||||
public List<GraphTargetItem> output;
|
||||
|
||||
public UnknownJumpException(Stack stack, int ip, List<GraphTargetItem> output) {
|
||||
this.stack = stack;
|
||||
this.ip = ip;
|
||||
this.output = output;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Unknown jump to " + ip;
|
||||
}
|
||||
}
|
||||
813
src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java
Normal file
813
src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java
Normal file
@@ -0,0 +1,813 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.graph;
|
||||
|
||||
import com.jpexs.decompiler.flash.BaseLocalData;
|
||||
import com.jpexs.decompiler.flash.FinalProcessLocalData;
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.AVM2LocalData;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.IfStrictEqIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.IfStrictNeIns;
|
||||
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.GetLocalTypeIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.KillIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ReturnValueIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushIntegerTypeIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.FilteredCheckAVM2Item;
|
||||
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.NextNameAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.NextValueAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.NullAVM2Item;
|
||||
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.SetTypeAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.WithAVM2Item;
|
||||
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.operations.StrictEqAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.operations.StrictNeqAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.ABCException;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.ecma.EcmaScript;
|
||||
import com.jpexs.decompiler.graph.Graph;
|
||||
import com.jpexs.decompiler.graph.GraphPart;
|
||||
import com.jpexs.decompiler.graph.GraphPartMulti;
|
||||
import com.jpexs.decompiler.graph.GraphSource;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.Loop;
|
||||
import com.jpexs.decompiler.graph.model.BreakItem;
|
||||
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.SwitchItem;
|
||||
import com.jpexs.decompiler.graph.model.WhileItem;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class AVM2Graph extends Graph {
|
||||
|
||||
private final AVM2Code avm2code;
|
||||
private final ABC abc;
|
||||
private final MethodBody body;
|
||||
|
||||
public AVM2Code getCode() {
|
||||
return avm2code;
|
||||
}
|
||||
|
||||
public AVM2Graph(AVM2Code code, ABC abc, MethodBody body, boolean isStatic, int scriptIndex, int classIndex, HashMap<Integer, GraphTargetItem> localRegs, Stack<GraphTargetItem> scopeStack, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames, HashMap<Integer, Integer> localRegAssigmentIps, HashMap<Integer, List<Integer>> refs) {
|
||||
super(new AVM2GraphSource(code, isStatic, scriptIndex, classIndex, localRegs, scopeStack, abc, body, localRegNames, fullyQualifiedNames, localRegAssigmentIps, refs), body.getExceptionEntries());
|
||||
this.avm2code = code;
|
||||
this.abc = abc;
|
||||
this.body = body;
|
||||
/*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>());
|
||||
}*/
|
||||
|
||||
}
|
||||
|
||||
public static List<GraphTargetItem> translateViaGraph(String path, AVM2Code code, ABC abc, MethodBody body, boolean isStatic, int scriptIndex, int classIndex, HashMap<Integer, GraphTargetItem> localRegs, Stack<GraphTargetItem> scopeStack, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames, int staticOperation, HashMap<Integer, Integer> localRegAssigmentIps, HashMap<Integer, List<Integer>> refs) throws InterruptedException {
|
||||
AVM2Graph g = new AVM2Graph(code, abc, body, isStatic, scriptIndex, classIndex, localRegs, scopeStack, localRegNames, fullyQualifiedNames, localRegAssigmentIps, refs);
|
||||
|
||||
AVM2LocalData localData = new AVM2LocalData();
|
||||
localData.isStatic = isStatic;
|
||||
localData.classIndex = classIndex;
|
||||
localData.localRegs = localRegs;
|
||||
localData.scopeStack = scopeStack;
|
||||
localData.constants = abc.constants;
|
||||
localData.methodInfo = abc.method_info;
|
||||
localData.methodBody = body;
|
||||
localData.abc = abc;
|
||||
localData.localRegNames = localRegNames;
|
||||
localData.fullyQualifiedNames = fullyQualifiedNames;
|
||||
localData.parsedExceptions = new ArrayList<>();
|
||||
localData.finallyJumps = new ArrayList<>();
|
||||
localData.ignoredSwitches = new ArrayList<>();
|
||||
localData.scriptIndex = scriptIndex;
|
||||
localData.localRegAssignmentIps = new HashMap<>();
|
||||
localData.ip = 0;
|
||||
localData.refs = refs;
|
||||
localData.code = code;
|
||||
g.init(localData);
|
||||
List<GraphPart> allParts = new ArrayList<>();
|
||||
for (GraphPart head : g.heads) {
|
||||
populateParts(head, allParts);
|
||||
}
|
||||
return g.translate(localData, staticOperation, path);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void checkGraph(List<GraphPart> allBlocks) {
|
||||
for (ABCException ex : body.exceptions) {
|
||||
int startIp = avm2code.adr2pos(ex.start);
|
||||
int endIp = avm2code.adr2pos(ex.end);
|
||||
int targetIp = avm2code.adr2pos(ex.target);
|
||||
GraphPart target = null;
|
||||
for (GraphPart p : allBlocks) {
|
||||
if (p.start == targetIp) {
|
||||
target = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (GraphPart p : allBlocks) {
|
||||
if (p.start >= startIp && p.end <= endIp) {
|
||||
p.throwParts.add(target);
|
||||
target.refs.add(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*for(ABCException ex:body.exceptions){
|
||||
for(GraphPart p:allBlocks){
|
||||
boolean next_is_ex_start=false;
|
||||
for(GraphPart n:p.nextParts){
|
||||
if(n.start==code.adr2pos(ex.start)){
|
||||
next_is_ex_start = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(next_is_ex_start){
|
||||
for(GraphPart q:allBlocks){ //find target part
|
||||
if(q.start==code.adr2pos(ex.target)){
|
||||
p.nextParts.add(q);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<GraphTargetItem> check(GraphSource code, BaseLocalData localData, List<GraphPart> allParts, Stack<GraphTargetItem> stack, GraphPart parent, GraphPart part, List<GraphPart> stopPart, List<Loop> loops, List<GraphTargetItem> output, Loop currentLoop, int staticOperation, String path) throws InterruptedException {
|
||||
List<GraphTargetItem> ret = null;
|
||||
|
||||
AVM2LocalData aLocalData = (AVM2LocalData) localData;
|
||||
List<ABCException> parsedExceptions = aLocalData.parsedExceptions;
|
||||
List<Integer> finallyJumps = aLocalData.finallyJumps;
|
||||
List<Integer> ignoredSwitches = aLocalData.ignoredSwitches;
|
||||
int ip = part.start;
|
||||
int addr = this.avm2code.fixAddrAfterDebugLine(this.avm2code.pos2adr(part.start));
|
||||
int maxend = -1;
|
||||
List<ABCException> catchedExceptions = new ArrayList<>();
|
||||
for (int e = 0; e < body.exceptions.length; e++) {
|
||||
if (addr == this.avm2code.fixAddrAfterDebugLine(body.exceptions[e].start)) {
|
||||
if (!body.exceptions[e].isFinally()) {
|
||||
if (((body.exceptions[e].end) > maxend) && (!parsedExceptions.contains(body.exceptions[e]))) {
|
||||
catchedExceptions.clear();
|
||||
maxend = this.avm2code.fixAddrAfterDebugLine(body.exceptions[e].end);
|
||||
catchedExceptions.add(body.exceptions[e]);
|
||||
} else if (this.avm2code.fixAddrAfterDebugLine(body.exceptions[e].end) == maxend) {
|
||||
catchedExceptions.add(body.exceptions[e]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (catchedExceptions.size() > 0) {
|
||||
/*if (currentLoop != null) {
|
||||
//currentLoop.phase=0;
|
||||
}*/
|
||||
parsedExceptions.addAll(catchedExceptions);
|
||||
int endpos = code.adr2pos(this.avm2code.fixAddrAfterDebugLine(catchedExceptions.get(0).end));
|
||||
int endposStartBlock = code.adr2pos(catchedExceptions.get(0).end);
|
||||
|
||||
List<List<GraphTargetItem>> catchedCommands = new ArrayList<>();
|
||||
if (this.avm2code.code.get(endpos).definition instanceof JumpIns) {
|
||||
int afterCatchAddr = this.avm2code.pos2adr(endpos + 1) + this.avm2code.code.get(endpos).operands[0];
|
||||
int afterCatchPos = this.avm2code.adr2pos(afterCatchAddr);
|
||||
final AVM2Graph t = this;
|
||||
Collections.sort(catchedExceptions, new Comparator<ABCException>() {
|
||||
@Override
|
||||
public int compare(ABCException o1, ABCException o2) {
|
||||
return t.avm2code.fixAddrAfterDebugLine(o1.target) - t.avm2code.fixAddrAfterDebugLine(o2.target);
|
||||
}
|
||||
});
|
||||
|
||||
List<GraphTargetItem> finallyCommands = new ArrayList<>();
|
||||
int returnPos = afterCatchPos;
|
||||
for (int e = 0; e < body.exceptions.length; e++) {
|
||||
if (body.exceptions[e].isFinally()) {
|
||||
if (addr == this.avm2code.fixAddrAfterDebugLine(body.exceptions[e].start)) {
|
||||
if (afterCatchPos + 1 == code.adr2pos(this.avm2code.fixAddrAfterDebugLine(body.exceptions[e].end))) {
|
||||
AVM2Instruction jmpIns = this.avm2code.code.get(code.adr2pos(this.avm2code.fixAddrAfterDebugLine(body.exceptions[e].end)));
|
||||
|
||||
if (jmpIns.definition instanceof JumpIns) {
|
||||
int finStart = code.adr2pos(this.avm2code.fixAddrAfterDebugLine(body.exceptions[e].end) + jmpIns.getBytes().length + jmpIns.operands[0]);
|
||||
|
||||
GraphPart fpart = null;
|
||||
for (GraphPart p : allParts) {
|
||||
if (p.start == finStart) {
|
||||
fpart = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int swPos = -1;
|
||||
for (int f = finStart; f < this.avm2code.code.size(); f++) {
|
||||
if (this.avm2code.code.get(f).definition instanceof LookupSwitchIns) {
|
||||
AVM2Instruction swins = this.avm2code.code.get(f);
|
||||
if (swins.operands.length >= 3) {
|
||||
if (swins.operands[0] == swins.getBytes().length) {
|
||||
if (code.adr2pos(code.pos2adr(f) + swins.operands[2]) < finStart) {
|
||||
stack.push(new ExceptionAVM2Item(body.exceptions[e]));
|
||||
GraphPart fepart = null;
|
||||
for (GraphPart p : allParts) {
|
||||
if (p.start == f + 1) {
|
||||
fepart = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//this.code.code.get(f).ignored = true;
|
||||
//ignoredSwitches.add(f);
|
||||
swPos = f;
|
||||
|
||||
List<GraphPart> stopPart2 = new ArrayList<>(stopPart);
|
||||
stopPart2.add(fepart);
|
||||
//finallyCommands = printGraph(new ArrayList<GraphPart>(), localData, stack, allParts, parent, fpart, stopPart2, loops, staticOperation, path);
|
||||
returnPos = f + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//ignoredSwitches.add(-1);
|
||||
//int igs_size=ignoredSwitches.size();
|
||||
List<Integer> oldFinallyJumps = new ArrayList<>(finallyJumps);
|
||||
finallyJumps.clear();
|
||||
ignoredSwitches.add(swPos);
|
||||
finallyCommands = printGraph(localData, stack, allParts, parent, fpart, null, loops, staticOperation, path);
|
||||
//ignoredSwitches.remove(igs_size-1);
|
||||
finallyJumps.addAll(oldFinallyJumps);
|
||||
finallyJumps.add(finStart);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GraphPart retPart = null;
|
||||
for (GraphPart p : allParts) {
|
||||
if (p.start == returnPos) {
|
||||
retPart = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
List<GraphPart> catchParts = new ArrayList<>();
|
||||
for (int e = 0; e < catchedExceptions.size(); e++) {
|
||||
int eendpos;
|
||||
if (e < catchedExceptions.size() - 1) {
|
||||
eendpos = code.adr2pos(this.avm2code.fixAddrAfterDebugLine(catchedExceptions.get(e + 1).target)) - 2;
|
||||
} else {
|
||||
eendpos = afterCatchPos - 1;
|
||||
}
|
||||
|
||||
GraphPart npart = null;
|
||||
int findpos = code.adr2pos(catchedExceptions.get(e).target);
|
||||
for (GraphPart p : allParts) {
|
||||
if (p.start == findpos) {
|
||||
npart = p;
|
||||
catchParts.add(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GraphPart nepart = null;
|
||||
for (GraphPart p : allParts) {
|
||||
if (p.start == eendpos + 1) {
|
||||
nepart = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
stack.add(new ExceptionAVM2Item(catchedExceptions.get(e)));
|
||||
AVM2LocalData localData2 = new AVM2LocalData(aLocalData);
|
||||
localData2.scopeStack = new Stack<>();
|
||||
List<GraphPart> stopPart2 = new ArrayList<>(stopPart);
|
||||
stopPart2.add(nepart);
|
||||
if (retPart != null) {
|
||||
stopPart2.add(retPart);
|
||||
}
|
||||
catchedCommands.add(printGraph(localData2, stack, allParts, parent, npart, stopPart2, loops, staticOperation, path));
|
||||
}
|
||||
|
||||
GraphPart nepart = null;
|
||||
|
||||
for (GraphPart p : allParts) {
|
||||
if (p.start == endposStartBlock) {
|
||||
nepart = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
List<GraphPart> stopPart2 = new ArrayList<>(stopPart);
|
||||
stopPart2.add(nepart);
|
||||
stopPart2.addAll(catchParts);
|
||||
|
||||
if (retPart != null) {
|
||||
stopPart2.add(retPart);
|
||||
}
|
||||
List<GraphTargetItem> tryCommands = printGraph(localData, stack, allParts, parent, part, stopPart2, loops, staticOperation, path);
|
||||
|
||||
output.clear();
|
||||
output.add(new TryAVM2Item(tryCommands, catchedExceptions, catchedCommands, finallyCommands));
|
||||
ip = returnPos;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (ip != part.start) {
|
||||
part = null;
|
||||
for (GraphPart p : allParts) {
|
||||
List<GraphPart> ps = p.getSubParts();
|
||||
for (GraphPart p2 : ps) {
|
||||
if (p2.start == ip) {
|
||||
part = p2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ret = new ArrayList<>();
|
||||
ret.addAll(output);
|
||||
GraphTargetItem lop = checkLoop(part, stopPart, loops);
|
||||
if (lop == null) {
|
||||
ret.addAll(printGraph(localData, stack, allParts, null, part, stopPart, loops, staticOperation, path));
|
||||
} else {
|
||||
ret.add(lop);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (part.nextParts.isEmpty()) {
|
||||
if (this.avm2code.code.get(part.end).definition instanceof ReturnValueIns) { //returns in finally clause
|
||||
if (part.getHeight() >= 3) {
|
||||
if (this.avm2code.code.get(part.getPosAt(part.getHeight() - 2)).definition instanceof KillIns) {
|
||||
if (this.avm2code.code.get(part.getPosAt(part.getHeight() - 3)).definition instanceof GetLocalTypeIns) {
|
||||
if (output.size() >= 2) {
|
||||
if (output.get(output.size() - 2) instanceof SetLocalAVM2Item) {
|
||||
ret = new ArrayList<>();
|
||||
ret.addAll(output);
|
||||
ret.remove(ret.size() - 1);
|
||||
ret.add(new ReturnValueAVM2Item(this.avm2code.code.get(part.end), ((SetLocalAVM2Item) output.get(output.size() - 2)).value));
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((this.avm2code.code.get(part.end).definition instanceof LookupSwitchIns) && ignoredSwitches.contains(part.end)) {
|
||||
ret = new ArrayList<>();
|
||||
ret.addAll(output);
|
||||
return ret;
|
||||
}
|
||||
if (((part.nextParts.size() == 2)
|
||||
&& (!stack.isEmpty())
|
||||
&& (stack.peek() instanceof StrictEqAVM2Item)
|
||||
&& (part.nextParts.get(0).getHeight() >= 2)
|
||||
&& (this.avm2code.code.get(this.avm2code.fixIPAfterDebugLine(part.nextParts.get(0).start)).definition instanceof PushIntegerTypeIns)
|
||||
&& (!part.nextParts.get(0).nextParts.isEmpty())
|
||||
&& (this.avm2code.code.get(part.nextParts.get(0).nextParts.get(0).end).definition instanceof LookupSwitchIns))
|
||||
|| ((part.nextParts.size() == 2)
|
||||
&& (!stack.isEmpty())
|
||||
&& (stack.peek() instanceof StrictNeqAVM2Item)
|
||||
&& (part.nextParts.get(1).getHeight() >= 2)
|
||||
&& (this.avm2code.code.get(this.avm2code.fixIPAfterDebugLine(part.nextParts.get(1).start)).definition instanceof PushIntegerTypeIns)
|
||||
&& (!part.nextParts.get(1).nextParts.isEmpty())
|
||||
&& (this.avm2code.code.get(part.nextParts.get(1).nextParts.get(0).end).definition instanceof LookupSwitchIns))) {
|
||||
|
||||
if (stack.peek() instanceof StrictEqAVM2Item) {
|
||||
ignoredSwitches.add(part.nextParts.get(0).nextParts.get(0).end);
|
||||
} else {
|
||||
ignoredSwitches.add(part.nextParts.get(1).nextParts.get(0).end);
|
||||
}
|
||||
ret = new ArrayList<>();
|
||||
ret.addAll(output);
|
||||
boolean reversed = false;
|
||||
if (stack.peek() instanceof StrictEqAVM2Item) {
|
||||
reversed = true;
|
||||
}
|
||||
GraphTargetItem switchedObject = null;
|
||||
if (!output.isEmpty()) {
|
||||
if (output.get(output.size() - 1) instanceof SetLocalAVM2Item) {
|
||||
switchedObject = ((SetLocalAVM2Item) output.get(output.size() - 1)).value;
|
||||
}
|
||||
}
|
||||
if (switchedObject == null) {
|
||||
switchedObject = new NullAVM2Item(null);
|
||||
}
|
||||
HashMap<Integer, GraphTargetItem> caseValuesMap = new HashMap<>();
|
||||
|
||||
GraphTargetItem tar = stack.pop();
|
||||
if (tar instanceof StrictEqAVM2Item) {
|
||||
tar = ((StrictEqAVM2Item) tar).leftSide;
|
||||
}
|
||||
if (tar instanceof StrictNeqAVM2Item) {
|
||||
tar = ((StrictNeqAVM2Item) tar).leftSide;
|
||||
}
|
||||
caseValuesMap.put(this.avm2code.code.get(part.nextParts.get(reversed ? 0 : 1).start).operands[0], tar);
|
||||
|
||||
GraphPart switchLoc = part.nextParts.get(reversed ? 0 : 1).nextParts.get(0);
|
||||
|
||||
while ((this.avm2code.code.get(part.nextParts.get(reversed ? 1 : 0).end).definition instanceof IfStrictNeIns)
|
||||
|| (this.avm2code.code.get(part.nextParts.get(reversed ? 1 : 0).end).definition instanceof IfStrictEqIns)) {
|
||||
part = part.nextParts.get(reversed ? 1 : 0);
|
||||
translatePart(localData, part, stack, staticOperation, null);
|
||||
tar = stack.pop();
|
||||
if (tar instanceof StrictEqAVM2Item) {
|
||||
tar = ((StrictEqAVM2Item) tar).leftSide;
|
||||
}
|
||||
if (tar instanceof StrictNeqAVM2Item) {
|
||||
tar = ((StrictNeqAVM2Item) tar).leftSide;
|
||||
}
|
||||
if (this.avm2code.code.get(part.end).definition instanceof IfStrictNeIns) {
|
||||
reversed = false;
|
||||
} else {
|
||||
reversed = true;
|
||||
}
|
||||
GraphPart numPart = part.nextParts.get(reversed ? 0 : 1);
|
||||
AVM2Instruction ins = null;
|
||||
Stack<GraphTargetItem> sstack = new Stack<>();
|
||||
do {
|
||||
for (int n = 0; n < numPart.getHeight(); n++) {
|
||||
ins = this.avm2code.code.get(numPart.getPosAt(n));
|
||||
if (ins.definition instanceof LookupSwitchIns) {
|
||||
break;
|
||||
}
|
||||
ins.translate(localData, sstack, new ArrayList<GraphTargetItem>(), staticOperation, path);
|
||||
}
|
||||
if (numPart.nextParts.size() > 1) {
|
||||
break;
|
||||
} else {
|
||||
numPart = numPart.nextParts.get(0);
|
||||
}
|
||||
} while (!(this.avm2code.code.get(numPart.end).definition instanceof LookupSwitchIns));
|
||||
GraphTargetItem nt = sstack.peek();
|
||||
|
||||
if (!(nt instanceof IntegerValueAVM2Item)) {
|
||||
throw new RuntimeException("Invalid integer value in Switch");
|
||||
}
|
||||
IntegerValueAVM2Item iv = (IntegerValueAVM2Item) nt;
|
||||
caseValuesMap.put((int) (long) iv.value, tar);
|
||||
while (this.avm2code.code.get(part.nextParts.get(reversed ? 1 : 0).start).definition instanceof JumpIns) {
|
||||
reversed = false;
|
||||
part = part.nextParts.get(reversed ? 1 : 0);
|
||||
if (part instanceof GraphPartMulti) {
|
||||
part = ((GraphPartMulti) part).parts.get(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
boolean hasDefault = false;
|
||||
GraphPart dp = part.nextParts.get(reversed ? 1 : 0);
|
||||
while (this.avm2code.code.get(dp.start).definition instanceof JumpIns) {
|
||||
if (dp instanceof GraphPartMulti) {
|
||||
dp = ((GraphPartMulti) dp).parts.get(0);
|
||||
}
|
||||
dp = dp.nextParts.get(0);
|
||||
}
|
||||
|
||||
GraphPart numPart = dp;
|
||||
AVM2Instruction ins = null;
|
||||
Stack<GraphTargetItem> sstack = new Stack<>();
|
||||
do {
|
||||
for (int n = 0; n < numPart.getHeight(); n++) {
|
||||
ins = this.avm2code.code.get(numPart.getPosAt(n));
|
||||
if (ins.definition instanceof LookupSwitchIns) {
|
||||
break;
|
||||
}
|
||||
ins.translate(localData, sstack, new ArrayList<GraphTargetItem>(), staticOperation, path);
|
||||
}
|
||||
if (numPart.nextParts.size() > 1) {
|
||||
break;
|
||||
} else {
|
||||
numPart = numPart.nextParts.get(0);
|
||||
}
|
||||
} while (!(this.avm2code.code.get(numPart.end).definition instanceof LookupSwitchIns));
|
||||
GraphTargetItem nt = sstack.peek();
|
||||
if (nt instanceof IntegerValueAVM2Item) {
|
||||
hasDefault = true;
|
||||
}
|
||||
List<GraphTargetItem> caseValues = new ArrayList<>();
|
||||
for (int i = 0; i < switchLoc.nextParts.size() - 1; i++) {
|
||||
if (caseValuesMap.containsKey(i)) {
|
||||
caseValues.add(caseValuesMap.get(i));
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
List<List<GraphTargetItem>> caseCommands = new ArrayList<>();
|
||||
GraphPart next = null;
|
||||
|
||||
next = getMostCommonPart(localData, switchLoc.nextParts, loops);//getNextPartPath(loopContinues);
|
||||
currentLoop = new Loop(loops.size(), null, next);
|
||||
currentLoop.phase = 1;
|
||||
loops.add(currentLoop);
|
||||
//switchLoc.getNextPartPath(new ArrayList<GraphPart>());
|
||||
List<Integer> valuesMapping = new ArrayList<>();
|
||||
List<GraphPart> caseBodies = new ArrayList<>();
|
||||
for (int i = 0; i < caseValues.size(); i++) {
|
||||
GraphPart cur = switchLoc.nextParts.get(1 + i);
|
||||
if (!caseBodies.contains(cur)) {
|
||||
caseBodies.add(cur);
|
||||
}
|
||||
valuesMapping.add(caseBodies.indexOf(cur));
|
||||
}
|
||||
|
||||
List<GraphTargetItem> defaultCommands = new ArrayList<>();
|
||||
GraphPart defaultPart = null;
|
||||
if (hasDefault) {
|
||||
defaultPart = switchLoc.nextParts.get(switchLoc.nextParts.size() - 1);
|
||||
List<GraphPart> stopPart2 = new ArrayList<>(stopPart);
|
||||
stopPart2.add(next);
|
||||
defaultCommands = printGraph(localData, stack, allParts, switchLoc, defaultPart, stopPart2, loops, staticOperation, path);
|
||||
if (!defaultCommands.isEmpty()) {
|
||||
if (defaultCommands.get(defaultCommands.size() - 1) instanceof BreakItem) {
|
||||
if (((BreakItem) defaultCommands.get(defaultCommands.size() - 1)).loopId == currentLoop.id) {
|
||||
defaultCommands.remove(defaultCommands.size() - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<GraphPart> ignored = new ArrayList<>();
|
||||
for (Loop l : loops) {
|
||||
ignored.add(l.loopContinue);
|
||||
}
|
||||
|
||||
for (int i = 0; i < caseBodies.size(); i++) {
|
||||
List<GraphTargetItem> cc = new ArrayList<>();
|
||||
List<GraphPart> stopPart2 = new ArrayList<>(stopPart);
|
||||
for (int j = 0; j < caseBodies.size(); j++) {
|
||||
if (caseBodies.get(j) != caseBodies.get(i)) {
|
||||
stopPart2.add(caseBodies.get(j));
|
||||
}
|
||||
}
|
||||
if (hasDefault) {
|
||||
stopPart2.add(defaultPart);
|
||||
}
|
||||
|
||||
cc.addAll(0, printGraph(localData, stack, allParts, switchLoc, caseBodies.get(i), stopPart2, loops, staticOperation, path));
|
||||
caseCommands.add(cc);
|
||||
}
|
||||
|
||||
SwitchItem sti = new SwitchItem(null, currentLoop, switchedObject, caseValues, caseCommands, defaultCommands, valuesMapping);
|
||||
ret.add(sti);
|
||||
//loops.remove(currentLoop);
|
||||
if (next != null) {
|
||||
/*if (ti != null) {
|
||||
ret.add(ti);
|
||||
} else {*/
|
||||
currentLoop.phase = 2;
|
||||
ret.addAll(printGraph(localData, stack, allParts, null, next, stopPart, loops, staticOperation, path));
|
||||
//}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GraphPart checkPart(Stack<GraphTargetItem> stack, BaseLocalData localData, GraphPart next, List<GraphPart> allParts) {
|
||||
AVM2LocalData aLocalData = (AVM2LocalData) localData;
|
||||
List<Integer> finallyJumps = aLocalData.finallyJumps;
|
||||
List<Integer> ignoredSwitches = aLocalData.ignoredSwitches;
|
||||
GraphPart ret = next;
|
||||
for (int f = 0; f < finallyJumps.size(); f++) {
|
||||
int fip = finallyJumps.get(f);
|
||||
int swip = ignoredSwitches.get(f);
|
||||
if (next.start == fip) {
|
||||
if (stack != null && swip != -1) {
|
||||
AVM2Instruction swIns = avm2code.code.get(swip);
|
||||
GraphTargetItem t = stack.pop();
|
||||
Double dval = EcmaScript.toNumber(t.getResult());
|
||||
int val = (int) (double) dval;
|
||||
if (swIns.definition instanceof LookupSwitchIns) {
|
||||
List<Integer> branches = swIns.getBranches(code);
|
||||
int nip = branches.get(0);
|
||||
if (val >= 0 && val < branches.size() - 1) {
|
||||
nip = branches.get(1 + val);
|
||||
}
|
||||
for (GraphPart p : allParts) {
|
||||
if (p.start == nip) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
ret = null;
|
||||
}
|
||||
}
|
||||
ret = null;
|
||||
}
|
||||
}
|
||||
if (ret != next) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
int pos = next.start;
|
||||
int addr = this.avm2code.fixAddrAfterDebugLine(avm2code.pos2adr(pos));
|
||||
for (int e = 0; e < body.exceptions.length; e++) {
|
||||
if (body.exceptions[e].isFinally()) {
|
||||
if (addr == this.avm2code.fixAddrAfterDebugLine(body.exceptions[e].start)) {
|
||||
if (true) { //afterCatchPos + 1 == code.adr2pos(this.code.fixAddrAfterDebugLine(body.exceptions[e].end))) {
|
||||
AVM2Instruction jmpIns = this.avm2code.code.get(avm2code.adr2pos(this.avm2code.fixAddrAfterDebugLine(body.exceptions[e].end)));
|
||||
if (jmpIns.definition instanceof JumpIns) {
|
||||
int finStart = avm2code.adr2pos(this.avm2code.fixAddrAfterDebugLine(body.exceptions[e].end) + jmpIns.getBytes().length + jmpIns.operands[0]);
|
||||
finallyJumps.add(finStart);
|
||||
ignoredSwitches.add(-1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GraphTargetItem checkLoop(LoopItem loopItem, BaseLocalData localData, List<Loop> loops) {
|
||||
AVM2LocalData aLocalData = (AVM2LocalData) localData;
|
||||
if (loopItem instanceof WhileItem) {
|
||||
WhileItem w = (WhileItem) loopItem;
|
||||
|
||||
if ((!w.expression.isEmpty()) && (w.expression.get(w.expression.size() - 1) instanceof HasNextAVM2Item)) {
|
||||
if (((HasNextAVM2Item) w.expression.get(w.expression.size() - 1)).collection != null) {
|
||||
if (((HasNextAVM2Item) w.expression.get(w.expression.size() - 1)).collection.getNotCoerced().getThroughRegister() instanceof FilteredCheckAVM2Item) {
|
||||
//GraphTargetItem gti = ((HasNextAVM2Item) ((HasNextAVM2Item) w.expression.get(w.expression.size() - 1))).collection.getNotCoerced().getThroughRegister();
|
||||
if (w.commands.size() >= 3) { //((w.commands.size() == 3) || (w.commands.size() == 4)) {
|
||||
int pos = 0;
|
||||
while (w.commands.get(pos) instanceof SetLocalAVM2Item) {
|
||||
pos++;
|
||||
}
|
||||
GraphTargetItem ft = w.commands.get(pos);
|
||||
if (ft instanceof WithAVM2Item) {
|
||||
ft = w.commands.get(pos + 1);
|
||||
if (ft instanceof IfItem) {
|
||||
IfItem ift = (IfItem) ft;
|
||||
if (ift.onTrue.size() > 0) {
|
||||
ft = ift.onTrue.get(0);
|
||||
if (ft instanceof SetPropertyAVM2Item) {
|
||||
SetPropertyAVM2Item spt = (SetPropertyAVM2Item) ft;
|
||||
if (spt.object instanceof LocalRegAVM2Item) {
|
||||
int regIndex = ((LocalRegAVM2Item) spt.object).regIndex;
|
||||
HasNextAVM2Item iti = (HasNextAVM2Item) w.expression.get(w.expression.size() - 1);
|
||||
HashMap<Integer, GraphTargetItem> localRegs = aLocalData.localRegs;
|
||||
localRegs.put(regIndex, new FilterAVM2Item(null, iti.collection.getThroughRegister(), ift.expression));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (!w.commands.isEmpty()) {
|
||||
if (w.commands.get(0) instanceof SetTypeAVM2Item) {
|
||||
SetTypeAVM2Item sti = (SetTypeAVM2Item) w.commands.remove(0);
|
||||
GraphTargetItem gti = sti.getValue().getNotCoerced();
|
||||
if (gti instanceof NextValueAVM2Item) {
|
||||
return new ForEachInAVM2Item(w.src, w.loop, new InAVM2Item(null, sti.getObject(), ((HasNextAVM2Item) w.expression.get(w.expression.size() - 1)).collection), w.commands);
|
||||
} else if (gti instanceof NextNameAVM2Item) {
|
||||
return new ForInAVM2Item(w.src, w.loop, new InAVM2Item(null, sti.getObject(), ((HasNextAVM2Item) w.expression.get(w.expression.size() - 1)).collection), w.commands);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return loopItem;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalProcess(List<GraphTargetItem> list, int level, FinalProcessLocalData localData) {
|
||||
if (level == 0) {
|
||||
if (!list.isEmpty()) {
|
||||
if (list.get(list.size() - 1) instanceof ReturnVoidAVM2Item) {
|
||||
list.remove(list.size() - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*for (int i = 0; i < list.size(); i++) {
|
||||
|
||||
if (list.get(i) instanceof WhileItem) {
|
||||
WhileItem w = (WhileItem) list.get(i);
|
||||
|
||||
}
|
||||
}*/
|
||||
List<GraphTargetItem> ret = avm2code.clearTemporaryRegisters(list);
|
||||
if (ret != list) {
|
||||
list.clear();
|
||||
list.addAll(ret);
|
||||
}
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
if (list.get(i) instanceof SetTypeAVM2Item) {
|
||||
if (((SetTypeAVM2Item) list.get(i)).getValue() instanceof ExceptionAVM2Item) {
|
||||
list.remove(i);
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (list.get(i) instanceof IfItem) {
|
||||
IfItem ifi = (IfItem) list.get(i);
|
||||
if (((ifi.expression instanceof HasNextAVM2Item)
|
||||
|| ((ifi.expression instanceof NotItem)
|
||||
&& (((NotItem) ifi.expression).getOriginal() instanceof HasNextAVM2Item)))) {
|
||||
HasNextAVM2Item hnt = null;
|
||||
List<GraphTargetItem> body = new ArrayList<>();
|
||||
List<GraphTargetItem> nextbody = new ArrayList<>();
|
||||
if (ifi.expression instanceof NotItem) {
|
||||
hnt = (HasNextAVM2Item) ((NotItem) ifi.expression).getOriginal();
|
||||
body.addAll(ifi.onFalse);
|
||||
for (int j = i + 1; j < list.size();) {
|
||||
body.add(list.remove(i + 1));
|
||||
}
|
||||
nextbody = ifi.onTrue;
|
||||
} else {
|
||||
hnt = (HasNextAVM2Item) ifi.expression;
|
||||
body = ifi.onTrue;
|
||||
nextbody = ifi.onFalse;
|
||||
}
|
||||
if (!body.isEmpty()) {
|
||||
if (body.get(0) instanceof SetTypeAVM2Item) {
|
||||
SetTypeAVM2Item sti = (SetTypeAVM2Item) body.remove(0);
|
||||
GraphTargetItem gti = sti.getValue().getNotCoerced();
|
||||
GraphTargetItem repl = null;
|
||||
|
||||
if (gti instanceof NextValueAVM2Item) {
|
||||
repl = new ForEachInAVM2Item(ifi.src, new Loop(0, null, null), new InAVM2Item(null, sti.getObject(), hnt.collection), body);
|
||||
} else if (gti instanceof NextNameAVM2Item) {
|
||||
repl = new ForInAVM2Item(ifi.src, new Loop(0, null, null), new InAVM2Item(null, sti.getObject(), hnt.collection), body);
|
||||
}
|
||||
if (repl != null) {
|
||||
list.remove(i);
|
||||
list.add(i, repl);
|
||||
list.addAll(i + 1, nextbody);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isEmpty(List<GraphTargetItem> output) {
|
||||
if (super.isEmpty(output)) {
|
||||
return true;
|
||||
}
|
||||
for (GraphTargetItem i : output) {
|
||||
if (i instanceof SetLocalAVM2Item) {
|
||||
if (avm2code.isKilled(((SetLocalAVM2Item) i).regIndex, 0, avm2code.code.size() - 1)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AVM2LocalData prepareBranchLocalData(BaseLocalData localData) {
|
||||
AVM2LocalData aLocalData = (AVM2LocalData) localData;
|
||||
AVM2LocalData ret = new AVM2LocalData(aLocalData);
|
||||
Stack<GraphTargetItem> copyScopeStack = new Stack<>();
|
||||
copyScopeStack.addAll(ret.scopeStack);
|
||||
ret.scopeStack = copyScopeStack;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.graph;
|
||||
|
||||
import com.jpexs.decompiler.flash.BaseLocalData;
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.AVM2LocalData;
|
||||
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.GraphPart;
|
||||
import com.jpexs.decompiler.graph.GraphSource;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class AVM2GraphSource extends GraphSource {
|
||||
|
||||
private final AVM2Code code;
|
||||
boolean isStatic;
|
||||
int classIndex;
|
||||
int scriptIndex;
|
||||
HashMap<Integer, GraphTargetItem> localRegs;
|
||||
Stack<GraphTargetItem> scopeStack;
|
||||
ABC abc;
|
||||
MethodBody body;
|
||||
HashMap<Integer, String> localRegNames;
|
||||
List<String> fullyQualifiedNames;
|
||||
HashMap<Integer, Integer> localRegAssigmentIps;
|
||||
HashMap<Integer, List<Integer>> refs;
|
||||
|
||||
public AVM2Code getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public AVM2GraphSource(AVM2Code code, boolean isStatic, int scriptIndex, int classIndex, HashMap<Integer, GraphTargetItem> localRegs, Stack<GraphTargetItem> scopeStack, ABC abc, MethodBody body, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames, HashMap<Integer, Integer> localRegAssigmentIp, HashMap<Integer, List<Integer>> refs) {
|
||||
this.code = code;
|
||||
this.isStatic = isStatic;
|
||||
this.classIndex = classIndex;
|
||||
this.localRegs = localRegs;
|
||||
this.scopeStack = scopeStack;
|
||||
this.abc = abc;
|
||||
this.body = body;
|
||||
this.localRegNames = localRegNames;
|
||||
this.fullyQualifiedNames = fullyQualifiedNames;
|
||||
this.scriptIndex = scriptIndex;
|
||||
this.localRegAssigmentIps = localRegAssigmentIp;
|
||||
this.refs = refs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return code.code.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AVM2Instruction get(int pos) {
|
||||
return code.code.get(pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return code.code.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GraphTargetItem> translatePart(GraphPart part, BaseLocalData localData, Stack<GraphTargetItem> stack, int start, int end, int staticOperation, String path) throws InterruptedException {
|
||||
List<GraphTargetItem> ret = new ArrayList<>();
|
||||
Stack<GraphTargetItem> newstack = ((AVM2LocalData) localData).scopeStack;
|
||||
ConvertOutput co = code.toSourceOutput(path, part, false, isStatic, scriptIndex, classIndex, localRegs, stack, newstack, abc, abc.constants, abc.method_info, body, start, end, localRegNames, fullyQualifiedNames, new boolean[size()], localRegAssigmentIps, refs);
|
||||
ret.addAll(co.output);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int adr2pos(long adr) {
|
||||
return code.adr2pos(adr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long pos2adr(int pos) {
|
||||
return code.pos2adr(pos);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,364 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions;
|
||||
|
||||
import com.jpexs.decompiler.flash.BaseLocalData;
|
||||
import com.jpexs.decompiler.flash.abc.ABCOutputStream;
|
||||
import com.jpexs.decompiler.flash.abc.AVM2LocalData;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.ConstantPool;
|
||||
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.other.ReturnValueIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ReturnVoidIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ThrowIns;
|
||||
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
|
||||
import com.jpexs.decompiler.graph.GraphSource;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItem;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.model.LocalData;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
public class AVM2Instruction implements Serializable, GraphSourceItem {
|
||||
|
||||
public static final long serialVersionUID = 1L;
|
||||
public InstructionDefinition definition;
|
||||
public int[] operands;
|
||||
public long offset;
|
||||
public byte[] bytes;
|
||||
public String comment;
|
||||
public boolean ignored = false;
|
||||
public String labelname;
|
||||
public long mappedOffset = -1;
|
||||
public int changeJumpTo = -1;
|
||||
|
||||
public AVM2Instruction(long offset, InstructionDefinition definition, int[] operands, byte[] bytes) {
|
||||
this.definition = definition;
|
||||
this.operands = operands;
|
||||
this.offset = offset;
|
||||
this.bytes = bytes;
|
||||
}
|
||||
|
||||
public byte[] getBytes() {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
try {
|
||||
ABCOutputStream aos = new ABCOutputStream(bos);
|
||||
aos.write(definition.instructionCode);
|
||||
for (int i = 0; i < definition.operands.length; i++) {
|
||||
int opt = definition.operands[i] & 0xff00;
|
||||
switch (opt) {
|
||||
case AVM2Code.OPT_S24:
|
||||
aos.writeS24(operands[i]);
|
||||
break;
|
||||
case AVM2Code.OPT_U30:
|
||||
aos.writeU30(operands[i]);
|
||||
break;
|
||||
case AVM2Code.OPT_U8:
|
||||
aos.writeU8(operands[i]);
|
||||
break;
|
||||
case AVM2Code.OPT_BYTE:
|
||||
aos.writeU8(0xff & operands[i]);
|
||||
break;
|
||||
case AVM2Code.OPT_CASE_OFFSETS:
|
||||
|
||||
aos.writeU30(operands[i]); //case count
|
||||
for (int j = i + 1; j < operands.length; j++) {
|
||||
aos.writeS24(operands[j]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
//ignored
|
||||
}
|
||||
return bos.toByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder s = new StringBuilder();
|
||||
s.append(definition.instructionName);
|
||||
for (int i = 0; i < operands.length; i++) {
|
||||
s.append(" ");
|
||||
s.append(operands[i]);
|
||||
}
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
public List<Long> getOffsets() {
|
||||
List<Long> ret = new ArrayList<>();
|
||||
String s = "";
|
||||
for (int i = 0; i < definition.operands.length; i++) {
|
||||
switch (definition.operands[i]) {
|
||||
case AVM2Code.DAT_OFFSET:
|
||||
ret.add(offset + operands[i] + getBytes().length);
|
||||
break;
|
||||
case AVM2Code.DAT_CASE_BASEOFFSET:
|
||||
ret.add(offset + operands[i]);
|
||||
break;
|
||||
case AVM2Code.OPT_CASE_OFFSETS:
|
||||
for (int j = i + 1; j < operands.length; j++) {
|
||||
ret.add(offset + operands[j]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public List<Object> getParamsAsList(ConstantPool constants) {
|
||||
List<Object> s = new ArrayList<>();
|
||||
for (int i = 0; i < definition.operands.length; i++) {
|
||||
switch (definition.operands[i]) {
|
||||
case AVM2Code.DAT_MULTINAME_INDEX:
|
||||
s.add(constants.getMultiname(operands[i]));
|
||||
break;
|
||||
case AVM2Code.DAT_STRING_INDEX:
|
||||
s.add(constants.getString(operands[i]));
|
||||
break;
|
||||
case AVM2Code.DAT_INT_INDEX:
|
||||
s.add(Long.valueOf(constants.getInt(operands[i])));
|
||||
break;
|
||||
case AVM2Code.DAT_UINT_INDEX:
|
||||
s.add(new Long(constants.getUInt(operands[i])));
|
||||
break;
|
||||
case AVM2Code.DAT_DOUBLE_INDEX:
|
||||
s.add(Double.valueOf(constants.getDouble(operands[i])));
|
||||
break;
|
||||
case AVM2Code.DAT_OFFSET:
|
||||
s.add(new Long(offset + operands[i] + getBytes().length));
|
||||
break;
|
||||
case AVM2Code.DAT_CASE_BASEOFFSET:
|
||||
s.add(new Long(offset + operands[i]));
|
||||
break;
|
||||
case AVM2Code.OPT_CASE_OFFSETS:
|
||||
s.add(new Long(operands[i]));
|
||||
for (int j = i + 1; j < operands.length; j++) {
|
||||
s.add(new Long(offset + operands[j]));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
s.add(new Long(operands[i]));
|
||||
}
|
||||
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
public String getParams(ConstantPool constants, List<String> fullyQualifiedNames) {
|
||||
StringBuilder s = new StringBuilder();
|
||||
for (int i = 0; i < definition.operands.length; i++) {
|
||||
switch (definition.operands[i]) {
|
||||
case AVM2Code.DAT_MULTINAME_INDEX:
|
||||
if (operands[i] == 0) {
|
||||
s.append(" null");
|
||||
} else {
|
||||
s.append(" ");
|
||||
s.append(constants.getMultiname(operands[i]).toString(constants, fullyQualifiedNames));
|
||||
}
|
||||
/*s.append(" m[");
|
||||
s.append(operands[i]);
|
||||
s.append("]\"");
|
||||
if (constants.constant_multiname[operands[i]] == null) {
|
||||
s.append("");
|
||||
} else {
|
||||
s.append(Helper.escapeString(constants.constant_multiname[operands[i]].toString(constants, fullyQualifiedNames)));
|
||||
}
|
||||
s.append("\"");*/
|
||||
break;
|
||||
case AVM2Code.DAT_STRING_INDEX:
|
||||
if (operands[i] == 0) {
|
||||
s.append(" null");
|
||||
} else {
|
||||
s.append(" \"");
|
||||
s.append(Helper.escapeString(constants.getString(operands[i])));
|
||||
s.append("\"");
|
||||
}
|
||||
break;
|
||||
case AVM2Code.DAT_INT_INDEX:
|
||||
if (operands[i] == 0) {
|
||||
s.append(" null");
|
||||
} else {
|
||||
s.append(" ");
|
||||
s.append(constants.getInt(operands[i]));
|
||||
}
|
||||
break;
|
||||
case AVM2Code.DAT_UINT_INDEX:
|
||||
if (operands[i] == 0) {
|
||||
s.append(" null");
|
||||
} else {
|
||||
s.append(" ");
|
||||
s.append(constants.getUInt(operands[i]));
|
||||
}
|
||||
break;
|
||||
case AVM2Code.DAT_DOUBLE_INDEX:
|
||||
if (operands[i] == 0) {
|
||||
s.append(" null");
|
||||
} else {
|
||||
s.append(" ");
|
||||
s.append(constants.getDouble(operands[i]));
|
||||
}
|
||||
break;
|
||||
case AVM2Code.DAT_OFFSET:
|
||||
s.append(" ");
|
||||
s.append("ofs");
|
||||
s.append(Helper.formatAddress(offset + operands[i] + getBytes().length));
|
||||
break;
|
||||
case AVM2Code.DAT_CASE_BASEOFFSET:
|
||||
s.append(" ");
|
||||
s.append("ofs");
|
||||
s.append(Helper.formatAddress(offset + operands[i]));
|
||||
break;
|
||||
case AVM2Code.OPT_CASE_OFFSETS:
|
||||
s.append(" ");
|
||||
s.append(operands[i]);
|
||||
for (int j = i + 1; j < operands.length; j++) {
|
||||
s.append(" ");
|
||||
s.append("ofs");
|
||||
s.append(Helper.formatAddress(offset + operands[j]));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
s.append(" ");
|
||||
s.append(operands[i]);
|
||||
}
|
||||
|
||||
}
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
public String getComment() {
|
||||
if (ignored) {
|
||||
return " ;ignored";
|
||||
}
|
||||
if ((comment == null) || comment.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
return " ;" + comment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isIgnored() {
|
||||
return ignored;
|
||||
}
|
||||
|
||||
public GraphTextWriter toString(GraphTextWriter writer, LocalData localData) {
|
||||
writer.appendNoHilight(Helper.formatAddress(offset) + " " + Helper.padSpaceRight(Helper.byteArrToString(getBytes()), 30) + definition.instructionName);
|
||||
writer.appendNoHilight(getParams(localData.constantsAvm2, localData.fullyQualifiedNames) + getComment());
|
||||
return writer;
|
||||
}
|
||||
|
||||
public String toStringNoAddress(ConstantPool constants, List<String> fullyQualifiedNames) {
|
||||
String s = definition.instructionName;
|
||||
s += getParams(constants, fullyQualifiedNames) + getComment();
|
||||
return s;
|
||||
}
|
||||
public List<Object> replaceWith;
|
||||
|
||||
@Override
|
||||
public void translate(BaseLocalData localData, Stack<GraphTargetItem> stack, List<GraphTargetItem> output, int staticOperation, String path) throws InterruptedException {
|
||||
AVM2LocalData aLocalData = (AVM2LocalData) localData;
|
||||
definition.translate(aLocalData.isStatic,
|
||||
aLocalData.scriptIndex,
|
||||
aLocalData.classIndex,
|
||||
aLocalData.localRegs,
|
||||
stack,
|
||||
aLocalData.scopeStack,
|
||||
aLocalData.constants, this, aLocalData.methodInfo, output, aLocalData.methodBody, aLocalData.abc, aLocalData.localRegNames, aLocalData.fullyQualifiedNames, null, aLocalData.localRegAssignmentIps, aLocalData.ip, aLocalData.refs, aLocalData.code);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isJump() {
|
||||
return (definition instanceof JumpIns) || (fixedBranch > -1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBranch() {
|
||||
if (fixedBranch > -1) {
|
||||
return false;
|
||||
}
|
||||
return (definition instanceof IfTypeIns) || (definition instanceof LookupSwitchIns);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExit() {
|
||||
return (definition instanceof ReturnValueIns) || (definition instanceof ReturnVoidIns) || (definition instanceof ThrowIns);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getOffset() {
|
||||
return mappedOffset > -1 ? mappedOffset : offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Integer> getBranches(GraphSource code) {
|
||||
List<Integer> ret = new ArrayList<>();
|
||||
if (definition instanceof IfTypeIns) {
|
||||
|
||||
if (fixedBranch == -1 || fixedBranch == 0) {
|
||||
ret.add(code.adr2pos(offset + getBytes().length + operands[0]));
|
||||
}
|
||||
if (!(definition instanceof JumpIns)) {
|
||||
if (fixedBranch == -1 || fixedBranch == 1) {
|
||||
ret.add(code.adr2pos(offset + getBytes().length));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (definition instanceof LookupSwitchIns) {
|
||||
if (fixedBranch == -1 || fixedBranch == 0) {
|
||||
ret.add(code.adr2pos(offset + operands[0]));
|
||||
}
|
||||
for (int k = 2; k < operands.length; k++) {
|
||||
if (fixedBranch == -1 || fixedBranch == k - 1) {
|
||||
ret.add(code.adr2pos(offset + operands[k]));
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean ignoredLoops() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIgnored(boolean ignored, int pos) {
|
||||
this.ignored = ignored;
|
||||
}
|
||||
|
||||
public void setFixBranch(int pos) {
|
||||
this.fixedBranch = pos;
|
||||
}
|
||||
private int fixedBranch = -1;
|
||||
|
||||
public int getFixBranch() {
|
||||
return fixedBranch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDeobfuscatePop() {
|
||||
return definition instanceof DeobfuscatePopIns;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PopIns;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class DeobfuscatePopIns extends PopIns {
|
||||
|
||||
public DeobfuscatePopIns() {
|
||||
instructionName = "ffdec_deobfuscatepop";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions;
|
||||
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import java.util.Stack;
|
||||
|
||||
public interface IfTypeIns {
|
||||
|
||||
public abstract void translateInverted(java.util.HashMap<Integer, GraphTargetItem> localRegs, Stack<GraphTargetItem> stack, AVM2Instruction ins);
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.ConstantPool;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.LocalDataArea;
|
||||
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.model.AVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.FullMultinameAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.Stack;
|
||||
|
||||
public class InstructionDefinition implements Serializable {
|
||||
|
||||
public static final long serialVersionUID = 1L;
|
||||
|
||||
public int[] operands;
|
||||
public String instructionName = "";
|
||||
public int instructionCode = 0;
|
||||
|
||||
public InstructionDefinition(int instructionCode, String instructionName, int[] operands) {
|
||||
this.instructionCode = instructionCode;
|
||||
this.instructionName = instructionName;
|
||||
this.operands = operands;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder s = new StringBuilder();
|
||||
s.append(instructionName);
|
||||
for (int i = 0; i < operands.length; i++) {
|
||||
if ((operands[i] & 0xff00) == AVM2Code.OPT_U30) {
|
||||
s.append(" U30");
|
||||
}
|
||||
if ((operands[i] & 0xff00) == AVM2Code.OPT_U8) {
|
||||
s.append(" U8");
|
||||
}
|
||||
if ((operands[i] & 0xff00) == AVM2Code.OPT_BYTE) {
|
||||
s.append(" BYTE");
|
||||
}
|
||||
if ((operands[i] & 0xff00) == AVM2Code.OPT_S24) {
|
||||
s.append(" S24");
|
||||
}
|
||||
if ((operands[i] & 0xff00) == AVM2Code.OPT_CASE_OFFSETS) {
|
||||
s.append(" U30 S24,[S24]...");
|
||||
}
|
||||
}
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
public void execute(LocalDataArea lda, ConstantPool constants, List<Object> arguments) {
|
||||
throw new UnsupportedOperationException("Instruction " + instructionName + " not implemented");
|
||||
}
|
||||
|
||||
public void translate(boolean isStatic, int scriptIndex, int classIndex, java.util.HashMap<Integer, GraphTargetItem> localRegs, Stack<GraphTargetItem> stack, java.util.Stack<GraphTargetItem> scopeStack, ConstantPool constants, AVM2Instruction ins, List<MethodInfo> method_info, List<GraphTargetItem> output, MethodBody body, ABC abc, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames, String path, HashMap<Integer, Integer> localRegsAssignmentIps, int ip, HashMap<Integer, List<Integer>> refs, AVM2Code code) throws InterruptedException {
|
||||
}
|
||||
|
||||
protected FullMultinameAVM2Item resolveMultiname(Stack<GraphTargetItem> stack, ConstantPool constants, int multinameIndex, AVM2Instruction ins) {
|
||||
GraphTargetItem ns = null;
|
||||
GraphTargetItem name = null;
|
||||
if (constants.getMultiname(multinameIndex).needsName()) {
|
||||
name = (GraphTargetItem) stack.pop();
|
||||
}
|
||||
if (constants.getMultiname(multinameIndex).needsNs()) {
|
||||
ns = (GraphTargetItem) stack.pop();
|
||||
}
|
||||
return new FullMultinameAVM2Item(ins, multinameIndex, name, ns);
|
||||
}
|
||||
|
||||
protected int resolvedCount(ConstantPool 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, ConstantPool constants, int multinameIndex, AVM2Instruction ins, List<String> 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), ins.offset);
|
||||
}
|
||||
return name + ns;
|
||||
}
|
||||
|
||||
public int getStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
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<Integer>());
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.AVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
public interface SetTypeIns {
|
||||
|
||||
public abstract String getObject(Stack<AVM2Item> stack, ABC abc, AVM2Instruction ins, List<AVM2Item> output, MethodBody body, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames) throws InterruptedException;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class TagInstruction extends InstructionDefinition {
|
||||
|
||||
public static final long serialVersionUID = 1L;
|
||||
|
||||
public TagInstruction(String tagName) {
|
||||
super(-1, tagName, new int[0]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.ConstantPool;
|
||||
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.model.AlchemyLoadAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class Lf32Ins extends InstructionDefinition {
|
||||
|
||||
public Lf32Ins() {
|
||||
super(0x38, "lf32", new int[]{});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return 1 - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getScopeStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translate(boolean isStatic, int scriptIndex, int classIndex, HashMap<Integer, GraphTargetItem> localRegs, Stack<GraphTargetItem> stack, Stack<GraphTargetItem> scopeStack, ConstantPool constants, AVM2Instruction ins, List<MethodInfo> method_info, List<GraphTargetItem> output, MethodBody body, ABC abc, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames, String path, HashMap<Integer, Integer> localRegsAssignmentIps, int ip, HashMap<Integer, List<Integer>> refs, AVM2Code code) {
|
||||
GraphTargetItem ofs = stack.pop();
|
||||
stack.push(new AlchemyLoadAVM2Item(ins, ofs, instructionName));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.ConstantPool;
|
||||
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.model.AlchemyLoadAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class Lf64Ins extends InstructionDefinition {
|
||||
|
||||
public Lf64Ins() {
|
||||
super(0x39, "lf64", new int[]{});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return 1 - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getScopeStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translate(boolean isStatic, int scriptIndex, int classIndex, HashMap<Integer, GraphTargetItem> localRegs, Stack<GraphTargetItem> stack, Stack<GraphTargetItem> scopeStack, ConstantPool constants, AVM2Instruction ins, List<MethodInfo> method_info, List<GraphTargetItem> output, MethodBody body, ABC abc, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames, String path, HashMap<Integer, Integer> localRegsAssignmentIps, int ip, HashMap<Integer, List<Integer>> refs, AVM2Code code) {
|
||||
GraphTargetItem ofs = stack.pop();
|
||||
stack.push(new AlchemyLoadAVM2Item(ins, ofs, instructionName));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.ConstantPool;
|
||||
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.model.AlchemyLoadAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class Li16Ins extends InstructionDefinition {
|
||||
|
||||
public Li16Ins() {
|
||||
super(0x36, "li16", new int[]{});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return 1 - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getScopeStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translate(boolean isStatic, int scriptIndex, int classIndex, HashMap<Integer, GraphTargetItem> localRegs, Stack<GraphTargetItem> stack, Stack<GraphTargetItem> scopeStack, ConstantPool constants, AVM2Instruction ins, List<MethodInfo> method_info, List<GraphTargetItem> output, MethodBody body, ABC abc, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames, String path, HashMap<Integer, Integer> localRegsAssignmentIps, int ip, HashMap<Integer, List<Integer>> refs, AVM2Code code) {
|
||||
GraphTargetItem ofs = stack.pop();
|
||||
stack.push(new AlchemyLoadAVM2Item(ins, ofs, instructionName));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.ConstantPool;
|
||||
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.model.AlchemyLoadAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class Li32Ins extends InstructionDefinition {
|
||||
|
||||
public Li32Ins() {
|
||||
super(0x37, "li32", new int[]{});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return 1 - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getScopeStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translate(boolean isStatic, int scriptIndex, int classIndex, HashMap<Integer, GraphTargetItem> localRegs, Stack<GraphTargetItem> stack, Stack<GraphTargetItem> scopeStack, ConstantPool constants, AVM2Instruction ins, List<MethodInfo> method_info, List<GraphTargetItem> output, MethodBody body, ABC abc, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames, String path, HashMap<Integer, Integer> localRegsAssignmentIps, int ip, HashMap<Integer, List<Integer>> refs, AVM2Code code) {
|
||||
GraphTargetItem ofs = stack.pop();
|
||||
stack.push(new AlchemyLoadAVM2Item(ins, ofs, instructionName));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.ConstantPool;
|
||||
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.model.AlchemyLoadAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class Li8Ins extends InstructionDefinition {
|
||||
|
||||
public Li8Ins() {
|
||||
super(0x35, "li8", new int[]{});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return 1 - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getScopeStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translate(boolean isStatic, int scriptIndex, int classIndex, HashMap<Integer, GraphTargetItem> localRegs, Stack<GraphTargetItem> stack, Stack<GraphTargetItem> scopeStack, ConstantPool constants, AVM2Instruction ins, List<MethodInfo> method_info, List<GraphTargetItem> output, MethodBody body, ABC abc, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames, String path, HashMap<Integer, Integer> localRegsAssignmentIps, int ip, HashMap<Integer, List<Integer>> refs, AVM2Code code) {
|
||||
GraphTargetItem ofs = stack.pop();
|
||||
stack.push(new AlchemyLoadAVM2Item(ins, ofs, instructionName));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.ConstantPool;
|
||||
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.model.AlchemyStoreAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class Sf32Ins extends InstructionDefinition {
|
||||
|
||||
public Sf32Ins() {
|
||||
super(0x3D, "sf32", new int[]{});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getScopeStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translate(boolean isStatic, int scriptIndex, int classIndex, HashMap<Integer, GraphTargetItem> localRegs, Stack<GraphTargetItem> stack, Stack<GraphTargetItem> scopeStack, ConstantPool constants, AVM2Instruction ins, List<MethodInfo> method_info, List<GraphTargetItem> output, MethodBody body, ABC abc, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames, String path, HashMap<Integer, Integer> localRegsAssignmentIps, int ip, HashMap<Integer, List<Integer>> refs, AVM2Code code) {
|
||||
GraphTargetItem ofs = stack.pop();
|
||||
GraphTargetItem value = stack.pop();
|
||||
stack.push(new AlchemyStoreAVM2Item(ins, value, ofs, instructionName));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.ConstantPool;
|
||||
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.model.AlchemyStoreAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class Sf64Ins extends InstructionDefinition {
|
||||
|
||||
public Sf64Ins() {
|
||||
super(0x3E, "sf64", new int[]{});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getScopeStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translate(boolean isStatic, int scriptIndex, int classIndex, HashMap<Integer, GraphTargetItem> localRegs, Stack<GraphTargetItem> stack, Stack<GraphTargetItem> scopeStack, ConstantPool constants, AVM2Instruction ins, List<MethodInfo> method_info, List<GraphTargetItem> output, MethodBody body, ABC abc, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames, String path, HashMap<Integer, Integer> localRegsAssignmentIps, int ip, HashMap<Integer, List<Integer>> refs, AVM2Code code) {
|
||||
GraphTargetItem ofs = stack.pop();
|
||||
GraphTargetItem value = stack.pop();
|
||||
stack.push(new AlchemyStoreAVM2Item(ins, value, ofs, instructionName));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.ConstantPool;
|
||||
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.model.AlchemyStoreAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class Si16Ins extends InstructionDefinition {
|
||||
|
||||
public Si16Ins() {
|
||||
super(0x3B, "si16", new int[]{});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getScopeStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translate(boolean isStatic, int scriptIndex, int classIndex, HashMap<Integer, GraphTargetItem> localRegs, Stack<GraphTargetItem> stack, Stack<GraphTargetItem> scopeStack, ConstantPool constants, AVM2Instruction ins, List<MethodInfo> method_info, List<GraphTargetItem> output, MethodBody body, ABC abc, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames, String path, HashMap<Integer, Integer> localRegsAssignmentIps, int ip, HashMap<Integer, List<Integer>> refs, AVM2Code code) {
|
||||
GraphTargetItem ofs = stack.pop();
|
||||
GraphTargetItem value = stack.pop();
|
||||
stack.push(new AlchemyStoreAVM2Item(ins, value, ofs, instructionName));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.ConstantPool;
|
||||
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.model.AlchemyStoreAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class Si32Ins extends InstructionDefinition {
|
||||
|
||||
public Si32Ins() {
|
||||
super(0x3C, "si32", new int[]{});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getScopeStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translate(boolean isStatic, int scriptIndex, int classIndex, HashMap<Integer, GraphTargetItem> localRegs, Stack<GraphTargetItem> stack, Stack<GraphTargetItem> scopeStack, ConstantPool constants, AVM2Instruction ins, List<MethodInfo> method_info, List<GraphTargetItem> output, MethodBody body, ABC abc, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames, String path, HashMap<Integer, Integer> localRegsAssignmentIps, int ip, HashMap<Integer, List<Integer>> refs, AVM2Code code) {
|
||||
GraphTargetItem ofs = stack.pop();
|
||||
GraphTargetItem value = stack.pop();
|
||||
stack.push(new AlchemyStoreAVM2Item(ins, value, ofs, instructionName));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.ConstantPool;
|
||||
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.model.AlchemyStoreAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class Si8Ins extends InstructionDefinition {
|
||||
|
||||
public Si8Ins() {
|
||||
super(0x3A, "si8", new int[]{});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getScopeStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translate(boolean isStatic, int scriptIndex, int classIndex, HashMap<Integer, GraphTargetItem> localRegs, Stack<GraphTargetItem> stack, Stack<GraphTargetItem> scopeStack, ConstantPool constants, AVM2Instruction ins, List<MethodInfo> method_info, List<GraphTargetItem> output, MethodBody body, ABC abc, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames, String path, HashMap<Integer, Integer> localRegsAssignmentIps, int ip, HashMap<Integer, List<Integer>> refs, AVM2Code code) {
|
||||
GraphTargetItem ofs = stack.pop();
|
||||
GraphTargetItem value = stack.pop();
|
||||
stack.push(new AlchemyStoreAVM2Item(ins, value, ofs, instructionName));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.ConstantPool;
|
||||
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.model.AlchemySignExtendAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class Sxi16Ins extends InstructionDefinition {
|
||||
|
||||
public Sxi16Ins() {
|
||||
super(0x52, "sxi_16", new int[]{});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return 1 - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getScopeStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translate(boolean isStatic, int scriptIndex, int classIndex, HashMap<Integer, GraphTargetItem> localRegs, Stack<GraphTargetItem> stack, Stack<GraphTargetItem> scopeStack, ConstantPool constants, AVM2Instruction ins, List<MethodInfo> method_info, List<GraphTargetItem> output, MethodBody body, ABC abc, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames, String path, HashMap<Integer, Integer> localRegsAssignmentIps, int ip, HashMap<Integer, List<Integer>> refs, AVM2Code code) {
|
||||
GraphTargetItem value = stack.pop();
|
||||
stack.push(new AlchemySignExtendAVM2Item(ins, value, instructionName));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.ConstantPool;
|
||||
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.model.AlchemySignExtendAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class Sxi1Ins extends InstructionDefinition {
|
||||
|
||||
public Sxi1Ins() {
|
||||
super(0x50, "sxi_1", new int[]{});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return 1 - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getScopeStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translate(boolean isStatic, int scriptIndex, int classIndex, HashMap<Integer, GraphTargetItem> localRegs, Stack<GraphTargetItem> stack, Stack<GraphTargetItem> scopeStack, ConstantPool constants, AVM2Instruction ins, List<MethodInfo> method_info, List<GraphTargetItem> output, MethodBody body, ABC abc, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames, String path, HashMap<Integer, Integer> localRegsAssignmentIps, int ip, HashMap<Integer, List<Integer>> refs, AVM2Code code) {
|
||||
GraphTargetItem value = stack.pop();
|
||||
stack.push(new AlchemySignExtendAVM2Item(ins, value, instructionName));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.ConstantPool;
|
||||
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.model.AlchemySignExtendAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class Sxi8Ins extends InstructionDefinition {
|
||||
|
||||
public Sxi8Ins() {
|
||||
super(0x51, "sxi_8", new int[]{});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return 1 - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getScopeStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translate(boolean isStatic, int scriptIndex, int classIndex, HashMap<Integer, GraphTargetItem> localRegs, Stack<GraphTargetItem> stack, Stack<GraphTargetItem> scopeStack, ConstantPool constants, AVM2Instruction ins, List<MethodInfo> method_info, List<GraphTargetItem> output, MethodBody body, ABC abc, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames, String path, HashMap<Integer, Integer> localRegsAssignmentIps, int ip, HashMap<Integer, List<Integer>> refs, AVM2Code code) {
|
||||
GraphTargetItem value = stack.pop();
|
||||
stack.push(new AlchemySignExtendAVM2Item(ins, value, instructionName));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.ConstantPool;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.operations.AddAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
public class AddIIns extends AddIns {
|
||||
|
||||
public AddIIns() {
|
||||
instructionName = "add_i";
|
||||
instructionCode = 0xc5;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translate(boolean isStatic, int scriptIndex, int classIndex, java.util.HashMap<Integer, GraphTargetItem> localRegs, Stack<GraphTargetItem> stack, java.util.Stack<GraphTargetItem> scopeStack, ConstantPool constants, AVM2Instruction ins, List<MethodInfo> method_info, List<GraphTargetItem> output, MethodBody body, ABC abc, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames, String path, HashMap<Integer, Integer> localRegsAssignmentIps, int ip, HashMap<Integer, List<Integer>> refs, AVM2Code code) {
|
||||
GraphTargetItem v2 = (GraphTargetItem) stack.pop();
|
||||
GraphTargetItem v1 = (GraphTargetItem) stack.pop();
|
||||
stack.push(new AddAVM2Item(ins, v1, v2));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return -2 + 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.ConstantPool;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.LocalDataArea;
|
||||
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.model.operations.AddAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
public class AddIns extends InstructionDefinition {
|
||||
|
||||
public AddIns() {
|
||||
super(0xa0, "add", new int[]{});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(LocalDataArea lda, ConstantPool constants, List<Object> arguments) {
|
||||
Object o1 = lda.operandStack.pop();
|
||||
Object o2 = lda.operandStack.pop();
|
||||
if ((o1 instanceof Long) && ((o2 instanceof Long))) {
|
||||
Long ret = Long.valueOf(((Long) o1).longValue() + ((Long) o2).longValue());
|
||||
lda.operandStack.push(ret);
|
||||
} else if ((o1 instanceof Double) && ((o2 instanceof Double))) {
|
||||
Double ret = Double.valueOf(((Double) o1).doubleValue() + ((Double) o2).doubleValue());
|
||||
lda.operandStack.push(ret);
|
||||
} else if ((o1 instanceof Long) && ((o2 instanceof Double))) {
|
||||
Double ret = new Double(((Long) o1).longValue() + ((Double) o2).doubleValue());
|
||||
lda.operandStack.push(ret);
|
||||
} else if ((o1 instanceof Double) && ((o2 instanceof Long))) {
|
||||
Double ret = new Double(((Double) o1).doubleValue() + ((Long) o2).longValue());
|
||||
lda.operandStack.push(ret);
|
||||
} else {
|
||||
String s = o1.toString() + o2.toString();
|
||||
lda.operandStack.push(s);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translate(boolean isStatic, int scriptIndex, int classIndex, java.util.HashMap<Integer, GraphTargetItem> localRegs, Stack<GraphTargetItem> stack, java.util.Stack<GraphTargetItem> scopeStack, ConstantPool constants, AVM2Instruction ins, List<MethodInfo> method_info, List<GraphTargetItem> output, MethodBody body, ABC abc, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames, String path, HashMap<Integer, Integer> localRegsAssignmentIps, int ip, HashMap<Integer, List<Integer>> refs, AVM2Code code) {
|
||||
GraphTargetItem v2 = (GraphTargetItem) stack.pop();
|
||||
GraphTargetItem v1 = (GraphTargetItem) stack.pop();
|
||||
stack.push(new AddAVM2Item(ins, v1, v2));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return -2 + 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.ConstantPool;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.LocalDataArea;
|
||||
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.model.DecrementAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
public class DecrementIIns extends InstructionDefinition {
|
||||
|
||||
public DecrementIIns() {
|
||||
super(0xc1, "decrement_i", new int[]{});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(LocalDataArea lda, ConstantPool constants, List<Object> arguments) {
|
||||
Object obj = lda.operandStack.pop();
|
||||
if (obj instanceof Long) {
|
||||
Long obj2 = ((Long) obj).longValue() - 1;
|
||||
lda.operandStack.push(obj2);
|
||||
} else if (obj instanceof Double) {
|
||||
Double obj2 = ((Double) obj).doubleValue() - 1;
|
||||
lda.operandStack.push(obj2);
|
||||
}
|
||||
if (obj instanceof String) {
|
||||
Double obj2 = Double.parseDouble((String) obj) - 1;
|
||||
lda.operandStack.push(obj2);
|
||||
} else {
|
||||
throw new RuntimeException("Cannot decrement local register");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translate(boolean isStatic, int scriptIndex, int classIndex, java.util.HashMap<Integer, GraphTargetItem> localRegs, Stack<GraphTargetItem> stack, java.util.Stack<GraphTargetItem> scopeStack, ConstantPool constants, AVM2Instruction ins, List<MethodInfo> method_info, List<GraphTargetItem> output, MethodBody body, ABC abc, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames, String path, HashMap<Integer, Integer> localRegsAssignmentIps, int ip, HashMap<Integer, List<Integer>> refs, AVM2Code code) {
|
||||
stack.push(new DecrementAVM2Item(ins, (GraphTargetItem) stack.pop()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return -1 + 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.ConstantPool;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.LocalDataArea;
|
||||
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.model.DecrementAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
public class DecrementIns extends InstructionDefinition {
|
||||
|
||||
public DecrementIns() {
|
||||
super(0x93, "decrement", new int[]{});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(LocalDataArea lda, ConstantPool constants, List<Object> arguments) {
|
||||
Object obj = lda.operandStack.pop();
|
||||
if (obj instanceof Long) {
|
||||
Long obj2 = ((Long) obj).longValue() - 1;
|
||||
lda.operandStack.push(obj2);
|
||||
} else if (obj instanceof Double) {
|
||||
Double obj2 = ((Double) obj).doubleValue() - 1;
|
||||
lda.operandStack.push(obj2);
|
||||
}
|
||||
if (obj instanceof String) {
|
||||
Double obj2 = Double.parseDouble((String) obj) - 1;
|
||||
lda.operandStack.push(obj2);
|
||||
} else {
|
||||
throw new RuntimeException("Cannot decrement local register");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translate(boolean isStatic, int scriptIndex, int classIndex, java.util.HashMap<Integer, GraphTargetItem> localRegs, Stack<GraphTargetItem> stack, java.util.Stack<GraphTargetItem> scopeStack, ConstantPool constants, AVM2Instruction ins, List<MethodInfo> method_info, List<GraphTargetItem> output, MethodBody body, ABC abc, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames, String path, HashMap<Integer, Integer> localRegsAssignmentIps, int ip, HashMap<Integer, List<Integer>> refs, AVM2Code code) {
|
||||
stack.push(new DecrementAVM2Item(ins, (GraphTargetItem) stack.pop()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return -1 + 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.ConstantPool;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.LocalDataArea;
|
||||
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.model.operations.DivideAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
public class DivideIns extends InstructionDefinition {
|
||||
|
||||
public DivideIns() {
|
||||
super(0xa3, "divide", new int[]{});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(LocalDataArea lda, ConstantPool constants, List<Object> arguments) {
|
||||
Object o2 = lda.operandStack.pop();
|
||||
Object o1 = lda.operandStack.pop();
|
||||
if ((o1 instanceof Long) && ((o2 instanceof Long))) {
|
||||
Long ret = Long.valueOf(((Long) o1).longValue() / ((Long) o2).longValue());
|
||||
lda.operandStack.push(ret);
|
||||
} else if ((o1 instanceof Double) && ((o2 instanceof Double))) {
|
||||
Double ret = Double.valueOf(((Double) o1).doubleValue() / ((Double) o2).doubleValue());
|
||||
lda.operandStack.push(ret);
|
||||
} else if ((o1 instanceof Long) && ((o2 instanceof Double))) {
|
||||
Double ret = new Double(((Long) o1).longValue() / ((Double) o2).doubleValue());
|
||||
lda.operandStack.push(ret);
|
||||
} else if ((o1 instanceof Double) && ((o2 instanceof Long))) {
|
||||
Double ret = new Double(((Double) o1).doubleValue() / ((Long) o2).longValue());
|
||||
lda.operandStack.push(ret);
|
||||
} else {
|
||||
throw new RuntimeException("Cannot divide");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translate(boolean isStatic, int scriptIndex, int classIndex, java.util.HashMap<Integer, GraphTargetItem> localRegs, Stack<GraphTargetItem> stack, java.util.Stack<GraphTargetItem> scopeStack, ConstantPool constants, AVM2Instruction ins, List<MethodInfo> method_info, List<GraphTargetItem> output, MethodBody body, ABC abc, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames, String path, HashMap<Integer, Integer> localRegsAssignmentIps, int ip, HashMap<Integer, List<Integer>> refs, AVM2Code code) {
|
||||
GraphTargetItem v2 = (GraphTargetItem) stack.pop();
|
||||
GraphTargetItem v1 = (GraphTargetItem) stack.pop();
|
||||
stack.push(new DivideAVM2Item(ins, v1, v2));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return -2 + 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.ConstantPool;
|
||||
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.model.IncrementAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
public class IncrementIIns extends InstructionDefinition {
|
||||
|
||||
public IncrementIIns() {
|
||||
super(0xc0, "increment_i", new int[]{});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translate(boolean isStatic, int scriptIndex, int classIndex, java.util.HashMap<Integer, GraphTargetItem> localRegs, Stack<GraphTargetItem> stack, java.util.Stack<GraphTargetItem> scopeStack, ConstantPool constants, AVM2Instruction ins, List<MethodInfo> method_info, List<GraphTargetItem> output, MethodBody body, ABC abc, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames, String path, HashMap<Integer, Integer> localRegsAssignmentIps, int ip, HashMap<Integer, List<Integer>> refs, AVM2Code code) {
|
||||
stack.push(new IncrementAVM2Item(ins, (GraphTargetItem) stack.pop()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return -1 + 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.ConstantPool;
|
||||
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.model.IncrementAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
public class IncrementIns extends InstructionDefinition {
|
||||
|
||||
public IncrementIns() {
|
||||
super(0x91, "increment", new int[]{});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translate(boolean isStatic, int scriptIndex, int classIndex, java.util.HashMap<Integer, GraphTargetItem> localRegs, Stack<GraphTargetItem> stack, java.util.Stack<GraphTargetItem> scopeStack, ConstantPool constants, AVM2Instruction ins, List<MethodInfo> method_info, List<GraphTargetItem> output, MethodBody body, ABC abc, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames, String path, HashMap<Integer, Integer> localRegsAssignmentIps, int ip, HashMap<Integer, List<Integer>> refs, AVM2Code code) {
|
||||
stack.push(new IncrementAVM2Item(ins, (GraphTargetItem) stack.pop()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return -1 + 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.ConstantPool;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.LocalDataArea;
|
||||
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.model.operations.ModuloAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
public class ModuloIns extends InstructionDefinition {
|
||||
|
||||
public ModuloIns() {
|
||||
super(0xa4, "modulo", new int[]{});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(LocalDataArea lda, ConstantPool constants, List<Object> arguments) {
|
||||
Object o1 = lda.operandStack.pop();
|
||||
Object o2 = lda.operandStack.pop();
|
||||
|
||||
if ((o1 instanceof Long) && ((o2 instanceof Long))) {
|
||||
Long ret = Long.valueOf(((Long) o2).longValue() % ((Long) o1).longValue());
|
||||
lda.operandStack.push(ret);
|
||||
} else {
|
||||
throw new RuntimeException("Cannot modulo");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translate(boolean isStatic, int scriptIndex, int classIndex, java.util.HashMap<Integer, GraphTargetItem> localRegs, Stack<GraphTargetItem> stack, java.util.Stack<GraphTargetItem> scopeStack, ConstantPool constants, AVM2Instruction ins, List<MethodInfo> method_info, List<GraphTargetItem> output, MethodBody body, ABC abc, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames, String path, HashMap<Integer, Integer> localRegsAssignmentIps, int ip, HashMap<Integer, List<Integer>> refs, AVM2Code code) {
|
||||
GraphTargetItem v2 = (GraphTargetItem) stack.pop();
|
||||
GraphTargetItem v1 = (GraphTargetItem) stack.pop();
|
||||
stack.push(new ModuloAVM2Item(ins, v1, v2));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return -2 + 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.ConstantPool;
|
||||
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.model.operations.MultiplyAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
public class MultiplyIIns extends InstructionDefinition {
|
||||
|
||||
public MultiplyIIns() {
|
||||
super(0xc7, "multiply_i", new int[]{});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translate(boolean isStatic, int scriptIndex, int classIndex, java.util.HashMap<Integer, GraphTargetItem> localRegs, Stack<GraphTargetItem> stack, java.util.Stack<GraphTargetItem> scopeStack, ConstantPool constants, AVM2Instruction ins, List<MethodInfo> method_info, List<GraphTargetItem> output, MethodBody body, ABC abc, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames, String path, HashMap<Integer, Integer> localRegsAssignmentIps, int ip, HashMap<Integer, List<Integer>> refs, AVM2Code code) {
|
||||
GraphTargetItem v2 = (GraphTargetItem) stack.pop();
|
||||
GraphTargetItem v1 = (GraphTargetItem) stack.pop();
|
||||
stack.push(new MultiplyAVM2Item(ins, v1, v2));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return -2 + 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.ConstantPool;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.LocalDataArea;
|
||||
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.model.operations.MultiplyAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
public class MultiplyIns extends InstructionDefinition {
|
||||
|
||||
public MultiplyIns() {
|
||||
super(0xa2, "multiply", new int[]{});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(LocalDataArea lda, ConstantPool constants, List<Object> arguments) {
|
||||
Object o1 = lda.operandStack.pop();
|
||||
Object o2 = lda.operandStack.pop();
|
||||
if ((o1 instanceof Long) && ((o2 instanceof Long))) {
|
||||
Long ret = Long.valueOf(((Long) o1).longValue() * ((Long) o2).longValue());
|
||||
lda.operandStack.push(ret);
|
||||
} else if ((o1 instanceof Double) && ((o2 instanceof Double))) {
|
||||
Double ret = Double.valueOf(((Double) o1).doubleValue() * ((Double) o2).doubleValue());
|
||||
lda.operandStack.push(ret);
|
||||
} else if ((o1 instanceof Long) && ((o2 instanceof Double))) {
|
||||
Double ret = new Double(((Long) o1).longValue() * ((Double) o2).doubleValue());
|
||||
lda.operandStack.push(ret);
|
||||
} else if ((o1 instanceof Double) && ((o2 instanceof Long))) {
|
||||
Double ret = new Double(((Double) o1).doubleValue() * ((Long) o2).longValue());
|
||||
lda.operandStack.push(ret);
|
||||
} else {
|
||||
throw new RuntimeException("Cannot multiply");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translate(boolean isStatic, int scriptIndex, int classIndex, java.util.HashMap<Integer, GraphTargetItem> localRegs, Stack<GraphTargetItem> stack, java.util.Stack<GraphTargetItem> scopeStack, ConstantPool constants, AVM2Instruction ins, List<MethodInfo> method_info, List<GraphTargetItem> output, MethodBody body, ABC abc, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames, String path, HashMap<Integer, Integer> localRegsAssignmentIps, int ip, HashMap<Integer, List<Integer>> refs, AVM2Code code) {
|
||||
GraphTargetItem v2 = (GraphTargetItem) stack.pop();
|
||||
GraphTargetItem v1 = (GraphTargetItem) stack.pop();
|
||||
stack.push(new MultiplyAVM2Item(ins, v1, v2));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return -2 + 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.ConstantPool;
|
||||
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.model.operations.NegAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
public class NegateIIns extends InstructionDefinition {
|
||||
|
||||
public NegateIIns() {
|
||||
super(0xc4, "negate_i", new int[]{});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translate(boolean isStatic, int scriptIndex, int classIndex, java.util.HashMap<Integer, GraphTargetItem> localRegs, Stack<GraphTargetItem> stack, java.util.Stack<GraphTargetItem> scopeStack, ConstantPool constants, AVM2Instruction ins, List<MethodInfo> method_info, List<GraphTargetItem> output, MethodBody body, ABC abc, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames, String path, HashMap<Integer, Integer> localRegsAssignmentIps, int ip, HashMap<Integer, List<Integer>> refs, AVM2Code code) {
|
||||
GraphTargetItem v = (GraphTargetItem) stack.pop();
|
||||
stack.push(new NegAVM2Item(ins, v));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return -1 + 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.ConstantPool;
|
||||
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.model.operations.NegAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
public class NegateIns extends InstructionDefinition {
|
||||
|
||||
public NegateIns() {
|
||||
super(0x90, "negate", new int[]{});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translate(boolean isStatic, int scriptIndex, int classIndex, java.util.HashMap<Integer, GraphTargetItem> localRegs, Stack<GraphTargetItem> stack, java.util.Stack<GraphTargetItem> scopeStack, ConstantPool constants, AVM2Instruction ins, List<MethodInfo> method_info, List<GraphTargetItem> output, MethodBody body, ABC abc, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames, String path, HashMap<Integer, Integer> localRegsAssignmentIps, int ip, HashMap<Integer, List<Integer>> refs, AVM2Code code) {
|
||||
GraphTargetItem v = (GraphTargetItem) stack.pop();
|
||||
stack.push(new NegAVM2Item(ins, v));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStackDelta(AVM2Instruction ins, ABC abc) {
|
||||
return -1 + 1;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user