jump to resources view from hex view

This commit is contained in:
honfika@gmail.com
2016-08-01 16:53:54 +02:00
parent 234ed1c915
commit 5107a644cc
63 changed files with 23142 additions and 22930 deletions

View File

@@ -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

View File

@@ -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;

View File

@@ -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];
}
}

View File

@@ -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();
}

View File

@@ -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 {

View File

@@ -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());
}
}

View File

@@ -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();
}

View File

@@ -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;
}
}

View File

@@ -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
}

View File

@@ -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

View File

@@ -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());
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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
}
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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);
}

View File

@@ -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());
}
/**

View File

@@ -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
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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