jump to resources view from hex view

This commit is contained in:
2016-08-01 16:53:54 +02:00
parent 234ed1c915
commit 5107a644cc
63 changed files with 23142 additions and 22930 deletions
+111 -111
View File
@@ -1,111 +1,111 @@
/*
* Copyright (C) 2010-2016 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;
}
}
/*
* Copyright (C) 2010-2016 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;
}
}
+83 -83
View File
@@ -1,83 +1,83 @@
/*
* Copyright (C) 2010-2016 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 {
protected static final int kBlockHeaderSize = 8192; // Two pages: almost 64k entries
private static final int kMaxBlocks = (kBlockHeaderSize - 80) * 8;
private final long magic; // c3 ca 04 c1
private final long version; // 00 00 02 00
private final int this_file;
private final int next_file;
private final int entry_size;
private final int num_entries;
private final int max_entries;
private int empty[] = new int[4];
private int hints[] = new int[4];
private final int updating;
private int user[] = new int[5];
private final long allocation_map[];
public BlockFileHeader(InputStream is) throws IOException {
this.allocation_map = new long[kMaxBlocks / 32];
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();
}
}
}
/*
* Copyright (C) 2010-2016 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 {
protected static final int kBlockHeaderSize = 8192; // Two pages: almost 64k entries
private static final int kMaxBlocks = (kBlockHeaderSize - 80) * 8;
private final long magic; // c3 ca 04 c1
private final long version; // 00 00 02 00
private final int this_file;
private final int next_file;
private final int entry_size;
private final int num_entries;
private final int max_entries;
private int[] empty = new int[4];
private int[] hints = new int[4];
private final int updating;
private int[] user = new int[5];
private final long allocation_map[];
public BlockFileHeader(InputStream is) throws IOException {
this.allocation_map = new long[kMaxBlocks / 32];
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();
}
}
}
+151 -151
View File
@@ -1,151 +1,151 @@
/*
* Copyright (C) 2010-2016 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 {
private static final int EXTERNAL = 0;
private static final int RANKINGS = 1;
private static final int BLOCK_256 = 2;
private static final int BLOCK_1K = 3;
private static final int BLOCK_4K = 4;
private static final int BLOCK_FILES = 5;
private static final int BLOCK_ENTRIES = 6;
private static final int BLOCK_EVICTED = 7;
private static final String blockNames[] = new String[]{"EXTERNAL", "RANKINGS", "BLOCK_256", "BLOCK_1K", "BLOCK_4K", "BLOCK_FILES", "BLOCK_ENTRIES", "BLOCK_EVICTED"};
private static final int blockSizes[] = new int[]{0, 36, 256, 1024, 4096, 8, 104, 48};
private static final long kInitializedMask = 0x80000000L;
private static final long kFileTypeMask = 0x70000000L;
private static final int kFileTypeOffset = 28;
private static final long kReservedBitsMask = 0x0c000000L;
private static final long kNumBlocksMask = 0x03000000L;
private static final int kNumBlocksOffset = 24;
private static final long kFileSelectorMask = 0x00ff0000L;
private static final int FileSelectorOffset = 16;
private static final long kStartBlockMask = 0x0000FFFFL;
private static final long kFileNameMask = 0x0FFFFFFFL;
private final boolean initialized;
private final int fileType;
private int numBlocks;
private int fileSelector;
private int startBlock;
private int fileName;
private final long val;
private final 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;
}
}
/*
* Copyright (C) 2010-2016 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 {
private static final int EXTERNAL = 0;
private static final int RANKINGS = 1;
private static final int BLOCK_256 = 2;
private static final int BLOCK_1K = 3;
private static final int BLOCK_4K = 4;
private static final int BLOCK_FILES = 5;
private static final int BLOCK_ENTRIES = 6;
private static final int BLOCK_EVICTED = 7;
private static final String[] blockNames = new String[]{"EXTERNAL", "RANKINGS", "BLOCK_256", "BLOCK_1K", "BLOCK_4K", "BLOCK_FILES", "BLOCK_ENTRIES", "BLOCK_EVICTED"};
private static final int[] blockSizes = new int[]{0, 36, 256, 1024, 4096, 8, 104, 48};
private static final long kInitializedMask = 0x80000000L;
private static final long kFileTypeMask = 0x70000000L;
private static final int kFileTypeOffset = 28;
private static final long kReservedBitsMask = 0x0c000000L;
private static final long kNumBlocksMask = 0x03000000L;
private static final int kNumBlocksOffset = 24;
private static final long kFileSelectorMask = 0x00ff0000L;
private static final int FileSelectorOffset = 16;
private static final long kStartBlockMask = 0x0000FFFFL;
private static final long kFileNameMask = 0x0FFFFFFFL;
private final boolean initialized;
private final int fileType;
private int numBlocks;
private int fileSelector;
private int startBlock;
private int fileName;
private final long val;
private final 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;
}
}
+174 -174
View File
@@ -1,174 +1,174 @@
/*
* Copyright (C) 2010-2016 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];
if (iis.read(key) != key.length) {
throw new IOException();
}
}
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.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";
}
}
/*
* Copyright (C) 2010-2016 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];
if (iis.read(key) != key.length) {
throw new IOException();
}
}
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.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";
}
}
+127 -127
View File
@@ -1,127 +1,127 @@
/*
* Copyright (C) 2010-2016 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
}
}
/*
* Copyright (C) 2010-2016 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
}
}
+76 -76
View File
@@ -1,76 +1,76 @@
/*
* Copyright (C) 2010-2016 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);
}
}
/*
* Copyright (C) 2010-2016 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);
}
}
+83 -83
View File
@@ -1,83 +1,83 @@
/*
* Copyright (C) 2010-2016 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];
if (read(data) != len) {
throw new IOException();
}
return new String(data);
}
}
/*
* Copyright (C) 2010-2016 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];
if (read(data) != len) {
throw new IOException();
}
return new String(data);
}
}
+79 -79
View File
@@ -1,79 +1,79 @@
/*
* Copyright (C) 2010-2016 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();
}
}
}
/*
* Copyright (C) 2010-2016 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();
}
}
}
+167 -167
View File
@@ -1,167 +1,167 @@
/*
* Copyright (C) 2010-2016 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 volatile FirefoxCache instance;
private FirefoxCache() {
}
public static FirefoxCache getInstance() {
if (instance == null) {
synchronized (FirefoxCache.class) {
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;
}
}
/*
* Copyright (C) 2010-2016 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 volatile FirefoxCache instance;
private FirefoxCache() {
}
public static FirefoxCache getInstance() {
if (instance == null) {
synchronized (FirefoxCache.class) {
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;
}
}
+132 -132
View File
@@ -1,132 +1,132 @@
/*
* Copyright (C) 2010-2016 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() {
MetaData m = getMetaData();
if (m == null) {
return null;
}
String 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;
}
}
/*
* Copyright (C) 2010-2016 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() {
MetaData m = getMetaData();
if (m == null) {
return null;
}
String 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;
}
}
+93 -93
View File
@@ -1,93 +1,93 @@
/*
* Copyright (C) 2010-2016 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];
if (cis.read(req) != req.length) {
throw new IOException();
}
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;
}
}
}
/*
* Copyright (C) 2010-2016 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];
if (cis.read(req) != req.length) {
throw new IOException();
}
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;
}
}
}
@@ -1532,7 +1532,7 @@ public class CommandLineArgumentParser {
Integer min = null;
Integer max = null;
if (r.contains("-")) {
String ps[] = r.split("\\-");
String[] ps = r.split("\\-");
if (ps.length != 2) {
System.err.println("invalid range");
badArguments("select");
@@ -1,235 +1,235 @@
/*
* Copyright (C) 2010-2016 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.console;
import com.jpexs.helpers.utf8.Utf8Helper;
import com.sun.jna.Platform;
import com.sun.jna.WString;
import com.sun.jna.platform.win32.Advapi32Util;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.SHELLEXECUTEINFO;
import com.sun.jna.platform.win32.Shell32;
import com.sun.jna.platform.win32.Win32Exception;
import com.sun.jna.platform.win32.WinReg;
import com.sun.jna.platform.win32.WinUser;
import java.io.File;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author JPEXS
*/
public class ContextMenuTools {
public static String getAppDir() {
String path = Utf8Helper.urlDecode(ContextMenuTools.class.getProtectionDomain().getCodeSource().getLocation().getPath());
String appDir = new File(path).getParentFile().getAbsolutePath();
if (!appDir.endsWith("\\")) {
appDir += "\\";
}
return appDir;
}
public static boolean isAddedToContextMenu() {
if (!Platform.isWindows()) {
return false;
}
final WinReg.HKEY REG_CLASSES_HKEY = WinReg.HKEY_LOCAL_MACHINE;
final String REG_CLASSES_PATH = "Software\\Classes\\";
try {
if (!Advapi32Util.registryKeyExists(REG_CLASSES_HKEY, REG_CLASSES_PATH + ".swf")) {
return false;
}
String clsName = Advapi32Util.registryGetStringValue(REG_CLASSES_HKEY, REG_CLASSES_PATH + ".swf", "");
if (clsName == null) {
return false;
}
return Advapi32Util.registryKeyExists(REG_CLASSES_HKEY, REG_CLASSES_PATH + clsName + "\\shell\\ffdec");
} catch (Win32Exception ex) {
return false;
}
}
public static boolean addToContextMenu(boolean add, boolean fromCommandLine) {
if (add == isAddedToContextMenu()) {
return true;
}
String exeName = "ffdec.exe";
if (add) {
return addToContextMenu(add, fromCommandLine, exeName);
} else {
// remove both 32 and 64 bit references
return addToContextMenu(add, fromCommandLine, exeName)
&& addToContextMenu(add, fromCommandLine, "ffdec64.exe"); //remove 64 exe from previous versions
}
}
private static boolean addToContextMenu(boolean add, boolean fromCommandLine, String exeName) {
final String extensions[] = new String[]{"swf", "gfx"};
final WinReg.HKEY REG_CLASSES_HKEY = WinReg.HKEY_LOCAL_MACHINE;
final String REG_CLASSES_PATH = "Software\\Classes\\";
String appDir = getAppDir();
String verb = "ffdec";
String verbName = "Open with FFDec";
boolean exists;
try {
exists = Advapi32Util.registryKeyExists(REG_CLASSES_HKEY, REG_CLASSES_PATH + "Applications\\" + exeName);
if ((!exists) && add) { //add
Advapi32Util.registryCreateKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + "Applications\\" + exeName);
Advapi32Util.registryCreateKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + "Applications\\" + exeName + "\\shell");
Advapi32Util.registryCreateKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + "Applications\\" + exeName + "\\shell\\open");
Advapi32Util.registrySetStringValue(REG_CLASSES_HKEY, REG_CLASSES_PATH + "Applications\\" + exeName + "\\shell\\open", "", verbName);
Advapi32Util.registryCreateKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + "Applications\\" + exeName + "\\shell\\open\\command");
Advapi32Util.registrySetStringValue(REG_CLASSES_HKEY, REG_CLASSES_PATH + "Applications\\" + exeName + "\\shell\\open\\command", "", "\"" + appDir + exeName + "\" \"%1\"");
}
for (String ext : extensions) {
// 1) Add to context menu of SWF
if (!Advapi32Util.registryKeyExists(REG_CLASSES_HKEY, REG_CLASSES_PATH + "." + ext)) {
Advapi32Util.registryCreateKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + "." + ext);
Advapi32Util.registrySetStringValue(REG_CLASSES_HKEY, REG_CLASSES_PATH + "." + ext, "", "ShockwaveFlash.ShockwaveFlash");
}
if (Advapi32Util.registryValueExists(REG_CLASSES_HKEY, REG_CLASSES_PATH + "." + ext, "")) {
String clsName = Advapi32Util.registryGetStringValue(REG_CLASSES_HKEY, REG_CLASSES_PATH + "." + ext, "");
if (!Advapi32Util.registryKeyExists(REG_CLASSES_HKEY, REG_CLASSES_PATH + clsName)) {
Advapi32Util.registryCreateKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + clsName);
Advapi32Util.registrySetStringValue(REG_CLASSES_HKEY, REG_CLASSES_PATH + clsName, "", "Flash Movie");
}
if (!Advapi32Util.registryKeyExists(REG_CLASSES_HKEY, REG_CLASSES_PATH + clsName + "\\shell")) {
Advapi32Util.registryCreateKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + clsName + "\\shell");
}
exists = Advapi32Util.registryKeyExists(REG_CLASSES_HKEY, REG_CLASSES_PATH + clsName + "\\shell\\" + verb);
if ((!exists) && add) { //add
Advapi32Util.registryCreateKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + clsName + "\\shell\\" + verb);
Advapi32Util.registrySetStringValue(REG_CLASSES_HKEY, REG_CLASSES_PATH + clsName + "\\shell\\" + verb, "", verbName);
Advapi32Util.registryCreateKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + clsName + "\\shell\\" + verb + "\\command");
Advapi32Util.registrySetStringValue(REG_CLASSES_HKEY, REG_CLASSES_PATH + clsName + "\\shell\\" + verb + "\\command", "", "\"" + appDir + exeName + "\" \"%1\"");
}
if (exists && (!add)) { //remove
registryDeleteKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + clsName + "\\shell\\" + verb + "\\command");
registryDeleteKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + clsName + "\\shell\\" + verb);
}
}
exists = Advapi32Util.registryKeyExists(REG_CLASSES_HKEY, REG_CLASSES_PATH + "Applications\\" + exeName);
if (exists && (!add)) { //remove
registryDeleteKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + "Applications\\" + exeName + "\\shell\\open\\command");
registryDeleteKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + "Applications\\" + exeName + "\\shell\\open");
registryDeleteKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + "Applications\\" + exeName + "\\shell");
registryDeleteKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + "Applications\\" + exeName);
}
//2) Add to OpenWith list
if (Advapi32Util.registryValueExists(WinReg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\." + ext + "\\OpenWithList", "MRUList")) {
String mruList = Advapi32Util.registryGetStringValue(WinReg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\." + ext + "\\OpenWithList", "MRUList");
if (mruList != null) {
exists = false;
char appChar = 0;
for (int i = 0; i < mruList.length(); i++) {
String app = Advapi32Util.registryGetStringValue(WinReg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\." + ext + "\\OpenWithList", "" + mruList.charAt(i));
if (app.equals(exeName)) {
appChar = mruList.charAt(i);
exists = true;
break;
}
}
if ((!exists) && add) { //add
for (int c = 'a'; c <= 'z'; c++) {
if (mruList.indexOf(c) == -1) {
mruList += (char) c;
Advapi32Util.registrySetStringValue(WinReg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\." + ext + "\\OpenWithList", "" + (char) c, exeName);
Advapi32Util.registrySetStringValue(WinReg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\." + ext + "\\OpenWithList", "MRUList", mruList);
break;
}
}
}
if (exists && (!add)) { //remove
mruList = mruList.replace("" + appChar, "");
Advapi32Util.registrySetStringValue(WinReg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\." + ext + "\\OpenWithList", "MRUList", mruList);
registryDeleteValue(WinReg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\." + ext + "\\OpenWithList", "" + appChar);
}
}
}
//On some systems, file must be associated in SystemFileAssociations too
if (Advapi32Util.registryKeyExists(REG_CLASSES_HKEY, REG_CLASSES_PATH + "SystemFileAssociations")) {
exists = Advapi32Util.registryKeyExists(REG_CLASSES_HKEY, REG_CLASSES_PATH + "SystemFileAssociations\\." + ext + "\\Shell\\" + verb);
if ((!exists) && add) { //add
if (!Advapi32Util.registryKeyExists(REG_CLASSES_HKEY, REG_CLASSES_PATH + "SystemFileAssociations\\." + ext + "")) {
Advapi32Util.registryCreateKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + "SystemFileAssociations\\." + ext + "");
}
if (!Advapi32Util.registryKeyExists(REG_CLASSES_HKEY, REG_CLASSES_PATH + "SystemFileAssociations\\." + ext + "\\Shell")) {
Advapi32Util.registryCreateKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + "SystemFileAssociations\\." + ext + "\\Shell");
}
Advapi32Util.registryCreateKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + "SystemFileAssociations\\." + ext + "\\Shell\\" + verb);
Advapi32Util.registrySetStringValue(REG_CLASSES_HKEY, REG_CLASSES_PATH + "SystemFileAssociations\\." + ext + "\\Shell\\" + verb, "", verbName);
Advapi32Util.registryCreateKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + "SystemFileAssociations\\." + ext + "\\Shell\\" + verb + "\\Command");
Advapi32Util.registrySetStringValue(REG_CLASSES_HKEY, REG_CLASSES_PATH + "SystemFileAssociations\\." + ext + "\\Shell\\" + verb + "\\Command", "", "\"" + appDir + exeName + "\" \"%1\"");
}
if (exists && (!add)) { //remove
registryDeleteKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + "SystemFileAssociations\\." + ext + "\\Shell\\" + verb + "\\Command");
registryDeleteKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + "SystemFileAssociations\\." + ext + "\\Shell\\" + verb);
}
}
}
return true;
} catch (Exception ex) {
if (!fromCommandLine) {
//Updating registry failed, try elevating rights
SHELLEXECUTEINFO sei = new SHELLEXECUTEINFO();
sei.fMask = 0x00000040;
sei.lpVerb = new WString("runas");
sei.lpFile = new WString(appDir + exeName);
sei.lpParameters = new WString(add ? "-addtocontextmenu" : "-removefromcontextmenu");
sei.nShow = WinUser.SW_NORMAL;
Shell32.INSTANCE.ShellExecuteEx(sei);
//Wait till exit
Kernel32.INSTANCE.WaitForSingleObject(sei.hProcess, 1000 * 60 * 60 * 24 /*1 day max*/);
Kernel32.INSTANCE.CloseHandle(sei.hProcess);
} else {
Logger.getLogger(ContextMenuTools.class.getName()).log(Level.SEVERE, null, ex);
}
}
return false;
}
private static void registryDeleteKey(WinReg.HKEY hKey, String keyName) {
boolean exists = Advapi32Util.registryKeyExists(hKey, keyName);
if (exists) {
Advapi32Util.registryDeleteKey(hKey, keyName);
}
}
private static void registryDeleteValue(WinReg.HKEY root, String keyPath, String valueName) {
boolean exists = Advapi32Util.registryValueExists(root, keyPath, valueName);
if (exists) {
Advapi32Util.registryDeleteValue(root, keyPath, valueName);
}
}
}
/*
* Copyright (C) 2010-2016 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.console;
import com.jpexs.helpers.utf8.Utf8Helper;
import com.sun.jna.Platform;
import com.sun.jna.WString;
import com.sun.jna.platform.win32.Advapi32Util;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.SHELLEXECUTEINFO;
import com.sun.jna.platform.win32.Shell32;
import com.sun.jna.platform.win32.Win32Exception;
import com.sun.jna.platform.win32.WinReg;
import com.sun.jna.platform.win32.WinUser;
import java.io.File;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author JPEXS
*/
public class ContextMenuTools {
public static String getAppDir() {
String path = Utf8Helper.urlDecode(ContextMenuTools.class.getProtectionDomain().getCodeSource().getLocation().getPath());
String appDir = new File(path).getParentFile().getAbsolutePath();
if (!appDir.endsWith("\\")) {
appDir += "\\";
}
return appDir;
}
public static boolean isAddedToContextMenu() {
if (!Platform.isWindows()) {
return false;
}
final WinReg.HKEY REG_CLASSES_HKEY = WinReg.HKEY_LOCAL_MACHINE;
final String REG_CLASSES_PATH = "Software\\Classes\\";
try {
if (!Advapi32Util.registryKeyExists(REG_CLASSES_HKEY, REG_CLASSES_PATH + ".swf")) {
return false;
}
String clsName = Advapi32Util.registryGetStringValue(REG_CLASSES_HKEY, REG_CLASSES_PATH + ".swf", "");
if (clsName == null) {
return false;
}
return Advapi32Util.registryKeyExists(REG_CLASSES_HKEY, REG_CLASSES_PATH + clsName + "\\shell\\ffdec");
} catch (Win32Exception ex) {
return false;
}
}
public static boolean addToContextMenu(boolean add, boolean fromCommandLine) {
if (add == isAddedToContextMenu()) {
return true;
}
String exeName = "ffdec.exe";
if (add) {
return addToContextMenu(add, fromCommandLine, exeName);
} else {
// remove both 32 and 64 bit references
return addToContextMenu(add, fromCommandLine, exeName)
&& addToContextMenu(add, fromCommandLine, "ffdec64.exe"); //remove 64 exe from previous versions
}
}
private static boolean addToContextMenu(boolean add, boolean fromCommandLine, String exeName) {
final String[] extensions = new String[]{"swf", "gfx"};
final WinReg.HKEY REG_CLASSES_HKEY = WinReg.HKEY_LOCAL_MACHINE;
final String REG_CLASSES_PATH = "Software\\Classes\\";
String appDir = getAppDir();
String verb = "ffdec";
String verbName = "Open with FFDec";
boolean exists;
try {
exists = Advapi32Util.registryKeyExists(REG_CLASSES_HKEY, REG_CLASSES_PATH + "Applications\\" + exeName);
if ((!exists) && add) { //add
Advapi32Util.registryCreateKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + "Applications\\" + exeName);
Advapi32Util.registryCreateKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + "Applications\\" + exeName + "\\shell");
Advapi32Util.registryCreateKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + "Applications\\" + exeName + "\\shell\\open");
Advapi32Util.registrySetStringValue(REG_CLASSES_HKEY, REG_CLASSES_PATH + "Applications\\" + exeName + "\\shell\\open", "", verbName);
Advapi32Util.registryCreateKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + "Applications\\" + exeName + "\\shell\\open\\command");
Advapi32Util.registrySetStringValue(REG_CLASSES_HKEY, REG_CLASSES_PATH + "Applications\\" + exeName + "\\shell\\open\\command", "", "\"" + appDir + exeName + "\" \"%1\"");
}
for (String ext : extensions) {
// 1) Add to context menu of SWF
if (!Advapi32Util.registryKeyExists(REG_CLASSES_HKEY, REG_CLASSES_PATH + "." + ext)) {
Advapi32Util.registryCreateKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + "." + ext);
Advapi32Util.registrySetStringValue(REG_CLASSES_HKEY, REG_CLASSES_PATH + "." + ext, "", "ShockwaveFlash.ShockwaveFlash");
}
if (Advapi32Util.registryValueExists(REG_CLASSES_HKEY, REG_CLASSES_PATH + "." + ext, "")) {
String clsName = Advapi32Util.registryGetStringValue(REG_CLASSES_HKEY, REG_CLASSES_PATH + "." + ext, "");
if (!Advapi32Util.registryKeyExists(REG_CLASSES_HKEY, REG_CLASSES_PATH + clsName)) {
Advapi32Util.registryCreateKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + clsName);
Advapi32Util.registrySetStringValue(REG_CLASSES_HKEY, REG_CLASSES_PATH + clsName, "", "Flash Movie");
}
if (!Advapi32Util.registryKeyExists(REG_CLASSES_HKEY, REG_CLASSES_PATH + clsName + "\\shell")) {
Advapi32Util.registryCreateKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + clsName + "\\shell");
}
exists = Advapi32Util.registryKeyExists(REG_CLASSES_HKEY, REG_CLASSES_PATH + clsName + "\\shell\\" + verb);
if ((!exists) && add) { //add
Advapi32Util.registryCreateKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + clsName + "\\shell\\" + verb);
Advapi32Util.registrySetStringValue(REG_CLASSES_HKEY, REG_CLASSES_PATH + clsName + "\\shell\\" + verb, "", verbName);
Advapi32Util.registryCreateKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + clsName + "\\shell\\" + verb + "\\command");
Advapi32Util.registrySetStringValue(REG_CLASSES_HKEY, REG_CLASSES_PATH + clsName + "\\shell\\" + verb + "\\command", "", "\"" + appDir + exeName + "\" \"%1\"");
}
if (exists && (!add)) { //remove
registryDeleteKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + clsName + "\\shell\\" + verb + "\\command");
registryDeleteKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + clsName + "\\shell\\" + verb);
}
}
exists = Advapi32Util.registryKeyExists(REG_CLASSES_HKEY, REG_CLASSES_PATH + "Applications\\" + exeName);
if (exists && (!add)) { //remove
registryDeleteKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + "Applications\\" + exeName + "\\shell\\open\\command");
registryDeleteKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + "Applications\\" + exeName + "\\shell\\open");
registryDeleteKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + "Applications\\" + exeName + "\\shell");
registryDeleteKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + "Applications\\" + exeName);
}
//2) Add to OpenWith list
if (Advapi32Util.registryValueExists(WinReg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\." + ext + "\\OpenWithList", "MRUList")) {
String mruList = Advapi32Util.registryGetStringValue(WinReg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\." + ext + "\\OpenWithList", "MRUList");
if (mruList != null) {
exists = false;
char appChar = 0;
for (int i = 0; i < mruList.length(); i++) {
String app = Advapi32Util.registryGetStringValue(WinReg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\." + ext + "\\OpenWithList", "" + mruList.charAt(i));
if (app.equals(exeName)) {
appChar = mruList.charAt(i);
exists = true;
break;
}
}
if ((!exists) && add) { //add
for (int c = 'a'; c <= 'z'; c++) {
if (mruList.indexOf(c) == -1) {
mruList += (char) c;
Advapi32Util.registrySetStringValue(WinReg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\." + ext + "\\OpenWithList", "" + (char) c, exeName);
Advapi32Util.registrySetStringValue(WinReg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\." + ext + "\\OpenWithList", "MRUList", mruList);
break;
}
}
}
if (exists && (!add)) { //remove
mruList = mruList.replace("" + appChar, "");
Advapi32Util.registrySetStringValue(WinReg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\." + ext + "\\OpenWithList", "MRUList", mruList);
registryDeleteValue(WinReg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\." + ext + "\\OpenWithList", "" + appChar);
}
}
}
//On some systems, file must be associated in SystemFileAssociations too
if (Advapi32Util.registryKeyExists(REG_CLASSES_HKEY, REG_CLASSES_PATH + "SystemFileAssociations")) {
exists = Advapi32Util.registryKeyExists(REG_CLASSES_HKEY, REG_CLASSES_PATH + "SystemFileAssociations\\." + ext + "\\Shell\\" + verb);
if ((!exists) && add) { //add
if (!Advapi32Util.registryKeyExists(REG_CLASSES_HKEY, REG_CLASSES_PATH + "SystemFileAssociations\\." + ext + "")) {
Advapi32Util.registryCreateKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + "SystemFileAssociations\\." + ext + "");
}
if (!Advapi32Util.registryKeyExists(REG_CLASSES_HKEY, REG_CLASSES_PATH + "SystemFileAssociations\\." + ext + "\\Shell")) {
Advapi32Util.registryCreateKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + "SystemFileAssociations\\." + ext + "\\Shell");
}
Advapi32Util.registryCreateKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + "SystemFileAssociations\\." + ext + "\\Shell\\" + verb);
Advapi32Util.registrySetStringValue(REG_CLASSES_HKEY, REG_CLASSES_PATH + "SystemFileAssociations\\." + ext + "\\Shell\\" + verb, "", verbName);
Advapi32Util.registryCreateKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + "SystemFileAssociations\\." + ext + "\\Shell\\" + verb + "\\Command");
Advapi32Util.registrySetStringValue(REG_CLASSES_HKEY, REG_CLASSES_PATH + "SystemFileAssociations\\." + ext + "\\Shell\\" + verb + "\\Command", "", "\"" + appDir + exeName + "\" \"%1\"");
}
if (exists && (!add)) { //remove
registryDeleteKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + "SystemFileAssociations\\." + ext + "\\Shell\\" + verb + "\\Command");
registryDeleteKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + "SystemFileAssociations\\." + ext + "\\Shell\\" + verb);
}
}
}
return true;
} catch (Exception ex) {
if (!fromCommandLine) {
//Updating registry failed, try elevating rights
SHELLEXECUTEINFO sei = new SHELLEXECUTEINFO();
sei.fMask = 0x00000040;
sei.lpVerb = new WString("runas");
sei.lpFile = new WString(appDir + exeName);
sei.lpParameters = new WString(add ? "-addtocontextmenu" : "-removefromcontextmenu");
sei.nShow = WinUser.SW_NORMAL;
Shell32.INSTANCE.ShellExecuteEx(sei);
//Wait till exit
Kernel32.INSTANCE.WaitForSingleObject(sei.hProcess, 1000 * 60 * 60 * 24 /*1 day max*/);
Kernel32.INSTANCE.CloseHandle(sei.hProcess);
} else {
Logger.getLogger(ContextMenuTools.class.getName()).log(Level.SEVERE, null, ex);
}
}
return false;
}
private static void registryDeleteKey(WinReg.HKEY hKey, String keyName) {
boolean exists = Advapi32Util.registryKeyExists(hKey, keyName);
if (exists) {
Advapi32Util.registryDeleteKey(hKey, keyName);
}
}
private static void registryDeleteValue(WinReg.HKEY root, String keyPath, String valueName) {
boolean exists = Advapi32Util.registryValueExists(root, keyPath, valueName);
if (exists) {
Advapi32Util.registryDeleteValue(root, keyPath, valueName);
}
}
}
@@ -256,7 +256,7 @@ public class AdvancedSettingsDialog extends AppDialog {
Map<String, Component> tabs = new HashMap<>();
getCategories(componentsMap, tabs, skinComboBox, getResourceBundle());
String catOrder[] = new String[]{"ui", "display", "decompilation", "script", "format", "export", "import", "paths", "limit", "update", "debug", "other"};
String[] catOrder = new String[]{"ui", "display", "decompilation", "script", "format", "export", "import", "paths", "limit", "update", "debug", "other"};
for (String cat : catOrder) {
if (!tabs.containsKey(cat)) {
File diff suppressed because it is too large Load Diff
@@ -1,366 +1,366 @@
/*
* Copyright (C) 2010-2016 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.gui;
import com.jpexs.decompiler.flash.abc.ScriptPack;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.exporters.modes.BinaryDataExportMode;
import com.jpexs.decompiler.flash.exporters.modes.ButtonExportMode;
import com.jpexs.decompiler.flash.exporters.modes.FontExportMode;
import com.jpexs.decompiler.flash.exporters.modes.FrameExportMode;
import com.jpexs.decompiler.flash.exporters.modes.ImageExportMode;
import com.jpexs.decompiler.flash.exporters.modes.MorphShapeExportMode;
import com.jpexs.decompiler.flash.exporters.modes.MovieExportMode;
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
import com.jpexs.decompiler.flash.exporters.modes.ShapeExportMode;
import com.jpexs.decompiler.flash.exporters.modes.SoundExportMode;
import com.jpexs.decompiler.flash.exporters.modes.SpriteExportMode;
import com.jpexs.decompiler.flash.exporters.modes.SymbolClassExportMode;
import com.jpexs.decompiler.flash.exporters.modes.TextExportMode;
import com.jpexs.decompiler.flash.gui.tagtree.TagTreeModel;
import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag;
import com.jpexs.decompiler.flash.tags.DefineVideoStreamTag;
import com.jpexs.decompiler.flash.tags.base.ASMSource;
import com.jpexs.decompiler.flash.tags.base.ButtonTag;
import com.jpexs.decompiler.flash.tags.base.FontTag;
import com.jpexs.decompiler.flash.tags.base.ImageTag;
import com.jpexs.decompiler.flash.tags.base.MorphShapeTag;
import com.jpexs.decompiler.flash.tags.base.ShapeTag;
import com.jpexs.decompiler.flash.tags.base.SoundTag;
import com.jpexs.decompiler.flash.tags.base.SymbolClassTypeTag;
import com.jpexs.decompiler.flash.tags.base.TextTag;
import com.jpexs.decompiler.flash.timeline.Frame;
import com.jpexs.decompiler.flash.treeitems.TreeItem;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.util.Arrays;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
/**
*
* @author JPEXS
*/
public class ExportDialog extends AppDialog {
private int result = ERROR_OPTION;
String[] optionNames = {
TagTreeModel.FOLDER_SHAPES,
TagTreeModel.FOLDER_TEXTS,
TagTreeModel.FOLDER_IMAGES,
TagTreeModel.FOLDER_MOVIES,
TagTreeModel.FOLDER_SOUNDS,
TagTreeModel.FOLDER_SCRIPTS,
TagTreeModel.FOLDER_BINARY_DATA,
TagTreeModel.FOLDER_FRAMES,
TagTreeModel.FOLDER_SPRITES,
TagTreeModel.FOLDER_BUTTONS,
TagTreeModel.FOLDER_FONTS,
TagTreeModel.FOLDER_MORPHSHAPES,
"symbolclass"
};
//Display options only when these classes found
Class[][] objClasses = {
{ShapeTag.class},
{TextTag.class},
{ImageTag.class},
{DefineVideoStreamTag.class},
{SoundTag.class},
{ASMSource.class, ScriptPack.class},
{DefineBinaryDataTag.class},
{Frame.class},
{Frame.class},
{ButtonTag.class},
{FontTag.class},
{MorphShapeTag.class},
{SymbolClassTypeTag.class}
};
//Enum classes for values
Class[] optionClasses = {
ShapeExportMode.class,
TextExportMode.class,
ImageExportMode.class,
MovieExportMode.class,
SoundExportMode.class,
ScriptExportMode.class,
BinaryDataExportMode.class,
FrameExportMode.class,
SpriteExportMode.class,
ButtonExportMode.class,
FontExportMode.class,
MorphShapeExportMode.class,
SymbolClassExportMode.class
};
Class[] zoomClasses = {
ShapeExportMode.class,
TextExportMode.class,
FrameExportMode.class,
MorphShapeExportMode.class
};
private final JComboBox[] combos;
private final JCheckBox[] checkBoxes;
private final JCheckBox selectAllCheckBox;
private JTextField zoomTextField = new JTextField();
public <E> E getValue(Class<E> option) {
for (int i = 0; i < optionClasses.length; i++) {
if (option == optionClasses[i]) {
E values[] = option.getEnumConstants();
return values[combos[i].getSelectedIndex()];
}
}
return null;
}
public boolean isOptionEnabled(Class<?> option) {
for (int i = 0; i < optionClasses.length; i++) {
if (option == optionClasses[i]) {
return checkBoxes[i].isSelected();
}
}
return false;
}
public double getZoom() {
return Double.parseDouble(zoomTextField.getText()) / 100;
}
private void saveConfig() {
StringBuilder cfg = new StringBuilder();
for (int i = 0; i < optionNames.length; i++) {
int selIndex = combos[i].getSelectedIndex();
Class c = optionClasses[i];
Object vals[] = c.getEnumConstants();
String key = optionNames[i] + "." + vals[selIndex].toString().toLowerCase();
if (i > 0) {
cfg.append(",");
}
cfg.append(key);
}
Configuration.lastSelectedExportZoom.set(Double.parseDouble(zoomTextField.getText()) / 100);
Configuration.lastSelectedExportFormats.set(cfg.toString());
}
public ExportDialog(List<TreeItem> exportables) {
setTitle(translate("dialog.title"));
setResizable(false);
Container cnt = getContentPane();
cnt.setLayout(new BorderLayout());
JPanel comboPanel = new JPanel(null);
int labWidth = 0;
boolean[] exportableExistsArray = new boolean[optionNames.length];
for (int i = 0; i < optionNames.length; i++) {
boolean exportableExists = false;
if (exportables == null) {
exportableExists = true;
} else {
for (TreeItem e : exportables) {
for (int j = 0; j < objClasses[i].length; j++) {
if (objClasses[i][j].isInstance(e)) {
exportableExists = true;
}
}
}
}
if (!exportableExists) {
continue;
}
exportableExistsArray[i] = true;
JLabel label = new JLabel(translate(optionNames[i]));
if (label.getPreferredSize().width > labWidth) {
labWidth = label.getPreferredSize().width;
}
}
String exportFormatsStr = Configuration.lastSelectedExportFormats.get();
if ("".equals(exportFormatsStr)) {
exportFormatsStr = null;
}
String exportFormatsArr[] = new String[0];
if (exportFormatsStr != null) {
if (exportFormatsStr.contains(",")) {
exportFormatsArr = exportFormatsStr.split(",");
} else {
exportFormatsArr = new String[]{exportFormatsStr};
}
}
int comboWidth = 200;
int checkBoxWidth;
int top = 10;
List<String> exportFormats = Arrays.asList(exportFormatsArr);
combos = new JComboBox[optionNames.length];
checkBoxes = new JCheckBox[optionNames.length];
selectAllCheckBox = new JCheckBox();
checkBoxWidth = selectAllCheckBox.getPreferredSize().width;
selectAllCheckBox.setBounds(10 + labWidth + 10 + comboWidth + 10, top, checkBoxWidth, selectAllCheckBox.getPreferredSize().height);
selectAllCheckBox.setSelected(true);
selectAllCheckBox.addActionListener((ActionEvent e) -> {
boolean selected = selectAllCheckBox.isSelected();
for (JCheckBox checkBox : checkBoxes) {
if (checkBox != null) {
checkBox.setSelected(selected);
}
}
});
comboPanel.add(selectAllCheckBox);
top += selectAllCheckBox.getHeight();
boolean zoomable = false;
for (int i = 0; i < optionNames.length; i++) {
Class c = optionClasses[i];
Object vals[] = c.getEnumConstants();
String names[] = new String[vals.length];
int itemIndex = -1;
for (int j = 0; j < vals.length; j++) {
String key = optionNames[i] + "." + vals[j].toString().toLowerCase();
if (exportFormats.contains(key)) {
itemIndex = j;
}
names[j] = translate(key);
}
combos[i] = new JComboBox<>(names);
if (itemIndex > -1) {
combos[i].setSelectedIndex(itemIndex);
}
combos[i].setBounds(10 + labWidth + 10, top, comboWidth, combos[i].getPreferredSize().height);
checkBoxes[i] = new JCheckBox();
checkBoxes[i].setBounds(10 + labWidth + 10 + comboWidth + 10, top, checkBoxWidth, checkBoxes[i].getPreferredSize().height);
checkBoxes[i].setSelected(true);
if (!exportableExistsArray[i]) {
continue;
}
if (Arrays.asList(zoomClasses).contains(c)) {
zoomable = true;
}
JLabel lab = new JLabel(translate(optionNames[i]));
lab.setBounds(10, top, lab.getPreferredSize().width, lab.getPreferredSize().height);
comboPanel.add(lab);
comboPanel.add(checkBoxes[i]);
comboPanel.add(combos[i]);
top += combos[i].getHeight();
}
int zoomWidth = 50;
if (zoomable) {
top += 2;
JLabel zlab = new JLabel(translate("zoom"));
zlab.setBounds(10, top + 4, zlab.getPreferredSize().width, zlab.getPreferredSize().height);
zoomTextField.setBounds(10 + labWidth + 10, top, zoomWidth, zoomTextField.getPreferredSize().height);
JLabel pctLabel = new JLabel(translate("zoom.percent"));
pctLabel.setBounds(10 + labWidth + 10 + zoomWidth + 5, top + 4, 20, pctLabel.getPreferredSize().height);
comboPanel.add(zlab);
comboPanel.add(zoomTextField);
comboPanel.add(pctLabel);
top += zoomTextField.getHeight();
}
Dimension dim = new Dimension(10 + labWidth + 10 + checkBoxWidth + 10 + comboWidth + 10, top + 10);
comboPanel.setMinimumSize(dim);
comboPanel.setPreferredSize(dim);
cnt.add(comboPanel, BorderLayout.CENTER);
JPanel buttonsPanel = new JPanel(new FlowLayout());
JButton okButton = new JButton(translate("button.ok"));
okButton.addActionListener(this::okButtonActionPerformed);
JButton cancelButton = new JButton(translate("button.cancel"));
cancelButton.addActionListener(this::cancelButtonActionPerformed);
buttonsPanel.add(okButton);
buttonsPanel.add(cancelButton);
cnt.add(buttonsPanel, BorderLayout.SOUTH);
pack();
View.centerScreen(this);
View.setWindowIcon(this);
getRootPane().setDefaultButton(okButton);
setModal(true);
String pct = "" + Configuration.lastSelectedExportZoom.get() * 100;
if (pct.endsWith(".0")) {
pct = pct.substring(0, pct.length() - 2);
}
zoomTextField.setText(pct);
}
@Override
public void setVisible(boolean b) {
if (b) {
result = ERROR_OPTION;
}
super.setVisible(b);
}
private void okButtonActionPerformed(ActionEvent evt) {
result = OK_OPTION;
try {
saveConfig();
} catch (NumberFormatException nfe) {
JOptionPane.showMessageDialog(ExportDialog.this, translate("zoom.invalid"), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE);
zoomTextField.requestFocusInWindow();
return;
}
setVisible(false);
}
private void cancelButtonActionPerformed(ActionEvent evt) {
result = CANCEL_OPTION;
setVisible(false);
}
public int showExportDialog() {
setVisible(true);
return result;
}
}
/*
* Copyright (C) 2010-2016 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.gui;
import com.jpexs.decompiler.flash.abc.ScriptPack;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.exporters.modes.BinaryDataExportMode;
import com.jpexs.decompiler.flash.exporters.modes.ButtonExportMode;
import com.jpexs.decompiler.flash.exporters.modes.FontExportMode;
import com.jpexs.decompiler.flash.exporters.modes.FrameExportMode;
import com.jpexs.decompiler.flash.exporters.modes.ImageExportMode;
import com.jpexs.decompiler.flash.exporters.modes.MorphShapeExportMode;
import com.jpexs.decompiler.flash.exporters.modes.MovieExportMode;
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
import com.jpexs.decompiler.flash.exporters.modes.ShapeExportMode;
import com.jpexs.decompiler.flash.exporters.modes.SoundExportMode;
import com.jpexs.decompiler.flash.exporters.modes.SpriteExportMode;
import com.jpexs.decompiler.flash.exporters.modes.SymbolClassExportMode;
import com.jpexs.decompiler.flash.exporters.modes.TextExportMode;
import com.jpexs.decompiler.flash.gui.tagtree.TagTreeModel;
import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag;
import com.jpexs.decompiler.flash.tags.DefineVideoStreamTag;
import com.jpexs.decompiler.flash.tags.base.ASMSource;
import com.jpexs.decompiler.flash.tags.base.ButtonTag;
import com.jpexs.decompiler.flash.tags.base.FontTag;
import com.jpexs.decompiler.flash.tags.base.ImageTag;
import com.jpexs.decompiler.flash.tags.base.MorphShapeTag;
import com.jpexs.decompiler.flash.tags.base.ShapeTag;
import com.jpexs.decompiler.flash.tags.base.SoundTag;
import com.jpexs.decompiler.flash.tags.base.SymbolClassTypeTag;
import com.jpexs.decompiler.flash.tags.base.TextTag;
import com.jpexs.decompiler.flash.timeline.Frame;
import com.jpexs.decompiler.flash.treeitems.TreeItem;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.util.Arrays;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
/**
*
* @author JPEXS
*/
public class ExportDialog extends AppDialog {
private int result = ERROR_OPTION;
String[] optionNames = {
TagTreeModel.FOLDER_SHAPES,
TagTreeModel.FOLDER_TEXTS,
TagTreeModel.FOLDER_IMAGES,
TagTreeModel.FOLDER_MOVIES,
TagTreeModel.FOLDER_SOUNDS,
TagTreeModel.FOLDER_SCRIPTS,
TagTreeModel.FOLDER_BINARY_DATA,
TagTreeModel.FOLDER_FRAMES,
TagTreeModel.FOLDER_SPRITES,
TagTreeModel.FOLDER_BUTTONS,
TagTreeModel.FOLDER_FONTS,
TagTreeModel.FOLDER_MORPHSHAPES,
"symbolclass"
};
//Display options only when these classes found
Class[][] objClasses = {
{ShapeTag.class},
{TextTag.class},
{ImageTag.class},
{DefineVideoStreamTag.class},
{SoundTag.class},
{ASMSource.class, ScriptPack.class},
{DefineBinaryDataTag.class},
{Frame.class},
{Frame.class},
{ButtonTag.class},
{FontTag.class},
{MorphShapeTag.class},
{SymbolClassTypeTag.class}
};
//Enum classes for values
Class[] optionClasses = {
ShapeExportMode.class,
TextExportMode.class,
ImageExportMode.class,
MovieExportMode.class,
SoundExportMode.class,
ScriptExportMode.class,
BinaryDataExportMode.class,
FrameExportMode.class,
SpriteExportMode.class,
ButtonExportMode.class,
FontExportMode.class,
MorphShapeExportMode.class,
SymbolClassExportMode.class
};
Class[] zoomClasses = {
ShapeExportMode.class,
TextExportMode.class,
FrameExportMode.class,
MorphShapeExportMode.class
};
private final JComboBox[] combos;
private final JCheckBox[] checkBoxes;
private final JCheckBox selectAllCheckBox;
private JTextField zoomTextField = new JTextField();
public <E> E getValue(Class<E> option) {
for (int i = 0; i < optionClasses.length; i++) {
if (option == optionClasses[i]) {
E[] values = option.getEnumConstants();
return values[combos[i].getSelectedIndex()];
}
}
return null;
}
public boolean isOptionEnabled(Class<?> option) {
for (int i = 0; i < optionClasses.length; i++) {
if (option == optionClasses[i]) {
return checkBoxes[i].isSelected();
}
}
return false;
}
public double getZoom() {
return Double.parseDouble(zoomTextField.getText()) / 100;
}
private void saveConfig() {
StringBuilder cfg = new StringBuilder();
for (int i = 0; i < optionNames.length; i++) {
int selIndex = combos[i].getSelectedIndex();
Class c = optionClasses[i];
Object[] vals = c.getEnumConstants();
String key = optionNames[i] + "." + vals[selIndex].toString().toLowerCase();
if (i > 0) {
cfg.append(",");
}
cfg.append(key);
}
Configuration.lastSelectedExportZoom.set(Double.parseDouble(zoomTextField.getText()) / 100);
Configuration.lastSelectedExportFormats.set(cfg.toString());
}
public ExportDialog(List<TreeItem> exportables) {
setTitle(translate("dialog.title"));
setResizable(false);
Container cnt = getContentPane();
cnt.setLayout(new BorderLayout());
JPanel comboPanel = new JPanel(null);
int labWidth = 0;
boolean[] exportableExistsArray = new boolean[optionNames.length];
for (int i = 0; i < optionNames.length; i++) {
boolean exportableExists = false;
if (exportables == null) {
exportableExists = true;
} else {
for (TreeItem e : exportables) {
for (int j = 0; j < objClasses[i].length; j++) {
if (objClasses[i][j].isInstance(e)) {
exportableExists = true;
}
}
}
}
if (!exportableExists) {
continue;
}
exportableExistsArray[i] = true;
JLabel label = new JLabel(translate(optionNames[i]));
if (label.getPreferredSize().width > labWidth) {
labWidth = label.getPreferredSize().width;
}
}
String exportFormatsStr = Configuration.lastSelectedExportFormats.get();
if ("".equals(exportFormatsStr)) {
exportFormatsStr = null;
}
String[] exportFormatsArr = new String[0];
if (exportFormatsStr != null) {
if (exportFormatsStr.contains(",")) {
exportFormatsArr = exportFormatsStr.split(",");
} else {
exportFormatsArr = new String[]{exportFormatsStr};
}
}
int comboWidth = 200;
int checkBoxWidth;
int top = 10;
List<String> exportFormats = Arrays.asList(exportFormatsArr);
combos = new JComboBox[optionNames.length];
checkBoxes = new JCheckBox[optionNames.length];
selectAllCheckBox = new JCheckBox();
checkBoxWidth = selectAllCheckBox.getPreferredSize().width;
selectAllCheckBox.setBounds(10 + labWidth + 10 + comboWidth + 10, top, checkBoxWidth, selectAllCheckBox.getPreferredSize().height);
selectAllCheckBox.setSelected(true);
selectAllCheckBox.addActionListener((ActionEvent e) -> {
boolean selected = selectAllCheckBox.isSelected();
for (JCheckBox checkBox : checkBoxes) {
if (checkBox != null) {
checkBox.setSelected(selected);
}
}
});
comboPanel.add(selectAllCheckBox);
top += selectAllCheckBox.getHeight();
boolean zoomable = false;
for (int i = 0; i < optionNames.length; i++) {
Class c = optionClasses[i];
Object[] vals = c.getEnumConstants();
String[] names = new String[vals.length];
int itemIndex = -1;
for (int j = 0; j < vals.length; j++) {
String key = optionNames[i] + "." + vals[j].toString().toLowerCase();
if (exportFormats.contains(key)) {
itemIndex = j;
}
names[j] = translate(key);
}
combos[i] = new JComboBox<>(names);
if (itemIndex > -1) {
combos[i].setSelectedIndex(itemIndex);
}
combos[i].setBounds(10 + labWidth + 10, top, comboWidth, combos[i].getPreferredSize().height);
checkBoxes[i] = new JCheckBox();
checkBoxes[i].setBounds(10 + labWidth + 10 + comboWidth + 10, top, checkBoxWidth, checkBoxes[i].getPreferredSize().height);
checkBoxes[i].setSelected(true);
if (!exportableExistsArray[i]) {
continue;
}
if (Arrays.asList(zoomClasses).contains(c)) {
zoomable = true;
}
JLabel lab = new JLabel(translate(optionNames[i]));
lab.setBounds(10, top, lab.getPreferredSize().width, lab.getPreferredSize().height);
comboPanel.add(lab);
comboPanel.add(checkBoxes[i]);
comboPanel.add(combos[i]);
top += combos[i].getHeight();
}
int zoomWidth = 50;
if (zoomable) {
top += 2;
JLabel zlab = new JLabel(translate("zoom"));
zlab.setBounds(10, top + 4, zlab.getPreferredSize().width, zlab.getPreferredSize().height);
zoomTextField.setBounds(10 + labWidth + 10, top, zoomWidth, zoomTextField.getPreferredSize().height);
JLabel pctLabel = new JLabel(translate("zoom.percent"));
pctLabel.setBounds(10 + labWidth + 10 + zoomWidth + 5, top + 4, 20, pctLabel.getPreferredSize().height);
comboPanel.add(zlab);
comboPanel.add(zoomTextField);
comboPanel.add(pctLabel);
top += zoomTextField.getHeight();
}
Dimension dim = new Dimension(10 + labWidth + 10 + checkBoxWidth + 10 + comboWidth + 10, top + 10);
comboPanel.setMinimumSize(dim);
comboPanel.setPreferredSize(dim);
cnt.add(comboPanel, BorderLayout.CENTER);
JPanel buttonsPanel = new JPanel(new FlowLayout());
JButton okButton = new JButton(translate("button.ok"));
okButton.addActionListener(this::okButtonActionPerformed);
JButton cancelButton = new JButton(translate("button.cancel"));
cancelButton.addActionListener(this::cancelButtonActionPerformed);
buttonsPanel.add(okButton);
buttonsPanel.add(cancelButton);
cnt.add(buttonsPanel, BorderLayout.SOUTH);
pack();
View.centerScreen(this);
View.setWindowIcon(this);
getRootPane().setDefaultButton(okButton);
setModal(true);
String pct = "" + Configuration.lastSelectedExportZoom.get() * 100;
if (pct.endsWith(".0")) {
pct = pct.substring(0, pct.length() - 2);
}
zoomTextField.setText(pct);
}
@Override
public void setVisible(boolean b) {
if (b) {
result = ERROR_OPTION;
}
super.setVisible(b);
}
private void okButtonActionPerformed(ActionEvent evt) {
result = OK_OPTION;
try {
saveConfig();
} catch (NumberFormatException nfe) {
JOptionPane.showMessageDialog(ExportDialog.this, translate("zoom.invalid"), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE);
zoomTextField.requestFocusInWindow();
return;
}
setVisible(false);
}
private void cancelButtonActionPerformed(ActionEvent evt) {
result = CANCEL_OPTION;
setVisible(false);
}
public int showExportDialog() {
setVisible(true);
return result;
}
}
@@ -1,401 +1,401 @@
/*
* Copyright (C) 2010-2016 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.gui;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.tags.font.CharacterRanges;
import com.jpexs.helpers.Helper;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.FontFormatException;
import java.awt.event.ActionEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.filechooser.FileFilter;
/**
*
* @author JPEXS
*/
public class FontEmbedDialog extends AppDialog {
private static final int SAMPLE_MAX_LENGTH = 50;
private final JComboBox<FontFamily> familyNamesSelection;
private final JComboBox<FontFace> faceSelection;
private final JCheckBox[] rangeCheckboxes;
private final String rangeNames[];
private final JLabel[] rangeSamples;
private final JTextField individualCharsField;
private int result = ERROR_OPTION;
private JLabel individialSample;
private Font customFont;
private final JCheckBox allCheckbox;
public Font getSelectedFont() {
if (ttfFileRadio.isSelected() && customFont != null) {
return customFont;
}
return ((FontFace) faceSelection.getSelectedItem()).font;
}
public Set<Integer> getSelectedChars() {
Set<Integer> chars = new TreeSet<>();
Font f = getSelectedFont();
if (allCheckbox.isSelected()) {
for (int i = 0; i < rangeCheckboxes.length; i++) {
int codes[] = CharacterRanges.rangeCodes(i);
for (int c : codes) {
if (f.canDisplay(c)) {
chars.add(c);
}
}
}
} else {
for (int i = 0; i < rangeCheckboxes.length; i++) {
if (rangeCheckboxes[i].isSelected()) {
int codes[] = CharacterRanges.rangeCodes(i);
for (int c : codes) {
if (f.canDisplay(c)) {
chars.add(c);
}
}
}
}
String indStr = individualCharsField.getText();
for (int i = 0; i < indStr.length(); i++) {
if (f.canDisplay(indStr.codePointAt(i))) {
chars.add(indStr.codePointAt(i));
}
}
}
return chars;
}
private JRadioButton ttfFileRadio;
private JRadioButton installedRadio;
private void updateFaceSelection() {
faceSelection.setModel(FontPanel.getFaceModel((FontFamily) familyNamesSelection.getSelectedItem()));
}
public FontEmbedDialog(FontFace selectedFace, String selectedChars) {
setSize(900, 600);
setDefaultCloseOperation(HIDE_ON_CLOSE);
setTitle(translate("dialog.title"));
Container cnt = getContentPane();
cnt.setLayout(new BoxLayout(cnt, BoxLayout.Y_AXIS));
JPanel selFontPanel = new JPanel(new FlowLayout());
installedRadio = new JRadioButton(translate("installed"));
ttfFileRadio = new JRadioButton(translate("ttffile.noselection"));
ButtonGroup bg = new ButtonGroup();
bg.add(installedRadio);
bg.add(ttfFileRadio);
installedRadio.setSelected(true);
individialSample = new JLabel();
familyNamesSelection = new JComboBox<>(FontPanel.getFamilyModel());
familyNamesSelection.setSelectedItem(new FontFamily(selectedFace.font));
faceSelection = new JComboBox<>();
updateFaceSelection();
faceSelection.setSelectedItem(selectedFace);
JButton loadFromDiskButton = new JButton(View.getIcon("open16"));
loadFromDiskButton.setToolTipText(translate("button.loadfont"));
loadFromDiskButton.addActionListener(this::loadFromDiscButtonActionPerformed);
selFontPanel.add(installedRadio);
selFontPanel.add(familyNamesSelection);
selFontPanel.add(faceSelection);
selFontPanel.add(ttfFileRadio);
selFontPanel.add(loadFromDiskButton);
installedRadio.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
updateCheckboxes();
}
}
});
ttfFileRadio.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
if (ttfFileRadio.isSelected()) {
if (customFont == null) {
if (loadFromDisk()) {
updateCheckboxes();
} else {
installedRadio.setSelected(true);
}
} else {
updateCheckboxes();
}
}
}
}
});
cnt.add(selFontPanel);
JPanel rangesPanel = new JPanel();
rangesPanel.setLayout(new BoxLayout(rangesPanel, BoxLayout.Y_AXIS));
final int rc = CharacterRanges.rangeCount();
rangeCheckboxes = new JCheckBox[rc];
rangeSamples = new JLabel[rc];
rangeNames = new String[rc];
allCheckbox = new JCheckBox(translate("allcharacters"));
allCheckbox.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
for (int i = 0; i < rc; i++) {
rangeCheckboxes[i].setEnabled(false);
}
individualCharsField.setEnabled(false);
} else if (e.getStateChange() == ItemEvent.DESELECTED) {
for (int i = 0; i < rc; i++) {
rangeCheckboxes[i].setEnabled(true);
}
individualCharsField.setEnabled(true);
}
}
});
JPanel rangeRowPanel = new JPanel();
rangeRowPanel.setLayout(new BorderLayout());
rangeRowPanel.add(allCheckbox, BorderLayout.WEST);
rangeRowPanel.setAlignmentX(0);
rangesPanel.add(rangeRowPanel);
for (int i = 0; i < rc; i++) {
rangeNames[i] = CharacterRanges.rangeName(i);
rangeSamples[i] = new JLabel("");
rangeCheckboxes[i] = new JCheckBox(rangeNames[i]);
rangeRowPanel = new JPanel();
rangeRowPanel.setLayout(new BoxLayout(rangeRowPanel, BoxLayout.X_AXIS));
rangeRowPanel.add(rangeCheckboxes[i]);
rangeRowPanel.add(Box.createHorizontalGlue());
rangeRowPanel.add(rangeSamples[i]);
rangeRowPanel.setAlignmentX(0);
rangesPanel.add(rangeRowPanel);
}
cnt.add(new JScrollPane(rangesPanel));
JPanel specialPanel = new JPanel();
specialPanel.setLayout(new BoxLayout(specialPanel, BoxLayout.X_AXIS));
specialPanel.add(new JLabel(translate("label.individual")));
individualCharsField = new JTextField();
individualCharsField.setPreferredSize(new Dimension(100, individualCharsField.getPreferredSize().height));
individialSample = new JLabel();
specialPanel.add(individualCharsField);
cnt.add(specialPanel);
cnt.add(individialSample);
JPanel buttonsPanel = new JPanel(new FlowLayout());
JButton okButton = new JButton(AppStrings.translate("button.ok"));
okButton.addActionListener(this::okButtonActionPerformed);
JButton cancelButton = new JButton(AppStrings.translate("button.cancel"));
cancelButton.addActionListener(this::cancelButtonActionPerformed);
buttonsPanel.add(okButton);
buttonsPanel.add(cancelButton);
cnt.add(buttonsPanel);
View.setWindowIcon(this);
View.centerScreen(this);
setModalityType(ModalityType.APPLICATION_MODAL);
individualCharsField.setText(selectedChars);
getRootPane().setDefaultButton(okButton);
familyNamesSelection.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
updateFaceSelection();
updateCheckboxes();
}
});
faceSelection.addItemListener((ItemEvent e) -> {
updateCheckboxes();
});
updateCheckboxes();
individualCharsField.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
updateIndividual();
}
@Override
public void removeUpdate(DocumentEvent e) {
updateIndividual();
}
@Override
public void changedUpdate(DocumentEvent e) {
updateIndividual();
}
});
}
private void updateIndividual() {
String chars = individualCharsField.getText();
Font f = getSelectedFont();
StringBuilder visibleChars = new StringBuilder();
for (int i = 0; i < chars.length(); i++) {
if (f.canDisplay(chars.codePointAt(i))) {
visibleChars.append(chars.charAt(i));
}
}
individialSample.setText(visibleChars.toString());
}
private void updateCheckboxes() {
Font f = getSelectedFont().deriveFont(12f);
int rc = CharacterRanges.rangeCount();
Set<Integer> allChars = new HashSet<>();
for (int i = 0; i < rc; i++) {
rangeNames[i] = CharacterRanges.rangeName(i);
int codes[] = CharacterRanges.rangeCodes(i);
int avail = 0;
StringBuilder sample = new StringBuilder();
for (int c = 0; c < codes.length; c++) {
if (f.canDisplay(codes[c])) {
allChars.add(codes[c]);
if (avail < SAMPLE_MAX_LENGTH) {
sample.append((char) codes[c]);
}
avail++;
}
}
rangeSamples[i].setText(sample.toString());
rangeSamples[i].setFont(f);
rangeCheckboxes[i].setText(translate("range.description").replace("%available%", Integer.toString(avail)).replace("%name%", rangeNames[i]).replace("%total%", Integer.toString(codes.length)));
}
allCheckbox.setText(translate("allcharacters").replace("%available%", Integer.toString(allChars.size())));
individialSample.setFont(f);
updateIndividual();
}
@Override
public void setVisible(boolean b) {
if (b) {
result = ERROR_OPTION;
}
super.setVisible(b);
}
private void okButtonActionPerformed(ActionEvent evt) {
result = OK_OPTION;
setVisible(false);
}
private void cancelButtonActionPerformed(ActionEvent evt) {
result = CANCEL_OPTION;
setVisible(false);
}
private void loadFromDiscButtonActionPerformed(ActionEvent evt) {
if (customFont != null) {
if (loadFromDisk()) {
updateCheckboxes();
}
}
ttfFileRadio.setSelected(true);
}
private boolean loadFromDisk() {
JFileChooser fc = new JFileChooser();
fc.setCurrentDirectory(new File(Configuration.lastOpenDir.get()));
FileFilter ttfFilter = new FileFilter() {
@Override
public boolean accept(File f) {
return (f.getName().toLowerCase().endsWith(".ttf")) || (f.isDirectory());
}
@Override
public String getDescription() {
return translate("filter.ttf");
}
};
fc.setFileFilter(ttfFilter);
fc.setAcceptAllFileFilterUsed(true);
JFrame f = new JFrame();
View.setWindowIcon(f);
int returnVal = fc.showOpenDialog(f);
if (returnVal == JFileChooser.APPROVE_OPTION) {
Configuration.lastOpenDir.set(Helper.fixDialogFile(fc.getSelectedFile()).getParentFile().getAbsolutePath());
File selfile = Helper.fixDialogFile(fc.getSelectedFile());
try {
customFont = Font.createFont(Font.TRUETYPE_FONT, selfile);
ttfFileRadio.setText(translate("ttffile.selection").replace("%fontname%", customFont.getName()).replace("%filename%", selfile.getName()));
return true;
} catch (FontFormatException ex) {
JOptionPane.showMessageDialog(this, translate("error.invalidfontfile"), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE);
} catch (IOException ex) {
JOptionPane.showMessageDialog(this, translate("error.cannotreadfontfile"), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE);
}
}
return false;
}
public int showDialog() {
setVisible(true);
return result;
}
}
/*
* Copyright (C) 2010-2016 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.gui;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.tags.font.CharacterRanges;
import com.jpexs.helpers.Helper;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.FontFormatException;
import java.awt.event.ActionEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.filechooser.FileFilter;
/**
*
* @author JPEXS
*/
public class FontEmbedDialog extends AppDialog {
private static final int SAMPLE_MAX_LENGTH = 50;
private final JComboBox<FontFamily> familyNamesSelection;
private final JComboBox<FontFace> faceSelection;
private final JCheckBox[] rangeCheckboxes;
private final String rangeNames[];
private final JLabel[] rangeSamples;
private final JTextField individualCharsField;
private int result = ERROR_OPTION;
private JLabel individialSample;
private Font customFont;
private final JCheckBox allCheckbox;
public Font getSelectedFont() {
if (ttfFileRadio.isSelected() && customFont != null) {
return customFont;
}
return ((FontFace) faceSelection.getSelectedItem()).font;
}
public Set<Integer> getSelectedChars() {
Set<Integer> chars = new TreeSet<>();
Font f = getSelectedFont();
if (allCheckbox.isSelected()) {
for (int i = 0; i < rangeCheckboxes.length; i++) {
int[] codes = CharacterRanges.rangeCodes(i);
for (int c : codes) {
if (f.canDisplay(c)) {
chars.add(c);
}
}
}
} else {
for (int i = 0; i < rangeCheckboxes.length; i++) {
if (rangeCheckboxes[i].isSelected()) {
int[] codes = CharacterRanges.rangeCodes(i);
for (int c : codes) {
if (f.canDisplay(c)) {
chars.add(c);
}
}
}
}
String indStr = individualCharsField.getText();
for (int i = 0; i < indStr.length(); i++) {
if (f.canDisplay(indStr.codePointAt(i))) {
chars.add(indStr.codePointAt(i));
}
}
}
return chars;
}
private JRadioButton ttfFileRadio;
private JRadioButton installedRadio;
private void updateFaceSelection() {
faceSelection.setModel(FontPanel.getFaceModel((FontFamily) familyNamesSelection.getSelectedItem()));
}
public FontEmbedDialog(FontFace selectedFace, String selectedChars) {
setSize(900, 600);
setDefaultCloseOperation(HIDE_ON_CLOSE);
setTitle(translate("dialog.title"));
Container cnt = getContentPane();
cnt.setLayout(new BoxLayout(cnt, BoxLayout.Y_AXIS));
JPanel selFontPanel = new JPanel(new FlowLayout());
installedRadio = new JRadioButton(translate("installed"));
ttfFileRadio = new JRadioButton(translate("ttffile.noselection"));
ButtonGroup bg = new ButtonGroup();
bg.add(installedRadio);
bg.add(ttfFileRadio);
installedRadio.setSelected(true);
individialSample = new JLabel();
familyNamesSelection = new JComboBox<>(FontPanel.getFamilyModel());
familyNamesSelection.setSelectedItem(new FontFamily(selectedFace.font));
faceSelection = new JComboBox<>();
updateFaceSelection();
faceSelection.setSelectedItem(selectedFace);
JButton loadFromDiskButton = new JButton(View.getIcon("open16"));
loadFromDiskButton.setToolTipText(translate("button.loadfont"));
loadFromDiskButton.addActionListener(this::loadFromDiscButtonActionPerformed);
selFontPanel.add(installedRadio);
selFontPanel.add(familyNamesSelection);
selFontPanel.add(faceSelection);
selFontPanel.add(ttfFileRadio);
selFontPanel.add(loadFromDiskButton);
installedRadio.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
updateCheckboxes();
}
}
});
ttfFileRadio.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
if (ttfFileRadio.isSelected()) {
if (customFont == null) {
if (loadFromDisk()) {
updateCheckboxes();
} else {
installedRadio.setSelected(true);
}
} else {
updateCheckboxes();
}
}
}
}
});
cnt.add(selFontPanel);
JPanel rangesPanel = new JPanel();
rangesPanel.setLayout(new BoxLayout(rangesPanel, BoxLayout.Y_AXIS));
final int rc = CharacterRanges.rangeCount();
rangeCheckboxes = new JCheckBox[rc];
rangeSamples = new JLabel[rc];
rangeNames = new String[rc];
allCheckbox = new JCheckBox(translate("allcharacters"));
allCheckbox.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
for (int i = 0; i < rc; i++) {
rangeCheckboxes[i].setEnabled(false);
}
individualCharsField.setEnabled(false);
} else if (e.getStateChange() == ItemEvent.DESELECTED) {
for (int i = 0; i < rc; i++) {
rangeCheckboxes[i].setEnabled(true);
}
individualCharsField.setEnabled(true);
}
}
});
JPanel rangeRowPanel = new JPanel();
rangeRowPanel.setLayout(new BorderLayout());
rangeRowPanel.add(allCheckbox, BorderLayout.WEST);
rangeRowPanel.setAlignmentX(0);
rangesPanel.add(rangeRowPanel);
for (int i = 0; i < rc; i++) {
rangeNames[i] = CharacterRanges.rangeName(i);
rangeSamples[i] = new JLabel("");
rangeCheckboxes[i] = new JCheckBox(rangeNames[i]);
rangeRowPanel = new JPanel();
rangeRowPanel.setLayout(new BoxLayout(rangeRowPanel, BoxLayout.X_AXIS));
rangeRowPanel.add(rangeCheckboxes[i]);
rangeRowPanel.add(Box.createHorizontalGlue());
rangeRowPanel.add(rangeSamples[i]);
rangeRowPanel.setAlignmentX(0);
rangesPanel.add(rangeRowPanel);
}
cnt.add(new JScrollPane(rangesPanel));
JPanel specialPanel = new JPanel();
specialPanel.setLayout(new BoxLayout(specialPanel, BoxLayout.X_AXIS));
specialPanel.add(new JLabel(translate("label.individual")));
individualCharsField = new JTextField();
individualCharsField.setPreferredSize(new Dimension(100, individualCharsField.getPreferredSize().height));
individialSample = new JLabel();
specialPanel.add(individualCharsField);
cnt.add(specialPanel);
cnt.add(individialSample);
JPanel buttonsPanel = new JPanel(new FlowLayout());
JButton okButton = new JButton(AppStrings.translate("button.ok"));
okButton.addActionListener(this::okButtonActionPerformed);
JButton cancelButton = new JButton(AppStrings.translate("button.cancel"));
cancelButton.addActionListener(this::cancelButtonActionPerformed);
buttonsPanel.add(okButton);
buttonsPanel.add(cancelButton);
cnt.add(buttonsPanel);
View.setWindowIcon(this);
View.centerScreen(this);
setModalityType(ModalityType.APPLICATION_MODAL);
individualCharsField.setText(selectedChars);
getRootPane().setDefaultButton(okButton);
familyNamesSelection.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
updateFaceSelection();
updateCheckboxes();
}
});
faceSelection.addItemListener((ItemEvent e) -> {
updateCheckboxes();
});
updateCheckboxes();
individualCharsField.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
updateIndividual();
}
@Override
public void removeUpdate(DocumentEvent e) {
updateIndividual();
}
@Override
public void changedUpdate(DocumentEvent e) {
updateIndividual();
}
});
}
private void updateIndividual() {
String chars = individualCharsField.getText();
Font f = getSelectedFont();
StringBuilder visibleChars = new StringBuilder();
for (int i = 0; i < chars.length(); i++) {
if (f.canDisplay(chars.codePointAt(i))) {
visibleChars.append(chars.charAt(i));
}
}
individialSample.setText(visibleChars.toString());
}
private void updateCheckboxes() {
Font f = getSelectedFont().deriveFont(12f);
int rc = CharacterRanges.rangeCount();
Set<Integer> allChars = new HashSet<>();
for (int i = 0; i < rc; i++) {
rangeNames[i] = CharacterRanges.rangeName(i);
int[] codes = CharacterRanges.rangeCodes(i);
int avail = 0;
StringBuilder sample = new StringBuilder();
for (int c = 0; c < codes.length; c++) {
if (f.canDisplay(codes[c])) {
allChars.add(codes[c]);
if (avail < SAMPLE_MAX_LENGTH) {
sample.append((char) codes[c]);
}
avail++;
}
}
rangeSamples[i].setText(sample.toString());
rangeSamples[i].setFont(f);
rangeCheckboxes[i].setText(translate("range.description").replace("%available%", Integer.toString(avail)).replace("%name%", rangeNames[i]).replace("%total%", Integer.toString(codes.length)));
}
allCheckbox.setText(translate("allcharacters").replace("%available%", Integer.toString(allChars.size())));
individialSample.setFont(f);
updateIndividual();
}
@Override
public void setVisible(boolean b) {
if (b) {
result = ERROR_OPTION;
}
super.setVisible(b);
}
private void okButtonActionPerformed(ActionEvent evt) {
result = OK_OPTION;
setVisible(false);
}
private void cancelButtonActionPerformed(ActionEvent evt) {
result = CANCEL_OPTION;
setVisible(false);
}
private void loadFromDiscButtonActionPerformed(ActionEvent evt) {
if (customFont != null) {
if (loadFromDisk()) {
updateCheckboxes();
}
}
ttfFileRadio.setSelected(true);
}
private boolean loadFromDisk() {
JFileChooser fc = new JFileChooser();
fc.setCurrentDirectory(new File(Configuration.lastOpenDir.get()));
FileFilter ttfFilter = new FileFilter() {
@Override
public boolean accept(File f) {
return (f.getName().toLowerCase().endsWith(".ttf")) || (f.isDirectory());
}
@Override
public String getDescription() {
return translate("filter.ttf");
}
};
fc.setFileFilter(ttfFilter);
fc.setAcceptAllFileFilterUsed(true);
JFrame f = new JFrame();
View.setWindowIcon(f);
int returnVal = fc.showOpenDialog(f);
if (returnVal == JFileChooser.APPROVE_OPTION) {
Configuration.lastOpenDir.set(Helper.fixDialogFile(fc.getSelectedFile()).getParentFile().getAbsolutePath());
File selfile = Helper.fixDialogFile(fc.getSelectedFile());
try {
customFont = Font.createFont(Font.TRUETYPE_FONT, selfile);
ttfFileRadio.setText(translate("ttffile.selection").replace("%fontname%", customFont.getName()).replace("%filename%", selfile.getName()));
return true;
} catch (FontFormatException ex) {
JOptionPane.showMessageDialog(this, translate("error.invalidfontfile"), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE);
} catch (IOException ex) {
JOptionPane.showMessageDialog(this, translate("error.cannotreadfontfile"), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE);
}
}
return false;
}
public int showDialog() {
setVisible(true);
return result;
}
}
@@ -642,7 +642,7 @@ public class FontPanel extends JPanel {
Set<Integer> selChars = new HashSet<>();
try {
Font f = Font.createFont(Font.TRUETYPE_FONT, selfile);
int required[] = new int[]{0x0001, 0x0000, 0x000D, 0x0020};
int[] required = new int[]{0x0001, 0x0000, 0x000D, 0x0020};
loopi:
for (char i = 0; i < Character.MAX_VALUE; i++) {
for (int r : required) {
@@ -290,7 +290,7 @@ public class GenericTagPanel extends JPanel implements ChangeListener {
final int val = sb.getValue(); //save scroll top
SWFType swfType = field.getAnnotation(SWFType.class);
if (swfType != null && !swfType.countField().isEmpty()) { //Fields with same countField must be removed from too
Field fields[] = obj.getClass().getDeclaredFields();
Field[] fields = obj.getClass().getDeclaredFields();
for (int f = 0; f < fields.length; f++) {
SWFType fieldSwfType = fields[f].getAnnotation(SWFType.class);
if (fieldSwfType != null && fieldSwfType.countField().equals(swfType.countField())) {
@@ -338,7 +338,7 @@ public class GenericTagPanel extends JPanel implements ChangeListener {
final int val = sb.getValue(); //save scroll top
SWFType swfType = field.getAnnotation(SWFType.class);
if (swfType != null && !swfType.countField().isEmpty()) { //Fields with same countField must be enlarged too
Field fields[] = obj.getClass().getDeclaredFields();
Field[] fields = obj.getClass().getDeclaredFields();
for (int f = 0; f < fields.length; f++) {
SWFType fieldSwfType = fields[f].getAnnotation(SWFType.class);
if (fieldSwfType != null && fieldSwfType.countField().equals(swfType.countField())) {
@@ -1068,7 +1068,7 @@ public class GenericTagTreePanel extends GenericTagPanel {
List<Field> ret = fieldCache.get(cls);
if (ret == null) {
ret = new ArrayList<>();
Field fields[] = cls.getFields();
Field[] fields = cls.getFields();
for (Field f : fields) {
if (Modifier.isStatic(f.getModifiers())) {
continue;
@@ -1092,7 +1092,7 @@ public class GenericTagTreePanel extends GenericTagPanel {
private void addItem(Object obj, Field field, int index, Class<?> cls) {
SWFArray swfArray = field.getAnnotation(SWFArray.class);
if (swfArray != null && !swfArray.countField().isEmpty()) { //Fields with same countField must be enlarged too
Field fields[] = obj.getClass().getDeclaredFields();
Field[] fields = obj.getClass().getDeclaredFields();
List<Integer> sameFlds = new ArrayList<>();
for (int f = 0; f < fields.length; f++) {
SWFArray fieldSwfArray = fields[f].getAnnotation(SWFArray.class);
@@ -1154,7 +1154,7 @@ public class GenericTagTreePanel extends GenericTagPanel {
private void removeItem(Object obj, Field field, int index) {
SWFArray swfArray = field.getAnnotation(SWFArray.class);
if (swfArray != null && !swfArray.countField().isEmpty()) { //Fields with same countField must be removed from too
Field fields[] = obj.getClass().getDeclaredFields();
Field[] fields = obj.getClass().getDeclaredFields();
for (int f = 0; f < fields.length; f++) {
SWFArray fieldSwfArray = fields[f].getAnnotation(SWFArray.class);
if (fieldSwfArray != null && fieldSwfArray.countField().equals(swfArray.countField())) {
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,293 +1,293 @@
/*
* Copyright (C) 2010-2016 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.gui;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
/**
* Menu Builder. Creates menu.
*
* @author JPEXS
*/
public interface MenuBuilder {
public static class HotKey {
private static Map<Integer, String> keyCodesToNames = new HashMap<>();
private static Map<String, Integer> keyNamesToCodes = new HashMap<>();
{
Field[] fields = KeyEvent.class.getFields();
for (int i = 0; i < fields.length; i++) {
String fieldName = fields[i].getName();
// We only care about the field names corresponding to key codes
if (fieldName.startsWith("VK")) {
try {
int keyCode = fields[i].getInt(null);
String keyName = fieldName.substring(3);
keyCodesToNames.put(keyCode, keyName);
keyNamesToCodes.put(keyName, keyCode);
} catch (Exception ex) {
}
}
}
}
public int key;
public boolean shiftDown;
public boolean ctrlDown;
public boolean altDown;
@Override
public int hashCode() {
int hash = 7;
hash = 41 * hash + this.key;
hash = 41 * hash + (this.shiftDown ? 1 : 0);
hash = 41 * hash + (this.ctrlDown ? 1 : 0);
hash = 41 * hash + (this.altDown ? 1 : 0);
return hash;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final HotKey other = (HotKey) obj;
if (this.key != other.key) {
return false;
}
if (this.shiftDown != other.shiftDown) {
return false;
}
if (this.ctrlDown != other.ctrlDown) {
return false;
}
return (this.altDown == other.altDown);
}
public boolean matches(KeyEvent ev) {
return ev.getKeyCode() == key && ev.isControlDown() == ctrlDown && ev.isShiftDown() == shiftDown && ev.isAltDown() == altDown;
}
public int getModifier() {
return (shiftDown ? KeyEvent.SHIFT_MASK : 0) + (ctrlDown ? KeyEvent.CTRL_MASK : 0) + (altDown ? KeyEvent.ALT_MASK : 0);
}
public HotKey(String h) {
String parts[] = h.contains("+") ? h.split("\\+") : new String[]{h};
for (String s : parts) {
switch (s) {
case "SHIFT":
shiftDown = true;
break;
case "CTRL":
ctrlDown = true;
break;
case "ALT":
altDown = true;
break;
default:
if (keyNamesToCodes.containsKey(s)) {
key = keyNamesToCodes.get(s);
} else {
throw new IllegalArgumentException("Key " + s + " not found!");
}
}
}
}
public HotKey(KeyEvent ev) {
this(ev.getKeyCode(), ev.isShiftDown(), ev.isControlDown(), ev.isAltDown());
}
public HotKey(int key) {
this(key, false, false, false);
}
public HotKey(int key, boolean shiftDown, boolean ctrlDown, boolean altDown) {
this.key = key;
this.shiftDown = shiftDown;
this.ctrlDown = ctrlDown;
this.altDown = altDown;
}
@Override
public String toString() {
String s = "";
if (shiftDown) {
s += "SHIFT";
}
if (ctrlDown) {
if (!s.isEmpty()) {
s += "+";
}
s += "CTRL";
}
if (altDown) {
if (!s.isEmpty()) {
s += "+";
}
s += "ALT";
}
if (!s.isEmpty()) {
s += "+";
}
s += keyCodesToNames.get(key);
return s;
}
}
public static final int PRIORITY_LOW = 1;
public static final int PRIORITY_MEDIUM = 2;
public static final int PRIORITY_TOP = 3;
/**
* Initializes menuBuilder
*/
public void initMenu();
/**
* Adds separator
*
* @param parentPath Parent menu path
*/
public void addSeparator(String parentPath);
/**
* Adds menu item
*
* @param path Path
* @param title Title
* @param icon Icon - resource name
* @param action Action for clicking
* @param priority Priority
* @param subloader Action which loads menu inside
* @param isLeaf Has no subitems?
* @param key
* @param isOptional
*/
public void addMenuItem(String path, String title, String icon, ActionListener action, int priority, ActionListener subloader, boolean isLeaf, HotKey key, boolean isOptional);
/**
* Adds toggle item (radio/checkbox)
*
* @param path Path
* @param title Title
* @param group Group for toggling. Null = checkbox
* @param icon Icon - resource name
* @param action Action for clicking
* @param priority Priority
* @param key
*/
public void addToggleMenuItem(String path, String title, String group, String icon, ActionListener action, int priority, HotKey key);
/**
* Test menu checked (toggle)
*
* @param path Menu path
* @return True when checked
*/
public boolean isMenuChecked(String path);
/**
* Hotkey for menu
*
* @param path Menu path
* @return
*/
public HotKey getMenuHotkey(String path);
/**
* Sets menu checked (toggle)
*
* @param path Menu path
* @param checked Checked?
*/
public void setMenuChecked(String path, boolean checked);
/**
* Sets checked item from group
*
* @param group Group name
* @param selected Selected path
*/
public void setGroupSelection(String group, String selected);
/**
* Gets selected path from group
*
* @param group Group name
* @return Path
*/
public String getGroupSelection(String group);
/**
* Clears menu
*
* @param path Path of menu
*/
public void clearMenu(String path);
/**
* Sets enabled property of menu
*
* @param path Menu path
* @param enabled Enabled?
*/
public void setMenuEnabled(String path, boolean enabled);
/**
* Finished creating menu
*
* @param path Menu path
*/
public void finishMenu(String path);
/**
* Does this builder support actions for menus? (not menuitems)
*
* @return True if supports
*/
public boolean supportsMenuAction();
/**
* Does this builder support application menu (Path "_/...")
*
* @return True if supports
*/
public boolean supportsAppMenu();
}
/*
* Copyright (C) 2010-2016 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.gui;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
/**
* Menu Builder. Creates menu.
*
* @author JPEXS
*/
public interface MenuBuilder {
public static class HotKey {
private static Map<Integer, String> keyCodesToNames = new HashMap<>();
private static Map<String, Integer> keyNamesToCodes = new HashMap<>();
{
Field[] fields = KeyEvent.class.getFields();
for (int i = 0; i < fields.length; i++) {
String fieldName = fields[i].getName();
// We only care about the field names corresponding to key codes
if (fieldName.startsWith("VK")) {
try {
int keyCode = fields[i].getInt(null);
String keyName = fieldName.substring(3);
keyCodesToNames.put(keyCode, keyName);
keyNamesToCodes.put(keyName, keyCode);
} catch (Exception ex) {
}
}
}
}
public int key;
public boolean shiftDown;
public boolean ctrlDown;
public boolean altDown;
@Override
public int hashCode() {
int hash = 7;
hash = 41 * hash + this.key;
hash = 41 * hash + (this.shiftDown ? 1 : 0);
hash = 41 * hash + (this.ctrlDown ? 1 : 0);
hash = 41 * hash + (this.altDown ? 1 : 0);
return hash;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final HotKey other = (HotKey) obj;
if (this.key != other.key) {
return false;
}
if (this.shiftDown != other.shiftDown) {
return false;
}
if (this.ctrlDown != other.ctrlDown) {
return false;
}
return (this.altDown == other.altDown);
}
public boolean matches(KeyEvent ev) {
return ev.getKeyCode() == key && ev.isControlDown() == ctrlDown && ev.isShiftDown() == shiftDown && ev.isAltDown() == altDown;
}
public int getModifier() {
return (shiftDown ? KeyEvent.SHIFT_MASK : 0) + (ctrlDown ? KeyEvent.CTRL_MASK : 0) + (altDown ? KeyEvent.ALT_MASK : 0);
}
public HotKey(String h) {
String[] parts = h.contains("+") ? h.split("\\+") : new String[]{h};
for (String s : parts) {
switch (s) {
case "SHIFT":
shiftDown = true;
break;
case "CTRL":
ctrlDown = true;
break;
case "ALT":
altDown = true;
break;
default:
if (keyNamesToCodes.containsKey(s)) {
key = keyNamesToCodes.get(s);
} else {
throw new IllegalArgumentException("Key " + s + " not found!");
}
}
}
}
public HotKey(KeyEvent ev) {
this(ev.getKeyCode(), ev.isShiftDown(), ev.isControlDown(), ev.isAltDown());
}
public HotKey(int key) {
this(key, false, false, false);
}
public HotKey(int key, boolean shiftDown, boolean ctrlDown, boolean altDown) {
this.key = key;
this.shiftDown = shiftDown;
this.ctrlDown = ctrlDown;
this.altDown = altDown;
}
@Override
public String toString() {
String s = "";
if (shiftDown) {
s += "SHIFT";
}
if (ctrlDown) {
if (!s.isEmpty()) {
s += "+";
}
s += "CTRL";
}
if (altDown) {
if (!s.isEmpty()) {
s += "+";
}
s += "ALT";
}
if (!s.isEmpty()) {
s += "+";
}
s += keyCodesToNames.get(key);
return s;
}
}
public static final int PRIORITY_LOW = 1;
public static final int PRIORITY_MEDIUM = 2;
public static final int PRIORITY_TOP = 3;
/**
* Initializes menuBuilder
*/
public void initMenu();
/**
* Adds separator
*
* @param parentPath Parent menu path
*/
public void addSeparator(String parentPath);
/**
* Adds menu item
*
* @param path Path
* @param title Title
* @param icon Icon - resource name
* @param action Action for clicking
* @param priority Priority
* @param subloader Action which loads menu inside
* @param isLeaf Has no subitems?
* @param key
* @param isOptional
*/
public void addMenuItem(String path, String title, String icon, ActionListener action, int priority, ActionListener subloader, boolean isLeaf, HotKey key, boolean isOptional);
/**
* Adds toggle item (radio/checkbox)
*
* @param path Path
* @param title Title
* @param group Group for toggling. Null = checkbox
* @param icon Icon - resource name
* @param action Action for clicking
* @param priority Priority
* @param key
*/
public void addToggleMenuItem(String path, String title, String group, String icon, ActionListener action, int priority, HotKey key);
/**
* Test menu checked (toggle)
*
* @param path Menu path
* @return True when checked
*/
public boolean isMenuChecked(String path);
/**
* Hotkey for menu
*
* @param path Menu path
* @return
*/
public HotKey getMenuHotkey(String path);
/**
* Sets menu checked (toggle)
*
* @param path Menu path
* @param checked Checked?
*/
public void setMenuChecked(String path, boolean checked);
/**
* Sets checked item from group
*
* @param group Group name
* @param selected Selected path
*/
public void setGroupSelection(String group, String selected);
/**
* Gets selected path from group
*
* @param group Group name
* @return Path
*/
public String getGroupSelection(String group);
/**
* Clears menu
*
* @param path Path of menu
*/
public void clearMenu(String path);
/**
* Sets enabled property of menu
*
* @param path Menu path
* @param enabled Enabled?
*/
public void setMenuEnabled(String path, boolean enabled);
/**
* Finished creating menu
*
* @param path Menu path
*/
public void finishMenu(String path);
/**
* Does this builder support actions for menus? (not menuitems)
*
* @return True if supports
*/
public boolean supportsMenuAction();
/**
* Does this builder support application menu (Path "_/...")
*
* @return True if supports
*/
public boolean supportsAppMenu();
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,184 +1,184 @@
/*
* Copyright (C) 2010-2016 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.gui.abc;
import com.jpexs.decompiler.flash.abc.types.Namespace;
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
import com.jpexs.decompiler.flash.gui.AppDialog;
import com.jpexs.decompiler.flash.gui.AppStrings;
import com.jpexs.decompiler.flash.gui.View;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.event.AncestorEvent;
import javax.swing.event.AncestorListener;
/**
*
* @author JPEXS
*/
public class NewTraitDialog extends AppDialog {
private static final int modifiers[] = new int[]{
Namespace.KIND_PACKAGE,
Namespace.KIND_PRIVATE,
Namespace.KIND_PROTECTED,
Namespace.KIND_NAMESPACE,
Namespace.KIND_PACKAGE_INTERNAL,
Namespace.KIND_EXPLICIT,
Namespace.KIND_STATIC_PROTECTED
};
private static final int types[] = new int[]{
Trait.TRAIT_METHOD,
Trait.TRAIT_GETTER,
Trait.TRAIT_SETTER,
Trait.TRAIT_CONST,
Trait.TRAIT_SLOT
};
private final JComboBox<String> accessComboBox;
private final JComboBox<String> typeComboBox;
private final JCheckBox staticCheckbox;
private final JTextField nameField;
private int result = ERROR_OPTION;
public boolean getStatic() {
return staticCheckbox.isSelected();
}
public int getNamespaceKind() {
return modifiers[accessComboBox.getSelectedIndex()];
}
public int getTraitType() {
return types[typeComboBox.getSelectedIndex()];
}
public String getTraitName() {
return nameField.getText();
}
public NewTraitDialog() {
setSize(500, 300);
setTitle(translate("dialog.title"));
View.centerScreen(this);
View.setWindowIcon(this);
Container cnt = getContentPane();
cnt.setLayout(new BorderLayout());
JPanel optionsPanel = new JPanel(new FlowLayout());
//optionsPanel.add(new JLabel(translate("label.type")));
typeComboBox = new JComboBox<>(new String[]{
translate("type.method"),
translate("type.getter"),
translate("type.setter"),
translate("type.const"),
translate("type.slot"),});
staticCheckbox = new JCheckBox(translate("checkbox.static"));
optionsPanel.add(staticCheckbox);
String accessStrings[] = new String[modifiers.length];
for (int i = 0; i < accessStrings.length; i++) {
String pref = Namespace.kindToPrefix(modifiers[i]);
String name = Namespace.kindToStr(modifiers[i]);
accessStrings[i] = (pref.isEmpty() ? "" : pref + " ") + "(" + name + ")";
}
//optionsPanel.add(new JLabel(translate("label.access")));
accessComboBox = new JComboBox<>(accessStrings);
optionsPanel.add(accessComboBox);
optionsPanel.add(typeComboBox);
//optionsPanel.add(new JLabel(translate("label.name")));
nameField = new JTextField();
nameField.setPreferredSize(new Dimension(300, nameField.getPreferredSize().height));
optionsPanel.add(nameField);
cnt.add(optionsPanel, BorderLayout.CENTER);
JPanel buttonsPanel = new JPanel(new FlowLayout());
JButton buttonOk = new JButton(AppStrings.translate("button.ok"));
buttonOk.addActionListener(this::okButtonActionPerformed);
JButton buttonCancel = new JButton(AppStrings.translate("button.cancel"));
buttonCancel.addActionListener(this::cancelButtonActionPerformed);
buttonsPanel.add(buttonOk);
buttonsPanel.add(buttonCancel);
cnt.add(buttonsPanel, BorderLayout.SOUTH);
pack();
setDefaultCloseOperation(HIDE_ON_CLOSE);
setModalityType(ModalityType.APPLICATION_MODAL);
nameField.addAncestorListener(new AncestorListener() {
@Override
public void ancestorAdded(AncestorEvent event) {
JComponent component = event.getComponent();
component.requestFocusInWindow();
}
@Override
public void ancestorRemoved(AncestorEvent event) {
}
@Override
public void ancestorMoved(AncestorEvent event) {
}
});
getRootPane().setDefaultButton(buttonOk);
}
@Override
public void setVisible(boolean b) {
if (b) {
result = ERROR_OPTION;
nameField.setText("");
}
super.setVisible(b);
}
private void okButtonActionPerformed(ActionEvent evt) {
result = OK_OPTION;
if (nameField.getText().trim().isEmpty()) {
View.showMessageDialog(null, translate("error.name"), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE);
return;
}
setVisible(false);
}
private void cancelButtonActionPerformed(ActionEvent evt) {
result = CANCEL_OPTION;
setVisible(false);
}
public int showDialog() {
setVisible(true);
return result;
}
}
/*
* Copyright (C) 2010-2016 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.gui.abc;
import com.jpexs.decompiler.flash.abc.types.Namespace;
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
import com.jpexs.decompiler.flash.gui.AppDialog;
import com.jpexs.decompiler.flash.gui.AppStrings;
import com.jpexs.decompiler.flash.gui.View;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.event.AncestorEvent;
import javax.swing.event.AncestorListener;
/**
*
* @author JPEXS
*/
public class NewTraitDialog extends AppDialog {
private static final int[] modifiers = new int[]{
Namespace.KIND_PACKAGE,
Namespace.KIND_PRIVATE,
Namespace.KIND_PROTECTED,
Namespace.KIND_NAMESPACE,
Namespace.KIND_PACKAGE_INTERNAL,
Namespace.KIND_EXPLICIT,
Namespace.KIND_STATIC_PROTECTED
};
private static final int[] types = new int[]{
Trait.TRAIT_METHOD,
Trait.TRAIT_GETTER,
Trait.TRAIT_SETTER,
Trait.TRAIT_CONST,
Trait.TRAIT_SLOT
};
private final JComboBox<String> accessComboBox;
private final JComboBox<String> typeComboBox;
private final JCheckBox staticCheckbox;
private final JTextField nameField;
private int result = ERROR_OPTION;
public boolean getStatic() {
return staticCheckbox.isSelected();
}
public int getNamespaceKind() {
return modifiers[accessComboBox.getSelectedIndex()];
}
public int getTraitType() {
return types[typeComboBox.getSelectedIndex()];
}
public String getTraitName() {
return nameField.getText();
}
public NewTraitDialog() {
setSize(500, 300);
setTitle(translate("dialog.title"));
View.centerScreen(this);
View.setWindowIcon(this);
Container cnt = getContentPane();
cnt.setLayout(new BorderLayout());
JPanel optionsPanel = new JPanel(new FlowLayout());
//optionsPanel.add(new JLabel(translate("label.type")));
typeComboBox = new JComboBox<>(new String[]{
translate("type.method"),
translate("type.getter"),
translate("type.setter"),
translate("type.const"),
translate("type.slot"),});
staticCheckbox = new JCheckBox(translate("checkbox.static"));
optionsPanel.add(staticCheckbox);
String[] accessStrings = new String[modifiers.length];
for (int i = 0; i < accessStrings.length; i++) {
String pref = Namespace.kindToPrefix(modifiers[i]);
String name = Namespace.kindToStr(modifiers[i]);
accessStrings[i] = (pref.isEmpty() ? "" : pref + " ") + "(" + name + ")";
}
//optionsPanel.add(new JLabel(translate("label.access")));
accessComboBox = new JComboBox<>(accessStrings);
optionsPanel.add(accessComboBox);
optionsPanel.add(typeComboBox);
//optionsPanel.add(new JLabel(translate("label.name")));
nameField = new JTextField();
nameField.setPreferredSize(new Dimension(300, nameField.getPreferredSize().height));
optionsPanel.add(nameField);
cnt.add(optionsPanel, BorderLayout.CENTER);
JPanel buttonsPanel = new JPanel(new FlowLayout());
JButton buttonOk = new JButton(AppStrings.translate("button.ok"));
buttonOk.addActionListener(this::okButtonActionPerformed);
JButton buttonCancel = new JButton(AppStrings.translate("button.cancel"));
buttonCancel.addActionListener(this::cancelButtonActionPerformed);
buttonsPanel.add(buttonOk);
buttonsPanel.add(buttonCancel);
cnt.add(buttonsPanel, BorderLayout.SOUTH);
pack();
setDefaultCloseOperation(HIDE_ON_CLOSE);
setModalityType(ModalityType.APPLICATION_MODAL);
nameField.addAncestorListener(new AncestorListener() {
@Override
public void ancestorAdded(AncestorEvent event) {
JComponent component = event.getComponent();
component.requestFocusInWindow();
}
@Override
public void ancestorRemoved(AncestorEvent event) {
}
@Override
public void ancestorMoved(AncestorEvent event) {
}
});
getRootPane().setDefaultButton(buttonOk);
}
@Override
public void setVisible(boolean b) {
if (b) {
result = ERROR_OPTION;
nameField.setText("");
}
super.setVisible(b);
}
private void okButtonActionPerformed(ActionEvent evt) {
result = OK_OPTION;
if (nameField.getText().trim().isEmpty()) {
View.showMessageDialog(null, translate("error.name"), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE);
return;
}
setVisible(false);
}
private void cancelButtonActionPerformed(ActionEvent evt) {
result = CANCEL_OPTION;
setVisible(false);
}
public int showDialog() {
setVisible(true);
return result;
}
}
@@ -1,308 +1,308 @@
/*
* Copyright (C) 2010-2016 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.gui.debugger;
import com.jpexs.helpers.utf8.Utf8Helper;
import java.io.ByteArrayOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
/**
*
* @author JPEXS
*/
public class Debugger {
private static final Set<DebugListener> listeners = new HashSet<>();
public synchronized void addMessageListener(DebugListener l) {
listeners.add(l);
}
public synchronized void removeMessageListener(DebugListener l) {
listeners.remove(l);
}
private static class DebugHandler extends Thread {
private final Socket s;
private final int serverPort;
private static int maxid = 0;
private final int id;
public boolean finished = false;
private final Map<String, String> parameters = new HashMap<>();
public static final int MSG_STRING = 0;
public static final int MSG_LOADER_URL = 1;
public static final int MSG_LOADER_BYTES = 2;
public String getParameter(String name, String defValue) {
if (parameters.containsKey(name)) {
return parameters.get(name);
}
return defValue;
}
public int getVersionMajor() {
return Integer.parseInt(getParameter("debug.version.major", "1"));
}
public int getVersionMinor() {
return Integer.parseInt(getParameter("debug.version.major", "0"));
}
public boolean hasMsgType() {
return getVersionMajor() > 1 || getVersionMinor() > 0;
}
public DebugHandler(int serverPort, Socket s) {
this.s = s;
id = maxid++;
this.serverPort = serverPort;
}
public void cancel() {
try {
s.close();
} catch (IOException ex) {
//ignore
}
}
private int readType(InputStream is) throws IOException {
int type = is.read();
if (type == -1) {
throw new EOFException();
}
return type;
}
private byte[] readBytes(InputStream is) throws IOException {
int len = is.read();
if (len == -1) {
throw new EOFException();
}
int len2 = is.read();
if (len2 == -1) {
throw new EOFException();
}
int len3 = is.read();
if (len3 == -1) {
throw new EOFException();
}
int len4 = is.read();
if (len4 == -1) {
throw new EOFException();
}
len = (len << 24) + (len2 << 16) + (len3 << 8) + len4;
byte data[] = new byte[len];
int cnt;
int off = 0;
while (len > 0 && (cnt = is.read(data, off, len)) > 0) {
len -= cnt;
off += cnt;
}
return data;
}
private String readString(InputStream is) throws IOException {
int len = is.read();
if (len == -1) {
throw new EOFException();
}
int len2 = is.read();
if (len2 == -1) {
throw new EOFException();
}
len = (len << 8) + len2;
byte buf[] = new byte[len];
for (int i = 0; i < len; i++) {
int rd = is.read();
if (rd == -1) {
throw new EOFException();
}
buf[i] = (byte) rd;
}
return new String(buf, Utf8Helper.charset);
}
@Override
public void run() {
String clientName = Integer.toString(id);
try (InputStream is = s.getInputStream()) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int c;
do {
c = is.read();
if (c != 0) {
baos.write(c);
}
} while (c > 0);
String ret = baos.toString("UTF-8");
if (ret.equals("<policy-file-request/>")) {
try (OutputStream os = s.getOutputStream()) {
os.write(("<cross-domain-policy><allow-access-from domain=\"*\" to-ports=\"" + serverPort + "\" /></cross-domain-policy>").getBytes("UTF-8"));
}
} else {
if (!ret.isEmpty()) {
String param[] = (ret.contains(";") ? ret.split(";") : new String[]{ret});
for (String p : param) {
if (p.contains("=")) {
String key = p.substring(0, p.indexOf('='));
String val = p.substring(p.indexOf('=') + 1);
parameters.put(key, val);
} else {
parameters.put(p, "true");
}
}
}
boolean hasType = hasMsgType();
String name = readString(is);
if (!name.isEmpty()) {
clientName = name;
}
while (true) {
int type = 0;
if (hasType) {
type = readType(is);
}
switch (type) {
case MSG_STRING:
ret = readString(is);
for (DebugListener l : listeners) {
l.onMessage(clientName, ret);
}
break;
case MSG_LOADER_URL:
ret = readString(is);
for (DebugListener l : listeners) {
l.onLoaderURL(clientName, ret);
}
break;
case MSG_LOADER_BYTES:
byte retB[] = readBytes(is);
for (DebugListener l : listeners) {
l.onLoaderBytes(clientName, retB);
}
break;
}
}
}
} catch (IOException ex) {
//ignore
}
try {
s.close();
} catch (IOException ex) {
//ignore
}
finished = true;
for (DebugListener l : listeners) {
l.onFinish(clientName);
}
}
}
private static class DebugServerThread extends Thread {
private final int port;
private ServerSocket ss;
private final Map<Integer, DebugHandler> handlers = new WeakHashMap<>();
public DebugServerThread(int port) {
this.port = port;
}
@Override
public void run() {
try {
ss = new ServerSocket(port, 50, InetAddress.getByName("localhost"));
ss.setReuseAddress(true);
while (true) {
Socket s = ss.accept();
DebugHandler h = new DebugHandler(port, s);
handlers.put(h.id, h);
h.start();
}
} catch (IOException ex) {
//ignore
}
}
}
private final int port;
public Debugger(int port) {
this.port = port;
}
private DebugServerThread server = null;
public synchronized void start() {
if (server == null) {
server = new DebugServerThread(port);
server.start();
}
}
public synchronized boolean isRunning() {
return server != null;
}
public int getPort() {
return port;
}
public synchronized void stop() {
if (server != null) {
try {
server.ss.close();
} catch (IOException ex) {
//ignore
}
for (DebugHandler h : server.handlers.values()) {
h.cancel();
}
server.handlers.clear();
server = null;
}
}
}
/*
* Copyright (C) 2010-2016 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.gui.debugger;
import com.jpexs.helpers.utf8.Utf8Helper;
import java.io.ByteArrayOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
/**
*
* @author JPEXS
*/
public class Debugger {
private static final Set<DebugListener> listeners = new HashSet<>();
public synchronized void addMessageListener(DebugListener l) {
listeners.add(l);
}
public synchronized void removeMessageListener(DebugListener l) {
listeners.remove(l);
}
private static class DebugHandler extends Thread {
private final Socket s;
private final int serverPort;
private static int maxid = 0;
private final int id;
public boolean finished = false;
private final Map<String, String> parameters = new HashMap<>();
public static final int MSG_STRING = 0;
public static final int MSG_LOADER_URL = 1;
public static final int MSG_LOADER_BYTES = 2;
public String getParameter(String name, String defValue) {
if (parameters.containsKey(name)) {
return parameters.get(name);
}
return defValue;
}
public int getVersionMajor() {
return Integer.parseInt(getParameter("debug.version.major", "1"));
}
public int getVersionMinor() {
return Integer.parseInt(getParameter("debug.version.major", "0"));
}
public boolean hasMsgType() {
return getVersionMajor() > 1 || getVersionMinor() > 0;
}
public DebugHandler(int serverPort, Socket s) {
this.s = s;
id = maxid++;
this.serverPort = serverPort;
}
public void cancel() {
try {
s.close();
} catch (IOException ex) {
//ignore
}
}
private int readType(InputStream is) throws IOException {
int type = is.read();
if (type == -1) {
throw new EOFException();
}
return type;
}
private byte[] readBytes(InputStream is) throws IOException {
int len = is.read();
if (len == -1) {
throw new EOFException();
}
int len2 = is.read();
if (len2 == -1) {
throw new EOFException();
}
int len3 = is.read();
if (len3 == -1) {
throw new EOFException();
}
int len4 = is.read();
if (len4 == -1) {
throw new EOFException();
}
len = (len << 24) + (len2 << 16) + (len3 << 8) + len4;
byte[] data = new byte[len];
int cnt;
int off = 0;
while (len > 0 && (cnt = is.read(data, off, len)) > 0) {
len -= cnt;
off += cnt;
}
return data;
}
private String readString(InputStream is) throws IOException {
int len = is.read();
if (len == -1) {
throw new EOFException();
}
int len2 = is.read();
if (len2 == -1) {
throw new EOFException();
}
len = (len << 8) + len2;
byte[] buf = new byte[len];
for (int i = 0; i < len; i++) {
int rd = is.read();
if (rd == -1) {
throw new EOFException();
}
buf[i] = (byte) rd;
}
return new String(buf, Utf8Helper.charset);
}
@Override
public void run() {
String clientName = Integer.toString(id);
try (InputStream is = s.getInputStream()) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int c;
do {
c = is.read();
if (c != 0) {
baos.write(c);
}
} while (c > 0);
String ret = baos.toString("UTF-8");
if (ret.equals("<policy-file-request/>")) {
try (OutputStream os = s.getOutputStream()) {
os.write(("<cross-domain-policy><allow-access-from domain=\"*\" to-ports=\"" + serverPort + "\" /></cross-domain-policy>").getBytes("UTF-8"));
}
} else {
if (!ret.isEmpty()) {
String[] param = (ret.contains(";") ? ret.split(";") : new String[]{ret});
for (String p : param) {
if (p.contains("=")) {
String key = p.substring(0, p.indexOf('='));
String val = p.substring(p.indexOf('=') + 1);
parameters.put(key, val);
} else {
parameters.put(p, "true");
}
}
}
boolean hasType = hasMsgType();
String name = readString(is);
if (!name.isEmpty()) {
clientName = name;
}
while (true) {
int type = 0;
if (hasType) {
type = readType(is);
}
switch (type) {
case MSG_STRING:
ret = readString(is);
for (DebugListener l : listeners) {
l.onMessage(clientName, ret);
}
break;
case MSG_LOADER_URL:
ret = readString(is);
for (DebugListener l : listeners) {
l.onLoaderURL(clientName, ret);
}
break;
case MSG_LOADER_BYTES:
byte[] retB = readBytes(is);
for (DebugListener l : listeners) {
l.onLoaderBytes(clientName, retB);
}
break;
}
}
}
} catch (IOException ex) {
//ignore
}
try {
s.close();
} catch (IOException ex) {
//ignore
}
finished = true;
for (DebugListener l : listeners) {
l.onFinish(clientName);
}
}
}
private static class DebugServerThread extends Thread {
private final int port;
private ServerSocket ss;
private final Map<Integer, DebugHandler> handlers = new WeakHashMap<>();
public DebugServerThread(int port) {
this.port = port;
}
@Override
public void run() {
try {
ss = new ServerSocket(port, 50, InetAddress.getByName("localhost"));
ss.setReuseAddress(true);
while (true) {
Socket s = ss.accept();
DebugHandler h = new DebugHandler(port, s);
handlers.put(h.id, h);
h.start();
}
} catch (IOException ex) {
//ignore
}
}
}
private final int port;
public Debugger(int port) {
this.port = port;
}
private DebugServerThread server = null;
public synchronized void start() {
if (server == null) {
server = new DebugServerThread(port);
server.start();
}
}
public synchronized boolean isRunning() {
return server != null;
}
public int getPort() {
return port;
}
public synchronized void stop() {
if (server != null) {
try {
server.ss.close();
} catch (IOException ex) {
//ignore
}
for (DebugHandler h : server.handlers.values()) {
h.cancel();
}
server.handlers.clear();
server = null;
}
}
}
@@ -1,247 +1,247 @@
/*
* Copyright (C) 2010-2016 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.gui.debugger;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.ScriptPack;
import com.jpexs.decompiler.flash.abc.types.Multiname;
import com.jpexs.decompiler.flash.abc.types.Namespace;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.gui.DebugLogDialog;
import com.jpexs.decompiler.flash.gui.Main;
import com.jpexs.decompiler.flash.tags.ABCContainerTag;
import com.jpexs.decompiler.flash.tags.FileAttributesTag;
import com.jpexs.decompiler.flash.tags.Tag;
import com.jpexs.helpers.Helper;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
/**
*
* @author JPEXS
*/
public class DebuggerTools {
private static final Logger logger = Logger.getLogger(DebuggerTools.class.getName());
public static final String DEBUGGER_PACKAGE = "com.jpexs.decompiler.flash.debugger";
private static volatile Debugger debugger;
private static ScriptPack getDebuggerScriptPack(SWF swf) {
List<ABC> allAbcList = new ArrayList<>();
for (ABCContainerTag ac : swf.getAbcList()) {
allAbcList.add(ac.getABC());
}
for (ABCContainerTag ac : swf.getAbcList()) {
ABC a = ac.getABC();
for (ScriptPack m : a.getScriptPacks(DEBUGGER_PACKAGE, allAbcList)) {
if (isDebuggerClass(m.getClassPath().packageStr.toRawString(), null)) {
return m;
}
}
}
return null;
}
public static boolean hasDebugger(SWF swf) {
return getDebuggerScriptPack(swf) != null;
}
private static boolean isDebuggerClass(String tested, String cls) {
if (tested == null) {
return false;
}
// fast check, because dynamic regex compile and match is expensive
if (!tested.startsWith(DEBUGGER_PACKAGE)) {
return false;
}
if (cls == null) {
cls = "";
} else {
cls = "\\." + Pattern.quote(cls);
}
return tested.matches(Pattern.quote(DEBUGGER_PACKAGE) + "(\\.pkg[a-f0-9]+)?" + cls);
}
public static void injectDebugLoader(SWF swf) {
if (hasDebugger(swf)) {
ScriptPack dsp = getDebuggerScriptPack(swf);
String debuggerPkg = dsp.getClassPath().packageStr.toRawString();
for (ABCContainerTag ct : swf.getAbcList()) {
ABC a = ct.getABC();
if (dsp.abc == a) { //do not replace Loader in debugger itself
continue;
}
for (int i = 1; i < a.constants.getMultinameCount(); i++) {
Multiname m = a.constants.getMultiname(i);
if ("flash.display.Loader".equals(m.getNameWithNamespace(a.constants).toRawString())) {
m.namespace_index = a.constants.getNamespaceId(Namespace.KIND_PACKAGE, debuggerPkg, 0, true);
m.name_index = a.constants.getStringId("DebugLoader", true);
((Tag) ct).setModified(true);
} else if ("flash.utils.getDefinitionByName".equals(m.getNameWithNamespace(a.constants).toRawString())) {
m.namespace_index = a.constants.getNamespaceId(Namespace.KIND_PACKAGE, debuggerPkg, 0, true);
m.name_index = a.constants.getStringId("debugGetDefinitionByName", true);
((Tag) ct).setModified(true);
} else if ("flash.utils.getQualifiedClassName".equals(m.getNameWithNamespace(a.constants).toRawString())) {
m.namespace_index = a.constants.getNamespaceId(Namespace.KIND_PACKAGE, debuggerPkg, 0, true);
m.name_index = a.constants.getStringId("debugGetQualifiedClassName", true);
((Tag) ct).setModified(true);
} else if ("flash.utils.getQualifiedSuperclassName".equals(m.getNameWithNamespace(a.constants).toRawString())) {
m.namespace_index = a.constants.getNamespaceId(Namespace.KIND_PACKAGE, debuggerPkg, 0, true);
m.name_index = a.constants.getStringId("debugGetQualifiedSuperclassName", true);
((Tag) ct).setModified(true);
} else if ("flash.utils.describeType".equals(m.getNameWithNamespace(a.constants).toRawString())) {
m.namespace_index = a.constants.getNamespaceId(Namespace.KIND_PACKAGE, debuggerPkg, 0, true);
m.name_index = a.constants.getStringId("debugDescribeType", true);
((Tag) ct).setModified(true);
}
}
}
}
}
public static void replaceTraceCalls(SWF swf, String fname) {
if (hasDebugger(swf)) {
String debuggerPkg = getDebuggerScriptPack(swf).getClassPath().packageStr.toRawString();
//change trace to fname
for (ABCContainerTag ct : swf.getAbcList()) {
ABC a = ct.getABC();
for (int i = 1; i < a.constants.getMultinameCount(); i++) {
Multiname m = a.constants.getMultiname(i);
if ("trace".equals(m.getNameWithNamespace(a.constants).toRawString())) {
m.namespace_index = a.constants.getNamespaceId(Namespace.KIND_PACKAGE, debuggerPkg, 0, true);
m.name_index = a.constants.getStringId(fname, true);
((Tag) ct).setModified(true);
}
}
}
}
}
public static void switchDebugger(SWF swf) {
int port = Configuration.debuggerPort.get();
ScriptPack found = getDebuggerScriptPack(swf);
if (found != null) {
ABCContainerTag tag = found.abc.parentTag;
swf.removeTag((Tag) tag);
swf.getAbcList().remove(tag);
//Change all debugger calls to normal trace / Loader
for (ABCContainerTag ct : swf.getAbcList()) {
ABC a = ct.getABC();
for (int i = 1; i < a.constants.getMultinameCount(); i++) {
Multiname m = a.constants.getMultiname(i);
String packageStr = m.getNameWithNamespace(a.constants).toString();
if (isDebuggerClass(packageStr, "debugTrace")
|| isDebuggerClass(packageStr, "debugAlert")
|| isDebuggerClass(packageStr, "debugSocket")
|| isDebuggerClass(packageStr, "debugConsole")) {
m.name_index = a.constants.getStringId("trace", true);
m.namespace_index = a.constants.getNamespaceId(Namespace.KIND_PACKAGE, "", 0, true);
((Tag) ct).setModified(true);
} else if (isDebuggerClass(packageStr, "DebugLoader")) {
m.name_index = a.constants.getStringId("Loader", true);
m.namespace_index = a.constants.getNamespaceId(Namespace.KIND_PACKAGE, "flash.display", 0, true);
}
}
}
} else {
Random rnd = new Random();
byte rb[] = new byte[16];
rnd.nextBytes(rb);
String rhex = Helper.byteArrayToHex(rb);
try {
//load debug swf
SWF debugSWF = new SWF(Main.class.getClassLoader().getResourceAsStream("com/jpexs/decompiler/flash/gui/debugger/debug.swf"), false);
List<ABCContainerTag> al = swf.getAbcList();
ABCContainerTag firstAbc = al.isEmpty() ? null : al.get(0);
if (firstAbc == null) { //nothing to instrument?
return;
}
String newdebuggerpkg = DEBUGGER_PACKAGE;
if (Configuration.randomDebuggerPackage.get()) {
newdebuggerpkg += ".pkg" + rhex;
}
//add debug ABC tags to main SWF
for (ABCContainerTag ds : debugSWF.getAbcList()) {
ABC a = ds.getABC();
//Append random hex to Debugger package name
for (int i = 1; i < a.constants.getNamespaceCount(); i++) {
if (a.constants.getNamespace(i).hasName(DEBUGGER_PACKAGE, a.constants)) {
a.constants.getNamespace(i).name_index = a.constants.getStringId(newdebuggerpkg, true);
}
}
//Set debugger port to actually set port
for (int i = 0; i < a.constants.getIntCount(); i++) {
if (a.constants.getInt(i) == 123456L) {
a.constants.setInt(i, (long) port);
}
}
//Add to target SWF
((Tag) ds).setSwf(swf);
swf.addTag((Tag) ds, (Tag) firstAbc);
swf.getAbcList().add(swf.getAbcList().indexOf(firstAbc), ds);
((Tag) ds).setModified(true);
//To allow socket connection to FFDec. Is this safe?
FileAttributesTag ft = swf.getFileAttributes();
ft.useNetwork = true;
ft.setModified(true);
}
} catch (Exception ex) {
logger.log(Level.SEVERE, "Error while attaching debugger", ex);
//ignore
}
}
initDebugger();
}
public static Debugger initDebugger() {
if (debugger == null) {
synchronized (Main.class) {
if (debugger == null) {
Debugger dbg = new Debugger(Configuration.debuggerPort.get());
dbg.start();
debugger = dbg;
}
}
}
return debugger;
}
public static void debuggerShowLog() {
initDebugger();
if (Main.debugDialog == null) {
Main.debugDialog = new DebugLogDialog(debugger);
}
Main.debugDialog.setVisible(true);
}
}
/*
* Copyright (C) 2010-2016 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.gui.debugger;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.ScriptPack;
import com.jpexs.decompiler.flash.abc.types.Multiname;
import com.jpexs.decompiler.flash.abc.types.Namespace;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.gui.DebugLogDialog;
import com.jpexs.decompiler.flash.gui.Main;
import com.jpexs.decompiler.flash.tags.ABCContainerTag;
import com.jpexs.decompiler.flash.tags.FileAttributesTag;
import com.jpexs.decompiler.flash.tags.Tag;
import com.jpexs.helpers.Helper;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
/**
*
* @author JPEXS
*/
public class DebuggerTools {
private static final Logger logger = Logger.getLogger(DebuggerTools.class.getName());
public static final String DEBUGGER_PACKAGE = "com.jpexs.decompiler.flash.debugger";
private static volatile Debugger debugger;
private static ScriptPack getDebuggerScriptPack(SWF swf) {
List<ABC> allAbcList = new ArrayList<>();
for (ABCContainerTag ac : swf.getAbcList()) {
allAbcList.add(ac.getABC());
}
for (ABCContainerTag ac : swf.getAbcList()) {
ABC a = ac.getABC();
for (ScriptPack m : a.getScriptPacks(DEBUGGER_PACKAGE, allAbcList)) {
if (isDebuggerClass(m.getClassPath().packageStr.toRawString(), null)) {
return m;
}
}
}
return null;
}
public static boolean hasDebugger(SWF swf) {
return getDebuggerScriptPack(swf) != null;
}
private static boolean isDebuggerClass(String tested, String cls) {
if (tested == null) {
return false;
}
// fast check, because dynamic regex compile and match is expensive
if (!tested.startsWith(DEBUGGER_PACKAGE)) {
return false;
}
if (cls == null) {
cls = "";
} else {
cls = "\\." + Pattern.quote(cls);
}
return tested.matches(Pattern.quote(DEBUGGER_PACKAGE) + "(\\.pkg[a-f0-9]+)?" + cls);
}
public static void injectDebugLoader(SWF swf) {
if (hasDebugger(swf)) {
ScriptPack dsp = getDebuggerScriptPack(swf);
String debuggerPkg = dsp.getClassPath().packageStr.toRawString();
for (ABCContainerTag ct : swf.getAbcList()) {
ABC a = ct.getABC();
if (dsp.abc == a) { //do not replace Loader in debugger itself
continue;
}
for (int i = 1; i < a.constants.getMultinameCount(); i++) {
Multiname m = a.constants.getMultiname(i);
if ("flash.display.Loader".equals(m.getNameWithNamespace(a.constants).toRawString())) {
m.namespace_index = a.constants.getNamespaceId(Namespace.KIND_PACKAGE, debuggerPkg, 0, true);
m.name_index = a.constants.getStringId("DebugLoader", true);
((Tag) ct).setModified(true);
} else if ("flash.utils.getDefinitionByName".equals(m.getNameWithNamespace(a.constants).toRawString())) {
m.namespace_index = a.constants.getNamespaceId(Namespace.KIND_PACKAGE, debuggerPkg, 0, true);
m.name_index = a.constants.getStringId("debugGetDefinitionByName", true);
((Tag) ct).setModified(true);
} else if ("flash.utils.getQualifiedClassName".equals(m.getNameWithNamespace(a.constants).toRawString())) {
m.namespace_index = a.constants.getNamespaceId(Namespace.KIND_PACKAGE, debuggerPkg, 0, true);
m.name_index = a.constants.getStringId("debugGetQualifiedClassName", true);
((Tag) ct).setModified(true);
} else if ("flash.utils.getQualifiedSuperclassName".equals(m.getNameWithNamespace(a.constants).toRawString())) {
m.namespace_index = a.constants.getNamespaceId(Namespace.KIND_PACKAGE, debuggerPkg, 0, true);
m.name_index = a.constants.getStringId("debugGetQualifiedSuperclassName", true);
((Tag) ct).setModified(true);
} else if ("flash.utils.describeType".equals(m.getNameWithNamespace(a.constants).toRawString())) {
m.namespace_index = a.constants.getNamespaceId(Namespace.KIND_PACKAGE, debuggerPkg, 0, true);
m.name_index = a.constants.getStringId("debugDescribeType", true);
((Tag) ct).setModified(true);
}
}
}
}
}
public static void replaceTraceCalls(SWF swf, String fname) {
if (hasDebugger(swf)) {
String debuggerPkg = getDebuggerScriptPack(swf).getClassPath().packageStr.toRawString();
//change trace to fname
for (ABCContainerTag ct : swf.getAbcList()) {
ABC a = ct.getABC();
for (int i = 1; i < a.constants.getMultinameCount(); i++) {
Multiname m = a.constants.getMultiname(i);
if ("trace".equals(m.getNameWithNamespace(a.constants).toRawString())) {
m.namespace_index = a.constants.getNamespaceId(Namespace.KIND_PACKAGE, debuggerPkg, 0, true);
m.name_index = a.constants.getStringId(fname, true);
((Tag) ct).setModified(true);
}
}
}
}
}
public static void switchDebugger(SWF swf) {
int port = Configuration.debuggerPort.get();
ScriptPack found = getDebuggerScriptPack(swf);
if (found != null) {
ABCContainerTag tag = found.abc.parentTag;
swf.removeTag((Tag) tag);
swf.getAbcList().remove(tag);
//Change all debugger calls to normal trace / Loader
for (ABCContainerTag ct : swf.getAbcList()) {
ABC a = ct.getABC();
for (int i = 1; i < a.constants.getMultinameCount(); i++) {
Multiname m = a.constants.getMultiname(i);
String packageStr = m.getNameWithNamespace(a.constants).toString();
if (isDebuggerClass(packageStr, "debugTrace")
|| isDebuggerClass(packageStr, "debugAlert")
|| isDebuggerClass(packageStr, "debugSocket")
|| isDebuggerClass(packageStr, "debugConsole")) {
m.name_index = a.constants.getStringId("trace", true);
m.namespace_index = a.constants.getNamespaceId(Namespace.KIND_PACKAGE, "", 0, true);
((Tag) ct).setModified(true);
} else if (isDebuggerClass(packageStr, "DebugLoader")) {
m.name_index = a.constants.getStringId("Loader", true);
m.namespace_index = a.constants.getNamespaceId(Namespace.KIND_PACKAGE, "flash.display", 0, true);
}
}
}
} else {
Random rnd = new Random();
byte[] rb = new byte[16];
rnd.nextBytes(rb);
String rhex = Helper.byteArrayToHex(rb);
try {
//load debug swf
SWF debugSWF = new SWF(Main.class.getClassLoader().getResourceAsStream("com/jpexs/decompiler/flash/gui/debugger/debug.swf"), false);
List<ABCContainerTag> al = swf.getAbcList();
ABCContainerTag firstAbc = al.isEmpty() ? null : al.get(0);
if (firstAbc == null) { //nothing to instrument?
return;
}
String newdebuggerpkg = DEBUGGER_PACKAGE;
if (Configuration.randomDebuggerPackage.get()) {
newdebuggerpkg += ".pkg" + rhex;
}
//add debug ABC tags to main SWF
for (ABCContainerTag ds : debugSWF.getAbcList()) {
ABC a = ds.getABC();
//Append random hex to Debugger package name
for (int i = 1; i < a.constants.getNamespaceCount(); i++) {
if (a.constants.getNamespace(i).hasName(DEBUGGER_PACKAGE, a.constants)) {
a.constants.getNamespace(i).name_index = a.constants.getStringId(newdebuggerpkg, true);
}
}
//Set debugger port to actually set port
for (int i = 0; i < a.constants.getIntCount(); i++) {
if (a.constants.getInt(i) == 123456L) {
a.constants.setInt(i, (long) port);
}
}
//Add to target SWF
((Tag) ds).setSwf(swf);
swf.addTag((Tag) ds, (Tag) firstAbc);
swf.getAbcList().add(swf.getAbcList().indexOf(firstAbc), ds);
((Tag) ds).setModified(true);
//To allow socket connection to FFDec. Is this safe?
FileAttributesTag ft = swf.getFileAttributes();
ft.useNetwork = true;
ft.setModified(true);
}
} catch (Exception ex) {
logger.log(Level.SEVERE, "Error while attaching debugger", ex);
//ignore
}
}
initDebugger();
}
public static Debugger initDebugger() {
if (debugger == null) {
synchronized (Main.class) {
if (debugger == null) {
Debugger dbg = new Debugger(Configuration.debuggerPort.get());
dbg.start();
debugger = dbg;
}
}
}
return debugger;
}
public static void debuggerShowLog() {
initDebugger();
if (Main.debugDialog == null) {
Main.debugDialog = new DebugLogDialog(debugger);
}
Main.debugDialog.setVisible(true);
}
}
@@ -1,458 +1,541 @@
/*
* Copyright (C) 2010-2016 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.gui.dumpview;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.ABCInputStream;
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
import com.jpexs.decompiler.flash.action.Action;
import com.jpexs.decompiler.flash.action.ActionListReader;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.dumpview.DumpInfo;
import com.jpexs.decompiler.flash.dumpview.DumpInfoSwfNode;
import com.jpexs.decompiler.flash.gui.Main;
import com.jpexs.decompiler.flash.gui.MainPanel;
import com.jpexs.decompiler.flash.gui.TreeNodeType;
import com.jpexs.decompiler.flash.gui.View;
import com.jpexs.decompiler.flash.gui.tagtree.TagTree;
import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag;
import com.jpexs.decompiler.flash.tags.DefineBitsJPEG2Tag;
import com.jpexs.decompiler.flash.tags.DefineBitsJPEG3Tag;
import com.jpexs.decompiler.flash.tags.DefineBitsJPEG4Tag;
import com.jpexs.decompiler.flash.tags.DefineBitsLossless2Tag;
import com.jpexs.decompiler.flash.tags.DefineBitsLosslessTag;
import com.jpexs.decompiler.flash.tags.DefineBitsTag;
import com.jpexs.decompiler.flash.tags.DefineButton2Tag;
import com.jpexs.decompiler.flash.tags.DefineButtonTag;
import com.jpexs.decompiler.flash.tags.DefineEditTextTag;
import com.jpexs.decompiler.flash.tags.DefineFont2Tag;
import com.jpexs.decompiler.flash.tags.DefineFont3Tag;
import com.jpexs.decompiler.flash.tags.DefineFont4Tag;
import com.jpexs.decompiler.flash.tags.DefineFontTag;
import com.jpexs.decompiler.flash.tags.DefineMorphShape2Tag;
import com.jpexs.decompiler.flash.tags.DefineMorphShapeTag;
import com.jpexs.decompiler.flash.tags.DefineShape2Tag;
import com.jpexs.decompiler.flash.tags.DefineShape3Tag;
import com.jpexs.decompiler.flash.tags.DefineShape4Tag;
import com.jpexs.decompiler.flash.tags.DefineShapeTag;
import com.jpexs.decompiler.flash.tags.DefineSoundTag;
import com.jpexs.decompiler.flash.tags.DefineSpriteTag;
import com.jpexs.decompiler.flash.tags.DefineText2Tag;
import com.jpexs.decompiler.flash.tags.DefineTextTag;
import com.jpexs.decompiler.flash.tags.DefineVideoStreamTag;
import com.jpexs.decompiler.flash.tags.DoABC2Tag;
import com.jpexs.decompiler.flash.tags.DoABCTag;
import com.jpexs.decompiler.flash.tags.DoActionTag;
import com.jpexs.decompiler.flash.tags.DoInitActionTag;
import com.jpexs.decompiler.flash.tags.FileAttributesTag;
import com.jpexs.decompiler.flash.tags.MetadataTag;
import com.jpexs.decompiler.flash.tags.PlaceObject2Tag;
import com.jpexs.decompiler.flash.tags.PlaceObject3Tag;
import com.jpexs.decompiler.flash.tags.PlaceObject4Tag;
import com.jpexs.decompiler.flash.tags.PlaceObjectTag;
import com.jpexs.decompiler.flash.tags.RemoveObject2Tag;
import com.jpexs.decompiler.flash.tags.RemoveObjectTag;
import com.jpexs.decompiler.flash.tags.SetBackgroundColorTag;
import com.jpexs.decompiler.flash.tags.ShowFrameTag;
import com.jpexs.decompiler.flash.tags.SoundStreamHead2Tag;
import com.jpexs.decompiler.flash.tags.SoundStreamHeadTag;
import com.jpexs.decompiler.flash.tags.gfx.DefineCompactedFont;
import com.jpexs.helpers.Helper;
import com.jpexs.helpers.MemoryInputStream;
import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.plaf.basic.BasicLabelUI;
import javax.swing.plaf.basic.BasicTreeUI;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
/**
*
* @author JPEXS
*/
public class DumpTree extends JTree {
private static final Logger logger = Logger.getLogger(DumpTree.class.getName());
private final MainPanel mainPanel;
public class DumpTreeCellRenderer extends DefaultTreeCellRenderer {
public DumpTreeCellRenderer() {
setUI(new BasicLabelUI());
setOpaque(false);
setBackgroundNonSelectionColor(Color.white);
}
@Override
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
Component ret = super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
if (ret instanceof JLabel) {
JLabel lab = (JLabel) ret;
if (value instanceof DumpInfo) {
DumpInfo di = (DumpInfo) value;
TreeNodeType nodeType = null;
if ("".equals(di.type)) {
nodeType = TreeNodeType.FLASH;
} else if ("TAG".equals(di.type)) {
String name = di.name;
if (name.contains(" ")) {
name = name.substring(0, name.indexOf(' ')).trim();
}
switch (name) {
case DefineFontTag.NAME:
case DefineFont2Tag.NAME:
case DefineFont3Tag.NAME:
case DefineFont4Tag.NAME:
case DefineCompactedFont.NAME:
nodeType = TreeNodeType.FONT;
break;
case DefineTextTag.NAME:
case DefineText2Tag.NAME:
case DefineEditTextTag.NAME:
nodeType = TreeNodeType.TEXT;
break;
case DefineBitsTag.NAME:
case DefineBitsJPEG2Tag.NAME:
case DefineBitsJPEG3Tag.NAME:
case DefineBitsJPEG4Tag.NAME:
case DefineBitsLosslessTag.NAME:
case DefineBitsLossless2Tag.NAME:
nodeType = TreeNodeType.IMAGE;
break;
case DefineShapeTag.NAME:
case DefineShape2Tag.NAME:
case DefineShape3Tag.NAME:
case DefineShape4Tag.NAME:
nodeType = TreeNodeType.SHAPE;
break;
case DefineMorphShapeTag.NAME:
case DefineMorphShape2Tag.NAME:
nodeType = TreeNodeType.MORPH_SHAPE;
break;
case DefineSpriteTag.NAME:
nodeType = TreeNodeType.SPRITE;
break;
case DefineButtonTag.NAME:
case DefineButton2Tag.NAME:
nodeType = TreeNodeType.BUTTON;
break;
case DefineVideoStreamTag.NAME:
nodeType = TreeNodeType.MOVIE;
break;
case DefineSoundTag.NAME:
case SoundStreamHeadTag.NAME:
case SoundStreamHead2Tag.NAME:
nodeType = TreeNodeType.SOUND;
break;
case DefineBinaryDataTag.NAME:
nodeType = TreeNodeType.BINARY_DATA;
break;
case DoActionTag.NAME:
case DoInitActionTag.NAME:
case DoABCTag.NAME:
case DoABC2Tag.NAME:
nodeType = TreeNodeType.AS;
break;
case ShowFrameTag.NAME:
nodeType = TreeNodeType.FRAME; //show_frame?
break;
case SetBackgroundColorTag.NAME:
nodeType = TreeNodeType.SET_BACKGROUNDCOLOR;
break;
case FileAttributesTag.NAME:
nodeType = TreeNodeType.FILE_ATTRIBUTES;
break;
case MetadataTag.NAME:
nodeType = TreeNodeType.METADATA;
break;
case PlaceObjectTag.NAME:
case PlaceObject2Tag.NAME:
case PlaceObject3Tag.NAME:
case PlaceObject4Tag.NAME:
nodeType = TreeNodeType.PLACE_OBJECT;
break;
case RemoveObjectTag.NAME:
case RemoveObject2Tag.NAME:
nodeType = TreeNodeType.REMOVE_OBJECT;
break;
default:
nodeType = TreeNodeType.OTHER_TAG;
}
}
if (nodeType != null) {
lab.setIcon(TagTree.getIconForType(nodeType));
}
}
}
return ret;
}
}
public DumpTree(DumpTreeModel treeModel, MainPanel mainPanel) {
super(treeModel);
this.mainPanel = mainPanel;
setCellRenderer(new DumpTreeCellRenderer());
setRootVisible(false);
setBackground(Color.white);
setUI(new BasicTreeUI() {
{
setHashColor(Color.gray);
}
});
}
public void createContextMenu() {
final JPopupMenu contextPopupMenu = new JPopupMenu();
final JMenuItem expandRecursiveMenuItem = new JMenuItem(mainPanel.translate("contextmenu.expandAll"));
expandRecursiveMenuItem.addActionListener(this::expandRecursiveButtonActionPerformed);
contextPopupMenu.add(expandRecursiveMenuItem);
final JMenuItem saveToFileMenuItem = new JMenuItem(mainPanel.translate("contextmenu.saveToFile"));
saveToFileMenuItem.addActionListener(this::saveToFileButtonActionPerformed);
contextPopupMenu.add(saveToFileMenuItem);
final JMenuItem saveUncompressedToFileMenuItem = new JMenuItem(mainPanel.translate("contextmenu.saveUncompressedToFile"));
saveUncompressedToFileMenuItem.addActionListener(this::saveUncompressedToFileButtonActionPerformed);
contextPopupMenu.add(saveUncompressedToFileMenuItem);
final JMenuItem closeSelectionMenuItem = new JMenuItem(mainPanel.translate("contextmenu.closeSwf"));
closeSelectionMenuItem.addActionListener(this::closeSwfButtonActionPerformed);
contextPopupMenu.add(closeSelectionMenuItem);
final JMenuItem parseActionsMenuItem = new JMenuItem(mainPanel.translate("contextmenu.parseActions"));
parseActionsMenuItem.addActionListener(this::parseActionsButtonActionPerformed);
contextPopupMenu.add(parseActionsMenuItem);
final JMenuItem parseAbcMenuItem = new JMenuItem(mainPanel.translate("contextmenu.parseABC"));
parseAbcMenuItem.addActionListener(this::parseAbcButtonActionPerformed);
contextPopupMenu.add(parseAbcMenuItem);
final JMenuItem parseInstructionsMenuItem = new JMenuItem(mainPanel.translate("contextmenu.parseInstructions"));
parseInstructionsMenuItem.addActionListener(this::parseInstructionsButtonActionPerformed);
contextPopupMenu.add(parseInstructionsMenuItem);
addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (SwingUtilities.isRightMouseButton(e)) {
int row = getClosestRowForLocation(e.getX(), e.getY());
int[] selectionRows = getSelectionRows();
if (!Helper.contains(selectionRows, row)) {
setSelectionRow(row);
}
TreePath[] paths = getSelectionPaths();
if (paths == null || paths.length == 0) {
return;
}
closeSelectionMenuItem.setVisible(false);
expandRecursiveMenuItem.setVisible(false);
saveToFileMenuItem.setVisible(false);
saveUncompressedToFileMenuItem.setVisible(false);
parseActionsMenuItem.setVisible(false);
parseAbcMenuItem.setVisible(false);
parseInstructionsMenuItem.setVisible(false);
if (paths.length == 1) {
DumpInfo treeNode = (DumpInfo) paths[0].getLastPathComponent();
if (treeNode instanceof DumpInfoSwfNode) {
closeSelectionMenuItem.setVisible(true);
}
if (treeNode.getEndByte() - treeNode.startByte > 3) {
saveToFileMenuItem.setVisible(true);
if (treeNode.name.equals("bitmapAlphaData") || treeNode.name.equals("zlibBitmapData")) {
saveUncompressedToFileMenuItem.setVisible(true);
}
}
// todo honfika: do not use string names, because it has conflicts e.g with DefineFont.code
if (treeNode.name.equals("actionBytes") && treeNode.getChildCount() == 0) {
parseActionsMenuItem.setVisible(true);
}
if (treeNode.name.equals("abcBytes") && treeNode.getChildCount() == 0) {
parseAbcMenuItem.setVisible(true);
}
if (treeNode.name.equals("code") && treeNode.parent.name.equals("method_body") && treeNode.getChildCount() == 0) {
parseInstructionsMenuItem.setVisible(true);
}
TreeModel model = getModel();
expandRecursiveMenuItem.setVisible(model.getChildCount(treeNode) > 0);
}
contextPopupMenu.show(e.getComponent(), e.getX(), e.getY());
}
}
});
}
private void expandRecursiveButtonActionPerformed(ActionEvent evt) {
TreePath path = getSelectionPath();
if (path == null) {
return;
}
View.expandTreeNodes(this, path, true);
}
private void saveToFileButtonActionPerformed(ActionEvent evt) {
saveToFileButtonActionPerformed(false);
}
private void saveUncompressedToFileButtonActionPerformed(ActionEvent evt) {
saveToFileButtonActionPerformed(true);
}
private void saveToFileButtonActionPerformed(boolean decompress) {
TreePath[] paths = getSelectionPaths();
DumpInfo dumpInfo = (DumpInfo) paths[0].getLastPathComponent();
JFileChooser fc = new JFileChooser();
String selDir = Configuration.lastOpenDir.get();
fc.setCurrentDirectory(new File(selDir));
JFrame f = new JFrame();
View.setWindowIcon(f);
if (fc.showSaveDialog(f) == JFileChooser.APPROVE_OPTION) {
File sf = Helper.fixDialogFile(fc.getSelectedFile());
try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(sf))) {
if (decompress) {
byte[] data = DumpInfoSwfNode.getSwfNode(dumpInfo).getSwf().originalUncompressedData;
fos.write(SWFInputStream.uncompressByteArray(data, (int) dumpInfo.startByte, (int) (dumpInfo.getEndByte() - dumpInfo.startByte + 1)));
} else {
byte[] data = DumpInfoSwfNode.getSwfNode(dumpInfo).getSwf().originalUncompressedData;
fos.write(data, (int) dumpInfo.startByte, (int) (dumpInfo.getEndByte() - dumpInfo.startByte + 1));
}
} catch (IOException ex) {
logger.log(Level.SEVERE, null, ex);
}
}
}
private void parseActionsButtonActionPerformed(ActionEvent evt) {
TreePath[] paths = getSelectionPaths();
DumpInfo dumpInfo = (DumpInfo) paths[0].getLastPathComponent();
SWF swf = DumpInfoSwfNode.getSwfNode(dumpInfo).getSwf();
byte[] data = swf.originalUncompressedData;
int prevLength = (int) dumpInfo.startByte;
try {
SWFInputStream rri = new SWFInputStream(swf, data);
if (prevLength != 0) {
rri.seek(prevLength);
}
List<Action> actions = ActionListReader.getOriginalActions(rri, prevLength, (int) dumpInfo.getEndByte());
for (Action action : actions) {
DumpInfo di = new DumpInfo(action.toString(), "Action", null, action.getAddress(), action.getTotalActionLength());
di.parent = dumpInfo;
rri.dumpInfo = di;
rri.seek(action.getAddress());
rri.readAction();
dumpInfo.getChildInfos().add(di);
}
repaint();
} catch (IOException | InterruptedException ex) {
logger.log(Level.SEVERE, null, ex);
}
}
private void parseAbcButtonActionPerformed(ActionEvent evt) {
TreePath[] paths = getSelectionPaths();
DumpInfo dumpInfo = (DumpInfo) paths[0].getLastPathComponent();
SWF swf = DumpInfoSwfNode.getSwfNode(dumpInfo).getSwf();
byte[] data = swf.originalUncompressedData;
int prevLength = (int) dumpInfo.startByte;
try {
ABCInputStream ais = new ABCInputStream(new MemoryInputStream(data, 0, prevLength + (int) dumpInfo.lengthBytes));
ais.seek(prevLength);
ais.dumpInfo = dumpInfo;
new ABC(ais, swf, null);
} catch (IOException ex) {
logger.log(Level.SEVERE, null, ex);
}
repaint();
}
private void parseInstructionsButtonActionPerformed(ActionEvent evt) {
TreePath[] paths = getSelectionPaths();
DumpInfo dumpInfo = (DumpInfo) paths[0].getLastPathComponent();
SWF swf = DumpInfoSwfNode.getSwfNode(dumpInfo).getSwf();
byte[] data = swf.originalUncompressedData;
int prevLength = (int) dumpInfo.startByte;
try {
ABCInputStream ais = new ABCInputStream(new MemoryInputStream(data, 0, prevLength + (int) dumpInfo.lengthBytes));
ais.seek(prevLength);
ais.dumpInfo = dumpInfo;
new AVM2Code(ais, null /*FIXME! Pass correct body!*/);
} catch (IOException ex) {
logger.log(Level.SEVERE, null, ex);
}
repaint();
}
private void closeSwfButtonActionPerformed(ActionEvent evt) {
Main.closeFile(mainPanel.getCurrentSwfList());
}
@Override
public DumpTreeModel getModel() {
return (DumpTreeModel) super.getModel();
}
public void expandRoot() {
DumpTreeModel dtm = getModel();
DumpInfo root = dtm.getRoot();
expandPath(new TreePath(new Object[]{root}));
}
public void expandFirstLevelNodes() {
DumpTreeModel dtm = getModel();
DumpInfo root = dtm.getRoot();
int childCount = dtm.getChildCount(root);
expandPath(new TreePath(new Object[]{root}));
for (int i = 0; i < childCount; i++) {
expandPath(new TreePath(new Object[]{root, dtm.getChild(root, i)}));
}
}
}
/*
* Copyright (C) 2010-2016 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.gui.dumpview;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.ABCInputStream;
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
import com.jpexs.decompiler.flash.action.Action;
import com.jpexs.decompiler.flash.action.ActionListReader;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.dumpview.DumpInfo;
import com.jpexs.decompiler.flash.dumpview.DumpInfoSpecial;
import com.jpexs.decompiler.flash.dumpview.DumpInfoSpecialType;
import com.jpexs.decompiler.flash.dumpview.DumpInfoSwfNode;
import com.jpexs.decompiler.flash.gui.Main;
import com.jpexs.decompiler.flash.gui.MainPanel;
import com.jpexs.decompiler.flash.gui.TreeNodeType;
import com.jpexs.decompiler.flash.gui.View;
import com.jpexs.decompiler.flash.gui.tagtree.TagTree;
import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag;
import com.jpexs.decompiler.flash.tags.DefineBitsJPEG2Tag;
import com.jpexs.decompiler.flash.tags.DefineBitsJPEG3Tag;
import com.jpexs.decompiler.flash.tags.DefineBitsJPEG4Tag;
import com.jpexs.decompiler.flash.tags.DefineBitsLossless2Tag;
import com.jpexs.decompiler.flash.tags.DefineBitsLosslessTag;
import com.jpexs.decompiler.flash.tags.DefineBitsTag;
import com.jpexs.decompiler.flash.tags.DefineButton2Tag;
import com.jpexs.decompiler.flash.tags.DefineButtonTag;
import com.jpexs.decompiler.flash.tags.DefineEditTextTag;
import com.jpexs.decompiler.flash.tags.DefineFont2Tag;
import com.jpexs.decompiler.flash.tags.DefineFont3Tag;
import com.jpexs.decompiler.flash.tags.DefineFont4Tag;
import com.jpexs.decompiler.flash.tags.DefineFontTag;
import com.jpexs.decompiler.flash.tags.DefineMorphShape2Tag;
import com.jpexs.decompiler.flash.tags.DefineMorphShapeTag;
import com.jpexs.decompiler.flash.tags.DefineShape2Tag;
import com.jpexs.decompiler.flash.tags.DefineShape3Tag;
import com.jpexs.decompiler.flash.tags.DefineShape4Tag;
import com.jpexs.decompiler.flash.tags.DefineShapeTag;
import com.jpexs.decompiler.flash.tags.DefineSoundTag;
import com.jpexs.decompiler.flash.tags.DefineSpriteTag;
import com.jpexs.decompiler.flash.tags.DefineText2Tag;
import com.jpexs.decompiler.flash.tags.DefineTextTag;
import com.jpexs.decompiler.flash.tags.DefineVideoStreamTag;
import com.jpexs.decompiler.flash.tags.DoABC2Tag;
import com.jpexs.decompiler.flash.tags.DoABCTag;
import com.jpexs.decompiler.flash.tags.DoActionTag;
import com.jpexs.decompiler.flash.tags.DoInitActionTag;
import com.jpexs.decompiler.flash.tags.FileAttributesTag;
import com.jpexs.decompiler.flash.tags.MetadataTag;
import com.jpexs.decompiler.flash.tags.PlaceObject2Tag;
import com.jpexs.decompiler.flash.tags.PlaceObject3Tag;
import com.jpexs.decompiler.flash.tags.PlaceObject4Tag;
import com.jpexs.decompiler.flash.tags.PlaceObjectTag;
import com.jpexs.decompiler.flash.tags.RemoveObject2Tag;
import com.jpexs.decompiler.flash.tags.RemoveObjectTag;
import com.jpexs.decompiler.flash.tags.SetBackgroundColorTag;
import com.jpexs.decompiler.flash.tags.ShowFrameTag;
import com.jpexs.decompiler.flash.tags.SoundStreamHead2Tag;
import com.jpexs.decompiler.flash.tags.SoundStreamHeadTag;
import com.jpexs.decompiler.flash.tags.Tag;
import com.jpexs.decompiler.flash.tags.gfx.DefineCompactedFont;
import com.jpexs.helpers.Helper;
import com.jpexs.helpers.MemoryInputStream;
import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.plaf.basic.BasicLabelUI;
import javax.swing.plaf.basic.BasicTreeUI;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
/**
*
* @author JPEXS
*/
public class DumpTree extends JTree {
private static final Logger logger = Logger.getLogger(DumpTree.class.getName());
private final MainPanel mainPanel;
public class DumpTreeCellRenderer extends DefaultTreeCellRenderer {
public DumpTreeCellRenderer() {
setUI(new BasicLabelUI());
setOpaque(false);
setBackgroundNonSelectionColor(Color.white);
}
@Override
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
Component ret = super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
if (ret instanceof JLabel) {
JLabel lab = (JLabel) ret;
if (value instanceof DumpInfo) {
DumpInfo di = (DumpInfo) value;
TreeNodeType nodeType = null;
if ("".equals(di.type)) {
nodeType = TreeNodeType.FLASH;
} else if ("TAG".equals(di.type)) {
String name = di.name;
if (name.contains(" ")) {
name = name.substring(0, name.indexOf(' ')).trim();
}
switch (name) {
case DefineFontTag.NAME:
case DefineFont2Tag.NAME:
case DefineFont3Tag.NAME:
case DefineFont4Tag.NAME:
case DefineCompactedFont.NAME:
nodeType = TreeNodeType.FONT;
break;
case DefineTextTag.NAME:
case DefineText2Tag.NAME:
case DefineEditTextTag.NAME:
nodeType = TreeNodeType.TEXT;
break;
case DefineBitsTag.NAME:
case DefineBitsJPEG2Tag.NAME:
case DefineBitsJPEG3Tag.NAME:
case DefineBitsJPEG4Tag.NAME:
case DefineBitsLosslessTag.NAME:
case DefineBitsLossless2Tag.NAME:
nodeType = TreeNodeType.IMAGE;
break;
case DefineShapeTag.NAME:
case DefineShape2Tag.NAME:
case DefineShape3Tag.NAME:
case DefineShape4Tag.NAME:
nodeType = TreeNodeType.SHAPE;
break;
case DefineMorphShapeTag.NAME:
case DefineMorphShape2Tag.NAME:
nodeType = TreeNodeType.MORPH_SHAPE;
break;
case DefineSpriteTag.NAME:
nodeType = TreeNodeType.SPRITE;
break;
case DefineButtonTag.NAME:
case DefineButton2Tag.NAME:
nodeType = TreeNodeType.BUTTON;
break;
case DefineVideoStreamTag.NAME:
nodeType = TreeNodeType.MOVIE;
break;
case DefineSoundTag.NAME:
case SoundStreamHeadTag.NAME:
case SoundStreamHead2Tag.NAME:
nodeType = TreeNodeType.SOUND;
break;
case DefineBinaryDataTag.NAME:
nodeType = TreeNodeType.BINARY_DATA;
break;
case DoActionTag.NAME:
case DoInitActionTag.NAME:
case DoABCTag.NAME:
case DoABC2Tag.NAME:
nodeType = TreeNodeType.AS;
break;
case ShowFrameTag.NAME:
nodeType = TreeNodeType.FRAME; //show_frame?
break;
case SetBackgroundColorTag.NAME:
nodeType = TreeNodeType.SET_BACKGROUNDCOLOR;
break;
case FileAttributesTag.NAME:
nodeType = TreeNodeType.FILE_ATTRIBUTES;
break;
case MetadataTag.NAME:
nodeType = TreeNodeType.METADATA;
break;
case PlaceObjectTag.NAME:
case PlaceObject2Tag.NAME:
case PlaceObject3Tag.NAME:
case PlaceObject4Tag.NAME:
nodeType = TreeNodeType.PLACE_OBJECT;
break;
case RemoveObjectTag.NAME:
case RemoveObject2Tag.NAME:
nodeType = TreeNodeType.REMOVE_OBJECT;
break;
default:
nodeType = TreeNodeType.OTHER_TAG;
}
}
if (nodeType != null) {
lab.setIcon(TagTree.getIconForType(nodeType));
}
}
}
return ret;
}
}
public DumpTree(DumpTreeModel treeModel, MainPanel mainPanel) {
super(treeModel);
this.mainPanel = mainPanel;
setCellRenderer(new DumpTreeCellRenderer());
setRootVisible(false);
setBackground(Color.white);
setUI(new BasicTreeUI() {
{
setHashColor(Color.gray);
}
});
}
public void createContextMenu() {
final JPopupMenu contextPopupMenu = new JPopupMenu();
final JMenuItem expandRecursiveMenuItem = new JMenuItem(mainPanel.translate("contextmenu.expandAll"));
expandRecursiveMenuItem.addActionListener(this::expandRecursiveButtonActionPerformed);
contextPopupMenu.add(expandRecursiveMenuItem);
final JMenuItem saveToFileMenuItem = new JMenuItem(mainPanel.translate("contextmenu.saveToFile"));
saveToFileMenuItem.addActionListener(this::saveToFileButtonActionPerformed);
contextPopupMenu.add(saveToFileMenuItem);
final JMenuItem saveUncompressedToFileMenuItem = new JMenuItem(mainPanel.translate("contextmenu.saveUncompressedToFile"));
saveUncompressedToFileMenuItem.addActionListener(this::saveUncompressedToFileButtonActionPerformed);
contextPopupMenu.add(saveUncompressedToFileMenuItem);
final JMenuItem closeSelectionMenuItem = new JMenuItem(mainPanel.translate("contextmenu.closeSwf"));
closeSelectionMenuItem.addActionListener(this::closeSwfButtonActionPerformed);
contextPopupMenu.add(closeSelectionMenuItem);
final JMenuItem parseActionsMenuItem = new JMenuItem(mainPanel.translate("contextmenu.parseActions"));
parseActionsMenuItem.addActionListener(this::parseActionsButtonActionPerformed);
contextPopupMenu.add(parseActionsMenuItem);
final JMenuItem parseAbcMenuItem = new JMenuItem(mainPanel.translate("contextmenu.parseABC"));
parseAbcMenuItem.addActionListener(this::parseAbcButtonActionPerformed);
contextPopupMenu.add(parseAbcMenuItem);
final JMenuItem parseInstructionsMenuItem = new JMenuItem(mainPanel.translate("contextmenu.parseInstructions"));
parseInstructionsMenuItem.addActionListener(this::parseInstructionsButtonActionPerformed);
contextPopupMenu.add(parseInstructionsMenuItem);
final JMenuItem gotoTagMenuItem = new JMenuItem(mainPanel.translate("contextmenu.showInResources"));
gotoTagMenuItem.addActionListener(this::gotoTagButtonActionPerformed);
contextPopupMenu.add(gotoTagMenuItem);
final JMenuItem gotoActionListMenuItem = new JMenuItem(mainPanel.translate("contextmenu.showInResources"));
gotoActionListMenuItem.addActionListener(this::gotoActionListButtonActionPerformed);
contextPopupMenu.add(gotoActionListMenuItem);
final JMenuItem gotoMethodMenuItem = new JMenuItem(mainPanel.translate("contextmenu.showInResources"));
gotoMethodMenuItem.addActionListener(this::gotoMethodButtonActionPerformed);
contextPopupMenu.add(gotoMethodMenuItem);
addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (SwingUtilities.isRightMouseButton(e)) {
int row = getClosestRowForLocation(e.getX(), e.getY());
int[] selectionRows = getSelectionRows();
if (!Helper.contains(selectionRows, row)) {
setSelectionRow(row);
}
TreePath[] paths = getSelectionPaths();
if (paths == null || paths.length == 0) {
return;
}
closeSelectionMenuItem.setVisible(false);
expandRecursiveMenuItem.setVisible(false);
saveToFileMenuItem.setVisible(false);
saveUncompressedToFileMenuItem.setVisible(false);
parseActionsMenuItem.setVisible(false);
parseAbcMenuItem.setVisible(false);
parseInstructionsMenuItem.setVisible(false);
gotoTagMenuItem.setVisible(false);
gotoActionListMenuItem.setVisible(false);
gotoMethodMenuItem.setVisible(false);
if (paths.length == 1) {
DumpInfo treeNode = (DumpInfo) paths[0].getLastPathComponent();
DumpInfoSpecialType specialType = getSpecialType(treeNode);
if (treeNode instanceof DumpInfoSwfNode) {
closeSelectionMenuItem.setVisible(true);
}
if (treeNode.getEndByte() - treeNode.startByte > 3) {
saveToFileMenuItem.setVisible(true);
if (specialType == DumpInfoSpecialType.ZLIB_DATA) {
saveUncompressedToFileMenuItem.setVisible(true);
}
}
boolean noChild = treeNode.getChildCount() == 0;
if (noChild) {
switch (specialType) {
case ACTION_BYTES:
parseActionsMenuItem.setVisible(true);
break;
case ABC_BYTES:
parseAbcMenuItem.setVisible(true);
break;
case ABC_CODE:
parseInstructionsMenuItem.setVisible(true);
break;
}
}
switch (specialType) {
case TAG:
gotoTagMenuItem.setVisible(true);
break;
case ACTION_BYTES:
gotoActionListMenuItem.setVisible(true);
break;
case ABC_CODE:
case ABC_METHOD_BODY:
gotoMethodMenuItem.setVisible(true);
break;
}
TreeModel model = getModel();
expandRecursiveMenuItem.setVisible(model.getChildCount(treeNode) > 0);
}
contextPopupMenu.show(e.getComponent(), e.getX(), e.getY());
}
}
});
}
private DumpInfoSpecialType getSpecialType(DumpInfo dumpInfo) {
DumpInfoSpecialType specialType = dumpInfo instanceof DumpInfoSpecial
? ((DumpInfoSpecial) dumpInfo).specialType
: DumpInfoSpecialType.NONE;
return specialType;
}
private void expandRecursiveButtonActionPerformed(ActionEvent evt) {
TreePath path = getSelectionPath();
if (path == null) {
return;
}
View.expandTreeNodes(this, path, true);
}
private void saveToFileButtonActionPerformed(ActionEvent evt) {
saveToFileButtonActionPerformed(false);
}
private void saveUncompressedToFileButtonActionPerformed(ActionEvent evt) {
saveToFileButtonActionPerformed(true);
}
private void saveToFileButtonActionPerformed(boolean decompress) {
TreePath[] paths = getSelectionPaths();
DumpInfo dumpInfo = (DumpInfo) paths[0].getLastPathComponent();
JFileChooser fc = new JFileChooser();
String selDir = Configuration.lastOpenDir.get();
fc.setCurrentDirectory(new File(selDir));
JFrame f = new JFrame();
View.setWindowIcon(f);
if (fc.showSaveDialog(f) == JFileChooser.APPROVE_OPTION) {
File sf = Helper.fixDialogFile(fc.getSelectedFile());
try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(sf))) {
byte[] data = DumpInfoSwfNode.getSwfNode(dumpInfo).getSwf().originalUncompressedData;
if (decompress) {
fos.write(SWFInputStream.uncompressByteArray(data, (int) dumpInfo.startByte, (int) (dumpInfo.getEndByte() - dumpInfo.startByte + 1)));
} else {
fos.write(data, (int) dumpInfo.startByte, (int) (dumpInfo.getEndByte() - dumpInfo.startByte + 1));
}
} catch (IOException ex) {
logger.log(Level.SEVERE, null, ex);
}
}
}
private void parseActionsButtonActionPerformed(ActionEvent evt) {
TreePath[] paths = getSelectionPaths();
DumpInfo dumpInfo = (DumpInfo) paths[0].getLastPathComponent();
SWF swf = DumpInfoSwfNode.getSwfNode(dumpInfo).getSwf();
byte[] data = swf.originalUncompressedData;
int prevLength = (int) dumpInfo.startByte;
try {
SWFInputStream rri = new SWFInputStream(swf, data);
if (prevLength != 0) {
rri.seek(prevLength);
}
List<Action> actions = ActionListReader.getOriginalActions(rri, prevLength, (int) dumpInfo.getEndByte());
for (Action action : actions) {
DumpInfo di = new DumpInfo(action.toString(), "Action", null, action.getAddress(), action.getTotalActionLength());
di.parent = dumpInfo;
rri.dumpInfo = di;
rri.seek(action.getAddress());
rri.readAction();
dumpInfo.getChildInfos().add(di);
}
repaint();
} catch (IOException | InterruptedException ex) {
logger.log(Level.SEVERE, null, ex);
}
}
private void parseAbcButtonActionPerformed(ActionEvent evt) {
TreePath[] paths = getSelectionPaths();
DumpInfo dumpInfo = (DumpInfo) paths[0].getLastPathComponent();
SWF swf = DumpInfoSwfNode.getSwfNode(dumpInfo).getSwf();
byte[] data = swf.originalUncompressedData;
int prevLength = (int) dumpInfo.startByte;
try {
ABCInputStream ais = new ABCInputStream(new MemoryInputStream(data, 0, prevLength + (int) dumpInfo.lengthBytes));
ais.seek(prevLength);
ais.dumpInfo = dumpInfo;
new ABC(ais, swf, null);
} catch (IOException ex) {
logger.log(Level.SEVERE, null, ex);
}
repaint();
}
private void parseInstructionsButtonActionPerformed(ActionEvent evt) {
TreePath[] paths = getSelectionPaths();
DumpInfo dumpInfo = (DumpInfo) paths[0].getLastPathComponent();
SWF swf = DumpInfoSwfNode.getSwfNode(dumpInfo).getSwf();
byte[] data = swf.originalUncompressedData;
int prevLength = (int) dumpInfo.startByte;
try {
ABCInputStream ais = new ABCInputStream(new MemoryInputStream(data, 0, prevLength + (int) dumpInfo.lengthBytes));
ais.seek(prevLength);
ais.dumpInfo = dumpInfo;
new AVM2Code(ais, null /*FIXME! Pass correct body!*/);
} catch (IOException ex) {
logger.log(Level.SEVERE, null, ex);
}
repaint();
}
private void gotoTagButtonActionPerformed(ActionEvent evt) {
TreePath[] paths = getSelectionPaths();
DumpInfoSpecial dumpInfo = (DumpInfoSpecial) paths[0].getLastPathComponent();
SWF swf = DumpInfoSwfNode.getSwfNode(dumpInfo).getSwf();
long address = (long) (Long) dumpInfo.specialValue;
Tag foundTag = null;
for (Tag tag : swf.getTags()) {
if (tag.getOriginalRange().getPos() == address) {
foundTag = tag;
break;
}
}
if (foundTag != null) {
mainPanel.getMainFrame().getMenu().showResourcesView();
mainPanel.setTagTreeSelectedNode(foundTag);
}
}
private void gotoActionListButtonActionPerformed(ActionEvent evt) {
TreePath[] paths = getSelectionPaths();
DumpInfoSpecial dumpInfo = (DumpInfoSpecial) paths[0].getLastPathComponent();
SWF swf = DumpInfoSwfNode.getSwfNode(dumpInfo).getSwf();
long address = (long) (Long) dumpInfo.specialValue;
mainPanel.getMainFrame().getMenu().showResourcesView();
//mainPanel.setTagTreeSelectedNode(asm);
}
private void gotoMethodButtonActionPerformed(ActionEvent evt) {
TreePath[] paths = getSelectionPaths();
DumpInfoSpecial dumpInfo = (DumpInfoSpecial) paths[0].getLastPathComponent();
if (dumpInfo.specialType == DumpInfoSpecialType.ABC_CODE) {
dumpInfo = (DumpInfoSpecial) dumpInfo.parent; // method_body
}
SWF swf = DumpInfoSwfNode.getSwfNode(dumpInfo).getSwf();
int method_info = (int) dumpInfo.specialValue;
// todo
}
private void closeSwfButtonActionPerformed(ActionEvent evt) {
Main.closeFile(mainPanel.getCurrentSwfList());
}
@Override
public DumpTreeModel getModel() {
return (DumpTreeModel) super.getModel();
}
public void expandRoot() {
DumpTreeModel dtm = getModel();
DumpInfo root = dtm.getRoot();
expandPath(new TreePath(new Object[]{root}));
}
public void expandFirstLevelNodes() {
DumpTreeModel dtm = getModel();
DumpInfo root = dtm.getRoot();
int childCount = dtm.getChildCount(root);
expandPath(new TreePath(new Object[]{root}));
for (int i = 0; i < childCount; i++) {
expandPath(new TreePath(new Object[]{root, dtm.getChild(root, i)}));
}
}
}
File diff suppressed because it is too large Load Diff
@@ -1,97 +1,97 @@
/*
* Copyright (C) 2010-2016 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.gui.pipes;
import com.sun.jna.Platform;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.ptr.IntByReference;
import java.io.IOException;
import java.io.InputStream;
/**
*
* @author JPEXS
*/
public class PipeInputStream extends InputStream {
protected HANDLE pipe;
private boolean closed = false;
public PipeInputStream(String pipeName, boolean newpipe) throws IOException {
if (!Platform.isWindows()) {
throw new IOException("Cannot create Pipe on nonWindows OS");
}
String fullPipePath = "\\\\.\\pipe\\" + pipeName;
if (newpipe) {
pipe = Kernel32.INSTANCE.CreateNamedPipe(fullPipePath, Kernel32.PIPE_ACCESS_INBOUND, Kernel32.PIPE_TYPE_BYTE, 1, 4096, 4096, 0, null);
if (pipe == null || !Kernel32.INSTANCE.ConnectNamedPipe(pipe, null)) {
throw new IOException("Cannot connect to the pipe");
}
} else {
pipe = Kernel32.INSTANCE.CreateFile(fullPipePath, Kernel32.GENERIC_READ, Kernel32.FILE_SHARE_READ, null, Kernel32.OPEN_EXISTING, Kernel32.FILE_ATTRIBUTE_NORMAL, null);
}
if (pipe == null) {
throw new IOException("Cannot connect to the pipe");
}
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
try {
close();
} catch (IOException ex) {
//ignore
}
}
});
}
@Override
public synchronized void close() throws IOException {
if (!closed) {
Kernel32.INSTANCE.CloseHandle(pipe);
closed = true;
}
}
@Override
public synchronized int read() throws IOException {
byte d[] = new byte[1];
if (readPipe(d) == 0) {
return -1;
}
return d[0];
}
private int readPipe(byte res[]) throws IOException {
final IntByReference ibr = new IntByReference();
int read = 0;
while (read < res.length) {
byte[] data = new byte[res.length - read];
boolean result = Kernel32.INSTANCE.ReadFile(pipe, data, data.length, ibr, null);
if (!result) {
throw new IOException("Cannot read pipe. Error " + Kernel32.INSTANCE.GetLastError());
}
int readNow = ibr.getValue();
System.arraycopy(data, 0, res, read, readNow);
read += readNow;
}
return read;
}
}
/*
* Copyright (C) 2010-2016 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.gui.pipes;
import com.sun.jna.Platform;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.ptr.IntByReference;
import java.io.IOException;
import java.io.InputStream;
/**
*
* @author JPEXS
*/
public class PipeInputStream extends InputStream {
protected HANDLE pipe;
private boolean closed = false;
public PipeInputStream(String pipeName, boolean newpipe) throws IOException {
if (!Platform.isWindows()) {
throw new IOException("Cannot create Pipe on nonWindows OS");
}
String fullPipePath = "\\\\.\\pipe\\" + pipeName;
if (newpipe) {
pipe = Kernel32.INSTANCE.CreateNamedPipe(fullPipePath, Kernel32.PIPE_ACCESS_INBOUND, Kernel32.PIPE_TYPE_BYTE, 1, 4096, 4096, 0, null);
if (pipe == null || !Kernel32.INSTANCE.ConnectNamedPipe(pipe, null)) {
throw new IOException("Cannot connect to the pipe");
}
} else {
pipe = Kernel32.INSTANCE.CreateFile(fullPipePath, Kernel32.GENERIC_READ, Kernel32.FILE_SHARE_READ, null, Kernel32.OPEN_EXISTING, Kernel32.FILE_ATTRIBUTE_NORMAL, null);
}
if (pipe == null) {
throw new IOException("Cannot connect to the pipe");
}
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
try {
close();
} catch (IOException ex) {
//ignore
}
}
});
}
@Override
public synchronized void close() throws IOException {
if (!closed) {
Kernel32.INSTANCE.CloseHandle(pipe);
closed = true;
}
}
@Override
public synchronized int read() throws IOException {
byte[] d = new byte[1];
if (readPipe(d) == 0) {
return -1;
}
return d[0];
}
private int readPipe(byte res[]) throws IOException {
final IntByReference ibr = new IntByReference();
int read = 0;
while (read < res.length) {
byte[] data = new byte[res.length - read];
boolean result = Kernel32.INSTANCE.ReadFile(pipe, data, data.length, ibr, null);
if (!result) {
throw new IOException("Cannot read pipe. Error " + Kernel32.INSTANCE.GetLastError());
}
int readNow = ibr.getValue();
System.arraycopy(data, 0, res, read, readNow);
read += readNow;
}
return read;
}
}
@@ -1,85 +1,85 @@
/*
* Copyright (C) 2010-2016 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.gui.pipes;
import com.sun.jna.Platform;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.ptr.IntByReference;
import java.io.IOException;
import java.io.OutputStream;
/**
*
* @author JPEXS
*/
public class PipeOutputStream extends OutputStream {
protected HANDLE pipe;
private boolean closed = false;
public PipeOutputStream(String pipeName, boolean newPipe) throws IOException {
if (!Platform.isWindows()) {
throw new IOException("Cannot create Pipe on nonWindows OS");
}
String fullPipePath = "\\\\.\\pipe\\" + pipeName;
if (newPipe) {
pipe = Kernel32.INSTANCE.CreateNamedPipe(fullPipePath, Kernel32.PIPE_ACCESS_OUTBOUND, Kernel32.PIPE_TYPE_BYTE, 1, 4096, 4096, 0, null);
if (pipe == null || !Kernel32.INSTANCE.ConnectNamedPipe(pipe, null)) {
throw new IOException("Cannot connect to the pipe. Error " + Kernel32.INSTANCE.GetLastError());
}
} else {
pipe = Kernel32.INSTANCE.CreateFile(fullPipePath, Kernel32.GENERIC_WRITE, Kernel32.FILE_SHARE_WRITE, null, Kernel32.OPEN_EXISTING, Kernel32.FILE_ATTRIBUTE_NORMAL, null);
if (pipe == null) {
throw new IOException("Cannot connect to the pipe. Error " + Kernel32.INSTANCE.GetLastError());
}
}
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
try {
close();
} catch (IOException ex) {
//ignore
}
}
});
}
@Override
public synchronized void close() throws IOException {
if (!closed) {
Kernel32.INSTANCE.CloseHandle(pipe);
closed = true;
}
}
@Override
public synchronized void write(int b) throws IOException {
byte data[] = new byte[]{(byte) b};
IntByReference ibr = new IntByReference();
boolean result = Kernel32.INSTANCE.WriteFile(pipe, data, data.length, ibr, null);
if (!result) {
throw new IOException("Cannot write to the pipe. Error " + Kernel32.INSTANCE.GetLastError());
}
if (ibr.getValue() != data.length) {
throw new IOException("Cannot write to the pipe. Error " + Kernel32.INSTANCE.GetLastError());
}
}
}
/*
* Copyright (C) 2010-2016 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.gui.pipes;
import com.sun.jna.Platform;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.ptr.IntByReference;
import java.io.IOException;
import java.io.OutputStream;
/**
*
* @author JPEXS
*/
public class PipeOutputStream extends OutputStream {
protected HANDLE pipe;
private boolean closed = false;
public PipeOutputStream(String pipeName, boolean newPipe) throws IOException {
if (!Platform.isWindows()) {
throw new IOException("Cannot create Pipe on nonWindows OS");
}
String fullPipePath = "\\\\.\\pipe\\" + pipeName;
if (newPipe) {
pipe = Kernel32.INSTANCE.CreateNamedPipe(fullPipePath, Kernel32.PIPE_ACCESS_OUTBOUND, Kernel32.PIPE_TYPE_BYTE, 1, 4096, 4096, 0, null);
if (pipe == null || !Kernel32.INSTANCE.ConnectNamedPipe(pipe, null)) {
throw new IOException("Cannot connect to the pipe. Error " + Kernel32.INSTANCE.GetLastError());
}
} else {
pipe = Kernel32.INSTANCE.CreateFile(fullPipePath, Kernel32.GENERIC_WRITE, Kernel32.FILE_SHARE_WRITE, null, Kernel32.OPEN_EXISTING, Kernel32.FILE_ATTRIBUTE_NORMAL, null);
if (pipe == null) {
throw new IOException("Cannot connect to the pipe. Error " + Kernel32.INSTANCE.GetLastError());
}
}
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
try {
close();
} catch (IOException ex) {
//ignore
}
}
});
}
@Override
public synchronized void close() throws IOException {
if (!closed) {
Kernel32.INSTANCE.CloseHandle(pipe);
closed = true;
}
}
@Override
public synchronized void write(int b) throws IOException {
byte[] data = new byte[]{(byte) b};
IntByReference ibr = new IntByReference();
boolean result = Kernel32.INSTANCE.WriteFile(pipe, data, data.length, ibr, null);
if (!result) {
throw new IOException("Cannot write to the pipe. Error " + Kernel32.INSTANCE.GetLastError());
}
if (ibr.getValue() != data.length) {
throw new IOException("Cannot write to the pipe. Error " + Kernel32.INSTANCE.GetLastError());
}
}
}
File diff suppressed because it is too large Load Diff