mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-06-17 15:51:54 +00:00
jump to resources view from hex view
This commit is contained in:
@@ -123,6 +123,8 @@ import com.jpexs.decompiler.flash.amf.amf3.Amf3Value;
|
||||
import com.jpexs.decompiler.flash.amf.amf3.NoSerializerExistsException;
|
||||
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.tags.CSMTextSettingsTag;
|
||||
import com.jpexs.decompiler.flash.tags.DebugIDTag;
|
||||
import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag;
|
||||
@@ -392,17 +394,25 @@ public class SWFInputStream implements AutoCloseable {
|
||||
is.seek(pos - startingPos);
|
||||
}
|
||||
|
||||
private void newDumpLevel(String name, String type) {
|
||||
private DumpInfo newDumpLevel(String name, String type) {
|
||||
return newDumpLevel(name, type, DumpInfoSpecialType.NONE, null);
|
||||
}
|
||||
|
||||
private DumpInfo newDumpLevel(String name, String type, DumpInfoSpecialType specialType, Object specialValue) {
|
||||
if (dumpInfo != null) {
|
||||
long startByte = is.getPos();
|
||||
if (bitPos > 0) {
|
||||
startByte--;
|
||||
}
|
||||
DumpInfo di = new DumpInfo(name, type, null, startByte, bitPos, 0, 0);
|
||||
DumpInfo di = specialType == DumpInfoSpecialType.NONE
|
||||
? new DumpInfo(name, type, null, startByte, bitPos, 0, 0)
|
||||
: new DumpInfoSpecial(name, type, null, startByte, bitPos, 0, 0, specialType, specialValue);
|
||||
di.parent = dumpInfo;
|
||||
dumpInfo.getChildInfos().add(di);
|
||||
dumpInfo = di;
|
||||
}
|
||||
|
||||
return dumpInfo;
|
||||
}
|
||||
|
||||
private void endDumpLevel() {
|
||||
@@ -784,11 +794,26 @@ public class SWFInputStream implements AutoCloseable {
|
||||
* @throws IOException
|
||||
*/
|
||||
public ByteArrayRange readByteRangeEx(long count, String name) throws IOException {
|
||||
return readByteRangeEx(count, name, DumpInfoSpecialType.NONE, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads byte range from the stream
|
||||
*
|
||||
* @param count Number of bytes to read
|
||||
* @param name
|
||||
* @param specialType
|
||||
* @param specialValue
|
||||
* @return ByteArrayRange object
|
||||
* @throws IOException
|
||||
*/
|
||||
public ByteArrayRange readByteRangeEx(long count, String name, DumpInfoSpecialType specialType, Object specialValue) throws IOException {
|
||||
if (count <= 0) {
|
||||
return ByteArrayRange.EMPTY;
|
||||
}
|
||||
|
||||
newDumpLevel(name, "bytes");
|
||||
newDumpLevel(name, "bytes", specialType, specialValue);
|
||||
|
||||
int startPos = (int) getPos();
|
||||
skipBytesEx(count);
|
||||
endDumpLevel();
|
||||
@@ -1179,7 +1204,7 @@ public class SWFInputStream implements AutoCloseable {
|
||||
boolean isAS3 = false;
|
||||
while (available() > 0) {
|
||||
long pos = getPos();
|
||||
newDumpLevel(null, "TAG");
|
||||
newDumpLevel(null, "TAG", DumpInfoSpecialType.TAG, getPos());
|
||||
try {
|
||||
tag = readTag(timelined, level, pos, false, parallel1, skipUnusualTags, lazy);
|
||||
} catch (EOFException | EndOfStreamException ex) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -2095,9 +2095,9 @@ public class AVM2Code implements Cloneable {
|
||||
}
|
||||
// Declarations
|
||||
|
||||
DeclarationAVM2Item d[] = new DeclarationAVM2Item[regCount];
|
||||
DeclarationAVM2Item[] d = new DeclarationAVM2Item[regCount];
|
||||
|
||||
int param_types[] = abc.method_info.get(body.method_info).param_types;
|
||||
int[] param_types = abc.method_info.get(body.method_info).param_types;
|
||||
int r = 1;
|
||||
for (int i = 0; i < param_types.length; i++) {
|
||||
GraphTargetItem type;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,21 +1,21 @@
|
||||
package com.jpexs.decompiler.flash.abc.types;
|
||||
|
||||
public class Float4 {
|
||||
|
||||
public float values[] = new float[4];
|
||||
|
||||
public Float4(float value1, float value2, float value3, float value4) {
|
||||
this.values = new float[]{value1, value2, value3, value4};
|
||||
}
|
||||
|
||||
public Float4(float[] values) {
|
||||
if (values == null || values.length < 4) {
|
||||
throw new IllegalArgumentException("Invalid values size");
|
||||
}
|
||||
this.values[0] = values[0];
|
||||
this.values[1] = values[1];
|
||||
this.values[2] = values[2];
|
||||
this.values[3] = values[3];
|
||||
}
|
||||
|
||||
}
|
||||
package com.jpexs.decompiler.flash.abc.types;
|
||||
|
||||
public class Float4 {
|
||||
|
||||
public float[] values = new float[4];
|
||||
|
||||
public Float4(float value1, float value2, float value3, float value4) {
|
||||
this.values = new float[]{value1, value2, value3, value4};
|
||||
}
|
||||
|
||||
public Float4(float[] values) {
|
||||
if (values == null || values.length < 4) {
|
||||
throw new IllegalArgumentException("Invalid values size");
|
||||
}
|
||||
this.values[0] = values[0];
|
||||
this.values[1] = values[1];
|
||||
this.values[2] = values[2];
|
||||
this.values[3] = values[3];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -245,7 +245,7 @@ public class Amf3InputStream extends InputStream {
|
||||
}
|
||||
newDumpLevel(name, "UTF8-char");
|
||||
|
||||
byte buf[] = new byte[(int) byteLength]; //how about long strings(?), will the int length be enough?
|
||||
byte[] buf = new byte[(int) byteLength]; //how about long strings(?), will the int length be enough?
|
||||
int cnt = is.read(buf);
|
||||
if (cnt < buf.length) {
|
||||
throw new EndOfStreamException();
|
||||
@@ -487,7 +487,7 @@ public class Amf3InputStream extends InputStream {
|
||||
newDumpLevel("serializedData", "U8[]");
|
||||
MonitoredInputStream mis = new MonitoredInputStream(is);
|
||||
Map<String, Object> serMembers = serializers.get(className).readObject(className, mis);
|
||||
byte serData[] = mis.getReadData();
|
||||
byte[] serData = mis.getReadData();
|
||||
endDumpLevel();
|
||||
Traits unserTraits = new Traits(className, false, new ArrayList<>());
|
||||
retObjectType = new ObjectType(unserTraits, serData, serMembers);
|
||||
@@ -624,7 +624,7 @@ public class Amf3InputStream extends InputStream {
|
||||
renameU29("U29B-value", NO_REFERENCE_BIT_TEXT, "byte array length");
|
||||
int byteArrayLength = (int) (byteArrayU29 >> 1);
|
||||
newDumpLevel("bytes", "U8[]");
|
||||
byte byteArrayBuf[] = new byte[byteArrayLength];
|
||||
byte[] byteArrayBuf = new byte[byteArrayLength];
|
||||
if (is.read(byteArrayBuf) != byteArrayLength) {
|
||||
throw new EndOfStreamException();
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ public class Amf3OutputStream extends OutputStream {
|
||||
if (!val.isEmpty()) {
|
||||
stringTable.add(val);
|
||||
}
|
||||
byte data[] = val.getBytes("UTF-8");
|
||||
byte[] data = val.getBytes("UTF-8");
|
||||
writeU29((data.length << 1) | NO_REFERENCE_FLAG);
|
||||
writeBytes(data);
|
||||
} else {
|
||||
@@ -132,7 +132,7 @@ public class Amf3OutputStream extends OutputStream {
|
||||
int objectIndex = objectTable.indexOf(val);
|
||||
if (objectIndex == -1) {
|
||||
objectTable.add(val);
|
||||
byte data[] = val.getData();
|
||||
byte[] data = val.getData();
|
||||
writeU29((data.length << 1) | NO_REFERENCE_FLAG);
|
||||
writeBytes(data);
|
||||
} else {
|
||||
@@ -144,7 +144,7 @@ public class Amf3OutputStream extends OutputStream {
|
||||
int objectIndex = objectTable.indexOf(val);
|
||||
if (objectIndex == -1) {
|
||||
objectTable.add(val);
|
||||
byte data[] = val.getData().getBytes("UTF-8");
|
||||
byte[] data = val.getData().getBytes("UTF-8");
|
||||
writeU29((data.length << 1) | NO_REFERENCE_FLAG);
|
||||
writeBytes(data);
|
||||
} else {
|
||||
@@ -156,7 +156,7 @@ public class Amf3OutputStream extends OutputStream {
|
||||
int objectIndex = objectTable.indexOf(val);
|
||||
if (objectIndex == -1) {
|
||||
objectTable.add(val);
|
||||
byte data[] = val.getData().getBytes("UTF-8");
|
||||
byte[] data = val.getData().getBytes("UTF-8");
|
||||
writeU29((data.length << 1) | NO_REFERENCE_FLAG);
|
||||
writeBytes(data);
|
||||
} else {
|
||||
|
||||
@@ -1,356 +1,356 @@
|
||||
package com.jpexs.decompiler.flash.docs;
|
||||
|
||||
import com.jpexs.decompiler.flash.ApplicationInfo;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2InstructionFlag;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition;
|
||||
import com.jpexs.helpers.Cache;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import com.jpexs.helpers.utf8.Utf8Helper;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
import java.util.TreeSet;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Generator for AVM2 instruction set documentation.
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class As3PCodeDocs {
|
||||
|
||||
private static ResourceBundle prop;
|
||||
|
||||
private static Map<AVM2InstructionFlag, String> flagDescriptions = new HashMap<>();
|
||||
|
||||
private static Cache<String, String> docsCache = Cache.getInstance(false, true, "as3DocsCache");
|
||||
|
||||
private static Map<String, InstructionDefinition> nameToDef = new HashMap<>();
|
||||
|
||||
static final String NEWLINE = "\r\n";
|
||||
|
||||
static {
|
||||
prop = ResourceBundle.getBundle("com.jpexs.decompiler.flash.locales.docs.pcode.AS3");
|
||||
for (InstructionDefinition def : AVM2Code.allInstructionSet) {
|
||||
if (def == null) {
|
||||
continue;
|
||||
}
|
||||
nameToDef.put(def.instructionName, def);
|
||||
}
|
||||
|
||||
for (AVM2InstructionFlag flg : AVM2InstructionFlag.values()) {
|
||||
String flagIdent = makeIdent(flg.toString());
|
||||
String flagDescription = getProperty("instructionFlag." + flagIdent);
|
||||
flagDescriptions.put(flg, flagDescription);
|
||||
}
|
||||
}
|
||||
|
||||
private static String makeIdent(String name) {
|
||||
StringBuilder identName = new StringBuilder();
|
||||
boolean cap = false;
|
||||
for (int i = 0; i < name.length(); i++) {
|
||||
char c = name.charAt(i);
|
||||
if (c == '_') {
|
||||
cap = true;
|
||||
continue;
|
||||
}
|
||||
if (cap) {
|
||||
identName.append(c);
|
||||
cap = false;
|
||||
} else {
|
||||
identName.append(Character.toLowerCase(c));
|
||||
}
|
||||
}
|
||||
return identName.toString();
|
||||
}
|
||||
|
||||
public static String getDocsForIns(String insName, boolean showDataSize, boolean ui, boolean withStyle) {
|
||||
if (!nameToDef.containsKey(insName)) {
|
||||
return null;
|
||||
}
|
||||
return getDocsForIns(nameToDef.get(insName), showDataSize, ui, withStyle);
|
||||
}
|
||||
|
||||
private static String getProperty(String name) {
|
||||
if (prop.containsKey(name)) {
|
||||
return Helper.escapeHTML(prop.getString(name));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String htmlFooter() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append("</html>");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static String meta(String name, String content) {
|
||||
return "\t\t<meta name=\"" + name + "\" content=\"" + content + "\">" + NEWLINE;
|
||||
}
|
||||
|
||||
private static String metaProp(String name, String content) {
|
||||
return "\t\t<meta property=\"" + name + "\" content=\"" + content + "\">" + NEWLINE;
|
||||
}
|
||||
|
||||
private static String meta(String name, Date content) {
|
||||
return "\t\t<meta name=\"" + name + "\" content=\"" + getISO8601StringForDate(content) + "\">" + NEWLINE;
|
||||
}
|
||||
|
||||
private static String htmlHeader(String js, String style) {
|
||||
Date dateGenerated = new Date();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("<!DOCTYPE html>").append(NEWLINE).
|
||||
append("<html>").append(NEWLINE).
|
||||
append("\t<head>").append(NEWLINE);
|
||||
if (style != null && !style.isEmpty()) {
|
||||
sb.append("\t\t<style>").append(style).append("</style>").append(NEWLINE);
|
||||
}
|
||||
if (js != null && !js.isEmpty()) {
|
||||
sb.append("\t\t<script>").append(js).append("</script>").append(NEWLINE);
|
||||
}
|
||||
sb.append("\t\t<meta charset=\"UTF-8\">").append(NEWLINE).
|
||||
append(meta("generator", ApplicationInfo.applicationVerName)).
|
||||
append(meta("description", getProperty("ui.list.pageDescription"))).
|
||||
append(metaProp("og:title", getProperty("ui.list.pageTitle"))).
|
||||
append(metaProp("og:type", "article")).
|
||||
append(metaProp("og:description", getProperty("ui.list.pageDescription"))).
|
||||
append(meta("date", dateGenerated)).
|
||||
append("\t\t<title>").append(getProperty("ui.list.documentTitle")).append("</title>").append(NEWLINE).
|
||||
append("\t</head>").append(NEWLINE);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static String getDocsForIns(InstructionDefinition def, boolean showDataSize, boolean ui, boolean standalone) {
|
||||
final String cacheKey = def.instructionName + "|" + (showDataSize ? 1 : 0) + "|" + (ui ? 1 : 0) + "|" + (standalone ? 1 : 0);
|
||||
String v = docsCache.get(cacheKey);
|
||||
if (v != null) {
|
||||
return v;
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (standalone) {
|
||||
sb.append(htmlHeader("", getStyle()));
|
||||
}
|
||||
String insName = def.instructionName;
|
||||
|
||||
String insShortDescription = getProperty("instruction." + insName + ".shortDescription");
|
||||
String insDescription = getProperty("instruction." + insName + ".description");
|
||||
String stackBefore = def.hasFlag(AVM2InstructionFlag.UNKNOWN_STACK) ? "" : getProperty("instruction." + insName + ".stackBefore");
|
||||
String stackAfter = def.hasFlag(AVM2InstructionFlag.UNKNOWN_STACK) ? "" : getProperty("instruction." + insName + ".stackAfter");
|
||||
if (stackBefore.trim().isEmpty()) {
|
||||
stackBefore = getProperty("ui.stack.before.empty");
|
||||
} else {
|
||||
stackBefore = getProperty("ui.stack.before") + stackBefore;
|
||||
}
|
||||
if (stackAfter.trim().isEmpty()) {
|
||||
stackAfter = getProperty("ui.stack.before.empty");
|
||||
} else {
|
||||
stackAfter = getProperty("ui.stack.before") + stackAfter;
|
||||
}
|
||||
stackBefore = "<span class=\"stack-before\">" + stackBefore + "</span>";
|
||||
stackAfter = "<span class=\"stack-after\">" + stackAfter + "</span>";
|
||||
|
||||
String stack = def.hasFlag(AVM2InstructionFlag.UNKNOWN_STACK) ? getProperty("ui.unknown") : stackBefore + "<span class=\"stack-to\">" + getProperty("ui.stack.to") + "</span>" + stackAfter;
|
||||
String operandsDoc = def.hasFlag(AVM2InstructionFlag.UNKNOWN_OPERANDS) ? getProperty("ui.unknown") : getProperty("instruction." + insName + ".operands");
|
||||
|
||||
sb.append("<");
|
||||
sb.append(standalone ? "body" : "div");
|
||||
sb.append(" class=\"instruction");
|
||||
|
||||
for (AVM2InstructionFlag fl : def.flags) {
|
||||
sb.append(" instruction-flag-").append(makeIdent(fl.toString()));
|
||||
}
|
||||
sb.append("\">");
|
||||
|
||||
sb.append("<div class=\"instruction-signature\"><span class=\"instruction-code\">").append(String.format("0x%02X", def.instructionCode)).append("</span> <strong class=\"instruction-name\">").append(insName).append("</strong>");
|
||||
|
||||
if (def.hasFlag(AVM2InstructionFlag.UNKNOWN_OPERANDS)) {
|
||||
sb.append(" ").append(getProperty("ui.unknown")).append(NEWLINE);
|
||||
} else {
|
||||
String[] operandsDocs = operandsDoc.split(", ?");
|
||||
boolean first = true;
|
||||
if (def.operands.length > 0) {
|
||||
sb.append(" ");
|
||||
}
|
||||
for (int i = 0; i < def.operands.length; i++) {
|
||||
int op = def.operands[i];
|
||||
String opDoc = operandsDocs[i];
|
||||
String operandTypeRaw = AVM2Code.operandTypeToString(op, false);
|
||||
String operandTypeCombined = AVM2Code.operandTypeToString(op, true);
|
||||
if (operandTypeCombined.contains(", ")) {
|
||||
String operandTypesCombined[] = operandTypeCombined.split(", ?");
|
||||
String operandTypesRaw[] = operandTypeRaw.split(", ?");
|
||||
|
||||
for (int j = 0; j < operandTypesCombined.length; j++) {
|
||||
if (!first) {
|
||||
sb.append(", ");
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
opDoc = operandsDocs[i + j];
|
||||
operandTypeCombined = operandTypesCombined[j];
|
||||
operandTypeRaw = operandTypesRaw[j];
|
||||
operandTypeRaw = getProperty("operandType." + operandTypeRaw + (ui ? ".uiName" : ".name"));
|
||||
if (opDoc.equals("...")) {
|
||||
sb.append("...");
|
||||
} else {
|
||||
sb.append(opDoc);
|
||||
sb.append(":").append(showDataSize ? operandTypeCombined : operandTypeRaw);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!first) {
|
||||
sb.append(", ");
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
operandTypeRaw = getProperty("operandType." + operandTypeRaw + (ui ? ".uiName" : ".name"));
|
||||
|
||||
if (opDoc.equals(operandTypeRaw)) {
|
||||
sb.append(showDataSize ? operandTypeCombined : operandTypeRaw);
|
||||
} else {
|
||||
sb.append(opDoc).append(":").append(showDataSize ? operandTypeCombined : operandTypeRaw);
|
||||
}
|
||||
}
|
||||
}
|
||||
sb.append("</div>").append(NEWLINE);
|
||||
}
|
||||
|
||||
sb.append("<div class=\"short-description\">").append(insShortDescription).append("</div>").append(NEWLINE);
|
||||
|
||||
if (!insDescription.trim().isEmpty()) {
|
||||
sb.append("<div class=\"description\">").append("<strong class=\"description-title\">").append(getProperty("ui.description")).append("</strong>").append(insDescription).append("</div>").append(NEWLINE);
|
||||
}
|
||||
sb.append("<div class=\"stack\"><strong class=\"stack-title\">").append(getProperty("ui.stack")).append("</strong><span class=\"stack-values " + (def.hasFlag(AVM2InstructionFlag.UNKNOWN_STACK) ? " unknown" : "") + "\">").append(stack).append("</span>").append("</div>").append(NEWLINE);
|
||||
boolean flagsPrinted = false;
|
||||
|
||||
AVM2InstructionFlag flags[] = def.flags.clone();
|
||||
Arrays.sort(flags, Enum::compareTo);
|
||||
|
||||
for (AVM2InstructionFlag fl : flags) {
|
||||
if (!flagsPrinted) {
|
||||
flagsPrinted = true;
|
||||
sb.append("<strong class=\"flags-title\">").append(getProperty("ui.flags")).append("</strong>").append("<br />").append(NEWLINE).append("<ul class=\"flags\">").append(NEWLINE);
|
||||
}
|
||||
sb.append("\t<li class=\"flag flag-").append(makeIdent(fl.toString())).append("\">").append(flagDescriptions.get(fl));
|
||||
if (fl == AVM2InstructionFlag.DEPRECATED) {
|
||||
String depDetail = getProperty("instruction." + insName + ".deprecated");
|
||||
if (depDetail != null) {
|
||||
sb.append(": <span class=\"flag-deprecated-detail\">").append(depDetail).append("</span>");
|
||||
}
|
||||
}
|
||||
sb.append("</li>").append(NEWLINE);
|
||||
}
|
||||
if (flagsPrinted) {
|
||||
sb.append("</ul>").append(NEWLINE);
|
||||
}
|
||||
sb.append("</");
|
||||
sb.append(standalone ? "body" : "div"); //.instruction
|
||||
sb.append(">").append(NEWLINE);
|
||||
if (standalone) {
|
||||
sb.append(htmlFooter());
|
||||
}
|
||||
String r = sb.toString();
|
||||
docsCache.put(cacheKey, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
public static String getStyle() {
|
||||
String cached = docsCache.get("__style");
|
||||
if (cached != null) {
|
||||
return cached;
|
||||
}
|
||||
String style = "";
|
||||
InputStream is = As3PCodeDocs.class.getResourceAsStream("/com/jpexs/decompiler/flash/docs/docs.css");
|
||||
if (is == null) {
|
||||
Logger.getLogger(As3PCodeDocs.class.getName()).log(Level.SEVERE, "docs.css needed for documentation not found");
|
||||
} else {
|
||||
style = new String(Helper.readStream(is), Utf8Helper.charset);
|
||||
}
|
||||
|
||||
docsCache.put("__style", style);
|
||||
return style;
|
||||
}
|
||||
|
||||
public static String getJs() {
|
||||
String cached = docsCache.get("__js");
|
||||
if (cached != null) {
|
||||
return cached;
|
||||
}
|
||||
String js = "";
|
||||
InputStream is = As3PCodeDocs.class.getResourceAsStream("/com/jpexs/decompiler/flash/docs/docs.js");
|
||||
if (is == null) {
|
||||
Logger.getLogger(As3PCodeDocs.class.getName()).log(Level.SEVERE, "docs.js needed for documentation not found");
|
||||
} else {
|
||||
js = new String(Helper.readStream(is), Utf8Helper.charset);
|
||||
}
|
||||
|
||||
docsCache.put("__js", js);
|
||||
return js;
|
||||
}
|
||||
|
||||
private static String getISO8601StringForDate(Date date) {
|
||||
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
return dateFormat.format(date);
|
||||
}
|
||||
|
||||
public static String getAllInstructionDocs() {
|
||||
|
||||
String jsData = "";
|
||||
jsData += "var txt_filter_hide = \"" + getProperty("ui.filter.hide") + "\";" + NEWLINE;
|
||||
jsData += "var txt_filter_byname = \"" + getProperty("ui.filter.byname") + "\";" + NEWLINE;
|
||||
jsData += "var txt_filter_order = \"" + getProperty("ui.filter.order") + "\";" + NEWLINE;
|
||||
jsData += "var txt_filter_order_code = \"" + getProperty("ui.filter.order.code") + "\";" + NEWLINE;
|
||||
jsData += "var txt_filter_order_name = \"" + getProperty("ui.filter.order.name") + "\";" + NEWLINE;
|
||||
|
||||
jsData += "var order_set = \"name\";";
|
||||
jsData += "var flags_set = {};" + NEWLINE;
|
||||
jsData += "var flags = {};" + NEWLINE;
|
||||
for (AVM2InstructionFlag f : AVM2InstructionFlag.values()) {
|
||||
jsData += "flags[\"" + makeIdent(f.toString()) + "\"] = \"" + Helper.escapeJavaString(flagDescriptions.get(f)) + "\";" + NEWLINE;
|
||||
jsData += "flags_set[\"" + makeIdent(f.toString()) + "\"] = false;" + NEWLINE;
|
||||
}
|
||||
|
||||
AVM2InstructionFlag[] hideFlags = new AVM2InstructionFlag[]{AVM2InstructionFlag.NO_FLASH_PLAYER};
|
||||
for (AVM2InstructionFlag f : hideFlags) {
|
||||
jsData += "flags_set[\"" + makeIdent(f.toString()) + "\"] = true;" + NEWLINE;
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(htmlHeader(jsData + getJs(), getStyle()));
|
||||
sb.append("\t\t<h1>").append(getProperty("ui.list.heading")).append("</h1>").append(NEWLINE);
|
||||
sb.append("<span id=\"js-switcher\" class=\"js\"></span>");
|
||||
sb.append("\t\t<ul class=\"instruction-list\">").append(NEWLINE);
|
||||
Set<String> s = new TreeSet<>(nameToDef.keySet());
|
||||
for (String name : s) {
|
||||
InstructionDefinition def = nameToDef.get(name);
|
||||
if (def == null) {
|
||||
continue;
|
||||
}
|
||||
sb.append("\t\t\t<li class=\"instruction-item\">").append(NEWLINE);
|
||||
sb.append("\t\t\t\t").append(getDocsForIns(def, true, false, false).trim().replace(NEWLINE, NEWLINE + "\t\t\t\t")).append(NEWLINE);
|
||||
sb.append("\t\t\t</li>").append(NEWLINE);
|
||||
}
|
||||
sb.append("\t\t</ul>").append(NEWLINE);
|
||||
sb.append("\t</body>").append(NEWLINE);
|
||||
sb.append(htmlFooter());
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws UnsupportedEncodingException {
|
||||
System.out.println(getAllInstructionDocs());
|
||||
}
|
||||
}
|
||||
package com.jpexs.decompiler.flash.docs;
|
||||
|
||||
import com.jpexs.decompiler.flash.ApplicationInfo;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2InstructionFlag;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition;
|
||||
import com.jpexs.helpers.Cache;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import com.jpexs.helpers.utf8.Utf8Helper;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
import java.util.TreeSet;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Generator for AVM2 instruction set documentation.
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class As3PCodeDocs {
|
||||
|
||||
private static ResourceBundle prop;
|
||||
|
||||
private static Map<AVM2InstructionFlag, String> flagDescriptions = new HashMap<>();
|
||||
|
||||
private static Cache<String, String> docsCache = Cache.getInstance(false, true, "as3DocsCache");
|
||||
|
||||
private static Map<String, InstructionDefinition> nameToDef = new HashMap<>();
|
||||
|
||||
static final String NEWLINE = "\r\n";
|
||||
|
||||
static {
|
||||
prop = ResourceBundle.getBundle("com.jpexs.decompiler.flash.locales.docs.pcode.AS3");
|
||||
for (InstructionDefinition def : AVM2Code.allInstructionSet) {
|
||||
if (def == null) {
|
||||
continue;
|
||||
}
|
||||
nameToDef.put(def.instructionName, def);
|
||||
}
|
||||
|
||||
for (AVM2InstructionFlag flg : AVM2InstructionFlag.values()) {
|
||||
String flagIdent = makeIdent(flg.toString());
|
||||
String flagDescription = getProperty("instructionFlag." + flagIdent);
|
||||
flagDescriptions.put(flg, flagDescription);
|
||||
}
|
||||
}
|
||||
|
||||
private static String makeIdent(String name) {
|
||||
StringBuilder identName = new StringBuilder();
|
||||
boolean cap = false;
|
||||
for (int i = 0; i < name.length(); i++) {
|
||||
char c = name.charAt(i);
|
||||
if (c == '_') {
|
||||
cap = true;
|
||||
continue;
|
||||
}
|
||||
if (cap) {
|
||||
identName.append(c);
|
||||
cap = false;
|
||||
} else {
|
||||
identName.append(Character.toLowerCase(c));
|
||||
}
|
||||
}
|
||||
return identName.toString();
|
||||
}
|
||||
|
||||
public static String getDocsForIns(String insName, boolean showDataSize, boolean ui, boolean withStyle) {
|
||||
if (!nameToDef.containsKey(insName)) {
|
||||
return null;
|
||||
}
|
||||
return getDocsForIns(nameToDef.get(insName), showDataSize, ui, withStyle);
|
||||
}
|
||||
|
||||
private static String getProperty(String name) {
|
||||
if (prop.containsKey(name)) {
|
||||
return Helper.escapeHTML(prop.getString(name));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String htmlFooter() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append("</html>");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static String meta(String name, String content) {
|
||||
return "\t\t<meta name=\"" + name + "\" content=\"" + content + "\">" + NEWLINE;
|
||||
}
|
||||
|
||||
private static String metaProp(String name, String content) {
|
||||
return "\t\t<meta property=\"" + name + "\" content=\"" + content + "\">" + NEWLINE;
|
||||
}
|
||||
|
||||
private static String meta(String name, Date content) {
|
||||
return "\t\t<meta name=\"" + name + "\" content=\"" + getISO8601StringForDate(content) + "\">" + NEWLINE;
|
||||
}
|
||||
|
||||
private static String htmlHeader(String js, String style) {
|
||||
Date dateGenerated = new Date();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("<!DOCTYPE html>").append(NEWLINE).
|
||||
append("<html>").append(NEWLINE).
|
||||
append("\t<head>").append(NEWLINE);
|
||||
if (style != null && !style.isEmpty()) {
|
||||
sb.append("\t\t<style>").append(style).append("</style>").append(NEWLINE);
|
||||
}
|
||||
if (js != null && !js.isEmpty()) {
|
||||
sb.append("\t\t<script>").append(js).append("</script>").append(NEWLINE);
|
||||
}
|
||||
sb.append("\t\t<meta charset=\"UTF-8\">").append(NEWLINE).
|
||||
append(meta("generator", ApplicationInfo.applicationVerName)).
|
||||
append(meta("description", getProperty("ui.list.pageDescription"))).
|
||||
append(metaProp("og:title", getProperty("ui.list.pageTitle"))).
|
||||
append(metaProp("og:type", "article")).
|
||||
append(metaProp("og:description", getProperty("ui.list.pageDescription"))).
|
||||
append(meta("date", dateGenerated)).
|
||||
append("\t\t<title>").append(getProperty("ui.list.documentTitle")).append("</title>").append(NEWLINE).
|
||||
append("\t</head>").append(NEWLINE);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static String getDocsForIns(InstructionDefinition def, boolean showDataSize, boolean ui, boolean standalone) {
|
||||
final String cacheKey = def.instructionName + "|" + (showDataSize ? 1 : 0) + "|" + (ui ? 1 : 0) + "|" + (standalone ? 1 : 0);
|
||||
String v = docsCache.get(cacheKey);
|
||||
if (v != null) {
|
||||
return v;
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (standalone) {
|
||||
sb.append(htmlHeader("", getStyle()));
|
||||
}
|
||||
String insName = def.instructionName;
|
||||
|
||||
String insShortDescription = getProperty("instruction." + insName + ".shortDescription");
|
||||
String insDescription = getProperty("instruction." + insName + ".description");
|
||||
String stackBefore = def.hasFlag(AVM2InstructionFlag.UNKNOWN_STACK) ? "" : getProperty("instruction." + insName + ".stackBefore");
|
||||
String stackAfter = def.hasFlag(AVM2InstructionFlag.UNKNOWN_STACK) ? "" : getProperty("instruction." + insName + ".stackAfter");
|
||||
if (stackBefore.trim().isEmpty()) {
|
||||
stackBefore = getProperty("ui.stack.before.empty");
|
||||
} else {
|
||||
stackBefore = getProperty("ui.stack.before") + stackBefore;
|
||||
}
|
||||
if (stackAfter.trim().isEmpty()) {
|
||||
stackAfter = getProperty("ui.stack.before.empty");
|
||||
} else {
|
||||
stackAfter = getProperty("ui.stack.before") + stackAfter;
|
||||
}
|
||||
stackBefore = "<span class=\"stack-before\">" + stackBefore + "</span>";
|
||||
stackAfter = "<span class=\"stack-after\">" + stackAfter + "</span>";
|
||||
|
||||
String stack = def.hasFlag(AVM2InstructionFlag.UNKNOWN_STACK) ? getProperty("ui.unknown") : stackBefore + "<span class=\"stack-to\">" + getProperty("ui.stack.to") + "</span>" + stackAfter;
|
||||
String operandsDoc = def.hasFlag(AVM2InstructionFlag.UNKNOWN_OPERANDS) ? getProperty("ui.unknown") : getProperty("instruction." + insName + ".operands");
|
||||
|
||||
sb.append("<");
|
||||
sb.append(standalone ? "body" : "div");
|
||||
sb.append(" class=\"instruction");
|
||||
|
||||
for (AVM2InstructionFlag fl : def.flags) {
|
||||
sb.append(" instruction-flag-").append(makeIdent(fl.toString()));
|
||||
}
|
||||
sb.append("\">");
|
||||
|
||||
sb.append("<div class=\"instruction-signature\"><span class=\"instruction-code\">").append(String.format("0x%02X", def.instructionCode)).append("</span> <strong class=\"instruction-name\">").append(insName).append("</strong>");
|
||||
|
||||
if (def.hasFlag(AVM2InstructionFlag.UNKNOWN_OPERANDS)) {
|
||||
sb.append(" ").append(getProperty("ui.unknown")).append(NEWLINE);
|
||||
} else {
|
||||
String[] operandsDocs = operandsDoc.split(", ?");
|
||||
boolean first = true;
|
||||
if (def.operands.length > 0) {
|
||||
sb.append(" ");
|
||||
}
|
||||
for (int i = 0; i < def.operands.length; i++) {
|
||||
int op = def.operands[i];
|
||||
String opDoc = operandsDocs[i];
|
||||
String operandTypeRaw = AVM2Code.operandTypeToString(op, false);
|
||||
String operandTypeCombined = AVM2Code.operandTypeToString(op, true);
|
||||
if (operandTypeCombined.contains(", ")) {
|
||||
String[] operandTypesCombined = operandTypeCombined.split(", ?");
|
||||
String[] operandTypesRaw = operandTypeRaw.split(", ?");
|
||||
|
||||
for (int j = 0; j < operandTypesCombined.length; j++) {
|
||||
if (!first) {
|
||||
sb.append(", ");
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
opDoc = operandsDocs[i + j];
|
||||
operandTypeCombined = operandTypesCombined[j];
|
||||
operandTypeRaw = operandTypesRaw[j];
|
||||
operandTypeRaw = getProperty("operandType." + operandTypeRaw + (ui ? ".uiName" : ".name"));
|
||||
if (opDoc.equals("...")) {
|
||||
sb.append("...");
|
||||
} else {
|
||||
sb.append(opDoc);
|
||||
sb.append(":").append(showDataSize ? operandTypeCombined : operandTypeRaw);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!first) {
|
||||
sb.append(", ");
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
operandTypeRaw = getProperty("operandType." + operandTypeRaw + (ui ? ".uiName" : ".name"));
|
||||
|
||||
if (opDoc.equals(operandTypeRaw)) {
|
||||
sb.append(showDataSize ? operandTypeCombined : operandTypeRaw);
|
||||
} else {
|
||||
sb.append(opDoc).append(":").append(showDataSize ? operandTypeCombined : operandTypeRaw);
|
||||
}
|
||||
}
|
||||
}
|
||||
sb.append("</div>").append(NEWLINE);
|
||||
}
|
||||
|
||||
sb.append("<div class=\"short-description\">").append(insShortDescription).append("</div>").append(NEWLINE);
|
||||
|
||||
if (!insDescription.trim().isEmpty()) {
|
||||
sb.append("<div class=\"description\">").append("<strong class=\"description-title\">").append(getProperty("ui.description")).append("</strong>").append(insDescription).append("</div>").append(NEWLINE);
|
||||
}
|
||||
sb.append("<div class=\"stack\"><strong class=\"stack-title\">").append(getProperty("ui.stack")).append("</strong><span class=\"stack-values " + (def.hasFlag(AVM2InstructionFlag.UNKNOWN_STACK) ? " unknown" : "") + "\">").append(stack).append("</span>").append("</div>").append(NEWLINE);
|
||||
boolean flagsPrinted = false;
|
||||
|
||||
AVM2InstructionFlag[] flags = def.flags.clone();
|
||||
Arrays.sort(flags, Enum::compareTo);
|
||||
|
||||
for (AVM2InstructionFlag fl : flags) {
|
||||
if (!flagsPrinted) {
|
||||
flagsPrinted = true;
|
||||
sb.append("<strong class=\"flags-title\">").append(getProperty("ui.flags")).append("</strong>").append("<br />").append(NEWLINE).append("<ul class=\"flags\">").append(NEWLINE);
|
||||
}
|
||||
sb.append("\t<li class=\"flag flag-").append(makeIdent(fl.toString())).append("\">").append(flagDescriptions.get(fl));
|
||||
if (fl == AVM2InstructionFlag.DEPRECATED) {
|
||||
String depDetail = getProperty("instruction." + insName + ".deprecated");
|
||||
if (depDetail != null) {
|
||||
sb.append(": <span class=\"flag-deprecated-detail\">").append(depDetail).append("</span>");
|
||||
}
|
||||
}
|
||||
sb.append("</li>").append(NEWLINE);
|
||||
}
|
||||
if (flagsPrinted) {
|
||||
sb.append("</ul>").append(NEWLINE);
|
||||
}
|
||||
sb.append("</");
|
||||
sb.append(standalone ? "body" : "div"); //.instruction
|
||||
sb.append(">").append(NEWLINE);
|
||||
if (standalone) {
|
||||
sb.append(htmlFooter());
|
||||
}
|
||||
String r = sb.toString();
|
||||
docsCache.put(cacheKey, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
public static String getStyle() {
|
||||
String cached = docsCache.get("__style");
|
||||
if (cached != null) {
|
||||
return cached;
|
||||
}
|
||||
String style = "";
|
||||
InputStream is = As3PCodeDocs.class.getResourceAsStream("/com/jpexs/decompiler/flash/docs/docs.css");
|
||||
if (is == null) {
|
||||
Logger.getLogger(As3PCodeDocs.class.getName()).log(Level.SEVERE, "docs.css needed for documentation not found");
|
||||
} else {
|
||||
style = new String(Helper.readStream(is), Utf8Helper.charset);
|
||||
}
|
||||
|
||||
docsCache.put("__style", style);
|
||||
return style;
|
||||
}
|
||||
|
||||
public static String getJs() {
|
||||
String cached = docsCache.get("__js");
|
||||
if (cached != null) {
|
||||
return cached;
|
||||
}
|
||||
String js = "";
|
||||
InputStream is = As3PCodeDocs.class.getResourceAsStream("/com/jpexs/decompiler/flash/docs/docs.js");
|
||||
if (is == null) {
|
||||
Logger.getLogger(As3PCodeDocs.class.getName()).log(Level.SEVERE, "docs.js needed for documentation not found");
|
||||
} else {
|
||||
js = new String(Helper.readStream(is), Utf8Helper.charset);
|
||||
}
|
||||
|
||||
docsCache.put("__js", js);
|
||||
return js;
|
||||
}
|
||||
|
||||
private static String getISO8601StringForDate(Date date) {
|
||||
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
return dateFormat.format(date);
|
||||
}
|
||||
|
||||
public static String getAllInstructionDocs() {
|
||||
|
||||
String jsData = "";
|
||||
jsData += "var txt_filter_hide = \"" + getProperty("ui.filter.hide") + "\";" + NEWLINE;
|
||||
jsData += "var txt_filter_byname = \"" + getProperty("ui.filter.byname") + "\";" + NEWLINE;
|
||||
jsData += "var txt_filter_order = \"" + getProperty("ui.filter.order") + "\";" + NEWLINE;
|
||||
jsData += "var txt_filter_order_code = \"" + getProperty("ui.filter.order.code") + "\";" + NEWLINE;
|
||||
jsData += "var txt_filter_order_name = \"" + getProperty("ui.filter.order.name") + "\";" + NEWLINE;
|
||||
|
||||
jsData += "var order_set = \"name\";";
|
||||
jsData += "var flags_set = {};" + NEWLINE;
|
||||
jsData += "var flags = {};" + NEWLINE;
|
||||
for (AVM2InstructionFlag f : AVM2InstructionFlag.values()) {
|
||||
jsData += "flags[\"" + makeIdent(f.toString()) + "\"] = \"" + Helper.escapeJavaString(flagDescriptions.get(f)) + "\";" + NEWLINE;
|
||||
jsData += "flags_set[\"" + makeIdent(f.toString()) + "\"] = false;" + NEWLINE;
|
||||
}
|
||||
|
||||
AVM2InstructionFlag[] hideFlags = new AVM2InstructionFlag[]{AVM2InstructionFlag.NO_FLASH_PLAYER};
|
||||
for (AVM2InstructionFlag f : hideFlags) {
|
||||
jsData += "flags_set[\"" + makeIdent(f.toString()) + "\"] = true;" + NEWLINE;
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(htmlHeader(jsData + getJs(), getStyle()));
|
||||
sb.append("\t\t<h1>").append(getProperty("ui.list.heading")).append("</h1>").append(NEWLINE);
|
||||
sb.append("<span id=\"js-switcher\" class=\"js\"></span>");
|
||||
sb.append("\t\t<ul class=\"instruction-list\">").append(NEWLINE);
|
||||
Set<String> s = new TreeSet<>(nameToDef.keySet());
|
||||
for (String name : s) {
|
||||
InstructionDefinition def = nameToDef.get(name);
|
||||
if (def == null) {
|
||||
continue;
|
||||
}
|
||||
sb.append("\t\t\t<li class=\"instruction-item\">").append(NEWLINE);
|
||||
sb.append("\t\t\t\t").append(getDocsForIns(def, true, false, false).trim().replace(NEWLINE, NEWLINE + "\t\t\t\t")).append(NEWLINE);
|
||||
sb.append("\t\t\t</li>").append(NEWLINE);
|
||||
}
|
||||
sb.append("\t\t</ul>").append(NEWLINE);
|
||||
sb.append("\t</body>").append(NEWLINE);
|
||||
sb.append(htmlFooter());
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws UnsupportedEncodingException {
|
||||
System.out.println(getAllInstructionDocs());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,7 +94,6 @@ public class DumpInfo implements TreeItem {
|
||||
}
|
||||
|
||||
Collections.sort(childInfos, new Comparator<DumpInfo>() {
|
||||
|
||||
@Override
|
||||
public int compare(DumpInfo o1, DumpInfo o2) {
|
||||
int res = Long.compare(o1.startByte, o2.startByte);
|
||||
@@ -149,7 +148,7 @@ public class DumpInfo implements TreeItem {
|
||||
|
||||
@Override
|
||||
public SWF getSwf() {
|
||||
Tag tag = getTag();
|
||||
Tag tag = tagToResolve != null ? tagToResolve : resolvedTag;
|
||||
if (tag != null) {
|
||||
return tag.getSwf();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.dumpview;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class DumpInfoSpecial extends DumpInfo {
|
||||
|
||||
public DumpInfoSpecialType specialType;
|
||||
|
||||
public Object specialValue;
|
||||
|
||||
public DumpInfoSpecial(String name, String type, Object value, long startByte, int startBit, long lengthBytes, int lengthBits, DumpInfoSpecialType specialType) {
|
||||
super(name, type, value, startByte, startBit, lengthBytes, lengthBits);
|
||||
this.specialType = specialType;
|
||||
}
|
||||
|
||||
public DumpInfoSpecial(String name, String type, Object value, long startByte, int startBit, long lengthBytes, int lengthBits, DumpInfoSpecialType specialType, Object specialValue) {
|
||||
super(name, type, value, startByte, startBit, lengthBytes, lengthBits);
|
||||
this.specialType = specialType;
|
||||
this.specialValue = specialValue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.dumpview;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public enum DumpInfoSpecialType {
|
||||
NONE, ZLIB_DATA,
|
||||
TAG,
|
||||
ACTION_BYTES,
|
||||
ABC_BYTES, ABC_METHOD_BODY, ABC_CODE
|
||||
}
|
||||
@@ -270,7 +270,7 @@ public class Amf3Exporter {
|
||||
ret.append(indent(level)).append("}");
|
||||
} else if (object instanceof ByteArrayType) {
|
||||
ByteArrayType ba = (ByteArrayType) object;
|
||||
byte data[] = ba.getData();
|
||||
byte[] data = ba.getData();
|
||||
return "{" + newLine
|
||||
+ indent(level + 1) + "\"type\": \"ByteArray\"," + newLine
|
||||
+ addId
|
||||
|
||||
@@ -1,207 +1,207 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.helpers;
|
||||
|
||||
import com.jpexs.decompiler.flash.tags.enums.ImageFormat;
|
||||
import com.jpexs.decompiler.flash.types.RGBA;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.DataBufferInt;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Iterator;
|
||||
import java.util.Locale;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.imageio.ImageReader;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import org.monte.media.jpeg.CMYKJPEGImageReader;
|
||||
import org.monte.media.jpeg.CMYKJPEGImageReaderSpi;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ImageHelper {
|
||||
|
||||
static {
|
||||
ImageIO.setUseCache(false);
|
||||
}
|
||||
|
||||
public static BufferedImage read(byte[] data) throws IOException {
|
||||
return read(new ByteArrayInputStream(data));
|
||||
}
|
||||
|
||||
public static BufferedImage read(InputStream input) throws IOException {
|
||||
BufferedImage in;
|
||||
byte data[] = Helper.readStream(input);
|
||||
try (ImageInputStream iis = ImageIO.createImageInputStream(new ByteArrayInputStream(data))) {
|
||||
CMYKJPEGImageReader r = new CMYKJPEGImageReader(new CMYKJPEGImageReaderSpi());
|
||||
r.setInput(iis);
|
||||
in = r.read(0);
|
||||
} catch (IOException | ArrayIndexOutOfBoundsException ex) {
|
||||
try {
|
||||
in = ImageIO.read(ImageIO.createImageInputStream(new ByteArrayInputStream(data)));
|
||||
} catch (IOException ex1) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
int type = in.getType();
|
||||
if (type != BufferedImage.TYPE_INT_ARGB_PRE && type != BufferedImage.TYPE_INT_RGB) {
|
||||
// convert to ARGB
|
||||
int width = in.getWidth();
|
||||
int height = in.getHeight();
|
||||
int[] imgData = in.getRGB(0, 0, width, height, null, 0, width);
|
||||
BufferedImage newImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB_PRE);
|
||||
newImage.getRaster().setDataElements(0, 0, width, height, imgData);
|
||||
return newImage;
|
||||
}
|
||||
|
||||
return in;
|
||||
}
|
||||
|
||||
public static void write(BufferedImage image, ImageFormat format, File output) throws IOException {
|
||||
String formatName = getImageFormatString(format).toUpperCase(Locale.ENGLISH);
|
||||
if (format == ImageFormat.JPEG) {
|
||||
image = fixImageIOJpegBug(image);
|
||||
}
|
||||
|
||||
ImageIO.write(image, formatName, output);
|
||||
}
|
||||
|
||||
public static void write(BufferedImage image, ImageFormat format, OutputStream output) throws IOException {
|
||||
String formatName = getImageFormatString(format).toUpperCase(Locale.ENGLISH);
|
||||
if (format == ImageFormat.JPEG) {
|
||||
image = fixImageIOJpegBug(image);
|
||||
}
|
||||
|
||||
ImageIO.write(image, formatName, output);
|
||||
}
|
||||
|
||||
public static void write(BufferedImage image, ImageFormat format, ByteArrayOutputStream output) {
|
||||
String formatName = getImageFormatString(format).toUpperCase(Locale.ENGLISH);
|
||||
if (format == ImageFormat.JPEG) {
|
||||
image = fixImageIOJpegBug(image);
|
||||
} else {
|
||||
if (image.getType() == BufferedImage.TYPE_INT_ARGB_PRE) {
|
||||
BufferedImage image2 = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
|
||||
int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
|
||||
divideAlpha(pixels);
|
||||
|
||||
int[] pixels2 = ((DataBufferInt) image2.getRaster().getDataBuffer()).getData();
|
||||
for (int i = 0; i < pixels.length; i++) {
|
||||
pixels2[i] = pixels[i];
|
||||
}
|
||||
|
||||
image = image2;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
ImageIO.write(image, formatName, output);
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(ImageHelper.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static int max255(float val) {
|
||||
if (val > 255) {
|
||||
return 255;
|
||||
}
|
||||
return (int) val;
|
||||
}
|
||||
|
||||
private static void divideAlpha(int[] pixels) {
|
||||
for (int i = 0; i < pixels.length; i++) {
|
||||
pixels[i] = divideAlpha(pixels[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private static int divideAlpha(int value) {
|
||||
int a = (value >> 24) & 0xFF;
|
||||
int r = (value >> 16) & 0xFF;
|
||||
int g = (value >> 8) & 0xFF;
|
||||
int b = value & 0xFF;
|
||||
float multiplier = a == 0 ? 0 : 255.0f / a;
|
||||
r = max255(r * multiplier);
|
||||
g = max255(g * multiplier);
|
||||
b = max255(b * multiplier);
|
||||
return RGBA.toInt(r, g, b, a);
|
||||
}
|
||||
|
||||
private static BufferedImage fixImageIOJpegBug(BufferedImage image) {
|
||||
int type = image.getType();
|
||||
if (type != BufferedImage.TYPE_INT_RGB) {
|
||||
// convert to RGB without alpha channel
|
||||
int width = image.getWidth();
|
||||
int height = image.getHeight();
|
||||
BufferedImage newImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
|
||||
int[] pixels2 = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
|
||||
int[] pixels = image.getRGB(0, 0, width, height, null, 0, width);
|
||||
for (int i = 0; i < pixels.length; i++) {
|
||||
pixels2[i] = pixels[i] & 0xffffff;
|
||||
}
|
||||
|
||||
return newImage;
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
public static String getImageFormatString(ImageFormat format) {
|
||||
switch (format) {
|
||||
case UNKNOWN:
|
||||
return "unk";
|
||||
case JPEG:
|
||||
return "jpg";
|
||||
case GIF:
|
||||
return "gif";
|
||||
case PNG:
|
||||
return "png";
|
||||
case BMP:
|
||||
return "bmp";
|
||||
}
|
||||
|
||||
throw new Error("Unsuported image format: " + format);
|
||||
}
|
||||
|
||||
public static Dimension getDimesion(InputStream input) throws IOException {
|
||||
try (ImageInputStream in = ImageIO.createImageInputStream(input)) {
|
||||
final Iterator<ImageReader> readers = ImageIO.getImageReaders(in);
|
||||
if (readers.hasNext()) {
|
||||
ImageReader reader = readers.next();
|
||||
try {
|
||||
reader.setInput(in);
|
||||
return new Dimension(reader.getWidth(0), reader.getHeight(0));
|
||||
} finally {
|
||||
reader.dispose();
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
|
||||
BufferedImage image = read(input);
|
||||
return new Dimension(image.getWidth(), image.getHeight());
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.helpers;
|
||||
|
||||
import com.jpexs.decompiler.flash.tags.enums.ImageFormat;
|
||||
import com.jpexs.decompiler.flash.types.RGBA;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.DataBufferInt;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Iterator;
|
||||
import java.util.Locale;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.imageio.ImageReader;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import org.monte.media.jpeg.CMYKJPEGImageReader;
|
||||
import org.monte.media.jpeg.CMYKJPEGImageReaderSpi;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ImageHelper {
|
||||
|
||||
static {
|
||||
ImageIO.setUseCache(false);
|
||||
}
|
||||
|
||||
public static BufferedImage read(byte[] data) throws IOException {
|
||||
return read(new ByteArrayInputStream(data));
|
||||
}
|
||||
|
||||
public static BufferedImage read(InputStream input) throws IOException {
|
||||
BufferedImage in;
|
||||
byte[] data = Helper.readStream(input);
|
||||
try (ImageInputStream iis = ImageIO.createImageInputStream(new ByteArrayInputStream(data))) {
|
||||
CMYKJPEGImageReader r = new CMYKJPEGImageReader(new CMYKJPEGImageReaderSpi());
|
||||
r.setInput(iis);
|
||||
in = r.read(0);
|
||||
} catch (IOException | ArrayIndexOutOfBoundsException ex) {
|
||||
try {
|
||||
in = ImageIO.read(ImageIO.createImageInputStream(new ByteArrayInputStream(data)));
|
||||
} catch (IOException ex1) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
int type = in.getType();
|
||||
if (type != BufferedImage.TYPE_INT_ARGB_PRE && type != BufferedImage.TYPE_INT_RGB) {
|
||||
// convert to ARGB
|
||||
int width = in.getWidth();
|
||||
int height = in.getHeight();
|
||||
int[] imgData = in.getRGB(0, 0, width, height, null, 0, width);
|
||||
BufferedImage newImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB_PRE);
|
||||
newImage.getRaster().setDataElements(0, 0, width, height, imgData);
|
||||
return newImage;
|
||||
}
|
||||
|
||||
return in;
|
||||
}
|
||||
|
||||
public static void write(BufferedImage image, ImageFormat format, File output) throws IOException {
|
||||
String formatName = getImageFormatString(format).toUpperCase(Locale.ENGLISH);
|
||||
if (format == ImageFormat.JPEG) {
|
||||
image = fixImageIOJpegBug(image);
|
||||
}
|
||||
|
||||
ImageIO.write(image, formatName, output);
|
||||
}
|
||||
|
||||
public static void write(BufferedImage image, ImageFormat format, OutputStream output) throws IOException {
|
||||
String formatName = getImageFormatString(format).toUpperCase(Locale.ENGLISH);
|
||||
if (format == ImageFormat.JPEG) {
|
||||
image = fixImageIOJpegBug(image);
|
||||
}
|
||||
|
||||
ImageIO.write(image, formatName, output);
|
||||
}
|
||||
|
||||
public static void write(BufferedImage image, ImageFormat format, ByteArrayOutputStream output) {
|
||||
String formatName = getImageFormatString(format).toUpperCase(Locale.ENGLISH);
|
||||
if (format == ImageFormat.JPEG) {
|
||||
image = fixImageIOJpegBug(image);
|
||||
} else {
|
||||
if (image.getType() == BufferedImage.TYPE_INT_ARGB_PRE) {
|
||||
BufferedImage image2 = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
|
||||
int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
|
||||
divideAlpha(pixels);
|
||||
|
||||
int[] pixels2 = ((DataBufferInt) image2.getRaster().getDataBuffer()).getData();
|
||||
for (int i = 0; i < pixels.length; i++) {
|
||||
pixels2[i] = pixels[i];
|
||||
}
|
||||
|
||||
image = image2;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
ImageIO.write(image, formatName, output);
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(ImageHelper.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static int max255(float val) {
|
||||
if (val > 255) {
|
||||
return 255;
|
||||
}
|
||||
return (int) val;
|
||||
}
|
||||
|
||||
private static void divideAlpha(int[] pixels) {
|
||||
for (int i = 0; i < pixels.length; i++) {
|
||||
pixels[i] = divideAlpha(pixels[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private static int divideAlpha(int value) {
|
||||
int a = (value >> 24) & 0xFF;
|
||||
int r = (value >> 16) & 0xFF;
|
||||
int g = (value >> 8) & 0xFF;
|
||||
int b = value & 0xFF;
|
||||
float multiplier = a == 0 ? 0 : 255.0f / a;
|
||||
r = max255(r * multiplier);
|
||||
g = max255(g * multiplier);
|
||||
b = max255(b * multiplier);
|
||||
return RGBA.toInt(r, g, b, a);
|
||||
}
|
||||
|
||||
private static BufferedImage fixImageIOJpegBug(BufferedImage image) {
|
||||
int type = image.getType();
|
||||
if (type != BufferedImage.TYPE_INT_RGB) {
|
||||
// convert to RGB without alpha channel
|
||||
int width = image.getWidth();
|
||||
int height = image.getHeight();
|
||||
BufferedImage newImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
|
||||
int[] pixels2 = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
|
||||
int[] pixels = image.getRGB(0, 0, width, height, null, 0, width);
|
||||
for (int i = 0; i < pixels.length; i++) {
|
||||
pixels2[i] = pixels[i] & 0xffffff;
|
||||
}
|
||||
|
||||
return newImage;
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
public static String getImageFormatString(ImageFormat format) {
|
||||
switch (format) {
|
||||
case UNKNOWN:
|
||||
return "unk";
|
||||
case JPEG:
|
||||
return "jpg";
|
||||
case GIF:
|
||||
return "gif";
|
||||
case PNG:
|
||||
return "png";
|
||||
case BMP:
|
||||
return "bmp";
|
||||
}
|
||||
|
||||
throw new Error("Unsuported image format: " + format);
|
||||
}
|
||||
|
||||
public static Dimension getDimesion(InputStream input) throws IOException {
|
||||
try (ImageInputStream in = ImageIO.createImageInputStream(input)) {
|
||||
final Iterator<ImageReader> readers = ImageIO.getImageReaders(in);
|
||||
if (readers.hasNext()) {
|
||||
ImageReader reader = readers.next();
|
||||
try {
|
||||
reader.setInput(in);
|
||||
return new Dimension(reader.getWidth(0), reader.getHeight(0));
|
||||
} finally {
|
||||
reader.dispose();
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
|
||||
BufferedImage image = read(input);
|
||||
return new Dimension(image.getWidth(), image.getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,238 +1,239 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.tags;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.helpers.ImageHelper;
|
||||
import com.jpexs.decompiler.flash.tags.base.AloneTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ImageTag;
|
||||
import com.jpexs.decompiler.flash.tags.enums.ImageFormat;
|
||||
import com.jpexs.decompiler.flash.types.BasicType;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFType;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import com.jpexs.helpers.SerializableImage;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.DataBufferInt;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
@SWFVersion(from = 3) //Note: GIF and PNG since version
|
||||
public class DefineBitsJPEG3Tag extends ImageTag implements AloneTag {
|
||||
|
||||
public static final int ID = 35;
|
||||
|
||||
public static final String NAME = "DefineBitsJPEG3";
|
||||
|
||||
@SWFType(BasicType.UI8)
|
||||
public ByteArrayRange imageData;
|
||||
|
||||
@SWFType(BasicType.UI8)
|
||||
public ByteArrayRange bitmapAlphaData;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param swf
|
||||
*/
|
||||
public DefineBitsJPEG3Tag(SWF swf) {
|
||||
super(swf, ID, NAME, null);
|
||||
characterID = swf.getNextCharacterId();
|
||||
imageData = new ByteArrayRange(createEmptyImage());
|
||||
bitmapAlphaData = ByteArrayRange.EMPTY;
|
||||
forceWriteAsLong = true;
|
||||
}
|
||||
|
||||
public DefineBitsJPEG3Tag(SWF swf, ByteArrayRange data, int characterID, byte[] imageData) throws IOException {
|
||||
super(swf, ID, NAME, data);
|
||||
this.characterID = characterID;
|
||||
this.imageData = new ByteArrayRange(imageData);
|
||||
bitmapAlphaData = ByteArrayRange.EMPTY;
|
||||
forceWriteAsLong = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param sis
|
||||
* @param data
|
||||
* @throws IOException
|
||||
*/
|
||||
public DefineBitsJPEG3Tag(SWFInputStream sis, ByteArrayRange data) throws IOException {
|
||||
super(sis.getSwf(), ID, NAME, data);
|
||||
readData(sis, data, 0, false, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException {
|
||||
characterID = sis.readUI16("characterID");
|
||||
long alphaDataOffset = sis.readUI32("alphaDataOffset");
|
||||
imageData = sis.readByteRangeEx(alphaDataOffset, "imageData");
|
||||
bitmapAlphaData = sis.readByteRangeEx(sis.available(), "bitmapAlphaData");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets data bytes
|
||||
*
|
||||
* @param sos SWF output stream
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
@Override
|
||||
public void getData(SWFOutputStream sos) throws IOException {
|
||||
sos.writeUI16(characterID);
|
||||
sos.writeUI32(imageData.getLength());
|
||||
sos.write(imageData);
|
||||
sos.write(bitmapAlphaData);
|
||||
}
|
||||
|
||||
private byte[] createEmptyImage() {
|
||||
BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB_PRE);
|
||||
ByteArrayOutputStream bitmapDataOS = new ByteArrayOutputStream();
|
||||
ImageHelper.write(img, ImageFormat.JPEG, bitmapDataOS);
|
||||
return bitmapDataOS.toByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImage(byte[] data) throws IOException {
|
||||
if (ImageTag.getImageFormat(data) == ImageFormat.JPEG) {
|
||||
BufferedImage image = ImageHelper.read(data);
|
||||
byte[] ba = new byte[image.getWidth() * image.getHeight()];
|
||||
for (int i = 0; i < ba.length; i++) {
|
||||
ba[i] = (byte) 255;
|
||||
}
|
||||
|
||||
bitmapAlphaData = new ByteArrayRange(SWFOutputStream.compressByteArray(ba));
|
||||
} else {
|
||||
bitmapAlphaData = new ByteArrayRange(SWFOutputStream.compressByteArray(new byte[0]));
|
||||
}
|
||||
|
||||
imageData = new ByteArrayRange(data);
|
||||
clearCache();
|
||||
setModified(true);
|
||||
}
|
||||
|
||||
public byte[] getImageAlpha() throws IOException {
|
||||
return SWFInputStream.uncompressByteArray(bitmapAlphaData.getRangeData());
|
||||
}
|
||||
|
||||
public void setImageAlpha(byte[] data) throws IOException {
|
||||
ImageFormat fmt = ImageTag.getImageFormat(imageData);
|
||||
if (fmt != ImageFormat.JPEG) {
|
||||
throw new IOException("Only Jpeg can have alpha channel.");
|
||||
}
|
||||
|
||||
Dimension dimension = getImageDimension();
|
||||
if (data == null || data.length != dimension.getWidth() * dimension.getHeight()) {
|
||||
throw new IOException("Data length must match the size of the image.");
|
||||
}
|
||||
|
||||
bitmapAlphaData = new ByteArrayRange(SWFOutputStream.compressByteArray(data));
|
||||
clearCache();
|
||||
setModified(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageFormat getImageFormat() {
|
||||
ImageFormat fmt = getOriginalImageFormat();
|
||||
if (fmt == ImageFormat.JPEG && bitmapAlphaData.getLength() > 0) {
|
||||
fmt = ImageFormat.PNG; //transparency
|
||||
}
|
||||
return fmt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageFormat getOriginalImageFormat() {
|
||||
return ImageTag.getImageFormat(imageData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getOriginalImageData() {
|
||||
if (bitmapAlphaData.getLength() == 0) { // No alpha
|
||||
int errorLength = hasErrorHeader(imageData) ? 4 : 0;
|
||||
return new ByteArrayInputStream(imageData.getArray(), imageData.getPos() + errorLength, imageData.getLength() - errorLength);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SerializableImage getImage() {
|
||||
try {
|
||||
int errorLength = hasErrorHeader(imageData) ? 4 : 0;
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(imageData.getArray(), imageData.getPos() + errorLength, imageData.getLength() - errorLength);
|
||||
|
||||
BufferedImage image = ImageHelper.read(bis);
|
||||
if (image == null) {
|
||||
Logger.getLogger(DefineBitsJPEG3Tag.class.getName()).log(Level.SEVERE, "Failed to load image");
|
||||
return null;
|
||||
}
|
||||
|
||||
SerializableImage img = new SerializableImage(image);
|
||||
if (bitmapAlphaData.getLength() == 0) {
|
||||
return img;
|
||||
}
|
||||
|
||||
byte[] alphaData = getImageAlpha();
|
||||
if (alphaData.length == 0) {
|
||||
return img;
|
||||
}
|
||||
|
||||
int width = img.getWidth();
|
||||
int height = img.getHeight();
|
||||
SerializableImage img2 = new SerializableImage(width, height, SerializableImage.TYPE_INT_ARGB_PRE);
|
||||
int[] pixels = ((DataBufferInt) img.getRaster().getDataBuffer()).getData();
|
||||
int[] pixels2 = ((DataBufferInt) img2.getRaster().getDataBuffer()).getData();
|
||||
for (int i = 0; i < pixels.length; i++) {
|
||||
int a = alphaData[i] & 0xff;
|
||||
pixels2[i] = (pixels[i] & 0xffffff) | (a << 24);
|
||||
}
|
||||
|
||||
return img2;
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(DefineBitsJPEG3Tag.class.getName()).log(Level.SEVERE, "Failed to get image", ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getImageDimension() {
|
||||
if (cachedImage != null) {
|
||||
return new Dimension(cachedImage.getWidth(), cachedImage.getHeight());
|
||||
}
|
||||
|
||||
try {
|
||||
int errorLength = hasErrorHeader(imageData) ? 4 : 0;
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(imageData.getArray(), imageData.getPos() + errorLength, imageData.getLength() - errorLength);
|
||||
return ImageHelper.getDimesion(bis);
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(DefineBitsJPEG3Tag.class.getName()).log(Level.SEVERE, "Failed to get image dimension", ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.tags;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.dumpview.DumpInfoSpecialType;
|
||||
import com.jpexs.decompiler.flash.helpers.ImageHelper;
|
||||
import com.jpexs.decompiler.flash.tags.base.AloneTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ImageTag;
|
||||
import com.jpexs.decompiler.flash.tags.enums.ImageFormat;
|
||||
import com.jpexs.decompiler.flash.types.BasicType;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFType;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import com.jpexs.helpers.SerializableImage;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.DataBufferInt;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
@SWFVersion(from = 3) //Note: GIF and PNG since version
|
||||
public class DefineBitsJPEG3Tag extends ImageTag implements AloneTag {
|
||||
|
||||
public static final int ID = 35;
|
||||
|
||||
public static final String NAME = "DefineBitsJPEG3";
|
||||
|
||||
@SWFType(BasicType.UI8)
|
||||
public ByteArrayRange imageData;
|
||||
|
||||
@SWFType(BasicType.UI8)
|
||||
public ByteArrayRange bitmapAlphaData;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param swf
|
||||
*/
|
||||
public DefineBitsJPEG3Tag(SWF swf) {
|
||||
super(swf, ID, NAME, null);
|
||||
characterID = swf.getNextCharacterId();
|
||||
imageData = new ByteArrayRange(createEmptyImage());
|
||||
bitmapAlphaData = ByteArrayRange.EMPTY;
|
||||
forceWriteAsLong = true;
|
||||
}
|
||||
|
||||
public DefineBitsJPEG3Tag(SWF swf, ByteArrayRange data, int characterID, byte[] imageData) throws IOException {
|
||||
super(swf, ID, NAME, data);
|
||||
this.characterID = characterID;
|
||||
this.imageData = new ByteArrayRange(imageData);
|
||||
bitmapAlphaData = ByteArrayRange.EMPTY;
|
||||
forceWriteAsLong = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param sis
|
||||
* @param data
|
||||
* @throws IOException
|
||||
*/
|
||||
public DefineBitsJPEG3Tag(SWFInputStream sis, ByteArrayRange data) throws IOException {
|
||||
super(sis.getSwf(), ID, NAME, data);
|
||||
readData(sis, data, 0, false, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException {
|
||||
characterID = sis.readUI16("characterID");
|
||||
long alphaDataOffset = sis.readUI32("alphaDataOffset");
|
||||
imageData = sis.readByteRangeEx(alphaDataOffset, "imageData");
|
||||
bitmapAlphaData = sis.readByteRangeEx(sis.available(), "bitmapAlphaData", DumpInfoSpecialType.ZLIB_DATA, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets data bytes
|
||||
*
|
||||
* @param sos SWF output stream
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
@Override
|
||||
public void getData(SWFOutputStream sos) throws IOException {
|
||||
sos.writeUI16(characterID);
|
||||
sos.writeUI32(imageData.getLength());
|
||||
sos.write(imageData);
|
||||
sos.write(bitmapAlphaData);
|
||||
}
|
||||
|
||||
private byte[] createEmptyImage() {
|
||||
BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB_PRE);
|
||||
ByteArrayOutputStream bitmapDataOS = new ByteArrayOutputStream();
|
||||
ImageHelper.write(img, ImageFormat.JPEG, bitmapDataOS);
|
||||
return bitmapDataOS.toByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImage(byte[] data) throws IOException {
|
||||
if (ImageTag.getImageFormat(data) == ImageFormat.JPEG) {
|
||||
BufferedImage image = ImageHelper.read(data);
|
||||
byte[] ba = new byte[image.getWidth() * image.getHeight()];
|
||||
for (int i = 0; i < ba.length; i++) {
|
||||
ba[i] = (byte) 255;
|
||||
}
|
||||
|
||||
bitmapAlphaData = new ByteArrayRange(SWFOutputStream.compressByteArray(ba));
|
||||
} else {
|
||||
bitmapAlphaData = new ByteArrayRange(SWFOutputStream.compressByteArray(new byte[0]));
|
||||
}
|
||||
|
||||
imageData = new ByteArrayRange(data);
|
||||
clearCache();
|
||||
setModified(true);
|
||||
}
|
||||
|
||||
public byte[] getImageAlpha() throws IOException {
|
||||
return SWFInputStream.uncompressByteArray(bitmapAlphaData.getRangeData());
|
||||
}
|
||||
|
||||
public void setImageAlpha(byte[] data) throws IOException {
|
||||
ImageFormat fmt = ImageTag.getImageFormat(imageData);
|
||||
if (fmt != ImageFormat.JPEG) {
|
||||
throw new IOException("Only Jpeg can have alpha channel.");
|
||||
}
|
||||
|
||||
Dimension dimension = getImageDimension();
|
||||
if (data == null || data.length != dimension.getWidth() * dimension.getHeight()) {
|
||||
throw new IOException("Data length must match the size of the image.");
|
||||
}
|
||||
|
||||
bitmapAlphaData = new ByteArrayRange(SWFOutputStream.compressByteArray(data));
|
||||
clearCache();
|
||||
setModified(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageFormat getImageFormat() {
|
||||
ImageFormat fmt = getOriginalImageFormat();
|
||||
if (fmt == ImageFormat.JPEG && bitmapAlphaData.getLength() > 0) {
|
||||
fmt = ImageFormat.PNG; //transparency
|
||||
}
|
||||
return fmt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageFormat getOriginalImageFormat() {
|
||||
return ImageTag.getImageFormat(imageData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getOriginalImageData() {
|
||||
if (bitmapAlphaData.getLength() == 0) { // No alpha
|
||||
int errorLength = hasErrorHeader(imageData) ? 4 : 0;
|
||||
return new ByteArrayInputStream(imageData.getArray(), imageData.getPos() + errorLength, imageData.getLength() - errorLength);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SerializableImage getImage() {
|
||||
try {
|
||||
int errorLength = hasErrorHeader(imageData) ? 4 : 0;
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(imageData.getArray(), imageData.getPos() + errorLength, imageData.getLength() - errorLength);
|
||||
|
||||
BufferedImage image = ImageHelper.read(bis);
|
||||
if (image == null) {
|
||||
Logger.getLogger(DefineBitsJPEG3Tag.class.getName()).log(Level.SEVERE, "Failed to load image");
|
||||
return null;
|
||||
}
|
||||
|
||||
SerializableImage img = new SerializableImage(image);
|
||||
if (bitmapAlphaData.getLength() == 0) {
|
||||
return img;
|
||||
}
|
||||
|
||||
byte[] alphaData = getImageAlpha();
|
||||
if (alphaData.length == 0) {
|
||||
return img;
|
||||
}
|
||||
|
||||
int width = img.getWidth();
|
||||
int height = img.getHeight();
|
||||
SerializableImage img2 = new SerializableImage(width, height, SerializableImage.TYPE_INT_ARGB_PRE);
|
||||
int[] pixels = ((DataBufferInt) img.getRaster().getDataBuffer()).getData();
|
||||
int[] pixels2 = ((DataBufferInt) img2.getRaster().getDataBuffer()).getData();
|
||||
for (int i = 0; i < pixels.length; i++) {
|
||||
int a = alphaData[i] & 0xff;
|
||||
pixels2[i] = (pixels[i] & 0xffffff) | (a << 24);
|
||||
}
|
||||
|
||||
return img2;
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(DefineBitsJPEG3Tag.class.getName()).log(Level.SEVERE, "Failed to get image", ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getImageDimension() {
|
||||
if (cachedImage != null) {
|
||||
return new Dimension(cachedImage.getWidth(), cachedImage.getHeight());
|
||||
}
|
||||
|
||||
try {
|
||||
int errorLength = hasErrorHeader(imageData) ? 4 : 0;
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(imageData.getArray(), imageData.getPos() + errorLength, imageData.getLength() - errorLength);
|
||||
return ImageHelper.getDimesion(bis);
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(DefineBitsJPEG3Tag.class.getName()).log(Level.SEVERE, "Failed to get image dimension", ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,238 +1,239 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.tags;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.helpers.ImageHelper;
|
||||
import com.jpexs.decompiler.flash.tags.base.AloneTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ImageTag;
|
||||
import com.jpexs.decompiler.flash.tags.enums.ImageFormat;
|
||||
import com.jpexs.decompiler.flash.types.BasicType;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFType;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import com.jpexs.helpers.SerializableImage;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.DataBufferInt;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
@SWFVersion(from = 10)
|
||||
public class DefineBitsJPEG4Tag extends ImageTag implements AloneTag {
|
||||
|
||||
public static final int ID = 90;
|
||||
|
||||
public static final String NAME = "DefineBitsJPEG4";
|
||||
|
||||
@SWFType(BasicType.UI16)
|
||||
public int deblockParam;
|
||||
|
||||
@SWFType(BasicType.UI8)
|
||||
public ByteArrayRange imageData;
|
||||
|
||||
@SWFType(BasicType.UI8)
|
||||
public ByteArrayRange bitmapAlphaData;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param swf
|
||||
*/
|
||||
public DefineBitsJPEG4Tag(SWF swf) {
|
||||
super(swf, ID, NAME, null);
|
||||
characterID = swf.getNextCharacterId();
|
||||
imageData = new ByteArrayRange(createEmptyImage());
|
||||
bitmapAlphaData = ByteArrayRange.EMPTY;
|
||||
forceWriteAsLong = true;
|
||||
}
|
||||
|
||||
public DefineBitsJPEG4Tag(SWF swf, ByteArrayRange data, int characterID, byte[] imageData) throws IOException {
|
||||
super(swf, ID, NAME, data);
|
||||
this.characterID = characterID;
|
||||
this.imageData = new ByteArrayRange(imageData);
|
||||
bitmapAlphaData = ByteArrayRange.EMPTY;
|
||||
forceWriteAsLong = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param sis
|
||||
* @param data
|
||||
* @throws IOException
|
||||
*/
|
||||
public DefineBitsJPEG4Tag(SWFInputStream sis, ByteArrayRange data) throws IOException {
|
||||
super(sis.getSwf(), ID, NAME, data);
|
||||
readData(sis, data, 0, false, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException {
|
||||
characterID = sis.readUI16("characterID");
|
||||
long alphaDataOffset = sis.readUI32("alphaDataOffset");
|
||||
deblockParam = sis.readUI16("deblockParam");
|
||||
imageData = sis.readByteRangeEx(alphaDataOffset, "imageData");
|
||||
bitmapAlphaData = sis.readByteRangeEx(sis.available(), "bitmapAlphaData");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets data bytes
|
||||
*
|
||||
* @param sos SWF output stream
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
@Override
|
||||
public void getData(SWFOutputStream sos) throws IOException {
|
||||
sos.writeUI16(characterID);
|
||||
sos.writeUI32(imageData.getLength());
|
||||
sos.writeUI16(deblockParam);
|
||||
sos.write(imageData);
|
||||
sos.write(bitmapAlphaData);
|
||||
}
|
||||
|
||||
private byte[] createEmptyImage() {
|
||||
BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB_PRE);
|
||||
ByteArrayOutputStream bitmapDataOS = new ByteArrayOutputStream();
|
||||
ImageHelper.write(img, ImageFormat.JPEG, bitmapDataOS);
|
||||
return bitmapDataOS.toByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImage(byte[] data) throws IOException {
|
||||
if (ImageTag.getImageFormat(data) == ImageFormat.JPEG) {
|
||||
BufferedImage image = ImageHelper.read(data);
|
||||
byte[] ba = new byte[image.getWidth() * image.getHeight()];
|
||||
for (int i = 0; i < ba.length; i++) {
|
||||
ba[i] = (byte) 255;
|
||||
}
|
||||
|
||||
bitmapAlphaData = new ByteArrayRange(SWFOutputStream.compressByteArray(ba));
|
||||
} else {
|
||||
bitmapAlphaData = new ByteArrayRange(SWFOutputStream.compressByteArray(new byte[0]));
|
||||
}
|
||||
|
||||
imageData = new ByteArrayRange(data);
|
||||
clearCache();
|
||||
setModified(true);
|
||||
}
|
||||
|
||||
public byte[] getImageAlpha() throws IOException {
|
||||
return SWFInputStream.uncompressByteArray(bitmapAlphaData.getRangeData());
|
||||
}
|
||||
|
||||
public void setImageAlpha(byte[] data) throws IOException {
|
||||
ImageFormat fmt = ImageTag.getImageFormat(imageData);
|
||||
if (fmt != ImageFormat.JPEG) {
|
||||
throw new IOException("Only Jpeg can have alpha channel.");
|
||||
}
|
||||
|
||||
Dimension dimension = getImageDimension();
|
||||
if (data == null || data.length != dimension.getWidth() * dimension.getHeight()) {
|
||||
throw new IOException("Data length must match the size of the image.");
|
||||
}
|
||||
|
||||
bitmapAlphaData = new ByteArrayRange(SWFOutputStream.compressByteArray(data));
|
||||
clearCache();
|
||||
setModified(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageFormat getImageFormat() {
|
||||
ImageFormat fmt = getOriginalImageFormat();
|
||||
if (fmt == ImageFormat.JPEG && bitmapAlphaData.getLength() > 0) {
|
||||
fmt = ImageFormat.PNG; //transparency
|
||||
}
|
||||
return fmt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageFormat getOriginalImageFormat() {
|
||||
return ImageTag.getImageFormat(imageData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getOriginalImageData() {
|
||||
if (bitmapAlphaData.getLength() == 0) { // No alpha
|
||||
return new ByteArrayInputStream(imageData.getArray(), imageData.getPos(), imageData.getLength());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SerializableImage getImage() {
|
||||
try {
|
||||
BufferedImage image = ImageHelper.read(new ByteArrayInputStream(imageData.getArray(), imageData.getPos(), imageData.getLength()));
|
||||
if (image == null) {
|
||||
Logger.getLogger(DefineBitsJPEG4Tag.class.getName()).log(Level.SEVERE, "Failed to load image");
|
||||
return null;
|
||||
}
|
||||
|
||||
SerializableImage img = new SerializableImage(image);
|
||||
if (bitmapAlphaData.getLength() == 0) {
|
||||
return img;
|
||||
}
|
||||
|
||||
byte[] alphaData = getImageAlpha();
|
||||
if (alphaData.length == 0) {
|
||||
return img;
|
||||
}
|
||||
|
||||
int width = img.getWidth();
|
||||
int height = img.getHeight();
|
||||
SerializableImage img2 = new SerializableImage(width, height, SerializableImage.TYPE_INT_ARGB_PRE);
|
||||
int[] pixels = ((DataBufferInt) img.getRaster().getDataBuffer()).getData();
|
||||
int[] pixels2 = ((DataBufferInt) img2.getRaster().getDataBuffer()).getData();
|
||||
for (int i = 0; i < pixels.length; i++) {
|
||||
int a = alphaData[i] & 0xff;
|
||||
pixels2[i] = (pixels[i] & 0xffffff) | (a << 24);
|
||||
}
|
||||
|
||||
return img2;
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(DefineBitsJPEG4Tag.class.getName()).log(Level.SEVERE, "Failed to get image", ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getImageDimension() {
|
||||
if (cachedImage != null) {
|
||||
return new Dimension(cachedImage.getWidth(), cachedImage.getHeight());
|
||||
}
|
||||
|
||||
try {
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(imageData.getArray(), imageData.getPos(), imageData.getLength());
|
||||
return ImageHelper.getDimesion(bis);
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(DefineBitsJPEG3Tag.class.getName()).log(Level.SEVERE, "Failed to get image dimension", ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.tags;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.dumpview.DumpInfoSpecialType;
|
||||
import com.jpexs.decompiler.flash.helpers.ImageHelper;
|
||||
import com.jpexs.decompiler.flash.tags.base.AloneTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ImageTag;
|
||||
import com.jpexs.decompiler.flash.tags.enums.ImageFormat;
|
||||
import com.jpexs.decompiler.flash.types.BasicType;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFType;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import com.jpexs.helpers.SerializableImage;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.DataBufferInt;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
@SWFVersion(from = 10)
|
||||
public class DefineBitsJPEG4Tag extends ImageTag implements AloneTag {
|
||||
|
||||
public static final int ID = 90;
|
||||
|
||||
public static final String NAME = "DefineBitsJPEG4";
|
||||
|
||||
@SWFType(BasicType.UI16)
|
||||
public int deblockParam;
|
||||
|
||||
@SWFType(BasicType.UI8)
|
||||
public ByteArrayRange imageData;
|
||||
|
||||
@SWFType(BasicType.UI8)
|
||||
public ByteArrayRange bitmapAlphaData;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param swf
|
||||
*/
|
||||
public DefineBitsJPEG4Tag(SWF swf) {
|
||||
super(swf, ID, NAME, null);
|
||||
characterID = swf.getNextCharacterId();
|
||||
imageData = new ByteArrayRange(createEmptyImage());
|
||||
bitmapAlphaData = ByteArrayRange.EMPTY;
|
||||
forceWriteAsLong = true;
|
||||
}
|
||||
|
||||
public DefineBitsJPEG4Tag(SWF swf, ByteArrayRange data, int characterID, byte[] imageData) throws IOException {
|
||||
super(swf, ID, NAME, data);
|
||||
this.characterID = characterID;
|
||||
this.imageData = new ByteArrayRange(imageData);
|
||||
bitmapAlphaData = ByteArrayRange.EMPTY;
|
||||
forceWriteAsLong = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param sis
|
||||
* @param data
|
||||
* @throws IOException
|
||||
*/
|
||||
public DefineBitsJPEG4Tag(SWFInputStream sis, ByteArrayRange data) throws IOException {
|
||||
super(sis.getSwf(), ID, NAME, data);
|
||||
readData(sis, data, 0, false, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException {
|
||||
characterID = sis.readUI16("characterID");
|
||||
long alphaDataOffset = sis.readUI32("alphaDataOffset");
|
||||
deblockParam = sis.readUI16("deblockParam");
|
||||
imageData = sis.readByteRangeEx(alphaDataOffset, "imageData");
|
||||
bitmapAlphaData = sis.readByteRangeEx(sis.available(), "bitmapAlphaData", DumpInfoSpecialType.ZLIB_DATA, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets data bytes
|
||||
*
|
||||
* @param sos SWF output stream
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
@Override
|
||||
public void getData(SWFOutputStream sos) throws IOException {
|
||||
sos.writeUI16(characterID);
|
||||
sos.writeUI32(imageData.getLength());
|
||||
sos.writeUI16(deblockParam);
|
||||
sos.write(imageData);
|
||||
sos.write(bitmapAlphaData);
|
||||
}
|
||||
|
||||
private byte[] createEmptyImage() {
|
||||
BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB_PRE);
|
||||
ByteArrayOutputStream bitmapDataOS = new ByteArrayOutputStream();
|
||||
ImageHelper.write(img, ImageFormat.JPEG, bitmapDataOS);
|
||||
return bitmapDataOS.toByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImage(byte[] data) throws IOException {
|
||||
if (ImageTag.getImageFormat(data) == ImageFormat.JPEG) {
|
||||
BufferedImage image = ImageHelper.read(data);
|
||||
byte[] ba = new byte[image.getWidth() * image.getHeight()];
|
||||
for (int i = 0; i < ba.length; i++) {
|
||||
ba[i] = (byte) 255;
|
||||
}
|
||||
|
||||
bitmapAlphaData = new ByteArrayRange(SWFOutputStream.compressByteArray(ba));
|
||||
} else {
|
||||
bitmapAlphaData = new ByteArrayRange(SWFOutputStream.compressByteArray(new byte[0]));
|
||||
}
|
||||
|
||||
imageData = new ByteArrayRange(data);
|
||||
clearCache();
|
||||
setModified(true);
|
||||
}
|
||||
|
||||
public byte[] getImageAlpha() throws IOException {
|
||||
return SWFInputStream.uncompressByteArray(bitmapAlphaData.getRangeData());
|
||||
}
|
||||
|
||||
public void setImageAlpha(byte[] data) throws IOException {
|
||||
ImageFormat fmt = ImageTag.getImageFormat(imageData);
|
||||
if (fmt != ImageFormat.JPEG) {
|
||||
throw new IOException("Only Jpeg can have alpha channel.");
|
||||
}
|
||||
|
||||
Dimension dimension = getImageDimension();
|
||||
if (data == null || data.length != dimension.getWidth() * dimension.getHeight()) {
|
||||
throw new IOException("Data length must match the size of the image.");
|
||||
}
|
||||
|
||||
bitmapAlphaData = new ByteArrayRange(SWFOutputStream.compressByteArray(data));
|
||||
clearCache();
|
||||
setModified(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageFormat getImageFormat() {
|
||||
ImageFormat fmt = getOriginalImageFormat();
|
||||
if (fmt == ImageFormat.JPEG && bitmapAlphaData.getLength() > 0) {
|
||||
fmt = ImageFormat.PNG; //transparency
|
||||
}
|
||||
return fmt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageFormat getOriginalImageFormat() {
|
||||
return ImageTag.getImageFormat(imageData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getOriginalImageData() {
|
||||
if (bitmapAlphaData.getLength() == 0) { // No alpha
|
||||
return new ByteArrayInputStream(imageData.getArray(), imageData.getPos(), imageData.getLength());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SerializableImage getImage() {
|
||||
try {
|
||||
BufferedImage image = ImageHelper.read(new ByteArrayInputStream(imageData.getArray(), imageData.getPos(), imageData.getLength()));
|
||||
if (image == null) {
|
||||
Logger.getLogger(DefineBitsJPEG4Tag.class.getName()).log(Level.SEVERE, "Failed to load image");
|
||||
return null;
|
||||
}
|
||||
|
||||
SerializableImage img = new SerializableImage(image);
|
||||
if (bitmapAlphaData.getLength() == 0) {
|
||||
return img;
|
||||
}
|
||||
|
||||
byte[] alphaData = getImageAlpha();
|
||||
if (alphaData.length == 0) {
|
||||
return img;
|
||||
}
|
||||
|
||||
int width = img.getWidth();
|
||||
int height = img.getHeight();
|
||||
SerializableImage img2 = new SerializableImage(width, height, SerializableImage.TYPE_INT_ARGB_PRE);
|
||||
int[] pixels = ((DataBufferInt) img.getRaster().getDataBuffer()).getData();
|
||||
int[] pixels2 = ((DataBufferInt) img2.getRaster().getDataBuffer()).getData();
|
||||
for (int i = 0; i < pixels.length; i++) {
|
||||
int a = alphaData[i] & 0xff;
|
||||
pixels2[i] = (pixels[i] & 0xffffff) | (a << 24);
|
||||
}
|
||||
|
||||
return img2;
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(DefineBitsJPEG4Tag.class.getName()).log(Level.SEVERE, "Failed to get image", ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getImageDimension() {
|
||||
if (cachedImage != null) {
|
||||
return new Dimension(cachedImage.getWidth(), cachedImage.getHeight());
|
||||
}
|
||||
|
||||
try {
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(imageData.getArray(), imageData.getPos(), imageData.getLength());
|
||||
return ImageHelper.getDimesion(bis);
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(DefineBitsJPEG3Tag.class.getName()).log(Level.SEVERE, "Failed to get image dimension", ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,279 +1,281 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.tags;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.helpers.ImageHelper;
|
||||
import com.jpexs.decompiler.flash.tags.base.AloneTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ImageTag;
|
||||
import com.jpexs.decompiler.flash.tags.enums.ImageFormat;
|
||||
import com.jpexs.decompiler.flash.types.ALPHABITMAPDATA;
|
||||
import com.jpexs.decompiler.flash.types.ALPHACOLORMAPDATA;
|
||||
import com.jpexs.decompiler.flash.types.BasicType;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Conditional;
|
||||
import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Internal;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFType;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import com.jpexs.helpers.SerializableImage;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.image.DataBufferInt;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
@SWFVersion(from = 3)
|
||||
public class DefineBitsLossless2Tag extends ImageTag implements AloneTag {
|
||||
|
||||
public static final int ID = 36;
|
||||
|
||||
public static final String NAME = "DefineBitsLossless2";
|
||||
|
||||
@SWFType(BasicType.UI8)
|
||||
public int bitmapFormat;
|
||||
|
||||
@SWFType(BasicType.UI16)
|
||||
public int bitmapWidth;
|
||||
|
||||
@SWFType(BasicType.UI16)
|
||||
public int bitmapHeight;
|
||||
|
||||
@SWFType(BasicType.UI8)
|
||||
@Conditional(value = "bitmapFormat", options = {FORMAT_8BIT_COLORMAPPED})
|
||||
public int bitmapColorTableSize;
|
||||
|
||||
public ByteArrayRange zlibBitmapData;
|
||||
|
||||
public static final int FORMAT_8BIT_COLORMAPPED = 3;
|
||||
|
||||
public static final int FORMAT_32BIT_ARGB = 5;
|
||||
|
||||
@HideInRawEdit
|
||||
private ALPHACOLORMAPDATA colorMapData;
|
||||
|
||||
@HideInRawEdit
|
||||
private ALPHABITMAPDATA bitmapData;
|
||||
|
||||
@Internal
|
||||
private boolean decompressed = false;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param swf
|
||||
*/
|
||||
public DefineBitsLossless2Tag(SWF swf) {
|
||||
this(swf, null, swf.getNextCharacterId());
|
||||
}
|
||||
|
||||
public DefineBitsLossless2Tag(SWF swf, ByteArrayRange data, int characterID) {
|
||||
super(swf, ID, NAME, data);
|
||||
this.characterID = characterID;
|
||||
bitmapFormat = DefineBitsLossless2Tag.FORMAT_32BIT_ARGB;
|
||||
bitmapWidth = 1;
|
||||
bitmapHeight = 1;
|
||||
zlibBitmapData = new ByteArrayRange(createEmptyImage());
|
||||
forceWriteAsLong = true;
|
||||
}
|
||||
|
||||
public DefineBitsLossless2Tag(SWFInputStream sis, ByteArrayRange data) throws IOException {
|
||||
super(sis.getSwf(), ID, NAME, data);
|
||||
readData(sis, data, 0, false, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException {
|
||||
characterID = sis.readUI16("characterID");
|
||||
bitmapFormat = sis.readUI8("bitmapFormat");
|
||||
bitmapWidth = sis.readUI16("bitmapWidth");
|
||||
bitmapHeight = sis.readUI16("bitmapHeight");
|
||||
if (bitmapFormat == FORMAT_8BIT_COLORMAPPED) {
|
||||
bitmapColorTableSize = sis.readUI8("bitmapColorTableSize");
|
||||
}
|
||||
zlibBitmapData = sis.readByteRangeEx(sis.available(), "zlibBitmapData");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets data bytes
|
||||
*
|
||||
* @param sos SWF output stream
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
@Override
|
||||
public void getData(SWFOutputStream sos) throws IOException {
|
||||
sos.writeUI16(characterID);
|
||||
sos.writeUI8(bitmapFormat);
|
||||
sos.writeUI16(bitmapWidth);
|
||||
sos.writeUI16(bitmapHeight);
|
||||
if (bitmapFormat == FORMAT_8BIT_COLORMAPPED) {
|
||||
sos.writeUI8(bitmapColorTableSize);
|
||||
}
|
||||
sos.write(zlibBitmapData);
|
||||
}
|
||||
|
||||
private byte[] createEmptyImage() {
|
||||
try {
|
||||
ALPHABITMAPDATA bitmapData = new ALPHABITMAPDATA();
|
||||
bitmapData.bitmapPixelData = new int[]{0xff000000};
|
||||
ByteArrayOutputStream bitmapDataOS = new ByteArrayOutputStream();
|
||||
SWFOutputStream sos = new SWFOutputStream(bitmapDataOS, getVersion());
|
||||
sos.writeALPHABITMAPDATA(bitmapData, FORMAT_32BIT_ARGB, 1, 1);
|
||||
ByteArrayOutputStream zlibOS = new ByteArrayOutputStream();
|
||||
SWFOutputStream sos2 = new SWFOutputStream(zlibOS, getVersion());
|
||||
sos2.writeBytesZlib(bitmapDataOS.toByteArray());
|
||||
return zlibOS.toByteArray();
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(DefineBitsLossless2Tag.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImage(byte[] data) throws IOException {
|
||||
SerializableImage image = new SerializableImage(ImageHelper.read(data));
|
||||
ALPHABITMAPDATA bitmapData = new ALPHABITMAPDATA();
|
||||
int width = image.getWidth();
|
||||
int height = image.getHeight();
|
||||
bitmapData.bitmapPixelData = new int[width * height];
|
||||
int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
|
||||
for (int pos = 0; pos < pixels.length; pos++) {
|
||||
int argb = pixels[pos];
|
||||
int a = (argb >> 24) & 0xff;
|
||||
int r = (argb >> 16) & 0xff;
|
||||
int g = (argb >> 8) & 0xff;
|
||||
int b = argb & 0xff;
|
||||
|
||||
r = r * a / 255;
|
||||
g = g * a / 255;
|
||||
b = b * a / 255;
|
||||
|
||||
bitmapData.bitmapPixelData[pos] = ((a & 0xFF) << 24) | ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | (b & 0xFF);
|
||||
}
|
||||
|
||||
int format = FORMAT_32BIT_ARGB;
|
||||
ByteArrayOutputStream bitmapDataOS = new ByteArrayOutputStream();
|
||||
SWFOutputStream sos = new SWFOutputStream(bitmapDataOS, getVersion());
|
||||
sos.writeALPHABITMAPDATA(bitmapData, format, width, height);
|
||||
ByteArrayOutputStream zlibOS = new ByteArrayOutputStream();
|
||||
SWFOutputStream sos2 = new SWFOutputStream(zlibOS, getVersion());
|
||||
sos2.writeBytesZlib(bitmapDataOS.toByteArray());
|
||||
zlibBitmapData = new ByteArrayRange(zlibOS.toByteArray());
|
||||
bitmapFormat = format;
|
||||
bitmapWidth = width;
|
||||
bitmapHeight = height;
|
||||
decompressed = false;
|
||||
clearCache();
|
||||
setModified(true);
|
||||
}
|
||||
|
||||
public ALPHACOLORMAPDATA getColorMapData() {
|
||||
if (!decompressed) {
|
||||
uncompressData();
|
||||
}
|
||||
return colorMapData;
|
||||
}
|
||||
|
||||
public ALPHABITMAPDATA getBitmapData() {
|
||||
if (!decompressed) {
|
||||
uncompressData();
|
||||
}
|
||||
return bitmapData;
|
||||
}
|
||||
|
||||
private void uncompressData() {
|
||||
try {
|
||||
byte[] uncompressedData = SWFInputStream.uncompressByteArray(zlibBitmapData.getArray(), zlibBitmapData.getPos(), zlibBitmapData.getLength());
|
||||
SWFInputStream sis = new SWFInputStream(swf, uncompressedData);
|
||||
if (bitmapFormat == FORMAT_8BIT_COLORMAPPED) {
|
||||
colorMapData = sis.readALPHACOLORMAPDATA(bitmapColorTableSize, bitmapWidth, bitmapHeight, "colorMapData");
|
||||
} else if (bitmapFormat == FORMAT_32BIT_ARGB) {
|
||||
bitmapData = sis.readALPHABITMAPDATA(bitmapFormat, bitmapWidth, bitmapHeight, "bitmapData");
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
decompressed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageFormat getImageFormat() {
|
||||
return ImageFormat.PNG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageFormat getOriginalImageFormat() {
|
||||
return ImageFormat.PNG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getOriginalImageData() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SerializableImage getImage() {
|
||||
SerializableImage bi = new SerializableImage(bitmapWidth, bitmapHeight, SerializableImage.TYPE_INT_ARGB_PRE);
|
||||
int[] pixels = ((DataBufferInt) bi.getRaster().getDataBuffer()).getData();
|
||||
|
||||
ALPHACOLORMAPDATA colorMapData = null;
|
||||
ALPHABITMAPDATA bitmapData = null;
|
||||
if (bitmapFormat == DefineBitsLossless2Tag.FORMAT_8BIT_COLORMAPPED) {
|
||||
colorMapData = getColorMapData();
|
||||
}
|
||||
if (bitmapFormat == DefineBitsLossless2Tag.FORMAT_32BIT_ARGB) {
|
||||
bitmapData = getBitmapData();
|
||||
}
|
||||
int pos32aligned = 0;
|
||||
int pos = 0;
|
||||
for (int y = 0; y < bitmapHeight; y++) {
|
||||
for (int x = 0; x < bitmapWidth; x++) {
|
||||
int c = 0;
|
||||
if ((bitmapFormat == DefineBitsLossless2Tag.FORMAT_8BIT_COLORMAPPED)) {
|
||||
int colorTableIndex = colorMapData.colorMapPixelData[pos32aligned] & 0xff;
|
||||
if (colorTableIndex < colorMapData.colorTableRGB.length) {
|
||||
c = colorMapData.colorTableRGB[colorTableIndex];
|
||||
}
|
||||
}
|
||||
if ((bitmapFormat == DefineBitsLossless2Tag.FORMAT_32BIT_ARGB)) {
|
||||
c = bitmapData.bitmapPixelData[pos];
|
||||
}
|
||||
|
||||
pixels[pos] = c;
|
||||
pos32aligned++;
|
||||
pos++;
|
||||
}
|
||||
while ((pos32aligned % 4 != 0)) {
|
||||
pos32aligned++;
|
||||
}
|
||||
}
|
||||
|
||||
return bi;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getImageDimension() {
|
||||
return new Dimension(bitmapWidth, bitmapHeight);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.tags;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.dumpview.DumpInfoSpecialType;
|
||||
import com.jpexs.decompiler.flash.helpers.ImageHelper;
|
||||
import com.jpexs.decompiler.flash.tags.base.AloneTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ImageTag;
|
||||
import com.jpexs.decompiler.flash.tags.enums.ImageFormat;
|
||||
import com.jpexs.decompiler.flash.types.ALPHABITMAPDATA;
|
||||
import com.jpexs.decompiler.flash.types.ALPHACOLORMAPDATA;
|
||||
import com.jpexs.decompiler.flash.types.BasicType;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Conditional;
|
||||
import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Internal;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFType;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import com.jpexs.helpers.SerializableImage;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.image.DataBufferInt;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
@SWFVersion(from = 3)
|
||||
public class DefineBitsLossless2Tag extends ImageTag implements AloneTag {
|
||||
|
||||
public static final int ID = 36;
|
||||
|
||||
public static final String NAME = "DefineBitsLossless2";
|
||||
|
||||
@SWFType(BasicType.UI8)
|
||||
public int bitmapFormat;
|
||||
|
||||
@SWFType(BasicType.UI16)
|
||||
public int bitmapWidth;
|
||||
|
||||
@SWFType(BasicType.UI16)
|
||||
public int bitmapHeight;
|
||||
|
||||
@SWFType(BasicType.UI8)
|
||||
@Conditional(value = "bitmapFormat", options = {FORMAT_8BIT_COLORMAPPED})
|
||||
public int bitmapColorTableSize;
|
||||
|
||||
public ByteArrayRange zlibBitmapData;
|
||||
|
||||
public static final int FORMAT_8BIT_COLORMAPPED = 3;
|
||||
|
||||
public static final int FORMAT_32BIT_ARGB = 5;
|
||||
|
||||
@HideInRawEdit
|
||||
private ALPHACOLORMAPDATA colorMapData;
|
||||
|
||||
@HideInRawEdit
|
||||
private ALPHABITMAPDATA bitmapData;
|
||||
|
||||
@Internal
|
||||
private boolean decompressed = false;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param swf
|
||||
*/
|
||||
public DefineBitsLossless2Tag(SWF swf) {
|
||||
this(swf, null, swf.getNextCharacterId());
|
||||
}
|
||||
|
||||
public DefineBitsLossless2Tag(SWF swf, ByteArrayRange data, int characterID) {
|
||||
super(swf, ID, NAME, data);
|
||||
this.characterID = characterID;
|
||||
bitmapFormat = DefineBitsLossless2Tag.FORMAT_32BIT_ARGB;
|
||||
bitmapWidth = 1;
|
||||
bitmapHeight = 1;
|
||||
zlibBitmapData = new ByteArrayRange(createEmptyImage());
|
||||
forceWriteAsLong = true;
|
||||
}
|
||||
|
||||
public DefineBitsLossless2Tag(SWFInputStream sis, ByteArrayRange data) throws IOException {
|
||||
super(sis.getSwf(), ID, NAME, data);
|
||||
readData(sis, data, 0, false, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException {
|
||||
characterID = sis.readUI16("characterID");
|
||||
bitmapFormat = sis.readUI8("bitmapFormat");
|
||||
bitmapWidth = sis.readUI16("bitmapWidth");
|
||||
bitmapHeight = sis.readUI16("bitmapHeight");
|
||||
if (bitmapFormat == FORMAT_8BIT_COLORMAPPED) {
|
||||
bitmapColorTableSize = sis.readUI8("bitmapColorTableSize");
|
||||
}
|
||||
|
||||
zlibBitmapData = sis.readByteRangeEx(sis.available(), "zlibBitmapData", DumpInfoSpecialType.ZLIB_DATA, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets data bytes
|
||||
*
|
||||
* @param sos SWF output stream
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
@Override
|
||||
public void getData(SWFOutputStream sos) throws IOException {
|
||||
sos.writeUI16(characterID);
|
||||
sos.writeUI8(bitmapFormat);
|
||||
sos.writeUI16(bitmapWidth);
|
||||
sos.writeUI16(bitmapHeight);
|
||||
if (bitmapFormat == FORMAT_8BIT_COLORMAPPED) {
|
||||
sos.writeUI8(bitmapColorTableSize);
|
||||
}
|
||||
sos.write(zlibBitmapData);
|
||||
}
|
||||
|
||||
private byte[] createEmptyImage() {
|
||||
try {
|
||||
ALPHABITMAPDATA bitmapData = new ALPHABITMAPDATA();
|
||||
bitmapData.bitmapPixelData = new int[]{0xff000000};
|
||||
ByteArrayOutputStream bitmapDataOS = new ByteArrayOutputStream();
|
||||
SWFOutputStream sos = new SWFOutputStream(bitmapDataOS, getVersion());
|
||||
sos.writeALPHABITMAPDATA(bitmapData, FORMAT_32BIT_ARGB, 1, 1);
|
||||
ByteArrayOutputStream zlibOS = new ByteArrayOutputStream();
|
||||
SWFOutputStream sos2 = new SWFOutputStream(zlibOS, getVersion());
|
||||
sos2.writeBytesZlib(bitmapDataOS.toByteArray());
|
||||
return zlibOS.toByteArray();
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(DefineBitsLossless2Tag.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImage(byte[] data) throws IOException {
|
||||
SerializableImage image = new SerializableImage(ImageHelper.read(data));
|
||||
ALPHABITMAPDATA bitmapData = new ALPHABITMAPDATA();
|
||||
int width = image.getWidth();
|
||||
int height = image.getHeight();
|
||||
bitmapData.bitmapPixelData = new int[width * height];
|
||||
int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
|
||||
for (int pos = 0; pos < pixels.length; pos++) {
|
||||
int argb = pixels[pos];
|
||||
int a = (argb >> 24) & 0xff;
|
||||
int r = (argb >> 16) & 0xff;
|
||||
int g = (argb >> 8) & 0xff;
|
||||
int b = argb & 0xff;
|
||||
|
||||
r = r * a / 255;
|
||||
g = g * a / 255;
|
||||
b = b * a / 255;
|
||||
|
||||
bitmapData.bitmapPixelData[pos] = ((a & 0xFF) << 24) | ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | (b & 0xFF);
|
||||
}
|
||||
|
||||
int format = FORMAT_32BIT_ARGB;
|
||||
ByteArrayOutputStream bitmapDataOS = new ByteArrayOutputStream();
|
||||
SWFOutputStream sos = new SWFOutputStream(bitmapDataOS, getVersion());
|
||||
sos.writeALPHABITMAPDATA(bitmapData, format, width, height);
|
||||
ByteArrayOutputStream zlibOS = new ByteArrayOutputStream();
|
||||
SWFOutputStream sos2 = new SWFOutputStream(zlibOS, getVersion());
|
||||
sos2.writeBytesZlib(bitmapDataOS.toByteArray());
|
||||
zlibBitmapData = new ByteArrayRange(zlibOS.toByteArray());
|
||||
bitmapFormat = format;
|
||||
bitmapWidth = width;
|
||||
bitmapHeight = height;
|
||||
decompressed = false;
|
||||
clearCache();
|
||||
setModified(true);
|
||||
}
|
||||
|
||||
public ALPHACOLORMAPDATA getColorMapData() {
|
||||
if (!decompressed) {
|
||||
uncompressData();
|
||||
}
|
||||
return colorMapData;
|
||||
}
|
||||
|
||||
public ALPHABITMAPDATA getBitmapData() {
|
||||
if (!decompressed) {
|
||||
uncompressData();
|
||||
}
|
||||
return bitmapData;
|
||||
}
|
||||
|
||||
private void uncompressData() {
|
||||
try {
|
||||
byte[] uncompressedData = SWFInputStream.uncompressByteArray(zlibBitmapData.getArray(), zlibBitmapData.getPos(), zlibBitmapData.getLength());
|
||||
SWFInputStream sis = new SWFInputStream(swf, uncompressedData);
|
||||
if (bitmapFormat == FORMAT_8BIT_COLORMAPPED) {
|
||||
colorMapData = sis.readALPHACOLORMAPDATA(bitmapColorTableSize, bitmapWidth, bitmapHeight, "colorMapData");
|
||||
} else if (bitmapFormat == FORMAT_32BIT_ARGB) {
|
||||
bitmapData = sis.readALPHABITMAPDATA(bitmapFormat, bitmapWidth, bitmapHeight, "bitmapData");
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
decompressed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageFormat getImageFormat() {
|
||||
return ImageFormat.PNG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageFormat getOriginalImageFormat() {
|
||||
return ImageFormat.PNG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getOriginalImageData() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SerializableImage getImage() {
|
||||
SerializableImage bi = new SerializableImage(bitmapWidth, bitmapHeight, SerializableImage.TYPE_INT_ARGB_PRE);
|
||||
int[] pixels = ((DataBufferInt) bi.getRaster().getDataBuffer()).getData();
|
||||
|
||||
ALPHACOLORMAPDATA colorMapData = null;
|
||||
ALPHABITMAPDATA bitmapData = null;
|
||||
if (bitmapFormat == DefineBitsLossless2Tag.FORMAT_8BIT_COLORMAPPED) {
|
||||
colorMapData = getColorMapData();
|
||||
}
|
||||
if (bitmapFormat == DefineBitsLossless2Tag.FORMAT_32BIT_ARGB) {
|
||||
bitmapData = getBitmapData();
|
||||
}
|
||||
int pos32aligned = 0;
|
||||
int pos = 0;
|
||||
for (int y = 0; y < bitmapHeight; y++) {
|
||||
for (int x = 0; x < bitmapWidth; x++) {
|
||||
int c = 0;
|
||||
if ((bitmapFormat == DefineBitsLossless2Tag.FORMAT_8BIT_COLORMAPPED)) {
|
||||
int colorTableIndex = colorMapData.colorMapPixelData[pos32aligned] & 0xff;
|
||||
if (colorTableIndex < colorMapData.colorTableRGB.length) {
|
||||
c = colorMapData.colorTableRGB[colorTableIndex];
|
||||
}
|
||||
}
|
||||
if ((bitmapFormat == DefineBitsLossless2Tag.FORMAT_32BIT_ARGB)) {
|
||||
c = bitmapData.bitmapPixelData[pos];
|
||||
}
|
||||
|
||||
pixels[pos] = c;
|
||||
pos32aligned++;
|
||||
pos++;
|
||||
}
|
||||
while ((pos32aligned % 4 != 0)) {
|
||||
pos32aligned++;
|
||||
}
|
||||
}
|
||||
|
||||
return bi;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getImageDimension() {
|
||||
return new Dimension(bitmapWidth, bitmapHeight);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,279 +1,281 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.tags;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.helpers.ImageHelper;
|
||||
import com.jpexs.decompiler.flash.tags.base.AloneTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ImageTag;
|
||||
import com.jpexs.decompiler.flash.tags.enums.ImageFormat;
|
||||
import com.jpexs.decompiler.flash.types.BITMAPDATA;
|
||||
import com.jpexs.decompiler.flash.types.BasicType;
|
||||
import com.jpexs.decompiler.flash.types.COLORMAPDATA;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Conditional;
|
||||
import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Internal;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFType;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import com.jpexs.helpers.SerializableImage;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.image.DataBufferInt;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
@SWFVersion(from = 2)
|
||||
public class DefineBitsLosslessTag extends ImageTag implements AloneTag {
|
||||
|
||||
public static final int ID = 20;
|
||||
|
||||
public static final String NAME = "DefineBitsLossless";
|
||||
|
||||
@SWFType(BasicType.UI8)
|
||||
public int bitmapFormat;
|
||||
|
||||
@SWFType(BasicType.UI16)
|
||||
public int bitmapWidth;
|
||||
|
||||
@SWFType(BasicType.UI16)
|
||||
public int bitmapHeight;
|
||||
|
||||
@SWFType(BasicType.UI8)
|
||||
@Conditional(value = "bitmapFormat", options = {FORMAT_8BIT_COLORMAPPED})
|
||||
public int bitmapColorTableSize;
|
||||
|
||||
public ByteArrayRange zlibBitmapData;
|
||||
|
||||
public static final int FORMAT_8BIT_COLORMAPPED = 3;
|
||||
|
||||
public static final int FORMAT_15BIT_RGB = 4;
|
||||
|
||||
public static final int FORMAT_24BIT_RGB = 5;
|
||||
|
||||
@HideInRawEdit
|
||||
private COLORMAPDATA colorMapData;
|
||||
|
||||
@HideInRawEdit
|
||||
private BITMAPDATA bitmapData;
|
||||
|
||||
@Internal
|
||||
private boolean decompressed = false;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param swf
|
||||
*/
|
||||
public DefineBitsLosslessTag(SWF swf) {
|
||||
this(swf, null, swf.getNextCharacterId());
|
||||
}
|
||||
|
||||
public DefineBitsLosslessTag(SWF swf, ByteArrayRange data, int characterID) {
|
||||
super(swf, ID, NAME, data);
|
||||
this.characterID = characterID;
|
||||
bitmapFormat = DefineBitsLosslessTag.FORMAT_24BIT_RGB;
|
||||
bitmapWidth = 1;
|
||||
bitmapHeight = 1;
|
||||
zlibBitmapData = new ByteArrayRange(createEmptyImage());
|
||||
forceWriteAsLong = true;
|
||||
}
|
||||
|
||||
public DefineBitsLosslessTag(SWFInputStream sis, ByteArrayRange data) throws IOException {
|
||||
super(sis.getSwf(), ID, NAME, data);
|
||||
readData(sis, data, 0, false, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException {
|
||||
characterID = sis.readUI16("characterID");
|
||||
bitmapFormat = sis.readUI8("bitmapFormat");
|
||||
bitmapWidth = sis.readUI16("bitmapWidth");
|
||||
bitmapHeight = sis.readUI16("bitmapHeight");
|
||||
if (bitmapFormat == FORMAT_8BIT_COLORMAPPED) {
|
||||
bitmapColorTableSize = sis.readUI8("bitmapColorTableSize");
|
||||
}
|
||||
zlibBitmapData = sis.readByteRangeEx(sis.available(), "zlibBitmapData");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets data bytes
|
||||
*
|
||||
* @param sos SWF output stream
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
@Override
|
||||
public void getData(SWFOutputStream sos) throws IOException {
|
||||
sos.writeUI16(characterID);
|
||||
sos.writeUI8(bitmapFormat);
|
||||
sos.writeUI16(bitmapWidth);
|
||||
sos.writeUI16(bitmapHeight);
|
||||
if (bitmapFormat == FORMAT_8BIT_COLORMAPPED) {
|
||||
sos.writeUI8(bitmapColorTableSize);
|
||||
}
|
||||
sos.write(zlibBitmapData);
|
||||
}
|
||||
|
||||
private byte[] createEmptyImage() {
|
||||
try {
|
||||
BITMAPDATA bitmapData = new BITMAPDATA();
|
||||
bitmapData.bitmapPixelDataPix24 = new int[]{0xff000000};
|
||||
ByteArrayOutputStream bitmapDataOS = new ByteArrayOutputStream();
|
||||
SWFOutputStream sos = new SWFOutputStream(bitmapDataOS, getVersion());
|
||||
sos.writeBITMAPDATA(bitmapData, FORMAT_24BIT_RGB, 1, 1);
|
||||
ByteArrayOutputStream zlibOS = new ByteArrayOutputStream();
|
||||
SWFOutputStream sos2 = new SWFOutputStream(zlibOS, getVersion());
|
||||
sos2.writeBytesZlib(bitmapDataOS.toByteArray());
|
||||
return zlibOS.toByteArray();
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(DefineBitsLosslessTag.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImage(byte[] data) throws IOException {
|
||||
SerializableImage image = new SerializableImage(ImageHelper.read(data));
|
||||
int width = image.getWidth();
|
||||
int height = image.getHeight();
|
||||
bitmapData = new BITMAPDATA();
|
||||
bitmapData.bitmapPixelDataPix24 = new int[width * height];
|
||||
int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
|
||||
for (int pos = 0; pos < pixels.length; pos++) {
|
||||
// set the reserved bits to 0xff, because:
|
||||
// documentation says 0, but image is sometimes broken with 0, so there is 0xff, which works (maybe alpha?)
|
||||
int argb = pixels[pos] | 0xff000000;
|
||||
bitmapData.bitmapPixelDataPix24[pos] = argb;
|
||||
}
|
||||
|
||||
int format = FORMAT_24BIT_RGB;
|
||||
ByteArrayOutputStream bitmapDataOS = new ByteArrayOutputStream();
|
||||
SWFOutputStream sos = new SWFOutputStream(bitmapDataOS, getVersion());
|
||||
sos.writeBITMAPDATA(bitmapData, format, width, height);
|
||||
ByteArrayOutputStream zlibOS = new ByteArrayOutputStream();
|
||||
SWFOutputStream sos2 = new SWFOutputStream(zlibOS, getVersion());
|
||||
sos2.writeBytesZlib(bitmapDataOS.toByteArray());
|
||||
zlibBitmapData = new ByteArrayRange(zlibOS.toByteArray());
|
||||
bitmapFormat = format;
|
||||
bitmapWidth = width;
|
||||
bitmapHeight = height;
|
||||
decompressed = false;
|
||||
clearCache();
|
||||
setModified(true);
|
||||
}
|
||||
|
||||
public COLORMAPDATA getColorMapData() {
|
||||
if (!decompressed) {
|
||||
uncompressData();
|
||||
}
|
||||
return colorMapData;
|
||||
}
|
||||
|
||||
public BITMAPDATA getBitmapData() {
|
||||
if (!decompressed) {
|
||||
uncompressData();
|
||||
}
|
||||
return bitmapData;
|
||||
}
|
||||
|
||||
private void uncompressData() {
|
||||
try {
|
||||
byte[] uncompressedData = SWFInputStream.uncompressByteArray(zlibBitmapData.getArray(), zlibBitmapData.getPos(), zlibBitmapData.getLength());
|
||||
SWFInputStream sis = new SWFInputStream(swf, uncompressedData);
|
||||
if (bitmapFormat == FORMAT_8BIT_COLORMAPPED) {
|
||||
colorMapData = sis.readCOLORMAPDATA(bitmapColorTableSize, bitmapWidth, bitmapHeight, "colorMapData");
|
||||
} else if ((bitmapFormat == FORMAT_15BIT_RGB) || (bitmapFormat == FORMAT_24BIT_RGB)) {
|
||||
bitmapData = sis.readBITMAPDATA(bitmapFormat, bitmapWidth, bitmapHeight, "bitmapData");
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
decompressed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageFormat getImageFormat() {
|
||||
return ImageFormat.PNG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageFormat getOriginalImageFormat() {
|
||||
return ImageFormat.PNG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getOriginalImageData() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SerializableImage getImage() {
|
||||
int[] pixels = new int[bitmapWidth * bitmapHeight];
|
||||
if (bitmapFormat == DefineBitsLosslessTag.FORMAT_8BIT_COLORMAPPED) {
|
||||
COLORMAPDATA colorMapData = getColorMapData();
|
||||
int pos32aligned = 0;
|
||||
int pos = 0;
|
||||
for (int y = 0; y < bitmapHeight; y++) {
|
||||
for (int x = 0; x < bitmapWidth; x++) {
|
||||
int c = 0;
|
||||
int colorTableIndex = colorMapData.colorMapPixelData[pos32aligned] & 0xff;
|
||||
if (colorTableIndex < colorMapData.colorTableRGB.length) {
|
||||
c = colorMapData.colorTableRGB[colorTableIndex];
|
||||
}
|
||||
|
||||
pixels[pos++] = c;
|
||||
pos32aligned++;
|
||||
}
|
||||
|
||||
while ((pos32aligned % 4 != 0)) {
|
||||
pos32aligned++;
|
||||
}
|
||||
}
|
||||
} else if ((bitmapFormat == DefineBitsLosslessTag.FORMAT_15BIT_RGB) || (bitmapFormat == DefineBitsLosslessTag.FORMAT_24BIT_RGB)) {
|
||||
BITMAPDATA bitmapData = getBitmapData();
|
||||
int pos = 0;
|
||||
int[] bitmapPixelData = null;
|
||||
if (bitmapFormat == DefineBitsLosslessTag.FORMAT_15BIT_RGB) {
|
||||
bitmapPixelData = bitmapData.bitmapPixelDataPix15;
|
||||
} else if (bitmapFormat == DefineBitsLosslessTag.FORMAT_24BIT_RGB) {
|
||||
bitmapPixelData = bitmapData.bitmapPixelDataPix24;
|
||||
}
|
||||
|
||||
for (int y = 0; y < bitmapHeight; y++) {
|
||||
for (int x = 0; x < bitmapWidth; x++) {
|
||||
int c = bitmapPixelData[pos] | 0xff000000;
|
||||
pixels[pos++] = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SerializableImage bi = new SerializableImage(bitmapWidth, bitmapHeight, SerializableImage.TYPE_INT_RGB, pixels);
|
||||
return bi;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getImageDimension() {
|
||||
return new Dimension(bitmapWidth, bitmapHeight);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.tags;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.dumpview.DumpInfoSpecialType;
|
||||
import com.jpexs.decompiler.flash.helpers.ImageHelper;
|
||||
import com.jpexs.decompiler.flash.tags.base.AloneTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ImageTag;
|
||||
import com.jpexs.decompiler.flash.tags.enums.ImageFormat;
|
||||
import com.jpexs.decompiler.flash.types.BITMAPDATA;
|
||||
import com.jpexs.decompiler.flash.types.BasicType;
|
||||
import com.jpexs.decompiler.flash.types.COLORMAPDATA;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Conditional;
|
||||
import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Internal;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFType;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import com.jpexs.helpers.SerializableImage;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.image.DataBufferInt;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
@SWFVersion(from = 2)
|
||||
public class DefineBitsLosslessTag extends ImageTag implements AloneTag {
|
||||
|
||||
public static final int ID = 20;
|
||||
|
||||
public static final String NAME = "DefineBitsLossless";
|
||||
|
||||
@SWFType(BasicType.UI8)
|
||||
public int bitmapFormat;
|
||||
|
||||
@SWFType(BasicType.UI16)
|
||||
public int bitmapWidth;
|
||||
|
||||
@SWFType(BasicType.UI16)
|
||||
public int bitmapHeight;
|
||||
|
||||
@SWFType(BasicType.UI8)
|
||||
@Conditional(value = "bitmapFormat", options = {FORMAT_8BIT_COLORMAPPED})
|
||||
public int bitmapColorTableSize;
|
||||
|
||||
public ByteArrayRange zlibBitmapData;
|
||||
|
||||
public static final int FORMAT_8BIT_COLORMAPPED = 3;
|
||||
|
||||
public static final int FORMAT_15BIT_RGB = 4;
|
||||
|
||||
public static final int FORMAT_24BIT_RGB = 5;
|
||||
|
||||
@HideInRawEdit
|
||||
private COLORMAPDATA colorMapData;
|
||||
|
||||
@HideInRawEdit
|
||||
private BITMAPDATA bitmapData;
|
||||
|
||||
@Internal
|
||||
private boolean decompressed = false;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param swf
|
||||
*/
|
||||
public DefineBitsLosslessTag(SWF swf) {
|
||||
this(swf, null, swf.getNextCharacterId());
|
||||
}
|
||||
|
||||
public DefineBitsLosslessTag(SWF swf, ByteArrayRange data, int characterID) {
|
||||
super(swf, ID, NAME, data);
|
||||
this.characterID = characterID;
|
||||
bitmapFormat = DefineBitsLosslessTag.FORMAT_24BIT_RGB;
|
||||
bitmapWidth = 1;
|
||||
bitmapHeight = 1;
|
||||
zlibBitmapData = new ByteArrayRange(createEmptyImage());
|
||||
forceWriteAsLong = true;
|
||||
}
|
||||
|
||||
public DefineBitsLosslessTag(SWFInputStream sis, ByteArrayRange data) throws IOException {
|
||||
super(sis.getSwf(), ID, NAME, data);
|
||||
readData(sis, data, 0, false, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException {
|
||||
characterID = sis.readUI16("characterID");
|
||||
bitmapFormat = sis.readUI8("bitmapFormat");
|
||||
bitmapWidth = sis.readUI16("bitmapWidth");
|
||||
bitmapHeight = sis.readUI16("bitmapHeight");
|
||||
if (bitmapFormat == FORMAT_8BIT_COLORMAPPED) {
|
||||
bitmapColorTableSize = sis.readUI8("bitmapColorTableSize");
|
||||
}
|
||||
|
||||
zlibBitmapData = sis.readByteRangeEx(sis.available(), "zlibBitmapData", DumpInfoSpecialType.ZLIB_DATA, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets data bytes
|
||||
*
|
||||
* @param sos SWF output stream
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
@Override
|
||||
public void getData(SWFOutputStream sos) throws IOException {
|
||||
sos.writeUI16(characterID);
|
||||
sos.writeUI8(bitmapFormat);
|
||||
sos.writeUI16(bitmapWidth);
|
||||
sos.writeUI16(bitmapHeight);
|
||||
if (bitmapFormat == FORMAT_8BIT_COLORMAPPED) {
|
||||
sos.writeUI8(bitmapColorTableSize);
|
||||
}
|
||||
sos.write(zlibBitmapData);
|
||||
}
|
||||
|
||||
private byte[] createEmptyImage() {
|
||||
try {
|
||||
BITMAPDATA bitmapData = new BITMAPDATA();
|
||||
bitmapData.bitmapPixelDataPix24 = new int[]{0xff000000};
|
||||
ByteArrayOutputStream bitmapDataOS = new ByteArrayOutputStream();
|
||||
SWFOutputStream sos = new SWFOutputStream(bitmapDataOS, getVersion());
|
||||
sos.writeBITMAPDATA(bitmapData, FORMAT_24BIT_RGB, 1, 1);
|
||||
ByteArrayOutputStream zlibOS = new ByteArrayOutputStream();
|
||||
SWFOutputStream sos2 = new SWFOutputStream(zlibOS, getVersion());
|
||||
sos2.writeBytesZlib(bitmapDataOS.toByteArray());
|
||||
return zlibOS.toByteArray();
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(DefineBitsLosslessTag.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImage(byte[] data) throws IOException {
|
||||
SerializableImage image = new SerializableImage(ImageHelper.read(data));
|
||||
int width = image.getWidth();
|
||||
int height = image.getHeight();
|
||||
bitmapData = new BITMAPDATA();
|
||||
bitmapData.bitmapPixelDataPix24 = new int[width * height];
|
||||
int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
|
||||
for (int pos = 0; pos < pixels.length; pos++) {
|
||||
// set the reserved bits to 0xff, because:
|
||||
// documentation says 0, but image is sometimes broken with 0, so there is 0xff, which works (maybe alpha?)
|
||||
int argb = pixels[pos] | 0xff000000;
|
||||
bitmapData.bitmapPixelDataPix24[pos] = argb;
|
||||
}
|
||||
|
||||
int format = FORMAT_24BIT_RGB;
|
||||
ByteArrayOutputStream bitmapDataOS = new ByteArrayOutputStream();
|
||||
SWFOutputStream sos = new SWFOutputStream(bitmapDataOS, getVersion());
|
||||
sos.writeBITMAPDATA(bitmapData, format, width, height);
|
||||
ByteArrayOutputStream zlibOS = new ByteArrayOutputStream();
|
||||
SWFOutputStream sos2 = new SWFOutputStream(zlibOS, getVersion());
|
||||
sos2.writeBytesZlib(bitmapDataOS.toByteArray());
|
||||
zlibBitmapData = new ByteArrayRange(zlibOS.toByteArray());
|
||||
bitmapFormat = format;
|
||||
bitmapWidth = width;
|
||||
bitmapHeight = height;
|
||||
decompressed = false;
|
||||
clearCache();
|
||||
setModified(true);
|
||||
}
|
||||
|
||||
public COLORMAPDATA getColorMapData() {
|
||||
if (!decompressed) {
|
||||
uncompressData();
|
||||
}
|
||||
return colorMapData;
|
||||
}
|
||||
|
||||
public BITMAPDATA getBitmapData() {
|
||||
if (!decompressed) {
|
||||
uncompressData();
|
||||
}
|
||||
return bitmapData;
|
||||
}
|
||||
|
||||
private void uncompressData() {
|
||||
try {
|
||||
byte[] uncompressedData = SWFInputStream.uncompressByteArray(zlibBitmapData.getArray(), zlibBitmapData.getPos(), zlibBitmapData.getLength());
|
||||
SWFInputStream sis = new SWFInputStream(swf, uncompressedData);
|
||||
if (bitmapFormat == FORMAT_8BIT_COLORMAPPED) {
|
||||
colorMapData = sis.readCOLORMAPDATA(bitmapColorTableSize, bitmapWidth, bitmapHeight, "colorMapData");
|
||||
} else if ((bitmapFormat == FORMAT_15BIT_RGB) || (bitmapFormat == FORMAT_24BIT_RGB)) {
|
||||
bitmapData = sis.readBITMAPDATA(bitmapFormat, bitmapWidth, bitmapHeight, "bitmapData");
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
decompressed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageFormat getImageFormat() {
|
||||
return ImageFormat.PNG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageFormat getOriginalImageFormat() {
|
||||
return ImageFormat.PNG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getOriginalImageData() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SerializableImage getImage() {
|
||||
int[] pixels = new int[bitmapWidth * bitmapHeight];
|
||||
if (bitmapFormat == DefineBitsLosslessTag.FORMAT_8BIT_COLORMAPPED) {
|
||||
COLORMAPDATA colorMapData = getColorMapData();
|
||||
int pos32aligned = 0;
|
||||
int pos = 0;
|
||||
for (int y = 0; y < bitmapHeight; y++) {
|
||||
for (int x = 0; x < bitmapWidth; x++) {
|
||||
int c = 0;
|
||||
int colorTableIndex = colorMapData.colorMapPixelData[pos32aligned] & 0xff;
|
||||
if (colorTableIndex < colorMapData.colorTableRGB.length) {
|
||||
c = colorMapData.colorTableRGB[colorTableIndex];
|
||||
}
|
||||
|
||||
pixels[pos++] = c;
|
||||
pos32aligned++;
|
||||
}
|
||||
|
||||
while ((pos32aligned % 4 != 0)) {
|
||||
pos32aligned++;
|
||||
}
|
||||
}
|
||||
} else if ((bitmapFormat == DefineBitsLosslessTag.FORMAT_15BIT_RGB) || (bitmapFormat == DefineBitsLosslessTag.FORMAT_24BIT_RGB)) {
|
||||
BITMAPDATA bitmapData = getBitmapData();
|
||||
int pos = 0;
|
||||
int[] bitmapPixelData = null;
|
||||
if (bitmapFormat == DefineBitsLosslessTag.FORMAT_15BIT_RGB) {
|
||||
bitmapPixelData = bitmapData.bitmapPixelDataPix15;
|
||||
} else if (bitmapFormat == DefineBitsLosslessTag.FORMAT_24BIT_RGB) {
|
||||
bitmapPixelData = bitmapData.bitmapPixelDataPix24;
|
||||
}
|
||||
|
||||
for (int y = 0; y < bitmapHeight; y++) {
|
||||
for (int x = 0; x < bitmapWidth; x++) {
|
||||
int c = bitmapPixelData[pos] | 0xff000000;
|
||||
pixels[pos++] = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SerializableImage bi = new SerializableImage(bitmapWidth, bitmapHeight, SerializableImage.TYPE_INT_RGB, pixels);
|
||||
return bi;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getImageDimension() {
|
||||
return new Dimension(bitmapWidth, bitmapHeight);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,290 +1,291 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.tags;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.action.Action;
|
||||
import com.jpexs.decompiler.flash.tags.base.ASMSourceContainer;
|
||||
import com.jpexs.decompiler.flash.tags.base.BoundedTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ButtonAction;
|
||||
import com.jpexs.decompiler.flash.tags.base.ButtonTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
|
||||
import com.jpexs.decompiler.flash.timeline.DepthState;
|
||||
import com.jpexs.decompiler.flash.timeline.Frame;
|
||||
import com.jpexs.decompiler.flash.timeline.Timeline;
|
||||
import com.jpexs.decompiler.flash.types.BUTTONRECORD;
|
||||
import com.jpexs.decompiler.flash.types.BasicType;
|
||||
import com.jpexs.decompiler.flash.types.ColorTransform;
|
||||
import com.jpexs.decompiler.flash.types.MATRIX;
|
||||
import com.jpexs.decompiler.flash.types.RECT;
|
||||
import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFType;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import com.jpexs.helpers.Cache;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Defines a button character
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
@SWFVersion(from = 1)
|
||||
public class DefineButtonTag extends ButtonTag implements ASMSourceContainer {
|
||||
|
||||
public static final int ID = 7;
|
||||
|
||||
public static final String NAME = "DefineButton";
|
||||
|
||||
/**
|
||||
* ID for this character
|
||||
*/
|
||||
@SWFType(BasicType.UI16)
|
||||
public int buttonId;
|
||||
|
||||
/**
|
||||
* Characters that make up the button
|
||||
*/
|
||||
public List<BUTTONRECORD> characters;
|
||||
|
||||
/**
|
||||
* Actions to perform
|
||||
*/
|
||||
@HideInRawEdit
|
||||
public ByteArrayRange actionBytes;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param swf
|
||||
*/
|
||||
public DefineButtonTag(SWF swf) {
|
||||
super(swf, ID, NAME, null);
|
||||
buttonId = swf.getNextCharacterId();
|
||||
characters = new ArrayList<>();
|
||||
actionBytes = ByteArrayRange.EMPTY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param sis
|
||||
* @param data
|
||||
* @throws IOException
|
||||
*/
|
||||
public DefineButtonTag(SWFInputStream sis, ByteArrayRange data) throws IOException {
|
||||
super(sis.getSwf(), ID, NAME, data);
|
||||
readData(sis, data, 0, false, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException {
|
||||
buttonId = sis.readUI16("buttonId");
|
||||
characters = sis.readBUTTONRECORDList(false, "characters");
|
||||
actionBytes = sis.readByteRangeEx(sis.available(), "actionBytes");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets data bytes
|
||||
*
|
||||
* @param sos SWF output stream
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
@Override
|
||||
public void getData(SWFOutputStream sos) throws IOException {
|
||||
sos.writeUI16(buttonId);
|
||||
sos.writeBUTTONRECORDList(characters, false);
|
||||
sos.write(getActionBytes());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCharacterId() {
|
||||
return buttonId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCharacterId(int characterId) {
|
||||
this.buttonId = characterId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BUTTONRECORD> getRecords() {
|
||||
return characters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ButtonAction> getSubItems() {
|
||||
return Arrays.asList(new ButtonAction(this));
|
||||
}
|
||||
|
||||
public void setActions(List<Action> actions) {
|
||||
actionBytes = Action.actionsToByteArrayRange(actions, true, swf.version);
|
||||
}
|
||||
|
||||
public ByteArrayRange getActionBytes() {
|
||||
return actionBytes;
|
||||
}
|
||||
|
||||
public void setActionBytes(byte[] actionBytes) {
|
||||
this.actionBytes = new ByteArrayRange(actionBytes);
|
||||
}
|
||||
|
||||
public void setModified() {
|
||||
setModified(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replaceCharacter(int oldCharacterId, int newCharacterId) {
|
||||
boolean modified = false;
|
||||
for (int i = 0; i < characters.size(); i++) {
|
||||
BUTTONRECORD character = characters.get(i);
|
||||
if (character.characterId == oldCharacterId) {
|
||||
character.characterId = newCharacterId;
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
if (modified) {
|
||||
setModified(true);
|
||||
}
|
||||
return modified;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeCharacter(int characterId) {
|
||||
boolean modified = false;
|
||||
for (int i = 0; i < characters.size(); i++) {
|
||||
if (characters.get(i).characterId == characterId) {
|
||||
characters.remove(i);
|
||||
modified = true;
|
||||
i--;
|
||||
}
|
||||
}
|
||||
if (modified) {
|
||||
setModified(true);
|
||||
}
|
||||
return modified;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RECT getRect(Set<BoundedTag> added) {
|
||||
Cache<CharacterTag, RECT> cache = swf == null ? null : swf.getRectCache();
|
||||
RECT ret = cache == null ? null : cache.get(this);
|
||||
if (ret != null) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
RECT rect = new RECT(Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE);
|
||||
for (BUTTONRECORD r : characters) {
|
||||
CharacterTag ch = swf.getCharacter(r.characterId);
|
||||
if (ch instanceof BoundedTag) {
|
||||
BoundedTag bt = (BoundedTag) ch;
|
||||
if (!added.contains(bt)) {
|
||||
added.add(bt);
|
||||
RECT r2 = bt.getRect(added);
|
||||
added.remove(bt);
|
||||
MATRIX mat = r.placeMatrix;
|
||||
if (mat != null) {
|
||||
r2 = mat.apply(r2);
|
||||
}
|
||||
rect.Xmin = Math.min(r2.Xmin, rect.Xmin);
|
||||
rect.Ymin = Math.min(r2.Ymin, rect.Ymin);
|
||||
rect.Xmax = Math.max(r2.Xmax, rect.Xmax);
|
||||
rect.Ymax = Math.max(r2.Ymax, rect.Ymax);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cache != null) {
|
||||
cache.put(this, rect);
|
||||
}
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean trackAsMenu() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumFrames() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initTimeline(Timeline timeline) {
|
||||
DefineButtonCxformTag cxformTag = (DefineButtonCxformTag) swf.getCharacterIdTag(buttonId, DefineButtonCxformTag.ID);
|
||||
ColorTransform clrTrans = cxformTag == null ? null : cxformTag.buttonColorTransform;
|
||||
int maxDepth = 0;
|
||||
Frame frameUp = new Frame(timeline, 0);
|
||||
Frame frameDown = new Frame(timeline, 0);
|
||||
Frame frameOver = new Frame(timeline, 0);
|
||||
Frame frameHit = new Frame(timeline, 0);
|
||||
for (BUTTONRECORD r : this.characters) {
|
||||
|
||||
DepthState layer = new DepthState(swf, null);
|
||||
layer.colorTransForm = clrTrans;
|
||||
layer.blendMode = r.blendMode;
|
||||
layer.filters = r.filterList;
|
||||
layer.matrix = r.placeMatrix;
|
||||
layer.characterId = r.characterId;
|
||||
if (r.placeDepth > maxDepth) {
|
||||
maxDepth = r.placeDepth;
|
||||
}
|
||||
|
||||
if (r.buttonStateUp) {
|
||||
frameUp.layers.put(r.placeDepth, new DepthState(layer, frameUp, false));
|
||||
}
|
||||
if (r.buttonStateDown) {
|
||||
frameDown.layers.put(r.placeDepth, new DepthState(layer, frameDown, false));
|
||||
}
|
||||
if (r.buttonStateOver) {
|
||||
frameOver.layers.put(r.placeDepth, new DepthState(layer, frameOver, false));
|
||||
}
|
||||
if (r.buttonStateHitTest) {
|
||||
frameHit.layers.put(r.placeDepth, new DepthState(layer, frameHit, false));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
timeline.addFrame(frameUp);
|
||||
|
||||
if (frameOver.layers.isEmpty()) {
|
||||
frameOver = frameUp;
|
||||
}
|
||||
|
||||
timeline.addFrame(frameOver);
|
||||
|
||||
if (frameDown.layers.isEmpty()) {
|
||||
frameDown = frameOver;
|
||||
}
|
||||
|
||||
timeline.addFrame(frameDown);
|
||||
|
||||
if (frameHit.layers.isEmpty()) {
|
||||
frameHit = frameUp;
|
||||
}
|
||||
|
||||
timeline.addFrame(frameHit);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.tags;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.action.Action;
|
||||
import com.jpexs.decompiler.flash.dumpview.DumpInfoSpecialType;
|
||||
import com.jpexs.decompiler.flash.tags.base.ASMSourceContainer;
|
||||
import com.jpexs.decompiler.flash.tags.base.BoundedTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ButtonAction;
|
||||
import com.jpexs.decompiler.flash.tags.base.ButtonTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
|
||||
import com.jpexs.decompiler.flash.timeline.DepthState;
|
||||
import com.jpexs.decompiler.flash.timeline.Frame;
|
||||
import com.jpexs.decompiler.flash.timeline.Timeline;
|
||||
import com.jpexs.decompiler.flash.types.BUTTONRECORD;
|
||||
import com.jpexs.decompiler.flash.types.BasicType;
|
||||
import com.jpexs.decompiler.flash.types.ColorTransform;
|
||||
import com.jpexs.decompiler.flash.types.MATRIX;
|
||||
import com.jpexs.decompiler.flash.types.RECT;
|
||||
import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFType;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import com.jpexs.helpers.Cache;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Defines a button character
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
@SWFVersion(from = 1)
|
||||
public class DefineButtonTag extends ButtonTag implements ASMSourceContainer {
|
||||
|
||||
public static final int ID = 7;
|
||||
|
||||
public static final String NAME = "DefineButton";
|
||||
|
||||
/**
|
||||
* ID for this character
|
||||
*/
|
||||
@SWFType(BasicType.UI16)
|
||||
public int buttonId;
|
||||
|
||||
/**
|
||||
* Characters that make up the button
|
||||
*/
|
||||
public List<BUTTONRECORD> characters;
|
||||
|
||||
/**
|
||||
* Actions to perform
|
||||
*/
|
||||
@HideInRawEdit
|
||||
public ByteArrayRange actionBytes;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param swf
|
||||
*/
|
||||
public DefineButtonTag(SWF swf) {
|
||||
super(swf, ID, NAME, null);
|
||||
buttonId = swf.getNextCharacterId();
|
||||
characters = new ArrayList<>();
|
||||
actionBytes = ByteArrayRange.EMPTY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param sis
|
||||
* @param data
|
||||
* @throws IOException
|
||||
*/
|
||||
public DefineButtonTag(SWFInputStream sis, ByteArrayRange data) throws IOException {
|
||||
super(sis.getSwf(), ID, NAME, data);
|
||||
readData(sis, data, 0, false, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException {
|
||||
buttonId = sis.readUI16("buttonId");
|
||||
characters = sis.readBUTTONRECORDList(false, "characters");
|
||||
actionBytes = sis.readByteRangeEx(sis.available(), "actionBytes", DumpInfoSpecialType.ACTION_BYTES, sis.getPos());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets data bytes
|
||||
*
|
||||
* @param sos SWF output stream
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
@Override
|
||||
public void getData(SWFOutputStream sos) throws IOException {
|
||||
sos.writeUI16(buttonId);
|
||||
sos.writeBUTTONRECORDList(characters, false);
|
||||
sos.write(getActionBytes());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCharacterId() {
|
||||
return buttonId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCharacterId(int characterId) {
|
||||
this.buttonId = characterId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BUTTONRECORD> getRecords() {
|
||||
return characters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ButtonAction> getSubItems() {
|
||||
return Arrays.asList(new ButtonAction(this));
|
||||
}
|
||||
|
||||
public void setActions(List<Action> actions) {
|
||||
actionBytes = Action.actionsToByteArrayRange(actions, true, swf.version);
|
||||
}
|
||||
|
||||
public ByteArrayRange getActionBytes() {
|
||||
return actionBytes;
|
||||
}
|
||||
|
||||
public void setActionBytes(byte[] actionBytes) {
|
||||
this.actionBytes = new ByteArrayRange(actionBytes);
|
||||
}
|
||||
|
||||
public void setModified() {
|
||||
setModified(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replaceCharacter(int oldCharacterId, int newCharacterId) {
|
||||
boolean modified = false;
|
||||
for (int i = 0; i < characters.size(); i++) {
|
||||
BUTTONRECORD character = characters.get(i);
|
||||
if (character.characterId == oldCharacterId) {
|
||||
character.characterId = newCharacterId;
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
if (modified) {
|
||||
setModified(true);
|
||||
}
|
||||
return modified;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeCharacter(int characterId) {
|
||||
boolean modified = false;
|
||||
for (int i = 0; i < characters.size(); i++) {
|
||||
if (characters.get(i).characterId == characterId) {
|
||||
characters.remove(i);
|
||||
modified = true;
|
||||
i--;
|
||||
}
|
||||
}
|
||||
if (modified) {
|
||||
setModified(true);
|
||||
}
|
||||
return modified;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RECT getRect(Set<BoundedTag> added) {
|
||||
Cache<CharacterTag, RECT> cache = swf == null ? null : swf.getRectCache();
|
||||
RECT ret = cache == null ? null : cache.get(this);
|
||||
if (ret != null) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
RECT rect = new RECT(Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE);
|
||||
for (BUTTONRECORD r : characters) {
|
||||
CharacterTag ch = swf.getCharacter(r.characterId);
|
||||
if (ch instanceof BoundedTag) {
|
||||
BoundedTag bt = (BoundedTag) ch;
|
||||
if (!added.contains(bt)) {
|
||||
added.add(bt);
|
||||
RECT r2 = bt.getRect(added);
|
||||
added.remove(bt);
|
||||
MATRIX mat = r.placeMatrix;
|
||||
if (mat != null) {
|
||||
r2 = mat.apply(r2);
|
||||
}
|
||||
rect.Xmin = Math.min(r2.Xmin, rect.Xmin);
|
||||
rect.Ymin = Math.min(r2.Ymin, rect.Ymin);
|
||||
rect.Xmax = Math.max(r2.Xmax, rect.Xmax);
|
||||
rect.Ymax = Math.max(r2.Ymax, rect.Ymax);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cache != null) {
|
||||
cache.put(this, rect);
|
||||
}
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean trackAsMenu() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumFrames() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initTimeline(Timeline timeline) {
|
||||
DefineButtonCxformTag cxformTag = (DefineButtonCxformTag) swf.getCharacterIdTag(buttonId, DefineButtonCxformTag.ID);
|
||||
ColorTransform clrTrans = cxformTag == null ? null : cxformTag.buttonColorTransform;
|
||||
int maxDepth = 0;
|
||||
Frame frameUp = new Frame(timeline, 0);
|
||||
Frame frameDown = new Frame(timeline, 0);
|
||||
Frame frameOver = new Frame(timeline, 0);
|
||||
Frame frameHit = new Frame(timeline, 0);
|
||||
for (BUTTONRECORD r : this.characters) {
|
||||
|
||||
DepthState layer = new DepthState(swf, null);
|
||||
layer.colorTransForm = clrTrans;
|
||||
layer.blendMode = r.blendMode;
|
||||
layer.filters = r.filterList;
|
||||
layer.matrix = r.placeMatrix;
|
||||
layer.characterId = r.characterId;
|
||||
if (r.placeDepth > maxDepth) {
|
||||
maxDepth = r.placeDepth;
|
||||
}
|
||||
|
||||
if (r.buttonStateUp) {
|
||||
frameUp.layers.put(r.placeDepth, new DepthState(layer, frameUp, false));
|
||||
}
|
||||
if (r.buttonStateDown) {
|
||||
frameDown.layers.put(r.placeDepth, new DepthState(layer, frameDown, false));
|
||||
}
|
||||
if (r.buttonStateOver) {
|
||||
frameOver.layers.put(r.placeDepth, new DepthState(layer, frameOver, false));
|
||||
}
|
||||
if (r.buttonStateHitTest) {
|
||||
frameHit.layers.put(r.placeDepth, new DepthState(layer, frameHit, false));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
timeline.addFrame(frameUp);
|
||||
|
||||
if (frameOver.layers.isEmpty()) {
|
||||
frameOver = frameUp;
|
||||
}
|
||||
|
||||
timeline.addFrame(frameOver);
|
||||
|
||||
if (frameDown.layers.isEmpty()) {
|
||||
frameDown = frameOver;
|
||||
}
|
||||
|
||||
timeline.addFrame(frameDown);
|
||||
|
||||
if (frameHit.layers.isEmpty()) {
|
||||
frameHit = frameUp;
|
||||
}
|
||||
|
||||
timeline.addFrame(frameHit);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,229 +1,229 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.tags;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.ExportRectangle;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.Point;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterIdTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.DrawableTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.RenderContext;
|
||||
import com.jpexs.decompiler.flash.types.BasicType;
|
||||
import com.jpexs.decompiler.flash.types.RECT;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFType;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Shape;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.GeneralPath;
|
||||
import java.awt.geom.PathIterator;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
@SWFVersion(from = 8)
|
||||
public class DefineScalingGridTag extends Tag implements CharacterIdTag {
|
||||
|
||||
public static final int ID = 78;
|
||||
|
||||
public static final String NAME = "DefineScalingGrid";
|
||||
|
||||
@SWFType(BasicType.UI16)
|
||||
public int characterId;
|
||||
|
||||
public RECT splitter;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param swf
|
||||
*/
|
||||
public DefineScalingGridTag(SWF swf) {
|
||||
super(swf, ID, NAME, null);
|
||||
splitter = new RECT();
|
||||
}
|
||||
|
||||
public DefineScalingGridTag(SWFInputStream sis, ByteArrayRange data) throws IOException {
|
||||
super(sis.getSwf(), ID, NAME, data);
|
||||
readData(sis, data, 0, false, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException {
|
||||
characterId = sis.readUI16("characterId");
|
||||
splitter = sis.readRECT("splitter");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets data bytes
|
||||
*
|
||||
* @param sos SWF output stream
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
@Override
|
||||
public void getData(SWFOutputStream sos) throws IOException {
|
||||
sos.writeUI16(characterId);
|
||||
sos.writeRECT(splitter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCharacterId() {
|
||||
return characterId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCharacterId(int characterId) {
|
||||
this.characterId = characterId;
|
||||
}
|
||||
|
||||
private static double roundPixels(double v) {
|
||||
return v; //Math.rint(v / SWF.unitDivisor) * SWF.unitDivisor;
|
||||
}
|
||||
|
||||
private static double roundPixels20(double v) {
|
||||
return Math.rint(v / SWF.unitDivisor) * SWF.unitDivisor;
|
||||
}
|
||||
|
||||
private static Matrix rectToRectMatrix(ExportRectangle fromRect, ExportRectangle toRect) {
|
||||
Matrix toOrigin = Matrix.getTranslateInstance(roundPixels(-fromRect.xMin), roundPixels(-fromRect.yMin));
|
||||
Matrix scale = new Matrix();
|
||||
scale.scaleX = roundPixels(toRect.getWidth()) / roundPixels(fromRect.getWidth());
|
||||
scale.scaleY = roundPixels(toRect.getHeight()) / roundPixels(fromRect.getHeight());
|
||||
Matrix toDest = Matrix.getTranslateInstance(roundPixels(toRect.xMin), roundPixels(toRect.yMin));
|
||||
return toOrigin.preConcatenate(scale).preConcatenate(toDest);
|
||||
}
|
||||
|
||||
public RECT getRect() {
|
||||
Shape s = getOutline(0, 0, 0, new RenderContext(), new Matrix(), new Matrix(), true);
|
||||
if (s == null) {
|
||||
return null;
|
||||
}
|
||||
Rectangle r = s.getBounds();
|
||||
return new RECT(r.x, r.x + r.width, r.y, r.y + r.height);
|
||||
}
|
||||
|
||||
public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation, Matrix prevTransform, boolean stroked) {
|
||||
CharacterTag ct = swf.getCharacter(characterId);
|
||||
if (ct == null) {
|
||||
return null;
|
||||
}
|
||||
if (!(ct instanceof DrawableTag)) {
|
||||
return null;
|
||||
}
|
||||
double[] coords = new double[6];
|
||||
|
||||
DrawableTag dt = (DrawableTag) ct;
|
||||
Shape path = dt.getOutline(frame, time, ratio, renderContext, transformation, stroked);
|
||||
PathIterator iterator = path.getPathIterator(new AffineTransform());
|
||||
GeneralPath gp = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
|
||||
ExportRectangle boundsRect = new ExportRectangle(dt.getRect());
|
||||
ExportRectangle scalingGrid = new ExportRectangle(splitter);
|
||||
|
||||
ExportRectangle[] sourceRect = new ExportRectangle[9];
|
||||
ExportRectangle[] targetRect = new ExportRectangle[9];
|
||||
Matrix[] transforms = new Matrix[9];
|
||||
|
||||
getSlices(transformation.transform(boundsRect), boundsRect, scalingGrid, sourceRect, targetRect, transforms);
|
||||
|
||||
while (!iterator.isDone()) {
|
||||
int type = iterator.currentSegment(coords);
|
||||
for (int i = 0; i < 6; i += 2) {
|
||||
double x = coords[i];
|
||||
double y = coords[i + 1];
|
||||
for (int s = 0; s < 9; s++) {
|
||||
Point p = new Point(x, y);
|
||||
if (sourceRect[s].contains(p)) {
|
||||
p = transforms[s].transform(p);
|
||||
coords[i] = p.x;
|
||||
coords[i + 1] = p.y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
switch (type) {
|
||||
case PathIterator.SEG_MOVETO:
|
||||
gp.moveTo(coords[0], coords[1]);
|
||||
break;
|
||||
case PathIterator.SEG_LINETO:
|
||||
gp.lineTo(coords[0], coords[1]);
|
||||
break;
|
||||
case PathIterator.SEG_QUADTO:
|
||||
gp.quadTo(coords[0], coords[1], coords[2], coords[3]);
|
||||
break;
|
||||
case PathIterator.SEG_CUBICTO:
|
||||
gp.curveTo(coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]);
|
||||
break;
|
||||
case PathIterator.SEG_CLOSE:
|
||||
gp.closePath();
|
||||
break;
|
||||
}
|
||||
iterator.next();
|
||||
}
|
||||
return gp;
|
||||
}
|
||||
|
||||
public static void getSlices(ExportRectangle targetBounds, ExportRectangle boundsRect, ExportRectangle scalingGrid, ExportRectangle[] sourceRect, ExportRectangle[] targetRect, Matrix[] transforms) {
|
||||
|
||||
double src_x[] = new double[]{boundsRect.xMin, scalingGrid.xMin, scalingGrid.xMax, boundsRect.xMax};
|
||||
double dst_x[] = new double[]{targetBounds.xMin, targetBounds.xMin + scalingGrid.xMin, targetBounds.xMax - (boundsRect.xMax - scalingGrid.xMax), targetBounds.xMax};
|
||||
|
||||
double src_y[] = new double[]{boundsRect.yMin, scalingGrid.yMin, scalingGrid.yMax, boundsRect.yMax};
|
||||
double dst_y[] = new double[]{targetBounds.yMin, targetBounds.yMin + scalingGrid.yMin, targetBounds.yMax - (boundsRect.yMax - scalingGrid.yMax), targetBounds.yMax};
|
||||
|
||||
int pos = 0;
|
||||
for (int sy = 0; sy < 3; sy++) {
|
||||
for (int sx = 0; sx < 3; sx++) {
|
||||
sourceRect[pos] = new ExportRectangle(src_x[sx], src_y[sy], src_x[sx + 1], src_y[sy + 1]);
|
||||
targetRect[pos] = new ExportRectangle(dst_x[sx], dst_y[sy], dst_x[sx + 1], dst_y[sy + 1]);
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < targetRect.length; i++) {
|
||||
|
||||
/* sourceRect[i].xMax = roundPixels20(sourceRect[i].xMax);
|
||||
sourceRect[i].yMax = roundPixels20(sourceRect[i].yMax);
|
||||
sourceRect[i].xMin = roundPixels20(sourceRect[i].xMin);
|
||||
sourceRect[i].yMin = roundPixels20(sourceRect[i].yMin);
|
||||
*/
|
||||
//System.out.println("source[" + i + "]=" + sourceRect[i]);
|
||||
//System.out.println("target[" + i + "]=" + targetRect[i]);
|
||||
|
||||
/*targetRect[i].xMax = roundPixels20(targetRect[i].xMax);
|
||||
targetRect[i].yMax = roundPixels20(targetRect[i].yMax);
|
||||
targetRect[i].xMin = roundPixels20(targetRect[i].xMin);
|
||||
targetRect[i].yMin = roundPixels20(targetRect[i].yMin);
|
||||
*/
|
||||
transforms[i] = rectToRectMatrix(sourceRect[i], targetRect[i]);
|
||||
|
||||
targetRect[i].xMax = Math.rint(targetRect[i].xMax / SWF.unitDivisor);
|
||||
targetRect[i].yMax = Math.rint(targetRect[i].yMax / SWF.unitDivisor);
|
||||
targetRect[i].xMin = Math.rint(targetRect[i].xMin / SWF.unitDivisor);
|
||||
targetRect[i].yMin = Math.rint(targetRect[i].yMin / SWF.unitDivisor);
|
||||
|
||||
//targetRect[i].xMax += maxStroke;
|
||||
//Round to pixel boundary
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.tags;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.ExportRectangle;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.Point;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterIdTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.DrawableTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.RenderContext;
|
||||
import com.jpexs.decompiler.flash.types.BasicType;
|
||||
import com.jpexs.decompiler.flash.types.RECT;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFType;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Shape;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.GeneralPath;
|
||||
import java.awt.geom.PathIterator;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
@SWFVersion(from = 8)
|
||||
public class DefineScalingGridTag extends Tag implements CharacterIdTag {
|
||||
|
||||
public static final int ID = 78;
|
||||
|
||||
public static final String NAME = "DefineScalingGrid";
|
||||
|
||||
@SWFType(BasicType.UI16)
|
||||
public int characterId;
|
||||
|
||||
public RECT splitter;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param swf
|
||||
*/
|
||||
public DefineScalingGridTag(SWF swf) {
|
||||
super(swf, ID, NAME, null);
|
||||
splitter = new RECT();
|
||||
}
|
||||
|
||||
public DefineScalingGridTag(SWFInputStream sis, ByteArrayRange data) throws IOException {
|
||||
super(sis.getSwf(), ID, NAME, data);
|
||||
readData(sis, data, 0, false, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException {
|
||||
characterId = sis.readUI16("characterId");
|
||||
splitter = sis.readRECT("splitter");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets data bytes
|
||||
*
|
||||
* @param sos SWF output stream
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
@Override
|
||||
public void getData(SWFOutputStream sos) throws IOException {
|
||||
sos.writeUI16(characterId);
|
||||
sos.writeRECT(splitter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCharacterId() {
|
||||
return characterId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCharacterId(int characterId) {
|
||||
this.characterId = characterId;
|
||||
}
|
||||
|
||||
private static double roundPixels(double v) {
|
||||
return v; //Math.rint(v / SWF.unitDivisor) * SWF.unitDivisor;
|
||||
}
|
||||
|
||||
private static double roundPixels20(double v) {
|
||||
return Math.rint(v / SWF.unitDivisor) * SWF.unitDivisor;
|
||||
}
|
||||
|
||||
private static Matrix rectToRectMatrix(ExportRectangle fromRect, ExportRectangle toRect) {
|
||||
Matrix toOrigin = Matrix.getTranslateInstance(roundPixels(-fromRect.xMin), roundPixels(-fromRect.yMin));
|
||||
Matrix scale = new Matrix();
|
||||
scale.scaleX = roundPixels(toRect.getWidth()) / roundPixels(fromRect.getWidth());
|
||||
scale.scaleY = roundPixels(toRect.getHeight()) / roundPixels(fromRect.getHeight());
|
||||
Matrix toDest = Matrix.getTranslateInstance(roundPixels(toRect.xMin), roundPixels(toRect.yMin));
|
||||
return toOrigin.preConcatenate(scale).preConcatenate(toDest);
|
||||
}
|
||||
|
||||
public RECT getRect() {
|
||||
Shape s = getOutline(0, 0, 0, new RenderContext(), new Matrix(), new Matrix(), true);
|
||||
if (s == null) {
|
||||
return null;
|
||||
}
|
||||
Rectangle r = s.getBounds();
|
||||
return new RECT(r.x, r.x + r.width, r.y, r.y + r.height);
|
||||
}
|
||||
|
||||
public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation, Matrix prevTransform, boolean stroked) {
|
||||
CharacterTag ct = swf.getCharacter(characterId);
|
||||
if (ct == null) {
|
||||
return null;
|
||||
}
|
||||
if (!(ct instanceof DrawableTag)) {
|
||||
return null;
|
||||
}
|
||||
double[] coords = new double[6];
|
||||
|
||||
DrawableTag dt = (DrawableTag) ct;
|
||||
Shape path = dt.getOutline(frame, time, ratio, renderContext, transformation, stroked);
|
||||
PathIterator iterator = path.getPathIterator(new AffineTransform());
|
||||
GeneralPath gp = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
|
||||
ExportRectangle boundsRect = new ExportRectangle(dt.getRect());
|
||||
ExportRectangle scalingGrid = new ExportRectangle(splitter);
|
||||
|
||||
ExportRectangle[] sourceRect = new ExportRectangle[9];
|
||||
ExportRectangle[] targetRect = new ExportRectangle[9];
|
||||
Matrix[] transforms = new Matrix[9];
|
||||
|
||||
getSlices(transformation.transform(boundsRect), boundsRect, scalingGrid, sourceRect, targetRect, transforms);
|
||||
|
||||
while (!iterator.isDone()) {
|
||||
int type = iterator.currentSegment(coords);
|
||||
for (int i = 0; i < 6; i += 2) {
|
||||
double x = coords[i];
|
||||
double y = coords[i + 1];
|
||||
for (int s = 0; s < 9; s++) {
|
||||
Point p = new Point(x, y);
|
||||
if (sourceRect[s].contains(p)) {
|
||||
p = transforms[s].transform(p);
|
||||
coords[i] = p.x;
|
||||
coords[i + 1] = p.y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
switch (type) {
|
||||
case PathIterator.SEG_MOVETO:
|
||||
gp.moveTo(coords[0], coords[1]);
|
||||
break;
|
||||
case PathIterator.SEG_LINETO:
|
||||
gp.lineTo(coords[0], coords[1]);
|
||||
break;
|
||||
case PathIterator.SEG_QUADTO:
|
||||
gp.quadTo(coords[0], coords[1], coords[2], coords[3]);
|
||||
break;
|
||||
case PathIterator.SEG_CUBICTO:
|
||||
gp.curveTo(coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]);
|
||||
break;
|
||||
case PathIterator.SEG_CLOSE:
|
||||
gp.closePath();
|
||||
break;
|
||||
}
|
||||
iterator.next();
|
||||
}
|
||||
return gp;
|
||||
}
|
||||
|
||||
public static void getSlices(ExportRectangle targetBounds, ExportRectangle boundsRect, ExportRectangle scalingGrid, ExportRectangle[] sourceRect, ExportRectangle[] targetRect, Matrix[] transforms) {
|
||||
|
||||
double[] src_x = new double[]{boundsRect.xMin, scalingGrid.xMin, scalingGrid.xMax, boundsRect.xMax};
|
||||
double[] dst_x = new double[]{targetBounds.xMin, targetBounds.xMin + scalingGrid.xMin, targetBounds.xMax - (boundsRect.xMax - scalingGrid.xMax), targetBounds.xMax};
|
||||
|
||||
double[] src_y = new double[]{boundsRect.yMin, scalingGrid.yMin, scalingGrid.yMax, boundsRect.yMax};
|
||||
double[] dst_y = new double[]{targetBounds.yMin, targetBounds.yMin + scalingGrid.yMin, targetBounds.yMax - (boundsRect.yMax - scalingGrid.yMax), targetBounds.yMax};
|
||||
|
||||
int pos = 0;
|
||||
for (int sy = 0; sy < 3; sy++) {
|
||||
for (int sx = 0; sx < 3; sx++) {
|
||||
sourceRect[pos] = new ExportRectangle(src_x[sx], src_y[sy], src_x[sx + 1], src_y[sy + 1]);
|
||||
targetRect[pos] = new ExportRectangle(dst_x[sx], dst_y[sy], dst_x[sx + 1], dst_y[sy + 1]);
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < targetRect.length; i++) {
|
||||
|
||||
/* sourceRect[i].xMax = roundPixels20(sourceRect[i].xMax);
|
||||
sourceRect[i].yMax = roundPixels20(sourceRect[i].yMax);
|
||||
sourceRect[i].xMin = roundPixels20(sourceRect[i].xMin);
|
||||
sourceRect[i].yMin = roundPixels20(sourceRect[i].yMin);
|
||||
*/
|
||||
//System.out.println("source[" + i + "]=" + sourceRect[i]);
|
||||
//System.out.println("target[" + i + "]=" + targetRect[i]);
|
||||
|
||||
/*targetRect[i].xMax = roundPixels20(targetRect[i].xMax);
|
||||
targetRect[i].yMax = roundPixels20(targetRect[i].yMax);
|
||||
targetRect[i].xMin = roundPixels20(targetRect[i].xMin);
|
||||
targetRect[i].yMin = roundPixels20(targetRect[i].yMin);
|
||||
*/
|
||||
transforms[i] = rectToRectMatrix(sourceRect[i], targetRect[i]);
|
||||
|
||||
targetRect[i].xMax = Math.rint(targetRect[i].xMax / SWF.unitDivisor);
|
||||
targetRect[i].yMax = Math.rint(targetRect[i].yMax / SWF.unitDivisor);
|
||||
targetRect[i].xMin = Math.rint(targetRect[i].xMin / SWF.unitDivisor);
|
||||
targetRect[i].yMin = Math.rint(targetRect[i].yMin / SWF.unitDivisor);
|
||||
|
||||
//targetRect[i].xMax += maxStroke;
|
||||
//Round to pixel boundary
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,145 +1,146 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.tags;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.ABCInputStream;
|
||||
import com.jpexs.decompiler.flash.abc.types.ScriptInfo;
|
||||
import com.jpexs.decompiler.flash.types.BasicType;
|
||||
import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFField;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFType;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Defines a series of ActionScript 3 bytecodes to be executed
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
@SWFVersion(from = 9)
|
||||
public class DoABC2Tag extends Tag implements ABCContainerTag {
|
||||
|
||||
public static final int ID = 82;
|
||||
|
||||
public static final String NAME = "DoABC2";
|
||||
|
||||
/**
|
||||
* ActionScript 3 bytecodes
|
||||
*/
|
||||
@HideInRawEdit
|
||||
@SWFField
|
||||
private ABC abc;
|
||||
|
||||
/**
|
||||
* A 32-bit flags value, which may contain the following bits set:
|
||||
* kDoAbcLazyInitializeFlag = 1: Indicates that the ABC block should not be
|
||||
* executed immediately, but only parsed. A later finddef may cause its
|
||||
* scripts to execute.
|
||||
*/
|
||||
@SWFType(BasicType.UI32)
|
||||
public long flags;
|
||||
|
||||
/**
|
||||
* The name assigned to the bytecode.
|
||||
*/
|
||||
public String name;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param swf
|
||||
*/
|
||||
public DoABC2Tag(SWF swf) {
|
||||
super(swf, ID, NAME, null);
|
||||
name = "New DoABC";
|
||||
abc = new ABC(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param sis
|
||||
* @param data
|
||||
* @throws IOException
|
||||
*/
|
||||
public DoABC2Tag(SWFInputStream sis, ByteArrayRange data) throws IOException {
|
||||
super(sis.getSwf(), ID, NAME, data);
|
||||
readData(sis, data, 0, false, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException {
|
||||
flags = sis.readUI32("flags");
|
||||
name = sis.readString("name");
|
||||
|
||||
ABCInputStream ais = new ABCInputStream(sis.getBaseStream());
|
||||
|
||||
// put it to the dumpview:
|
||||
sis.readByteRangeEx(sis.available(), "abcBytes");
|
||||
abc = new ABC(ais, swf, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets data bytes
|
||||
*
|
||||
* @param sos SWF output stream
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
@Override
|
||||
public void getData(SWFOutputStream sos) throws IOException {
|
||||
sos.writeUI32(flags);
|
||||
sos.writeString(name);
|
||||
abc.saveToStream(sos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ABC getABC() {
|
||||
return abc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return super.getName() + " (" + name + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(ABCContainerTag o) {
|
||||
if (o instanceof DoABC2Tag) {
|
||||
DoABC2Tag n = (DoABC2Tag) o;
|
||||
int lastCmp = name.compareTo(n.name);
|
||||
return (lastCmp != 0 ? lastCmp
|
||||
: name.compareTo(n.name));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setModified(boolean value) {
|
||||
super.setModified(value);
|
||||
if (value == false && !isModified()) {
|
||||
ABC abc = getABC();
|
||||
for (ScriptInfo si : abc.script_info) {
|
||||
si.setModified(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.tags;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.ABCInputStream;
|
||||
import com.jpexs.decompiler.flash.abc.types.ScriptInfo;
|
||||
import com.jpexs.decompiler.flash.dumpview.DumpInfoSpecialType;
|
||||
import com.jpexs.decompiler.flash.types.BasicType;
|
||||
import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFField;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFType;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Defines a series of ActionScript 3 bytecodes to be executed
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
@SWFVersion(from = 9)
|
||||
public class DoABC2Tag extends Tag implements ABCContainerTag {
|
||||
|
||||
public static final int ID = 82;
|
||||
|
||||
public static final String NAME = "DoABC2";
|
||||
|
||||
/**
|
||||
* ActionScript 3 bytecodes
|
||||
*/
|
||||
@HideInRawEdit
|
||||
@SWFField
|
||||
private ABC abc;
|
||||
|
||||
/**
|
||||
* A 32-bit flags value, which may contain the following bits set:
|
||||
* kDoAbcLazyInitializeFlag = 1: Indicates that the ABC block should not be
|
||||
* executed immediately, but only parsed. A later finddef may cause its
|
||||
* scripts to execute.
|
||||
*/
|
||||
@SWFType(BasicType.UI32)
|
||||
public long flags;
|
||||
|
||||
/**
|
||||
* The name assigned to the bytecode.
|
||||
*/
|
||||
public String name;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param swf
|
||||
*/
|
||||
public DoABC2Tag(SWF swf) {
|
||||
super(swf, ID, NAME, null);
|
||||
name = "New DoABC";
|
||||
abc = new ABC(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param sis
|
||||
* @param data
|
||||
* @throws IOException
|
||||
*/
|
||||
public DoABC2Tag(SWFInputStream sis, ByteArrayRange data) throws IOException {
|
||||
super(sis.getSwf(), ID, NAME, data);
|
||||
readData(sis, data, 0, false, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException {
|
||||
flags = sis.readUI32("flags");
|
||||
name = sis.readString("name");
|
||||
|
||||
ABCInputStream ais = new ABCInputStream(sis.getBaseStream());
|
||||
|
||||
// put it to the dumpview:
|
||||
sis.readByteRangeEx(sis.available(), "abcBytes", DumpInfoSpecialType.ABC_BYTES, null);
|
||||
abc = new ABC(ais, swf, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets data bytes
|
||||
*
|
||||
* @param sos SWF output stream
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
@Override
|
||||
public void getData(SWFOutputStream sos) throws IOException {
|
||||
sos.writeUI32(flags);
|
||||
sos.writeString(name);
|
||||
abc.saveToStream(sos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ABC getABC() {
|
||||
return abc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return super.getName() + " (" + name + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(ABCContainerTag o) {
|
||||
if (o instanceof DoABC2Tag) {
|
||||
DoABC2Tag n = (DoABC2Tag) o;
|
||||
int lastCmp = name.compareTo(n.name);
|
||||
return (lastCmp != 0 ? lastCmp
|
||||
: name.compareTo(n.name));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setModified(boolean value) {
|
||||
super.setModified(value);
|
||||
if (value == false && !isModified()) {
|
||||
ABC abc = getABC();
|
||||
for (ScriptInfo si : abc.script_info) {
|
||||
si.setModified(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.ABCInputStream;
|
||||
import com.jpexs.decompiler.flash.abc.types.ScriptInfo;
|
||||
import com.jpexs.decompiler.flash.dumpview.DumpInfoSpecialType;
|
||||
import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFField;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
|
||||
@@ -72,9 +73,9 @@ public class DoABCTag extends Tag implements ABCContainerTag {
|
||||
@Override
|
||||
public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException {
|
||||
ABCInputStream ais = new ABCInputStream(sis.getBaseStream());
|
||||
|
||||
|
||||
// put it to the dumpview:
|
||||
sis.readByteRangeEx(sis.available(), "abcBytes");
|
||||
sis.readByteRangeEx(sis.available(), "abcBytes", DumpInfoSpecialType.ABC_BYTES, null);
|
||||
abc = new ABC(ais, swf, this);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.action.Action;
|
||||
import com.jpexs.decompiler.flash.action.ActionList;
|
||||
import com.jpexs.decompiler.flash.action.ConstantPoolTooBigException;
|
||||
import com.jpexs.decompiler.flash.dumpview.DumpInfoSpecialType;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
|
||||
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
|
||||
import com.jpexs.decompiler.flash.tags.base.ASMSource;
|
||||
@@ -102,7 +103,7 @@ public class DoActionTag extends Tag implements ASMSource {
|
||||
|
||||
@Override
|
||||
public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException {
|
||||
actionBytes = sis.readByteRangeEx(sis.available(), "actionBytes");
|
||||
actionBytes = sis.readByteRangeEx(sis.available(), "actionBytes", DumpInfoSpecialType.ACTION_BYTES, sis.getPos());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,252 +1,253 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.tags;
|
||||
|
||||
import com.jpexs.decompiler.flash.DisassemblyListener;
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.action.Action;
|
||||
import com.jpexs.decompiler.flash.action.ActionList;
|
||||
import com.jpexs.decompiler.flash.action.ConstantPoolTooBigException;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
|
||||
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
|
||||
import com.jpexs.decompiler.flash.tags.base.ASMSource;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterIdTag;
|
||||
import com.jpexs.decompiler.flash.types.BasicType;
|
||||
import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Internal;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFType;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
@SWFVersion(from = 6)
|
||||
public class DoInitActionTag extends Tag implements CharacterIdTag, ASMSource {
|
||||
|
||||
public static final int ID = 59;
|
||||
|
||||
public static final String NAME = "DoInitAction";
|
||||
|
||||
/**
|
||||
* Identifier of Sprite
|
||||
*/
|
||||
@SWFType(BasicType.UI16)
|
||||
public int spriteId = 0;
|
||||
|
||||
/**
|
||||
* List of actions to perform
|
||||
*/
|
||||
@HideInRawEdit
|
||||
public ByteArrayRange actionBytes;
|
||||
|
||||
@Internal
|
||||
private String scriptName = "-";
|
||||
|
||||
@Override
|
||||
public String getScriptName() {
|
||||
return scriptName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param swf
|
||||
*/
|
||||
public DoInitActionTag(SWF swf) {
|
||||
super(swf, ID, NAME, null);
|
||||
actionBytes = ByteArrayRange.EMPTY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setScriptName(String scriptName) {
|
||||
this.scriptName = scriptName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param sis
|
||||
* @param data
|
||||
* @throws IOException
|
||||
*/
|
||||
public DoInitActionTag(SWFInputStream sis, ByteArrayRange data) throws IOException {
|
||||
super(sis.getSwf(), ID, NAME, data);
|
||||
readData(sis, data, 0, false, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException {
|
||||
spriteId = sis.readUI16("spriteId");
|
||||
actionBytes = sis.readByteRangeEx(sis.available(), "actionBytes");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets data bytes
|
||||
*
|
||||
* @param sos SWF output stream
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
@Override
|
||||
public void getData(SWFOutputStream sos) throws IOException {
|
||||
sos.writeUI16(spriteId);
|
||||
sos.write(getActionBytes());
|
||||
//sos.write(Action.actionsToBytes(actions, true, version));
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not this object contains ASM source
|
||||
*
|
||||
* @return True when contains
|
||||
*/
|
||||
@Override
|
||||
public boolean containsSource() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts actions to ASM source
|
||||
*
|
||||
* @param exportMode PCode or hex?
|
||||
* @param writer
|
||||
* @param actions
|
||||
* @return ASM source
|
||||
* @throws java.lang.InterruptedException
|
||||
*/
|
||||
@Override
|
||||
public GraphTextWriter getASMSource(ScriptExportMode exportMode, GraphTextWriter writer, ActionList actions) throws InterruptedException {
|
||||
if (actions == null) {
|
||||
actions = getActions();
|
||||
}
|
||||
return Action.actionsToString(listeners, 0, actions, swf.version, exportMode, writer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionList getActions() throws InterruptedException {
|
||||
return SWF.getCachedActionList(this, listeners);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setActions(List<Action> actions) {
|
||||
actionBytes = Action.actionsToByteArrayRange(actions, true, swf.version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteArrayRange getActionBytes() {
|
||||
return actionBytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setActionBytes(byte[] actionBytes) {
|
||||
this.actionBytes = new ByteArrayRange(actionBytes);
|
||||
SWF.uncache(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setConstantPools(List<List<String>> constantPools) throws ConstantPoolTooBigException {
|
||||
Action.setConstantPools(this, constantPools, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setModified() {
|
||||
setModified(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphTextWriter getActionBytesAsHex(GraphTextWriter writer) {
|
||||
return Helper.byteArrayToHexWithHeader(writer, actionBytes.getRangeData());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCharacterId() {
|
||||
return spriteId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCharacterId(int characterId) {
|
||||
this.spriteId = characterId;
|
||||
}
|
||||
|
||||
List<DisassemblyListener> listeners = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void addDisassemblyListener(DisassemblyListener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeDisassemblyListener(DisassemblyListener listener) {
|
||||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExportFileName() {
|
||||
String expName = swf == null ? "" : swf.getExportName(spriteId);
|
||||
if (expName == null || expName.isEmpty()) {
|
||||
return super.getExportFileName();
|
||||
}
|
||||
String[] pathParts = expName.contains(".") ? expName.split("\\.") : new String[]{expName};
|
||||
return pathParts[pathParts.length - 1];
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
String expName = swf == null ? "" : swf.getExportName(spriteId);
|
||||
if (expName == null || expName.isEmpty()) {
|
||||
return super.getName();
|
||||
}
|
||||
String[] pathParts = expName.contains(".") ? expName.split("\\.") : new String[]{expName};
|
||||
return pathParts[pathParts.length - 1];
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphTextWriter getActionSourcePrefix(GraphTextWriter writer) {
|
||||
return writer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphTextWriter getActionSourceSuffix(GraphTextWriter writer) {
|
||||
return writer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPrefixLineCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String removePrefixAndSuffix(String source) {
|
||||
return source;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag getSourceTag() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSourceTag(Tag t) {
|
||||
//nothing
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.tags;
|
||||
|
||||
import com.jpexs.decompiler.flash.DisassemblyListener;
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.action.Action;
|
||||
import com.jpexs.decompiler.flash.action.ActionList;
|
||||
import com.jpexs.decompiler.flash.action.ConstantPoolTooBigException;
|
||||
import com.jpexs.decompiler.flash.dumpview.DumpInfoSpecialType;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
|
||||
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
|
||||
import com.jpexs.decompiler.flash.tags.base.ASMSource;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterIdTag;
|
||||
import com.jpexs.decompiler.flash.types.BasicType;
|
||||
import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Internal;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFType;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
@SWFVersion(from = 6)
|
||||
public class DoInitActionTag extends Tag implements CharacterIdTag, ASMSource {
|
||||
|
||||
public static final int ID = 59;
|
||||
|
||||
public static final String NAME = "DoInitAction";
|
||||
|
||||
/**
|
||||
* Identifier of Sprite
|
||||
*/
|
||||
@SWFType(BasicType.UI16)
|
||||
public int spriteId = 0;
|
||||
|
||||
/**
|
||||
* List of actions to perform
|
||||
*/
|
||||
@HideInRawEdit
|
||||
public ByteArrayRange actionBytes;
|
||||
|
||||
@Internal
|
||||
private String scriptName = "-";
|
||||
|
||||
@Override
|
||||
public String getScriptName() {
|
||||
return scriptName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param swf
|
||||
*/
|
||||
public DoInitActionTag(SWF swf) {
|
||||
super(swf, ID, NAME, null);
|
||||
actionBytes = ByteArrayRange.EMPTY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setScriptName(String scriptName) {
|
||||
this.scriptName = scriptName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param sis
|
||||
* @param data
|
||||
* @throws IOException
|
||||
*/
|
||||
public DoInitActionTag(SWFInputStream sis, ByteArrayRange data) throws IOException {
|
||||
super(sis.getSwf(), ID, NAME, data);
|
||||
readData(sis, data, 0, false, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException {
|
||||
spriteId = sis.readUI16("spriteId");
|
||||
actionBytes = sis.readByteRangeEx(sis.available(), "actionBytes", DumpInfoSpecialType.ACTION_BYTES, sis.getPos());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets data bytes
|
||||
*
|
||||
* @param sos SWF output stream
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
@Override
|
||||
public void getData(SWFOutputStream sos) throws IOException {
|
||||
sos.writeUI16(spriteId);
|
||||
sos.write(getActionBytes());
|
||||
//sos.write(Action.actionsToBytes(actions, true, version));
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not this object contains ASM source
|
||||
*
|
||||
* @return True when contains
|
||||
*/
|
||||
@Override
|
||||
public boolean containsSource() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts actions to ASM source
|
||||
*
|
||||
* @param exportMode PCode or hex?
|
||||
* @param writer
|
||||
* @param actions
|
||||
* @return ASM source
|
||||
* @throws java.lang.InterruptedException
|
||||
*/
|
||||
@Override
|
||||
public GraphTextWriter getASMSource(ScriptExportMode exportMode, GraphTextWriter writer, ActionList actions) throws InterruptedException {
|
||||
if (actions == null) {
|
||||
actions = getActions();
|
||||
}
|
||||
return Action.actionsToString(listeners, 0, actions, swf.version, exportMode, writer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionList getActions() throws InterruptedException {
|
||||
return SWF.getCachedActionList(this, listeners);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setActions(List<Action> actions) {
|
||||
actionBytes = Action.actionsToByteArrayRange(actions, true, swf.version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteArrayRange getActionBytes() {
|
||||
return actionBytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setActionBytes(byte[] actionBytes) {
|
||||
this.actionBytes = new ByteArrayRange(actionBytes);
|
||||
SWF.uncache(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setConstantPools(List<List<String>> constantPools) throws ConstantPoolTooBigException {
|
||||
Action.setConstantPools(this, constantPools, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setModified() {
|
||||
setModified(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphTextWriter getActionBytesAsHex(GraphTextWriter writer) {
|
||||
return Helper.byteArrayToHexWithHeader(writer, actionBytes.getRangeData());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCharacterId() {
|
||||
return spriteId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCharacterId(int characterId) {
|
||||
this.spriteId = characterId;
|
||||
}
|
||||
|
||||
List<DisassemblyListener> listeners = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void addDisassemblyListener(DisassemblyListener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeDisassemblyListener(DisassemblyListener listener) {
|
||||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExportFileName() {
|
||||
String expName = swf == null ? "" : swf.getExportName(spriteId);
|
||||
if (expName == null || expName.isEmpty()) {
|
||||
return super.getExportFileName();
|
||||
}
|
||||
String[] pathParts = expName.contains(".") ? expName.split("\\.") : new String[]{expName};
|
||||
return pathParts[pathParts.length - 1];
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
String expName = swf == null ? "" : swf.getExportName(spriteId);
|
||||
if (expName == null || expName.isEmpty()) {
|
||||
return super.getName();
|
||||
}
|
||||
String[] pathParts = expName.contains(".") ? expName.split("\\.") : new String[]{expName};
|
||||
return pathParts[pathParts.length - 1];
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphTextWriter getActionSourcePrefix(GraphTextWriter writer) {
|
||||
return writer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphTextWriter getActionSourceSuffix(GraphTextWriter writer) {
|
||||
return writer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPrefixLineCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String removePrefixAndSuffix(String source) {
|
||||
return source;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag getSourceTag() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSourceTag(Tag t) {
|
||||
//nothing
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,344 +1,345 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.types;
|
||||
|
||||
import com.jpexs.decompiler.flash.DisassemblyListener;
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.action.Action;
|
||||
import com.jpexs.decompiler.flash.action.ActionList;
|
||||
import com.jpexs.decompiler.flash.action.ConstantPoolTooBigException;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
|
||||
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ASMSource;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Conditional;
|
||||
import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Internal;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFType;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Actions to execute at particular button events
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class BUTTONCONDACTION implements ASMSource, Serializable {
|
||||
|
||||
private SWF swf;
|
||||
|
||||
private Tag tag;
|
||||
|
||||
private String scriptName = "-";
|
||||
|
||||
@Override
|
||||
public String getScriptName() {
|
||||
return scriptName;
|
||||
}
|
||||
|
||||
// Constructor for Generic tag editor.
|
||||
public BUTTONCONDACTION() {
|
||||
swf = null;
|
||||
tag = null;
|
||||
actionBytes = new ByteArrayRange(SWFInputStream.BYTE_ARRAY_EMPTY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setScriptName(String scriptName) {
|
||||
this.scriptName = scriptName;
|
||||
}
|
||||
|
||||
public BUTTONCONDACTION(SWF swf, SWFInputStream sis, Tag tag) throws IOException {
|
||||
this.swf = swf;
|
||||
this.tag = tag;
|
||||
int condActionSize = sis.readUI16("condActionSize");
|
||||
isLast = condActionSize <= 0;
|
||||
condIdleToOverDown = sis.readUB(1, "condIdleToOverDown") == 1;
|
||||
condOutDownToIdle = sis.readUB(1, "condOutDownToIdle") == 1;
|
||||
condOutDownToOverDown = sis.readUB(1, "condOutDownToOverDown") == 1;
|
||||
condOverDownToOutDown = sis.readUB(1, "condOverDownToOutDown") == 1;
|
||||
condOverDownToOverUp = sis.readUB(1, "condOverDownToOverUp") == 1;
|
||||
condOverUpToOverDown = sis.readUB(1, "condOverUpToOverDown") == 1;
|
||||
condOverUpToIddle = sis.readUB(1, "condOverUpToIddle") == 1;
|
||||
condIdleToOverUp = sis.readUB(1, "condIdleToOverUp") == 1;
|
||||
condKeyPress = (int) sis.readUB(7, "condKeyPress");
|
||||
condOverDownToIdle = sis.readUB(1, "condOverDownToIdle") == 1;
|
||||
actionBytes = sis.readByteRangeEx(condActionSize <= 0 ? sis.available() : condActionSize - 4, "actionBytes");
|
||||
}
|
||||
|
||||
@Override
|
||||
public SWF getSwf() {
|
||||
return swf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this BUTTONCONDACTION last in the list?
|
||||
*/
|
||||
@Internal
|
||||
public boolean isLast;
|
||||
|
||||
/**
|
||||
* Idle to OverDown
|
||||
*/
|
||||
public boolean condIdleToOverDown;
|
||||
|
||||
/**
|
||||
* OutDown to Idle
|
||||
*/
|
||||
public boolean condOutDownToIdle;
|
||||
|
||||
/**
|
||||
* OutDown to OverDown
|
||||
*/
|
||||
public boolean condOutDownToOverDown;
|
||||
|
||||
/**
|
||||
* OverDown to OutDown
|
||||
*/
|
||||
public boolean condOverDownToOutDown;
|
||||
|
||||
/**
|
||||
* OverDown to OverUp
|
||||
*/
|
||||
public boolean condOverDownToOverUp;
|
||||
|
||||
/**
|
||||
* OverUp to OverDown
|
||||
*/
|
||||
public boolean condOverUpToOverDown;
|
||||
|
||||
/**
|
||||
* OverUp to Idle
|
||||
*/
|
||||
public boolean condOverUpToIddle;
|
||||
|
||||
/**
|
||||
* Idle to OverUp
|
||||
*/
|
||||
public boolean condIdleToOverUp;
|
||||
|
||||
/**
|
||||
* @since SWF 4 key code
|
||||
*/
|
||||
@SWFType(value = BasicType.UB, count = 7)
|
||||
@Conditional(minSwfVersion = 4)
|
||||
public int condKeyPress;
|
||||
|
||||
/**
|
||||
* OverDown to Idle
|
||||
*/
|
||||
public boolean condOverDownToIdle;
|
||||
|
||||
/**
|
||||
* Actions to perform in byte array
|
||||
*/
|
||||
@HideInRawEdit
|
||||
public ByteArrayRange actionBytes;
|
||||
|
||||
/**
|
||||
* Sets actions associated with this object
|
||||
*
|
||||
* @param actions Action list
|
||||
*/
|
||||
/*public void setActions(List<Action> actions) {
|
||||
this.actions = actions;
|
||||
}*/
|
||||
/**
|
||||
* Returns a string representation of the object
|
||||
*
|
||||
* @return a string representation of the object.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BUTTONCONDACTION";
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts actions to ASM source
|
||||
*
|
||||
* @param exportMode PCode or hex?
|
||||
* @param writer
|
||||
* @param actions
|
||||
* @return ASM source
|
||||
* @throws java.lang.InterruptedException
|
||||
*/
|
||||
@Override
|
||||
public GraphTextWriter getASMSource(ScriptExportMode exportMode, GraphTextWriter writer, ActionList actions) throws InterruptedException {
|
||||
if (actions == null) {
|
||||
actions = getActions();
|
||||
}
|
||||
return Action.actionsToString(listeners, 0, actions, swf.version, exportMode, writer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not this object contains ASM source
|
||||
*
|
||||
* @return True when contains
|
||||
*/
|
||||
@Override
|
||||
public boolean containsSource() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns actions associated with this object
|
||||
*
|
||||
* @return List of actions
|
||||
* @throws java.lang.InterruptedException
|
||||
*/
|
||||
@Override
|
||||
public ActionList getActions() throws InterruptedException {
|
||||
return SWF.getCachedActionList(this, listeners);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setActions(List<Action> actions) {
|
||||
actionBytes = Action.actionsToByteArrayRange(actions, true, swf.version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteArrayRange getActionBytes() {
|
||||
return actionBytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setActionBytes(byte[] actionBytes) {
|
||||
this.actionBytes = new ByteArrayRange(actionBytes);
|
||||
SWF.uncache(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setConstantPools(List<List<String>> constantPools) throws ConstantPoolTooBigException {
|
||||
Action.setConstantPools(this, constantPools, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setModified() {
|
||||
if (tag != null) {
|
||||
tag.setModified(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isModified() {
|
||||
if (tag != null) {
|
||||
return tag.isModified();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphTextWriter getActionBytesAsHex(GraphTextWriter writer) {
|
||||
return Helper.byteArrayToHexWithHeader(writer, actionBytes.getRangeData());
|
||||
}
|
||||
|
||||
List<DisassemblyListener> listeners = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void addDisassemblyListener(DisassemblyListener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeDisassemblyListener(DisassemblyListener listener) {
|
||||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
private String getHeader(boolean asFilename) {
|
||||
List<String> events = new ArrayList<>();
|
||||
if (condOverUpToOverDown) {
|
||||
events.add("press");
|
||||
}
|
||||
if (condOverDownToOverUp) {
|
||||
events.add("release");
|
||||
}
|
||||
if (condOutDownToIdle) {
|
||||
events.add("releaseOutside");
|
||||
}
|
||||
if (condIdleToOverUp) {
|
||||
events.add("rollOver");
|
||||
}
|
||||
if (condOverUpToIddle) {
|
||||
events.add("rollOut");
|
||||
}
|
||||
if (condOverDownToOutDown) {
|
||||
events.add("dragOut");
|
||||
}
|
||||
if (condOutDownToOverDown) {
|
||||
events.add("dragOver");
|
||||
}
|
||||
if (condKeyPress > 0) {
|
||||
if (asFilename) {
|
||||
events.add("keyPress " + Helper.makeFileName(CLIPACTIONRECORD.keyToString(condKeyPress).replace("<", "").replace(">", "")) + "");
|
||||
} else {
|
||||
events.add("keyPress \"" + CLIPACTIONRECORD.keyToString(condKeyPress) + "\"");
|
||||
}
|
||||
}
|
||||
String onStr = "";
|
||||
for (int i = 0; i < events.size(); i++) {
|
||||
if (i > 0) {
|
||||
onStr += ", ";
|
||||
}
|
||||
onStr += events.get(i);
|
||||
}
|
||||
return "on(" + onStr + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphTextWriter getActionSourcePrefix(GraphTextWriter writer) {
|
||||
writer.appendNoHilight(getHeader(false));
|
||||
writer.appendNoHilight("{").newLine();
|
||||
return writer.indent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphTextWriter getActionSourceSuffix(GraphTextWriter writer) {
|
||||
writer.unindent();
|
||||
return writer.appendNoHilight("}").newLine();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPrefixLineCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String removePrefixAndSuffix(String source) {
|
||||
return Helper.unindentRows(1, 1, source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExportFileName() {
|
||||
return getHeader(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag getSourceTag() {
|
||||
return tag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSourceTag(Tag t) {
|
||||
this.tag = t;
|
||||
this.swf = t.getSwf();
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.types;
|
||||
|
||||
import com.jpexs.decompiler.flash.DisassemblyListener;
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.action.Action;
|
||||
import com.jpexs.decompiler.flash.action.ActionList;
|
||||
import com.jpexs.decompiler.flash.action.ConstantPoolTooBigException;
|
||||
import com.jpexs.decompiler.flash.dumpview.DumpInfoSpecialType;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
|
||||
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ASMSource;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Conditional;
|
||||
import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Internal;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFType;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Actions to execute at particular button events
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class BUTTONCONDACTION implements ASMSource, Serializable {
|
||||
|
||||
private SWF swf;
|
||||
|
||||
private Tag tag;
|
||||
|
||||
private String scriptName = "-";
|
||||
|
||||
@Override
|
||||
public String getScriptName() {
|
||||
return scriptName;
|
||||
}
|
||||
|
||||
// Constructor for Generic tag editor.
|
||||
public BUTTONCONDACTION() {
|
||||
swf = null;
|
||||
tag = null;
|
||||
actionBytes = new ByteArrayRange(SWFInputStream.BYTE_ARRAY_EMPTY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setScriptName(String scriptName) {
|
||||
this.scriptName = scriptName;
|
||||
}
|
||||
|
||||
public BUTTONCONDACTION(SWF swf, SWFInputStream sis, Tag tag) throws IOException {
|
||||
this.swf = swf;
|
||||
this.tag = tag;
|
||||
int condActionSize = sis.readUI16("condActionSize");
|
||||
isLast = condActionSize <= 0;
|
||||
condIdleToOverDown = sis.readUB(1, "condIdleToOverDown") == 1;
|
||||
condOutDownToIdle = sis.readUB(1, "condOutDownToIdle") == 1;
|
||||
condOutDownToOverDown = sis.readUB(1, "condOutDownToOverDown") == 1;
|
||||
condOverDownToOutDown = sis.readUB(1, "condOverDownToOutDown") == 1;
|
||||
condOverDownToOverUp = sis.readUB(1, "condOverDownToOverUp") == 1;
|
||||
condOverUpToOverDown = sis.readUB(1, "condOverUpToOverDown") == 1;
|
||||
condOverUpToIddle = sis.readUB(1, "condOverUpToIddle") == 1;
|
||||
condIdleToOverUp = sis.readUB(1, "condIdleToOverUp") == 1;
|
||||
condKeyPress = (int) sis.readUB(7, "condKeyPress");
|
||||
condOverDownToIdle = sis.readUB(1, "condOverDownToIdle") == 1;
|
||||
actionBytes = sis.readByteRangeEx(condActionSize <= 0 ? sis.available() : condActionSize - 4, "actionBytes", DumpInfoSpecialType.ACTION_BYTES, sis.getPos());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SWF getSwf() {
|
||||
return swf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this BUTTONCONDACTION last in the list?
|
||||
*/
|
||||
@Internal
|
||||
public boolean isLast;
|
||||
|
||||
/**
|
||||
* Idle to OverDown
|
||||
*/
|
||||
public boolean condIdleToOverDown;
|
||||
|
||||
/**
|
||||
* OutDown to Idle
|
||||
*/
|
||||
public boolean condOutDownToIdle;
|
||||
|
||||
/**
|
||||
* OutDown to OverDown
|
||||
*/
|
||||
public boolean condOutDownToOverDown;
|
||||
|
||||
/**
|
||||
* OverDown to OutDown
|
||||
*/
|
||||
public boolean condOverDownToOutDown;
|
||||
|
||||
/**
|
||||
* OverDown to OverUp
|
||||
*/
|
||||
public boolean condOverDownToOverUp;
|
||||
|
||||
/**
|
||||
* OverUp to OverDown
|
||||
*/
|
||||
public boolean condOverUpToOverDown;
|
||||
|
||||
/**
|
||||
* OverUp to Idle
|
||||
*/
|
||||
public boolean condOverUpToIddle;
|
||||
|
||||
/**
|
||||
* Idle to OverUp
|
||||
*/
|
||||
public boolean condIdleToOverUp;
|
||||
|
||||
/**
|
||||
* @since SWF 4 key code
|
||||
*/
|
||||
@SWFType(value = BasicType.UB, count = 7)
|
||||
@Conditional(minSwfVersion = 4)
|
||||
public int condKeyPress;
|
||||
|
||||
/**
|
||||
* OverDown to Idle
|
||||
*/
|
||||
public boolean condOverDownToIdle;
|
||||
|
||||
/**
|
||||
* Actions to perform in byte array
|
||||
*/
|
||||
@HideInRawEdit
|
||||
public ByteArrayRange actionBytes;
|
||||
|
||||
/**
|
||||
* Sets actions associated with this object
|
||||
*
|
||||
* @param actions Action list
|
||||
*/
|
||||
/*public void setActions(List<Action> actions) {
|
||||
this.actions = actions;
|
||||
}*/
|
||||
/**
|
||||
* Returns a string representation of the object
|
||||
*
|
||||
* @return a string representation of the object.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BUTTONCONDACTION";
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts actions to ASM source
|
||||
*
|
||||
* @param exportMode PCode or hex?
|
||||
* @param writer
|
||||
* @param actions
|
||||
* @return ASM source
|
||||
* @throws java.lang.InterruptedException
|
||||
*/
|
||||
@Override
|
||||
public GraphTextWriter getASMSource(ScriptExportMode exportMode, GraphTextWriter writer, ActionList actions) throws InterruptedException {
|
||||
if (actions == null) {
|
||||
actions = getActions();
|
||||
}
|
||||
return Action.actionsToString(listeners, 0, actions, swf.version, exportMode, writer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not this object contains ASM source
|
||||
*
|
||||
* @return True when contains
|
||||
*/
|
||||
@Override
|
||||
public boolean containsSource() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns actions associated with this object
|
||||
*
|
||||
* @return List of actions
|
||||
* @throws java.lang.InterruptedException
|
||||
*/
|
||||
@Override
|
||||
public ActionList getActions() throws InterruptedException {
|
||||
return SWF.getCachedActionList(this, listeners);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setActions(List<Action> actions) {
|
||||
actionBytes = Action.actionsToByteArrayRange(actions, true, swf.version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteArrayRange getActionBytes() {
|
||||
return actionBytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setActionBytes(byte[] actionBytes) {
|
||||
this.actionBytes = new ByteArrayRange(actionBytes);
|
||||
SWF.uncache(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setConstantPools(List<List<String>> constantPools) throws ConstantPoolTooBigException {
|
||||
Action.setConstantPools(this, constantPools, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setModified() {
|
||||
if (tag != null) {
|
||||
tag.setModified(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isModified() {
|
||||
if (tag != null) {
|
||||
return tag.isModified();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphTextWriter getActionBytesAsHex(GraphTextWriter writer) {
|
||||
return Helper.byteArrayToHexWithHeader(writer, actionBytes.getRangeData());
|
||||
}
|
||||
|
||||
List<DisassemblyListener> listeners = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void addDisassemblyListener(DisassemblyListener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeDisassemblyListener(DisassemblyListener listener) {
|
||||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
private String getHeader(boolean asFilename) {
|
||||
List<String> events = new ArrayList<>();
|
||||
if (condOverUpToOverDown) {
|
||||
events.add("press");
|
||||
}
|
||||
if (condOverDownToOverUp) {
|
||||
events.add("release");
|
||||
}
|
||||
if (condOutDownToIdle) {
|
||||
events.add("releaseOutside");
|
||||
}
|
||||
if (condIdleToOverUp) {
|
||||
events.add("rollOver");
|
||||
}
|
||||
if (condOverUpToIddle) {
|
||||
events.add("rollOut");
|
||||
}
|
||||
if (condOverDownToOutDown) {
|
||||
events.add("dragOut");
|
||||
}
|
||||
if (condOutDownToOverDown) {
|
||||
events.add("dragOver");
|
||||
}
|
||||
if (condKeyPress > 0) {
|
||||
if (asFilename) {
|
||||
events.add("keyPress " + Helper.makeFileName(CLIPACTIONRECORD.keyToString(condKeyPress).replace("<", "").replace(">", "")) + "");
|
||||
} else {
|
||||
events.add("keyPress \"" + CLIPACTIONRECORD.keyToString(condKeyPress) + "\"");
|
||||
}
|
||||
}
|
||||
String onStr = "";
|
||||
for (int i = 0; i < events.size(); i++) {
|
||||
if (i > 0) {
|
||||
onStr += ", ";
|
||||
}
|
||||
onStr += events.get(i);
|
||||
}
|
||||
return "on(" + onStr + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphTextWriter getActionSourcePrefix(GraphTextWriter writer) {
|
||||
writer.appendNoHilight(getHeader(false));
|
||||
writer.appendNoHilight("{").newLine();
|
||||
return writer.indent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphTextWriter getActionSourceSuffix(GraphTextWriter writer) {
|
||||
writer.unindent();
|
||||
return writer.appendNoHilight("}").newLine();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPrefixLineCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String removePrefixAndSuffix(String source) {
|
||||
return Helper.unindentRows(1, 1, source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExportFileName() {
|
||||
return getHeader(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag getSourceTag() {
|
||||
return tag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSourceTag(Tag t) {
|
||||
this.tag = t;
|
||||
this.swf = t.getSwf();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,300 +1,301 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.types;
|
||||
|
||||
import com.jpexs.decompiler.flash.DisassemblyListener;
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.action.Action;
|
||||
import com.jpexs.decompiler.flash.action.ActionList;
|
||||
import com.jpexs.decompiler.flash.action.ConstantPoolTooBigException;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
|
||||
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ASMSource;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Conditional;
|
||||
import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Internal;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Event handler
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class CLIPACTIONRECORD implements ASMSource, Serializable {
|
||||
|
||||
private String scriptName = "-";
|
||||
|
||||
@Override
|
||||
public String getScriptName() {
|
||||
return scriptName;
|
||||
}
|
||||
|
||||
public static String keyToString(int key) {
|
||||
if ((key < CLIPACTIONRECORD.KEYNAMES.length) && (key > 0) && (CLIPACTIONRECORD.KEYNAMES[key] != null)) {
|
||||
return CLIPACTIONRECORD.KEYNAMES[key];
|
||||
} else {
|
||||
return "" + (char) key;
|
||||
}
|
||||
}
|
||||
|
||||
public static final String[] KEYNAMES = {
|
||||
null,
|
||||
"<Left>",
|
||||
"<Right>",
|
||||
"<Home>",
|
||||
"<End>",
|
||||
"<Insert>",
|
||||
"<Delete>",
|
||||
null,
|
||||
"<Backspace>",
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
"<Enter>",
|
||||
"<Up>",
|
||||
"<Down>",
|
||||
"<PageUp>",
|
||||
"<PageDown>",
|
||||
"<Tab>",
|
||||
"<Escape>",
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
"<Space>"
|
||||
};
|
||||
|
||||
@Internal
|
||||
private SWF swf;
|
||||
|
||||
@Internal
|
||||
private Tag tag;
|
||||
|
||||
// Constructor for Generic tag editor. TODO:Handle this somehow better
|
||||
public CLIPACTIONRECORD() {
|
||||
swf = null;
|
||||
tag = null;
|
||||
eventFlags = new CLIPEVENTFLAGS();
|
||||
actionBytes = ByteArrayRange.EMPTY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setScriptName(String scriptName) {
|
||||
this.scriptName = scriptName;
|
||||
}
|
||||
|
||||
public CLIPACTIONRECORD(SWF swf, SWFInputStream sis, Tag tag) throws IOException {
|
||||
this.swf = swf;
|
||||
this.tag = tag;
|
||||
eventFlags = sis.readCLIPEVENTFLAGS("eventFlags");
|
||||
if (eventFlags.isClear()) {
|
||||
return;
|
||||
}
|
||||
long actionRecordSize = sis.readUI32("actionRecordSize");
|
||||
if (eventFlags.clipEventKeyPress) {
|
||||
keyCode = sis.readUI8("keyCode");
|
||||
actionRecordSize--;
|
||||
}
|
||||
actionBytes = sis.readByteRangeEx(actionRecordSize, "actionBytes");
|
||||
}
|
||||
|
||||
@Override
|
||||
public SWF getSwf() {
|
||||
return swf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Events to which this handler applies
|
||||
*/
|
||||
public CLIPEVENTFLAGS eventFlags;
|
||||
|
||||
/**
|
||||
* If EventFlags contain ClipEventKeyPress: Key code to trap
|
||||
*/
|
||||
@Conditional("eventFlags.clipEventKeyPress")
|
||||
public int keyCode;
|
||||
|
||||
/**
|
||||
* Actions to perform
|
||||
*/
|
||||
@HideInRawEdit
|
||||
public ByteArrayRange actionBytes;
|
||||
|
||||
/**
|
||||
* Returns a string representation of the object
|
||||
*
|
||||
* @return a string representation of the object.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return eventFlags.getHeader(keyCode, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns header with events converted to string
|
||||
*
|
||||
* @return String representation of events
|
||||
*/
|
||||
public String getHeader() {
|
||||
String ret;
|
||||
ret = eventFlags.toString();
|
||||
if (eventFlags.clipEventKeyPress) {
|
||||
ret = ret.replace("keyPress", "keyPress<" + keyCode + ">");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts actions to ASM source
|
||||
*
|
||||
* @param exportMode PCode or hex?
|
||||
* @param writer
|
||||
* @param actions
|
||||
* @return ASM source
|
||||
* @throws java.lang.InterruptedException
|
||||
*/
|
||||
@Override
|
||||
public GraphTextWriter getASMSource(ScriptExportMode exportMode, GraphTextWriter writer, ActionList actions) throws InterruptedException {
|
||||
if (actions == null) {
|
||||
actions = getActions();
|
||||
}
|
||||
return Action.actionsToString(listeners, 0, actions, swf.version, exportMode, writer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not this object contains ASM source
|
||||
*
|
||||
* @return True when contains
|
||||
*/
|
||||
@Override
|
||||
public boolean containsSource() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionList getActions() throws InterruptedException {
|
||||
return SWF.getCachedActionList(this, listeners);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setActions(List<Action> actions) {
|
||||
actionBytes = Action.actionsToByteArrayRange(actions, true, swf.version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteArrayRange getActionBytes() {
|
||||
return actionBytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setActionBytes(byte[] actionBytes) {
|
||||
this.actionBytes = new ByteArrayRange(actionBytes);
|
||||
SWF.uncache(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setConstantPools(List<List<String>> constantPools) throws ConstantPoolTooBigException {
|
||||
Action.setConstantPools(this, constantPools, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setModified() {
|
||||
if (tag != null) {
|
||||
tag.setModified(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isModified() {
|
||||
if (tag != null) {
|
||||
return tag.isModified();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphTextWriter getActionBytesAsHex(GraphTextWriter writer) {
|
||||
return Helper.byteArrayToHexWithHeader(writer, actionBytes.getRangeData());
|
||||
}
|
||||
|
||||
List<DisassemblyListener> listeners = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void addDisassemblyListener(DisassemblyListener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeDisassemblyListener(DisassemblyListener listener) {
|
||||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphTextWriter getActionSourcePrefix(GraphTextWriter writer) {
|
||||
writer.appendNoHilight(eventFlags.getHeader(keyCode, false));
|
||||
writer.appendNoHilight("{").newLine();
|
||||
return writer.indent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphTextWriter getActionSourceSuffix(GraphTextWriter writer) {
|
||||
writer.unindent();
|
||||
return writer.appendNoHilight("}").newLine();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPrefixLineCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String removePrefixAndSuffix(String source) {
|
||||
return Helper.unindentRows(1, 1, source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExportFileName() {
|
||||
return eventFlags.getHeader(keyCode, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag getSourceTag() {
|
||||
return tag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSourceTag(Tag t) {
|
||||
this.tag = t;
|
||||
this.swf = t.getSwf();
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.types;
|
||||
|
||||
import com.jpexs.decompiler.flash.DisassemblyListener;
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.action.Action;
|
||||
import com.jpexs.decompiler.flash.action.ActionList;
|
||||
import com.jpexs.decompiler.flash.action.ConstantPoolTooBigException;
|
||||
import com.jpexs.decompiler.flash.dumpview.DumpInfoSpecialType;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
|
||||
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ASMSource;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Conditional;
|
||||
import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Internal;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Event handler
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class CLIPACTIONRECORD implements ASMSource, Serializable {
|
||||
|
||||
private String scriptName = "-";
|
||||
|
||||
@Override
|
||||
public String getScriptName() {
|
||||
return scriptName;
|
||||
}
|
||||
|
||||
public static String keyToString(int key) {
|
||||
if ((key < CLIPACTIONRECORD.KEYNAMES.length) && (key > 0) && (CLIPACTIONRECORD.KEYNAMES[key] != null)) {
|
||||
return CLIPACTIONRECORD.KEYNAMES[key];
|
||||
} else {
|
||||
return "" + (char) key;
|
||||
}
|
||||
}
|
||||
|
||||
public static final String[] KEYNAMES = {
|
||||
null,
|
||||
"<Left>",
|
||||
"<Right>",
|
||||
"<Home>",
|
||||
"<End>",
|
||||
"<Insert>",
|
||||
"<Delete>",
|
||||
null,
|
||||
"<Backspace>",
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
"<Enter>",
|
||||
"<Up>",
|
||||
"<Down>",
|
||||
"<PageUp>",
|
||||
"<PageDown>",
|
||||
"<Tab>",
|
||||
"<Escape>",
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
"<Space>"
|
||||
};
|
||||
|
||||
@Internal
|
||||
private SWF swf;
|
||||
|
||||
@Internal
|
||||
private Tag tag;
|
||||
|
||||
// Constructor for Generic tag editor. TODO:Handle this somehow better
|
||||
public CLIPACTIONRECORD() {
|
||||
swf = null;
|
||||
tag = null;
|
||||
eventFlags = new CLIPEVENTFLAGS();
|
||||
actionBytes = ByteArrayRange.EMPTY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setScriptName(String scriptName) {
|
||||
this.scriptName = scriptName;
|
||||
}
|
||||
|
||||
public CLIPACTIONRECORD(SWF swf, SWFInputStream sis, Tag tag) throws IOException {
|
||||
this.swf = swf;
|
||||
this.tag = tag;
|
||||
eventFlags = sis.readCLIPEVENTFLAGS("eventFlags");
|
||||
if (eventFlags.isClear()) {
|
||||
return;
|
||||
}
|
||||
long actionRecordSize = sis.readUI32("actionRecordSize");
|
||||
if (eventFlags.clipEventKeyPress) {
|
||||
keyCode = sis.readUI8("keyCode");
|
||||
actionRecordSize--;
|
||||
}
|
||||
actionBytes = sis.readByteRangeEx(actionRecordSize, "actionBytes", DumpInfoSpecialType.ACTION_BYTES, sis.getPos());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SWF getSwf() {
|
||||
return swf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Events to which this handler applies
|
||||
*/
|
||||
public CLIPEVENTFLAGS eventFlags;
|
||||
|
||||
/**
|
||||
* If EventFlags contain ClipEventKeyPress: Key code to trap
|
||||
*/
|
||||
@Conditional("eventFlags.clipEventKeyPress")
|
||||
public int keyCode;
|
||||
|
||||
/**
|
||||
* Actions to perform
|
||||
*/
|
||||
@HideInRawEdit
|
||||
public ByteArrayRange actionBytes;
|
||||
|
||||
/**
|
||||
* Returns a string representation of the object
|
||||
*
|
||||
* @return a string representation of the object.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return eventFlags.getHeader(keyCode, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns header with events converted to string
|
||||
*
|
||||
* @return String representation of events
|
||||
*/
|
||||
public String getHeader() {
|
||||
String ret;
|
||||
ret = eventFlags.toString();
|
||||
if (eventFlags.clipEventKeyPress) {
|
||||
ret = ret.replace("keyPress", "keyPress<" + keyCode + ">");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts actions to ASM source
|
||||
*
|
||||
* @param exportMode PCode or hex?
|
||||
* @param writer
|
||||
* @param actions
|
||||
* @return ASM source
|
||||
* @throws java.lang.InterruptedException
|
||||
*/
|
||||
@Override
|
||||
public GraphTextWriter getASMSource(ScriptExportMode exportMode, GraphTextWriter writer, ActionList actions) throws InterruptedException {
|
||||
if (actions == null) {
|
||||
actions = getActions();
|
||||
}
|
||||
return Action.actionsToString(listeners, 0, actions, swf.version, exportMode, writer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not this object contains ASM source
|
||||
*
|
||||
* @return True when contains
|
||||
*/
|
||||
@Override
|
||||
public boolean containsSource() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionList getActions() throws InterruptedException {
|
||||
return SWF.getCachedActionList(this, listeners);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setActions(List<Action> actions) {
|
||||
actionBytes = Action.actionsToByteArrayRange(actions, true, swf.version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteArrayRange getActionBytes() {
|
||||
return actionBytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setActionBytes(byte[] actionBytes) {
|
||||
this.actionBytes = new ByteArrayRange(actionBytes);
|
||||
SWF.uncache(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setConstantPools(List<List<String>> constantPools) throws ConstantPoolTooBigException {
|
||||
Action.setConstantPools(this, constantPools, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setModified() {
|
||||
if (tag != null) {
|
||||
tag.setModified(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isModified() {
|
||||
if (tag != null) {
|
||||
return tag.isModified();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphTextWriter getActionBytesAsHex(GraphTextWriter writer) {
|
||||
return Helper.byteArrayToHexWithHeader(writer, actionBytes.getRangeData());
|
||||
}
|
||||
|
||||
List<DisassemblyListener> listeners = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void addDisassemblyListener(DisassemblyListener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeDisassemblyListener(DisassemblyListener listener) {
|
||||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphTextWriter getActionSourcePrefix(GraphTextWriter writer) {
|
||||
writer.appendNoHilight(eventFlags.getHeader(keyCode, false));
|
||||
writer.appendNoHilight("{").newLine();
|
||||
return writer.indent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphTextWriter getActionSourceSuffix(GraphTextWriter writer) {
|
||||
writer.unindent();
|
||||
return writer.appendNoHilight("}").newLine();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPrefixLineCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String removePrefixAndSuffix(String source) {
|
||||
return Helper.unindentRows(1, 1, source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExportFileName() {
|
||||
return eventFlags.getHeader(keyCode, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag getSourceTag() {
|
||||
return tag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSourceTag(Tag t) {
|
||||
this.tag = t;
|
||||
this.swf = t.getSwf();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1691,7 +1691,7 @@ public class XFLConverter {
|
||||
}
|
||||
}
|
||||
|
||||
byte imageBytes[] = Helper.readStream(imageTag.getImageData());
|
||||
byte[] imageBytes = Helper.readStream(imageTag.getImageData());
|
||||
SerializableImage image = imageTag.getImageCached();
|
||||
ImageFormat format = imageTag.getImageFormat();
|
||||
String symbolFile = "bitmap" + symbol.getCharacterId() + imageTag.getImageFormat().getExtension();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user