mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-07-15 17:08:07 +00:00
better handling of corrupt swf files
This commit is contained in:
@@ -868,7 +868,7 @@ public final class SWF implements TreeItem, Timelined {
|
||||
}
|
||||
|
||||
@Override
|
||||
public RECT getRect() {
|
||||
public RECT getRect(Set<BoundedTag> added) {
|
||||
return displayRect;
|
||||
}
|
||||
|
||||
@@ -2498,16 +2498,16 @@ public final class SWF implements TreeItem, Timelined {
|
||||
|
||||
String assetName;
|
||||
Tag drawableTag = (Tag) drawable;
|
||||
RECT boundRect = drawable.getRect(new HashSet<BoundedTag>());
|
||||
if (exporter.exportedTags.containsKey(drawableTag)) {
|
||||
assetName = exporter.exportedTags.get(drawableTag);
|
||||
} else {
|
||||
assetName = getTagIdPrefix(drawableTag, exporter);
|
||||
exporter.exportedTags.put(drawableTag, assetName);
|
||||
exporter.createDefGroup(new ExportRectangle(drawable.getRect()), assetName);
|
||||
exporter.createDefGroup(new ExportRectangle(boundRect), assetName);
|
||||
drawable.toSVG(exporter, layer.ratio, clrTrans, level + 1);
|
||||
exporter.endGroup();
|
||||
}
|
||||
RECT boundRect = drawable.getRect();
|
||||
ExportRectangle rect = new ExportRectangle(boundRect);
|
||||
|
||||
// TODO: if (layer.filters != null)
|
||||
@@ -2661,7 +2661,7 @@ public final class SWF implements TreeItem, Timelined {
|
||||
}
|
||||
}
|
||||
|
||||
RECT boundRect = drawable.getRect();
|
||||
RECT boundRect = drawable.getRect(new HashSet<BoundedTag>());
|
||||
ExportRectangle rect = new ExportRectangle(boundRect);
|
||||
rect = mat.transform(rect);
|
||||
Matrix m = mat.clone();
|
||||
@@ -2809,7 +2809,7 @@ public final class SWF implements TreeItem, Timelined {
|
||||
BoundedTag b = (BoundedTag) character;
|
||||
g.setPaint(new Color(255, 255, 255, 128));
|
||||
g.setComposite(BlendComposite.Invert);
|
||||
RECT r = b.getRect();
|
||||
RECT r = b.getRect(new HashSet<BoundedTag>());
|
||||
int div = (int) unzoom;
|
||||
g.drawString(character.toString(), r.Xmin / div + 3, r.Ymin / div + 15);
|
||||
g.draw(new Rectangle(r.Xmin / div, r.Ymin / div, r.getWidth() / div, r.getHeight() / div));
|
||||
|
||||
@@ -403,6 +403,14 @@ public class SWFInputStream implements AutoCloseable {
|
||||
dumpInfo = dumpInfo.parent;
|
||||
}
|
||||
}
|
||||
|
||||
private void endDumpLevelUntil(DumpInfo di) {
|
||||
if (di != null) {
|
||||
while (dumpInfo != null && dumpInfo != di) {
|
||||
endDumpLevel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads one byte from the stream
|
||||
@@ -951,14 +959,14 @@ public class SWFInputStream implements AutoCloseable {
|
||||
|
||||
private class TagResolutionTask implements Callable<Tag> {
|
||||
|
||||
private final Tag tag;
|
||||
private final TagStub tag;
|
||||
private final DumpInfo dumpInfo;
|
||||
private final int level;
|
||||
private final boolean parallel;
|
||||
private final boolean skipUnusualTags;
|
||||
private final boolean gfx;
|
||||
|
||||
public TagResolutionTask(Tag tag, DumpInfo dumpInfo, int level, boolean parallel, boolean skipUnusualTags, boolean gfx) {
|
||||
public TagResolutionTask(TagStub tag, DumpInfo dumpInfo, int level, boolean parallel, boolean skipUnusualTags, boolean gfx) {
|
||||
this.tag = tag;
|
||||
this.dumpInfo = dumpInfo;
|
||||
this.level = level;
|
||||
@@ -969,6 +977,7 @@ public class SWFInputStream implements AutoCloseable {
|
||||
|
||||
@Override
|
||||
public Tag call() throws Exception {
|
||||
DumpInfo di = dumpInfo;
|
||||
try {
|
||||
Tag t = resolveTag(tag, level, parallel, skipUnusualTags, gfx);
|
||||
if (dumpInfo!= null && t != null) {
|
||||
@@ -976,6 +985,7 @@ public class SWFInputStream implements AutoCloseable {
|
||||
}
|
||||
return t;
|
||||
} catch (EndOfStreamException ex) {
|
||||
tag.getDataStream().endDumpLevelUntil(di);
|
||||
logger.log(Level.SEVERE, null, ex);
|
||||
return tag;
|
||||
}
|
||||
@@ -1006,7 +1016,7 @@ public class SWFInputStream implements AutoCloseable {
|
||||
List<Tag> tags = new ArrayList<>();
|
||||
Tag tag;
|
||||
boolean isAS3 = false;
|
||||
while (true) {
|
||||
while (available() > 0) {
|
||||
long pos = getPos();
|
||||
newDumpLevel(null, "TAG");
|
||||
try {
|
||||
@@ -1037,7 +1047,9 @@ public class SWFInputStream implements AutoCloseable {
|
||||
} else {
|
||||
switch (tag.getId()) {
|
||||
case FileAttributesTag.ID: //FileAttributes
|
||||
tag = resolveTag(tag, level, parallel, skipUnusualTags, gfx);
|
||||
if (tag instanceof TagStub) {
|
||||
tag = resolveTag((TagStub) tag, level, parallel, skipUnusualTags, gfx);
|
||||
}
|
||||
FileAttributesTag fileAttributes = (FileAttributesTag) tag;
|
||||
if (fileAttributes.actionScript3) {
|
||||
isAS3 = true;
|
||||
@@ -1077,9 +1089,9 @@ public class SWFInputStream implements AutoCloseable {
|
||||
|
||||
}
|
||||
}
|
||||
if (parseTags && doParse) {
|
||||
if (parseTags && doParse && tag instanceof TagStub) {
|
||||
if (parallel) {
|
||||
Future<Tag> future = executor.submit(new TagResolutionTask(tag, di, level, parallel, skipUnusualTags, gfx));
|
||||
Future<Tag> future = executor.submit(new TagResolutionTask((TagStub) tag, di, level, parallel, skipUnusualTags, gfx));
|
||||
futureResults.add(future);
|
||||
}
|
||||
}
|
||||
@@ -1105,17 +1117,12 @@ public class SWFInputStream implements AutoCloseable {
|
||||
return tags;
|
||||
}
|
||||
|
||||
public static Tag resolveTag(Tag tag, int level, boolean parallel, boolean skipUnusualTags, boolean gfx) throws InterruptedException {
|
||||
public static Tag resolveTag(TagStub tag, int level, boolean parallel, boolean skipUnusualTags, boolean gfx) throws InterruptedException {
|
||||
Tag ret;
|
||||
|
||||
if (!(tag instanceof TagStub)) {
|
||||
return tag;
|
||||
}
|
||||
|
||||
ByteArrayRange data = tag.getOriginalRange();
|
||||
SWF swf = tag.getSwf();
|
||||
TagStub tagStub = (TagStub) tag;
|
||||
SWFInputStream sis = tagStub.getDataStream();
|
||||
SWFInputStream sis = tag.getDataStream();
|
||||
|
||||
try {
|
||||
switch (tag.getId()) {
|
||||
@@ -1425,21 +1432,28 @@ public class SWFInputStream implements AutoCloseable {
|
||||
}
|
||||
int headerLength = readLong ? 6 : 2;
|
||||
SWFInputStream tagDataStream = getLimitedStream((int) tagLength);
|
||||
int available = available();
|
||||
if (tagLength > available) {
|
||||
tagLength = available;
|
||||
}
|
||||
|
||||
ByteArrayRange dataRange = new ByteArrayRange(swf.uncompressedData, (int) pos, (int) (tagLength + headerLength));
|
||||
TagStub tagStub = new TagStub(swf, tagID, "Unresolved", dataRange, tagDataStream);
|
||||
tagStub.forceWriteAsLong = readLong;
|
||||
Tag ret = tagStub;
|
||||
ret.forceWriteAsLong = readLong;
|
||||
skipBytes((int) tagLength);
|
||||
|
||||
if (resolve) {
|
||||
DumpInfo di = dumpInfo;
|
||||
try {
|
||||
ret = resolveTag(ret, level, parallel, skipUnusualTags, gfx);
|
||||
ret = resolveTag(tagStub, level, parallel, skipUnusualTags, gfx);
|
||||
} catch (EndOfStreamException ex) {
|
||||
tagDataStream.endDumpLevelUntil(di);
|
||||
logger.log(Level.SEVERE, "Problem in " + timelined.toString(), ex);
|
||||
}
|
||||
|
||||
if (Configuration.debugMode.get()) {
|
||||
byte[] data = ret.getOriginalData();
|
||||
byte[] data = ret.getOriginalData().getRangeData();
|
||||
byte[] dataNew = ret.getData();
|
||||
int ignoreFirst = 0;
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
@@ -2566,7 +2580,8 @@ public class SWFInputStream implements AutoCloseable {
|
||||
}
|
||||
if (stateNewStyles) {
|
||||
if (morphShape) {
|
||||
//This should never happen
|
||||
// This should never happen
|
||||
throw new IOException("MorphShape should not have new styles.");
|
||||
} else {
|
||||
scr.fillStyles = readFILLSTYLEARRAY(shapeNum, "fillStyles");
|
||||
scr.lineStyles = readLINESTYLEARRAY(shapeNum, "lineStyles");
|
||||
|
||||
@@ -27,6 +27,7 @@ import com.jpexs.decompiler.flash.exporters.morphshape.CanvasMorphShapeExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.settings.MorphShapeExportSettings;
|
||||
import com.jpexs.decompiler.flash.tags.DefineMorphShapeTag;
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
import com.jpexs.decompiler.flash.tags.base.BoundedTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.MorphShapeTag;
|
||||
import com.jpexs.decompiler.flash.types.CXFORMWITHALPHA;
|
||||
@@ -79,7 +80,7 @@ public class MorphShapeExporter {
|
||||
switch (settings.mode) {
|
||||
case SVG:
|
||||
try (FileOutputStream fos = new FileOutputStream(file)) {
|
||||
ExportRectangle rect = new ExportRectangle(mst.getRect());
|
||||
ExportRectangle rect = new ExportRectangle(mst.getRect(new HashSet<BoundedTag>()));
|
||||
SVGExporter exporter = new SVGExporter(rect);
|
||||
mst.toSVG(exporter, -2, new CXFORMWITHALPHA(), 0);
|
||||
fos.write(Utf8Helper.getBytes(exporter.getSVG()));
|
||||
|
||||
@@ -27,6 +27,7 @@ import com.jpexs.decompiler.flash.exporters.modes.ShapeExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.settings.ShapeExportSettings;
|
||||
import com.jpexs.decompiler.flash.exporters.shape.CanvasShapeExporter;
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
import com.jpexs.decompiler.flash.tags.base.BoundedTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ShapeTag;
|
||||
import com.jpexs.decompiler.flash.types.CXFORMWITHALPHA;
|
||||
@@ -88,14 +89,14 @@ public class ShapeExporter {
|
||||
switch (settings.mode) {
|
||||
case SVG:
|
||||
try (FileOutputStream fos = new FileOutputStream(file)) {
|
||||
ExportRectangle rect = new ExportRectangle(st.getRect());
|
||||
ExportRectangle rect = new ExportRectangle(st.getRect(new HashSet<BoundedTag>()));
|
||||
SVGExporter exporter = new SVGExporter(rect);
|
||||
st.toSVG(exporter, -2, new CXFORMWITHALPHA(), 0);
|
||||
fos.write(Utf8Helper.getBytes(exporter.getSVG()));
|
||||
}
|
||||
break;
|
||||
case PNG:
|
||||
RECT rect = st.getRect();
|
||||
RECT rect = st.getRect(new HashSet<BoundedTag>());
|
||||
int newWidth = (int) (rect.getWidth() / SWF.unitDivisor);
|
||||
int newHeight = (int) (rect.getHeight() / SWF.unitDivisor);
|
||||
SerializableImage img = new SerializableImage(newWidth, newHeight, SerializableImage.TYPE_INT_ARGB);
|
||||
|
||||
@@ -1,130 +1,132 @@
|
||||
/*
|
||||
* Copyright (C) 2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.exporters;
|
||||
|
||||
import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler;
|
||||
import com.jpexs.decompiler.flash.RetryTask;
|
||||
import com.jpexs.decompiler.flash.RunnableIOEx;
|
||||
import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.ExportRectangle;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.TextExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.settings.TextExportSettings;
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
import com.jpexs.decompiler.flash.tags.base.TextTag;
|
||||
import com.jpexs.decompiler.flash.types.CXFORMWITHALPHA;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import com.jpexs.helpers.utf8.Utf8Helper;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class TextExporter {
|
||||
|
||||
public static final String TEXT_EXPORT_FOLDER = "texts";
|
||||
public static final String TEXT_EXPORT_FILENAME_FORMATTED = "textsformatted.txt";
|
||||
public static final String TEXT_EXPORT_FILENAME_PLAIN = "textsplain.txt";
|
||||
|
||||
public List<File> exportTexts(AbortRetryIgnoreHandler handler, String outdir, List<Tag> tags, final TextExportSettings settings) throws IOException {
|
||||
List<File> ret = new ArrayList<>();
|
||||
if (tags.isEmpty()) {
|
||||
return ret;
|
||||
}
|
||||
File foutdir = new File(outdir);
|
||||
if (!foutdir.exists()) {
|
||||
if (!foutdir.mkdirs()) {
|
||||
if (!foutdir.exists()) {
|
||||
throw new IOException("Cannot create directory " + outdir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (settings.mode == TextExportMode.SVG) {
|
||||
for (Tag t : tags) {
|
||||
if (t instanceof TextTag) {
|
||||
final TextTag textTag = (TextTag) t;
|
||||
final File file = new File(outdir + File.separator + textTag.getCharacterId() + ".svg");
|
||||
new RetryTask(new RunnableIOEx() {
|
||||
@Override
|
||||
public void run() throws IOException {
|
||||
try (FileOutputStream fos = new FileOutputStream(file)) {
|
||||
ExportRectangle rect = new ExportRectangle(textTag.getRect());
|
||||
SVGExporter exporter = new SVGExporter(rect);
|
||||
textTag.toSVG(exporter, -2, new CXFORMWITHALPHA(), 0);
|
||||
fos.write(Utf8Helper.getBytes(exporter.getSVG()));
|
||||
}
|
||||
}
|
||||
}, handler).run();
|
||||
ret.add(file);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (settings.singleFile) {
|
||||
final File file = new File(outdir + File.separator
|
||||
+ (settings.mode == TextExportMode.FORMATTED ? TEXT_EXPORT_FILENAME_FORMATTED : TEXT_EXPORT_FILENAME_PLAIN));
|
||||
try (FileOutputStream fos = new FileOutputStream(file)) {
|
||||
for (final Tag t : tags) {
|
||||
if (t instanceof TextTag) {
|
||||
final TextTag textTag = (TextTag) t;
|
||||
new RetryTask(new RunnableIOEx() {
|
||||
@Override
|
||||
public void run() throws IOException {
|
||||
fos.write(Utf8Helper.getBytes("ID: " + textTag.getCharacterId() + Helper.newLine));
|
||||
if (settings.mode == TextExportMode.FORMATTED) {
|
||||
fos.write(Utf8Helper.getBytes(textTag.getFormattedText()));
|
||||
} else {
|
||||
fos.write(Utf8Helper.getBytes(textTag.getText(Configuration.textExportSingleFileRecordSeparator.get())));
|
||||
}
|
||||
fos.write(Utf8Helper.getBytes(Helper.newLine + Configuration.textExportSingleFileSeparator.get() + Helper.newLine));
|
||||
}
|
||||
}, handler).run();
|
||||
}
|
||||
}
|
||||
}
|
||||
ret.add(file);
|
||||
} else {
|
||||
for (Tag t : tags) {
|
||||
if (t instanceof TextTag) {
|
||||
final TextTag textTag = (TextTag) t;
|
||||
final File file = new File(outdir + File.separator + textTag.getCharacterId() + ".txt");
|
||||
new RetryTask(new RunnableIOEx() {
|
||||
@Override
|
||||
public void run() throws IOException {
|
||||
try (FileOutputStream fos = new FileOutputStream(file)) {
|
||||
if (settings.mode == TextExportMode.FORMATTED) {
|
||||
fos.write(Utf8Helper.getBytes(textTag.getFormattedText()));
|
||||
} else {
|
||||
fos.write(Utf8Helper.getBytes(textTag.getText(Configuration.textExportSingleFileRecordSeparator.get())));
|
||||
}
|
||||
}
|
||||
}
|
||||
}, handler).run();
|
||||
ret.add(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.exporters;
|
||||
|
||||
import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler;
|
||||
import com.jpexs.decompiler.flash.RetryTask;
|
||||
import com.jpexs.decompiler.flash.RunnableIOEx;
|
||||
import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.ExportRectangle;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.TextExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.settings.TextExportSettings;
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
import com.jpexs.decompiler.flash.tags.base.BoundedTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.TextTag;
|
||||
import com.jpexs.decompiler.flash.types.CXFORMWITHALPHA;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import com.jpexs.helpers.utf8.Utf8Helper;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class TextExporter {
|
||||
|
||||
public static final String TEXT_EXPORT_FOLDER = "texts";
|
||||
public static final String TEXT_EXPORT_FILENAME_FORMATTED = "textsformatted.txt";
|
||||
public static final String TEXT_EXPORT_FILENAME_PLAIN = "textsplain.txt";
|
||||
|
||||
public List<File> exportTexts(AbortRetryIgnoreHandler handler, String outdir, List<Tag> tags, final TextExportSettings settings) throws IOException {
|
||||
List<File> ret = new ArrayList<>();
|
||||
if (tags.isEmpty()) {
|
||||
return ret;
|
||||
}
|
||||
File foutdir = new File(outdir);
|
||||
if (!foutdir.exists()) {
|
||||
if (!foutdir.mkdirs()) {
|
||||
if (!foutdir.exists()) {
|
||||
throw new IOException("Cannot create directory " + outdir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (settings.mode == TextExportMode.SVG) {
|
||||
for (Tag t : tags) {
|
||||
if (t instanceof TextTag) {
|
||||
final TextTag textTag = (TextTag) t;
|
||||
final File file = new File(outdir + File.separator + textTag.getCharacterId() + ".svg");
|
||||
new RetryTask(new RunnableIOEx() {
|
||||
@Override
|
||||
public void run() throws IOException {
|
||||
try (FileOutputStream fos = new FileOutputStream(file)) {
|
||||
ExportRectangle rect = new ExportRectangle(textTag.getRect(new HashSet<BoundedTag>()));
|
||||
SVGExporter exporter = new SVGExporter(rect);
|
||||
textTag.toSVG(exporter, -2, new CXFORMWITHALPHA(), 0);
|
||||
fos.write(Utf8Helper.getBytes(exporter.getSVG()));
|
||||
}
|
||||
}
|
||||
}, handler).run();
|
||||
ret.add(file);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (settings.singleFile) {
|
||||
final File file = new File(outdir + File.separator
|
||||
+ (settings.mode == TextExportMode.FORMATTED ? TEXT_EXPORT_FILENAME_FORMATTED : TEXT_EXPORT_FILENAME_PLAIN));
|
||||
try (FileOutputStream fos = new FileOutputStream(file)) {
|
||||
for (final Tag t : tags) {
|
||||
if (t instanceof TextTag) {
|
||||
final TextTag textTag = (TextTag) t;
|
||||
new RetryTask(new RunnableIOEx() {
|
||||
@Override
|
||||
public void run() throws IOException {
|
||||
fos.write(Utf8Helper.getBytes("ID: " + textTag.getCharacterId() + Helper.newLine));
|
||||
if (settings.mode == TextExportMode.FORMATTED) {
|
||||
fos.write(Utf8Helper.getBytes(textTag.getFormattedText()));
|
||||
} else {
|
||||
fos.write(Utf8Helper.getBytes(textTag.getText(Configuration.textExportSingleFileRecordSeparator.get())));
|
||||
}
|
||||
fos.write(Utf8Helper.getBytes(Helper.newLine + Configuration.textExportSingleFileSeparator.get() + Helper.newLine));
|
||||
}
|
||||
}, handler).run();
|
||||
}
|
||||
}
|
||||
}
|
||||
ret.add(file);
|
||||
} else {
|
||||
for (Tag t : tags) {
|
||||
if (t instanceof TextTag) {
|
||||
final TextTag textTag = (TextTag) t;
|
||||
final File file = new File(outdir + File.separator + textTag.getCharacterId() + ".txt");
|
||||
new RetryTask(new RunnableIOEx() {
|
||||
@Override
|
||||
public void run() throws IOException {
|
||||
try (FileOutputStream fos = new FileOutputStream(file)) {
|
||||
if (settings.mode == TextExportMode.FORMATTED) {
|
||||
fos.write(Utf8Helper.getBytes(textTag.getFormattedText()));
|
||||
} else {
|
||||
fos.write(Utf8Helper.getBytes(textTag.getText(Configuration.textExportSingleFileRecordSeparator.get())));
|
||||
}
|
||||
}
|
||||
}
|
||||
}, handler).run();
|
||||
ret.add(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.jpexs.decompiler.flash.gui.generictageditors.NumberEditor;
|
||||
import com.jpexs.decompiler.flash.gui.generictageditors.ReflectionTools;
|
||||
import com.jpexs.decompiler.flash.gui.generictageditors.StringEditor;
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
import com.jpexs.decompiler.flash.tags.TagStub;
|
||||
import com.jpexs.decompiler.flash.types.ARGB;
|
||||
import com.jpexs.decompiler.flash.types.BasicType;
|
||||
import com.jpexs.decompiler.flash.types.RGB;
|
||||
@@ -661,7 +662,9 @@ public class GenericTagTreePanel extends GenericTagPanel {
|
||||
this.tag = tag;
|
||||
SWF swf = tag.getSwf();
|
||||
try {
|
||||
this.editedTag = SWFInputStream.resolveTag(tag, 0, false, true, swf.gfx);
|
||||
if (tag instanceof TagStub) {
|
||||
this.editedTag = SWFInputStream.resolveTag((TagStub)tag, 0, false, true, swf.gfx);
|
||||
}
|
||||
} catch (InterruptedException ex) {
|
||||
}
|
||||
tree.setEditable(edit);
|
||||
|
||||
@@ -54,6 +54,7 @@ import java.awt.geom.AffineTransform;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
@@ -213,7 +214,7 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis
|
||||
|
||||
Timeline tim = ((Timelined) timelined).getTimeline();
|
||||
BoundedTag bounded = (BoundedTag) timelined;
|
||||
RECT rect = bounded.getRect();
|
||||
RECT rect = bounded.getRect(new HashSet<BoundedTag>());
|
||||
int width = rect.getWidth();
|
||||
double scale = 1.0;
|
||||
/*if (width > swf.displayRect.getWidth()) {
|
||||
@@ -495,7 +496,7 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis
|
||||
if (img == null) {
|
||||
if (drawable instanceof BoundedTag) {
|
||||
BoundedTag bounded = (BoundedTag) drawable;
|
||||
RECT rect = bounded.getRect();
|
||||
RECT rect = bounded.getRect(new HashSet<BoundedTag>());
|
||||
if (rect == null) { //??? Why?
|
||||
rect = new RECT(0, 0, 1, 1);
|
||||
}
|
||||
|
||||
@@ -169,10 +169,12 @@ import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
@@ -245,7 +247,7 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec
|
||||
private JTextField filterField = new MyTextField("");
|
||||
private JPanel searchPanel;
|
||||
private final PreviewPanel previewPanel;
|
||||
private HeaderInfoPanel headerPanel;
|
||||
private final HeaderInfoPanel headerPanel;
|
||||
private DumpViewPanel dumpViewPanel;
|
||||
private final JPanel treePanel;
|
||||
private TreePanelMode treePanelMode;
|
||||
@@ -2315,7 +2317,7 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec
|
||||
DefineSpriteTag parentSprite = (DefineSpriteTag) fn.getParent();
|
||||
controlTags = parentSprite.subTags;
|
||||
containerId = parentSprite.spriteId;
|
||||
rect = parentSprite.getRect();
|
||||
rect = parentSprite.getRect(new HashSet<BoundedTag>());
|
||||
totalFrameCount = parentSprite.frameCount;
|
||||
timelined = parentSprite;
|
||||
}
|
||||
@@ -2513,7 +2515,7 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec
|
||||
if (tim != null) {
|
||||
return tim;
|
||||
}
|
||||
tim = new Timeline(tag.getSwf(), new ArrayList<Tag>(), ((CharacterTag) tag).getCharacterId(), getRect());
|
||||
tim = new Timeline(tag.getSwf(), new ArrayList<Tag>(), ((CharacterTag) tag).getCharacterId(), getRect(new HashSet<BoundedTag>()));
|
||||
if (tag instanceof MorphShapeTag) {
|
||||
tim.frameRate = MORPH_SHAPE_ANIMATION_FRAME_RATE;
|
||||
int framesCnt = tim.frameRate * MORPH_SHAPE_ANIMATION_LENGTH;
|
||||
@@ -2544,8 +2546,8 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec
|
||||
ds.matrix = new MATRIX();
|
||||
f.layers.put(1, ds);
|
||||
tim.frames.add(f);
|
||||
}
|
||||
tim.displayRect = getRect();
|
||||
}
|
||||
tim.displayRect = getRect(new HashSet<BoundedTag>());
|
||||
return tim;
|
||||
}
|
||||
|
||||
@@ -2555,8 +2557,12 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec
|
||||
}
|
||||
|
||||
@Override
|
||||
public RECT getRect() {
|
||||
return ((BoundedTag) tag).getRect();
|
||||
public RECT getRect(Set<BoundedTag> added) {
|
||||
BoundedTag bt = (BoundedTag) tag;
|
||||
if (!added.contains(bt)) {
|
||||
return bt.getRect(added);
|
||||
}
|
||||
return new RECT(Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ import java.awt.event.ActionEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.util.HashSet;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
@@ -185,7 +186,7 @@ public class PreviewImage extends JPanel {
|
||||
height = (imgSrc.getHeight());
|
||||
} else if (treeItem instanceof BoundedTag) {
|
||||
BoundedTag boundedTag = (BoundedTag) treeItem;
|
||||
RECT rect = boundedTag.getRect();
|
||||
RECT rect = boundedTag.getRect(new HashSet<BoundedTag>());
|
||||
width = (int) (rect.getWidth() / SWF.unitDivisor) + 1;
|
||||
height = (int) (rect.getHeight() / SWF.unitDivisor) + 1;
|
||||
m.translate(-rect.Xmin, -rect.Ymin);
|
||||
|
||||
@@ -575,7 +575,7 @@ public class PreviewPanel extends JSplitPane implements ActionListener {
|
||||
}
|
||||
mat = Helper.deepCopy(mat);
|
||||
if (parent instanceof BoundedTag) {
|
||||
RECT r = ((BoundedTag) parent).getRect();
|
||||
RECT r = ((BoundedTag) parent).getRect(new HashSet<BoundedTag>());
|
||||
mat.translateX = mat.translateX + width / 2 - r.getWidth() / 2;
|
||||
mat.translateY = mat.translateY + height / 2 - r.getHeight() / 2;
|
||||
} else {
|
||||
@@ -617,7 +617,7 @@ public class PreviewPanel extends JSplitPane implements ActionListener {
|
||||
mat.translateX = 0;
|
||||
mat.translateY = 0;
|
||||
if (tagObj instanceof BoundedTag) {
|
||||
RECT r = ((BoundedTag) tagObj).getRect();
|
||||
RECT r = ((BoundedTag) tagObj).getRect(new HashSet<BoundedTag>());
|
||||
mat.translateX = -r.Xmin;
|
||||
mat.translateY = -r.Ymin;
|
||||
mat.translateX = mat.translateX + width / 2 - r.getWidth() / 2;
|
||||
|
||||
@@ -42,6 +42,7 @@ import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
@@ -123,7 +124,7 @@ public class DefineButton2Tag extends ButtonTag implements Container {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
OutputStream os = baos;
|
||||
if (Configuration.debugCopy.get()) {
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(getOriginalData());
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(getOriginalData().getRangeData());
|
||||
os = new CopyOutputStream(os, bais);
|
||||
}
|
||||
SWFOutputStream sos = new SWFOutputStream(os, getVersion());
|
||||
@@ -199,7 +200,7 @@ public class DefineButton2Tag extends ButtonTag implements Container {
|
||||
private static final Cache<RECT> rectCache = Cache.getInstance(true);
|
||||
|
||||
@Override
|
||||
public RECT getRect() {
|
||||
public RECT getRect(Set<BoundedTag> added) {
|
||||
if (rectCache.contains(this)) {
|
||||
return rectCache.get(this);
|
||||
}
|
||||
@@ -207,15 +208,19 @@ public class DefineButton2Tag extends ButtonTag implements Container {
|
||||
for (BUTTONRECORD r : characters) {
|
||||
CharacterTag ch = swf.characters.get(r.characterId);
|
||||
if (ch instanceof BoundedTag) {
|
||||
RECT r2 = ((BoundedTag) ch).getRect();
|
||||
MATRIX mat = r.placeMatrix;
|
||||
if (mat != null) {
|
||||
r2 = mat.apply(r2);
|
||||
BoundedTag bt = (BoundedTag) ch;
|
||||
if (!added.contains(bt)) {
|
||||
added.add(bt);
|
||||
RECT r2 = bt.getRect(added);
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
rectCache.put(this, rect);
|
||||
@@ -252,7 +257,7 @@ public class DefineButton2Tag extends ButtonTag implements Container {
|
||||
if (timeline != null) {
|
||||
return timeline;
|
||||
}
|
||||
timeline = new Timeline(swf, new ArrayList<Tag>(), buttonId, getRect());
|
||||
timeline = new Timeline(swf, new ArrayList<Tag>(), buttonId, getRect(new HashSet<BoundedTag>()));
|
||||
|
||||
int maxDepth = 0;
|
||||
Frame frameUp = new Frame(timeline);
|
||||
|
||||
@@ -47,6 +47,7 @@ import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
@@ -117,7 +118,7 @@ public class DefineButtonTag extends ButtonTag implements ASMSource {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
OutputStream os = baos;
|
||||
if (Configuration.debugCopy.get()) {
|
||||
os = new CopyOutputStream(os, new ByteArrayInputStream(getOriginalData()));
|
||||
os = new CopyOutputStream(os, new ByteArrayInputStream(getOriginalData().getRangeData()));
|
||||
}
|
||||
SWFOutputStream sos = new SWFOutputStream(os, getVersion());
|
||||
try {
|
||||
@@ -233,7 +234,7 @@ public class DefineButtonTag extends ButtonTag implements ASMSource {
|
||||
private static final Cache<RECT> rectCache = Cache.getInstance(true);
|
||||
|
||||
@Override
|
||||
public RECT getRect() {
|
||||
public RECT getRect(Set<BoundedTag> added) {
|
||||
if (rectCache.contains(this)) {
|
||||
return rectCache.get(this);
|
||||
}
|
||||
@@ -241,15 +242,19 @@ public class DefineButtonTag extends ButtonTag implements ASMSource {
|
||||
for (BUTTONRECORD r : characters) {
|
||||
CharacterTag ch = swf.characters.get(r.characterId);
|
||||
if (ch instanceof BoundedTag) {
|
||||
RECT r2 = ((BoundedTag) ch).getRect();
|
||||
MATRIX mat = r.placeMatrix;
|
||||
if (mat != null) {
|
||||
r2 = mat.apply(r2);
|
||||
BoundedTag bt = (BoundedTag) ch;
|
||||
if (!added.contains(bt)){
|
||||
added.add(bt);
|
||||
RECT r2 = bt.getRect(added);
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,7 +323,7 @@ public class DefineButtonTag extends ButtonTag implements ASMSource {
|
||||
if (timeline != null) {
|
||||
return timeline;
|
||||
}
|
||||
timeline = new Timeline(swf, new ArrayList<Tag>(), buttonId, getRect());
|
||||
timeline = new Timeline(swf, new ArrayList<Tag>(), buttonId, getRect(new HashSet<BoundedTag>()));
|
||||
|
||||
ColorTransform clrTrans = null;
|
||||
for (Tag t : swf.tags) {
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
|
||||
import com.jpexs.decompiler.flash.tags.base.BoundedTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.FontTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.MissingCharacterHandler;
|
||||
import com.jpexs.decompiler.flash.tags.base.TextTag;
|
||||
@@ -54,6 +55,7 @@ import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.Stack;
|
||||
@@ -622,7 +624,7 @@ public class DefineEditTextTag extends TextTag {
|
||||
}
|
||||
|
||||
@Override
|
||||
public RECT getRect() {
|
||||
public RECT getRect(Set<BoundedTag> added) {
|
||||
return bounds;
|
||||
}
|
||||
|
||||
@@ -779,7 +781,7 @@ public class DefineEditTextTag extends TextTag {
|
||||
// border is always black, fill color is always white?
|
||||
RGB borderColor = new RGBA(Color.black);
|
||||
RGB fillColor = new RGBA(Color.white);
|
||||
drawBorder(swf, image, borderColor, fillColor, getRect(), getTextMatrix(), transformation, colorTransform);
|
||||
drawBorder(swf, image, borderColor, fillColor, getRect(new HashSet<BoundedTag>()), getTextMatrix(), transformation, colorTransform);
|
||||
}
|
||||
if (hasText) {
|
||||
DynamicTextModel textModel = new DynamicTextModel();
|
||||
|
||||
@@ -187,7 +187,7 @@ public class DefineFont3Tag extends FontTag {
|
||||
OutputStream os = baos;
|
||||
SWFOutputStream sos = new SWFOutputStream(os, getVersion());
|
||||
if (Configuration.debugCopy.get()) {
|
||||
sos = new SWFOutputStream(new CopyOutputStream(sos, new ByteArrayInputStream(getOriginalData())), getVersion());
|
||||
sos = new SWFOutputStream(new CopyOutputStream(sos, new ByteArrayInputStream(getOriginalData().getRangeData())), getVersion());
|
||||
}
|
||||
try {
|
||||
List<Long> offsetTable = new ArrayList<>();
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.jpexs.decompiler.flash.exporters.morphshape.CanvasMorphShapeExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.morphshape.SVGMorphShapeExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.shape.BitmapExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.shape.SVGShapeExporter;
|
||||
import com.jpexs.decompiler.flash.tags.base.BoundedTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.MorphShapeTag;
|
||||
import com.jpexs.decompiler.flash.timeline.DepthState;
|
||||
@@ -98,7 +99,7 @@ public class DefineMorphShape2Tag extends CharacterTag implements MorphShapeTag
|
||||
}
|
||||
|
||||
@Override
|
||||
public RECT getRect() {
|
||||
public RECT getRect(Set<BoundedTag> added) {
|
||||
RECT rect = new RECT();
|
||||
rect.Xmin = Math.min(startBounds.Xmin, endBounds.Xmin);
|
||||
rect.Ymin = Math.min(startBounds.Ymin, endBounds.Ymin);
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.jpexs.decompiler.flash.exporters.morphshape.CanvasMorphShapeExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.morphshape.SVGMorphShapeExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.shape.BitmapExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.shape.SVGShapeExporter;
|
||||
import com.jpexs.decompiler.flash.tags.base.BoundedTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.MorphShapeTag;
|
||||
import com.jpexs.decompiler.flash.timeline.DepthState;
|
||||
@@ -143,7 +144,7 @@ public class DefineMorphShapeTag extends CharacterTag implements MorphShapeTag {
|
||||
}
|
||||
|
||||
@Override
|
||||
public RECT getRect() {
|
||||
public RECT getRect(Set<BoundedTag> added) {
|
||||
RECT rect = new RECT();
|
||||
rect.Xmin = Math.min(startBounds.Xmin, endBounds.Xmin);
|
||||
rect.Ymin = Math.min(startBounds.Ymin, endBounds.Ymin);
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.jpexs.decompiler.flash.tags;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.tags.base.BoundedTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ShapeTag;
|
||||
import com.jpexs.decompiler.flash.types.BasicType;
|
||||
import com.jpexs.decompiler.flash.types.RECT;
|
||||
@@ -64,7 +65,7 @@ public class DefineShape2Tag extends ShapeTag {
|
||||
}
|
||||
|
||||
@Override
|
||||
public RECT getRect() {
|
||||
public RECT getRect(Set<BoundedTag> added) {
|
||||
return shapeBounds;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.jpexs.decompiler.flash.tags;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.tags.base.BoundedTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ShapeTag;
|
||||
import com.jpexs.decompiler.flash.types.BasicType;
|
||||
import com.jpexs.decompiler.flash.types.RECT;
|
||||
@@ -59,7 +60,7 @@ public class DefineShape3Tag extends ShapeTag {
|
||||
}
|
||||
|
||||
@Override
|
||||
public RECT getRect() {
|
||||
public RECT getRect(Set<BoundedTag> added) {
|
||||
return shapeBounds;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.jpexs.decompiler.flash.tags;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.tags.base.BoundedTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ShapeTag;
|
||||
import com.jpexs.decompiler.flash.types.BasicType;
|
||||
import com.jpexs.decompiler.flash.types.RECT;
|
||||
@@ -72,7 +73,7 @@ public class DefineShape4Tag extends ShapeTag {
|
||||
}
|
||||
|
||||
@Override
|
||||
public RECT getRect() {
|
||||
public RECT getRect(Set<BoundedTag> added) {
|
||||
return shapeBounds;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.jpexs.decompiler.flash.tags;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.tags.base.BoundedTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ShapeTag;
|
||||
import com.jpexs.decompiler.flash.types.BasicType;
|
||||
import com.jpexs.decompiler.flash.types.RECT;
|
||||
@@ -61,7 +62,7 @@ public class DefineShapeTag extends ShapeTag {
|
||||
}
|
||||
|
||||
@Override
|
||||
public RECT getRect() {
|
||||
public RECT getRect(Set<BoundedTag> added) {
|
||||
return shapeBounds;
|
||||
}
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ public class DefineSpriteTag extends CharacterTag implements Container, Drawable
|
||||
@Override
|
||||
public Timeline getTimeline() {
|
||||
if (timeline == null) {
|
||||
timeline = new Timeline(swf, subTags, spriteId, getRect());
|
||||
timeline = new Timeline(swf, subTags, spriteId, getRect(new HashSet<BoundedTag>()));
|
||||
}
|
||||
return timeline;
|
||||
}
|
||||
@@ -99,14 +99,18 @@ public class DefineSpriteTag extends CharacterTag implements Container, Drawable
|
||||
return spriteId;
|
||||
}
|
||||
|
||||
private RECT getCharacterBounds(Set<Integer> characters) {
|
||||
private RECT getCharacterBounds(Set<Integer> characters, Set<BoundedTag> added) {
|
||||
RECT ret = new RECT(Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE);
|
||||
boolean foundSomething = false;
|
||||
for (int c : characters) {
|
||||
Tag t = swf.characters.get(c);
|
||||
RECT r = null;
|
||||
if (t instanceof BoundedTag) {
|
||||
r = ((BoundedTag) t).getRect();
|
||||
BoundedTag bt = (BoundedTag) t;
|
||||
if (!added.contains(bt)) {
|
||||
added.add(bt);
|
||||
r = bt.getRect(added);
|
||||
}
|
||||
}
|
||||
if (r != null) {
|
||||
foundSomething = true;
|
||||
@@ -121,14 +125,14 @@ public class DefineSpriteTag extends CharacterTag implements Container, Drawable
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static final Cache<RECT> rectCache = Cache.getInstance(true);
|
||||
|
||||
@Override
|
||||
public RECT getRect() {
|
||||
public RECT getRect(Set<BoundedTag> added) {
|
||||
if (rectCache.contains(this)) {
|
||||
return rectCache.get(this);
|
||||
}
|
||||
RECT emptyRet = new RECT();
|
||||
RECT ret = new RECT(Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE);
|
||||
HashMap<Integer, Integer> depthMap = new HashMap<>();
|
||||
boolean foundSomething = false;
|
||||
@@ -156,7 +160,7 @@ public class DefineSpriteTag extends CharacterTag implements Container, Drawable
|
||||
}
|
||||
Set<Integer> need = new HashSet<>();
|
||||
need.add(characterId);
|
||||
RECT r = getCharacterBounds(need);
|
||||
RECT r = getCharacterBounds(need, added);
|
||||
|
||||
if (m != null) {
|
||||
AffineTransform trans = SWF.matrixToTransform(m);
|
||||
@@ -205,7 +209,7 @@ public class DefineSpriteTag extends CharacterTag implements Container, Drawable
|
||||
spriteId = sis.readUI16("spriteId");
|
||||
frameCount = sis.readUI16("frameCount");
|
||||
List<Tag> subTags = sis.readTagList(this, level + 1, parallel, skipUnusualTags, true, swf.gfx);
|
||||
if (subTags.get(subTags.size() - 1).getId() == EndTag.ID) {
|
||||
if (subTags.size() > 0 && subTags.get(subTags.size() - 1).getId() == EndTag.ID) {
|
||||
hasEndTag = true;
|
||||
subTags.remove(subTags.size() - 1);
|
||||
}
|
||||
@@ -223,7 +227,7 @@ public class DefineSpriteTag extends CharacterTag implements Container, Drawable
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
OutputStream os = baos;
|
||||
if (Configuration.debugCopy.get()) {
|
||||
os = new CopyOutputStream(os, new ByteArrayInputStream(getOriginalData()));
|
||||
os = new CopyOutputStream(os, new ByteArrayInputStream(getOriginalData().getRangeData()));
|
||||
}
|
||||
SWFOutputStream sos = new SWFOutputStream(os, getVersion());
|
||||
try {
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
|
||||
import com.jpexs.decompiler.flash.tags.base.BoundedTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.FontTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.MissingCharacterHandler;
|
||||
import com.jpexs.decompiler.flash.tags.base.TextTag;
|
||||
@@ -44,6 +45,7 @@ import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
@@ -414,7 +416,7 @@ public class DefineText2Tag extends TextTag {
|
||||
}
|
||||
|
||||
@Override
|
||||
public RECT getRect() {
|
||||
public RECT getRect(Set<BoundedTag> added) {
|
||||
return textBounds;
|
||||
}
|
||||
|
||||
@@ -510,7 +512,7 @@ public class DefineText2Tag extends TextTag {
|
||||
|
||||
@Override
|
||||
public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level) {
|
||||
staticTextToSVG(swf, textRecords, 2, exporter, getRect(), getTextMatrix(), colorTransform);
|
||||
staticTextToSVG(swf, textRecords, 2, exporter, getRect(new HashSet<BoundedTag>()), getTextMatrix(), colorTransform);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
|
||||
import com.jpexs.decompiler.flash.tags.base.BoundedTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.FontTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.MissingCharacterHandler;
|
||||
import com.jpexs.decompiler.flash.tags.base.TextTag;
|
||||
@@ -45,6 +46,7 @@ import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
@@ -490,7 +492,7 @@ public class DefineTextTag extends TextTag {
|
||||
}
|
||||
|
||||
@Override
|
||||
public RECT getRect() {
|
||||
public RECT getRect(Set<BoundedTag> added) {
|
||||
return textBounds;
|
||||
}
|
||||
|
||||
@@ -526,7 +528,7 @@ public class DefineTextTag extends TextTag {
|
||||
|
||||
@Override
|
||||
public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level) {
|
||||
staticTextToSVG(swf, textRecords, 1, exporter, getRect(), getTextMatrix(), colorTransform);
|
||||
staticTextToSVG(swf, textRecords, 1, exporter, getRect(new HashSet<BoundedTag>()), getTextMatrix(), colorTransform);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -29,6 +29,7 @@ import com.jpexs.helpers.ByteArrayRange;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -116,7 +117,7 @@ public class DefineVideoStreamTag extends CharacterTag implements BoundedTag {
|
||||
}
|
||||
|
||||
@Override
|
||||
public RECT getRect() {
|
||||
public RECT getRect(Set<BoundedTag> added) {
|
||||
return new RECT(0, (int) (SWF.unitDivisor * width), 0, (int) (SWF.unitDivisor * height));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ public class DoABCDefineTag extends Tag implements ABCContainerTag {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
OutputStream os = bos;
|
||||
if (Configuration.debugCopy.get()) {
|
||||
os = new CopyOutputStream(os, new ByteArrayInputStream(getOriginalData()));
|
||||
os = new CopyOutputStream(os, new ByteArrayInputStream(getOriginalData().getRangeData()));
|
||||
}
|
||||
try (SWFOutputStream sos = new SWFOutputStream(os, getVersion())) {
|
||||
sos.writeUI32(flags);
|
||||
|
||||
@@ -73,7 +73,7 @@ public class DoABCTag extends Tag implements ABCContainerTag {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
OutputStream os = bos;
|
||||
if (Configuration.debugCopy.get()) {
|
||||
os = new CopyOutputStream(os, new ByteArrayInputStream(getOriginalData()));
|
||||
os = new CopyOutputStream(os, new ByteArrayInputStream(getOriginalData().getRangeData()));
|
||||
}
|
||||
try (SWFOutputStream sos = new SWFOutputStream(os, getVersion())) {
|
||||
abc.saveToStream(sos);
|
||||
|
||||
@@ -69,7 +69,7 @@ public class DoActionTag extends Tag implements ASMSource {
|
||||
*/
|
||||
public DoActionTag(SWF swf, ByteArrayRange data) {
|
||||
super(swf, ID, "DoAction", data);
|
||||
actionBytes = new ByteArrayRange(new byte[0]);
|
||||
actionBytes = new ByteArrayRange();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,402 +1,402 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.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.CopyOutputStream;
|
||||
import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterIdTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.Container;
|
||||
import com.jpexs.decompiler.flash.tags.base.ContainerItem;
|
||||
import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag;
|
||||
import com.jpexs.decompiler.flash.types.BasicType;
|
||||
import com.jpexs.decompiler.flash.types.CLIPACTIONS;
|
||||
import com.jpexs.decompiler.flash.types.CXFORMWITHALPHA;
|
||||
import com.jpexs.decompiler.flash.types.ColorTransform;
|
||||
import com.jpexs.decompiler.flash.types.MATRIX;
|
||||
import com.jpexs.decompiler.flash.types.RGBA;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Conditional;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Internal;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFType;
|
||||
import com.jpexs.decompiler.flash.types.filters.FILTER;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Extends the functionality of the PlaceObject2Tag
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class PlaceObject2Tag extends CharacterIdTag implements Container, PlaceObjectTypeTag {
|
||||
|
||||
/**
|
||||
* @since SWF 5 Has clip actions (sprite characters only)
|
||||
*/
|
||||
public boolean placeFlagHasClipActions;
|
||||
/**
|
||||
* Has clip depth
|
||||
*/
|
||||
public boolean placeFlagHasClipDepth;
|
||||
/**
|
||||
* Has name
|
||||
*/
|
||||
public boolean placeFlagHasName;
|
||||
/**
|
||||
* Has ratio
|
||||
*/
|
||||
public boolean placeFlagHasRatio;
|
||||
/**
|
||||
* Has color transform
|
||||
*/
|
||||
public boolean placeFlagHasColorTransform;
|
||||
/**
|
||||
* Has matrix
|
||||
*/
|
||||
public boolean placeFlagHasMatrix;
|
||||
/**
|
||||
* Places a character
|
||||
*/
|
||||
public boolean placeFlagHasCharacter;
|
||||
/**
|
||||
* Defines a character to be moved
|
||||
*/
|
||||
public boolean placeFlagMove;
|
||||
/**
|
||||
* Depth of character
|
||||
*/
|
||||
@SWFType(BasicType.UI16)
|
||||
public int depth;
|
||||
/**
|
||||
* If PlaceFlagHasCharacter, ID of character to place
|
||||
*/
|
||||
@SWFType(BasicType.UI16)
|
||||
@Conditional("placeFlagHasCharacter")
|
||||
public int characterId;
|
||||
/**
|
||||
* If PlaceFlagHasMatrix, Transform matrix data
|
||||
*/
|
||||
@Conditional("placeFlagHasMatrix")
|
||||
public MATRIX matrix;
|
||||
/**
|
||||
* If PlaceFlagHasColorTransform, Color transform data
|
||||
*/
|
||||
@Conditional("placeFlagHasColorTransform")
|
||||
public CXFORMWITHALPHA colorTransform;
|
||||
/**
|
||||
* If PlaceFlagHasRatio, ratio
|
||||
*/
|
||||
@SWFType(BasicType.UI16)
|
||||
@Conditional("placeFlagHasRatio")
|
||||
public int ratio;
|
||||
/**
|
||||
* If PlaceFlagHasName, Name of character
|
||||
*/
|
||||
@Conditional("placeFlagHasName")
|
||||
public String name;
|
||||
/**
|
||||
* If PlaceFlagHasClipDepth, Clip depth
|
||||
*/
|
||||
@Conditional("placeFlagHasClipDepth")
|
||||
public int clipDepth;
|
||||
/**
|
||||
* @since SWF 5 If PlaceFlagHasClipActions, Clip Actions Data
|
||||
*/
|
||||
@Conditional("placeFlagHasClipActions")
|
||||
@Internal //TODO: make editable
|
||||
public CLIPACTIONS clipActions;
|
||||
public static final int ID = 26;
|
||||
|
||||
@Override
|
||||
public int getClipDepth() {
|
||||
if (placeFlagHasClipDepth) {
|
||||
return clipDepth;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FILTER> getFilters() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets data bytes
|
||||
*
|
||||
* @return Bytes of data
|
||||
*/
|
||||
@Override
|
||||
public byte[] getData() {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
OutputStream os = baos;
|
||||
if (Configuration.debugCopy.get()) {
|
||||
os = new CopyOutputStream(os, new ByteArrayInputStream(getOriginalData()));
|
||||
}
|
||||
SWFOutputStream sos = new SWFOutputStream(os, getVersion());
|
||||
try {
|
||||
sos.writeUB(1, placeFlagHasClipActions ? 1 : 0);
|
||||
sos.writeUB(1, placeFlagHasClipDepth ? 1 : 0);
|
||||
sos.writeUB(1, placeFlagHasName ? 1 : 0);
|
||||
sos.writeUB(1, placeFlagHasRatio ? 1 : 0);
|
||||
sos.writeUB(1, placeFlagHasColorTransform ? 1 : 0);
|
||||
sos.writeUB(1, placeFlagHasMatrix ? 1 : 0);
|
||||
sos.writeUB(1, placeFlagHasCharacter ? 1 : 0);
|
||||
sos.writeUB(1, placeFlagMove ? 1 : 0);
|
||||
sos.writeUI16(depth);
|
||||
if (placeFlagHasCharacter) {
|
||||
sos.writeUI16(characterId);
|
||||
}
|
||||
if (placeFlagHasMatrix) {
|
||||
sos.writeMatrix(matrix);
|
||||
}
|
||||
if (placeFlagHasColorTransform) {
|
||||
sos.writeCXFORMWITHALPHA(colorTransform);
|
||||
}
|
||||
if (placeFlagHasRatio) {
|
||||
sos.writeUI16(ratio);
|
||||
}
|
||||
if (placeFlagHasName) {
|
||||
sos.writeString(name);
|
||||
}
|
||||
if (placeFlagHasClipDepth) {
|
||||
sos.writeUI16(clipDepth);
|
||||
}
|
||||
if (placeFlagHasClipActions) {
|
||||
sos.writeCLIPACTIONS(clipActions);
|
||||
}
|
||||
sos.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
public PlaceObject2Tag(SWF swf, boolean placeFlagHasClipActions, boolean placeFlagHasClipDepth, boolean placeFlagHasName, boolean placeFlagHasRatio, boolean placeFlagHasColorTransform, boolean placeFlagHasMatrix, boolean placeFlagHasCharacter, boolean placeFlagMove, int depth, int characterId, MATRIX matrix, CXFORMWITHALPHA colorTransform, int ratio, String name, int clipDepth, CLIPACTIONS clipActions) {
|
||||
super(swf, ID, "PlaceObject2", null);
|
||||
this.placeFlagHasClipActions = placeFlagHasClipActions;
|
||||
this.placeFlagHasClipDepth = placeFlagHasClipDepth;
|
||||
this.placeFlagHasName = placeFlagHasName;
|
||||
this.placeFlagHasRatio = placeFlagHasRatio;
|
||||
this.placeFlagHasColorTransform = placeFlagHasColorTransform;
|
||||
this.placeFlagHasMatrix = placeFlagHasMatrix;
|
||||
this.placeFlagHasCharacter = placeFlagHasCharacter;
|
||||
this.placeFlagMove = placeFlagMove;
|
||||
this.depth = depth;
|
||||
this.characterId = characterId;
|
||||
this.matrix = matrix;
|
||||
this.colorTransform = colorTransform;
|
||||
this.ratio = ratio;
|
||||
this.name = name;
|
||||
this.clipDepth = clipDepth;
|
||||
this.clipActions = clipActions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param sis
|
||||
* @param data
|
||||
* @throws IOException
|
||||
*/
|
||||
public PlaceObject2Tag(SWFInputStream sis, ByteArrayRange data) throws IOException {
|
||||
super(sis.getSwf(), ID, "PlaceObject2", data);
|
||||
placeFlagHasClipActions = sis.readUB(1, "placeFlagHasClipActions") == 1;
|
||||
placeFlagHasClipDepth = sis.readUB(1, "placeFlagHasClipDepth") == 1;
|
||||
placeFlagHasName = sis.readUB(1, "placeFlagHasName") == 1;
|
||||
placeFlagHasRatio = sis.readUB(1, "placeFlagHasRatio") == 1;
|
||||
placeFlagHasColorTransform = sis.readUB(1, "placeFlagHasColorTransform") == 1;
|
||||
placeFlagHasMatrix = sis.readUB(1, "placeFlagHasMatrix") == 1;
|
||||
placeFlagHasCharacter = sis.readUB(1, "placeFlagHasCharacter") == 1;
|
||||
placeFlagMove = sis.readUB(1, "placeFlagMove") == 1;
|
||||
|
||||
depth = sis.readUI16("depth");
|
||||
if (placeFlagHasCharacter) {
|
||||
characterId = sis.readUI16("characterId");
|
||||
}
|
||||
if (placeFlagHasMatrix) {
|
||||
matrix = sis.readMatrix("matrix");
|
||||
}
|
||||
if (placeFlagHasColorTransform) {
|
||||
colorTransform = sis.readCXFORMWITHALPHA("colorTransform");
|
||||
}
|
||||
if (placeFlagHasRatio) {
|
||||
ratio = sis.readUI16("ratio");
|
||||
}
|
||||
if (placeFlagHasName) {
|
||||
name = sis.readString("name");
|
||||
}
|
||||
if (placeFlagHasClipDepth) {
|
||||
clipDepth = sis.readUI16("clipDepth");
|
||||
}
|
||||
if (placeFlagHasClipActions) {
|
||||
clipActions = sis.readCLIPACTIONS(swf, this, "clipActions");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all sub-items
|
||||
*
|
||||
* @return List of sub-items
|
||||
*/
|
||||
@Override
|
||||
public List<ContainerItem> getSubItems() {
|
||||
List<ContainerItem> ret = new ArrayList<>();
|
||||
if (placeFlagHasClipActions) {
|
||||
ret.addAll(clipActions.clipActionRecords);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns number of sub-items
|
||||
*
|
||||
* @return Number of sub-items
|
||||
*/
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
if (!placeFlagHasClipActions) {
|
||||
return 0;
|
||||
}
|
||||
return clipActions.clipActionRecords.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getNeededCharacters(Set<Integer> needed) {
|
||||
if (placeFlagHasCharacter) {
|
||||
needed.add(characterId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeCharacter(int characterId) {
|
||||
// the place object tag will be removed
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCharacterId() {
|
||||
if (placeFlagHasCharacter) {
|
||||
return characterId;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDepth() {
|
||||
return depth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MATRIX getMatrix() {
|
||||
if (placeFlagHasMatrix) {
|
||||
return matrix;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInstanceName() {
|
||||
if (placeFlagHasName) {
|
||||
return name;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ColorTransform getColorTransform() {
|
||||
if (placeFlagHasColorTransform) {
|
||||
return colorTransform;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBlendMode() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cacheAsBitmap() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClassName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVisible() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RGBA getBackgroundColor() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean flagMove() {
|
||||
return placeFlagMove;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRatio() {
|
||||
if (!placeFlagHasRatio) {
|
||||
return -1;
|
||||
}
|
||||
return ratio;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInstanceName(String name) {
|
||||
placeFlagHasName = true;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClassName(String className) {
|
||||
//not supported
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (placeFlagHasName) {
|
||||
return super.toString() + " (" + name + ")";
|
||||
} else {
|
||||
return super.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CLIPACTIONS getClipActions() {
|
||||
if (placeFlagHasClipActions) {
|
||||
return clipActions;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.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.CopyOutputStream;
|
||||
import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterIdTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.Container;
|
||||
import com.jpexs.decompiler.flash.tags.base.ContainerItem;
|
||||
import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag;
|
||||
import com.jpexs.decompiler.flash.types.BasicType;
|
||||
import com.jpexs.decompiler.flash.types.CLIPACTIONS;
|
||||
import com.jpexs.decompiler.flash.types.CXFORMWITHALPHA;
|
||||
import com.jpexs.decompiler.flash.types.ColorTransform;
|
||||
import com.jpexs.decompiler.flash.types.MATRIX;
|
||||
import com.jpexs.decompiler.flash.types.RGBA;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Conditional;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Internal;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFType;
|
||||
import com.jpexs.decompiler.flash.types.filters.FILTER;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Extends the functionality of the PlaceObject2Tag
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class PlaceObject2Tag extends CharacterIdTag implements Container, PlaceObjectTypeTag {
|
||||
|
||||
/**
|
||||
* @since SWF 5 Has clip actions (sprite characters only)
|
||||
*/
|
||||
public boolean placeFlagHasClipActions;
|
||||
/**
|
||||
* Has clip depth
|
||||
*/
|
||||
public boolean placeFlagHasClipDepth;
|
||||
/**
|
||||
* Has name
|
||||
*/
|
||||
public boolean placeFlagHasName;
|
||||
/**
|
||||
* Has ratio
|
||||
*/
|
||||
public boolean placeFlagHasRatio;
|
||||
/**
|
||||
* Has color transform
|
||||
*/
|
||||
public boolean placeFlagHasColorTransform;
|
||||
/**
|
||||
* Has matrix
|
||||
*/
|
||||
public boolean placeFlagHasMatrix;
|
||||
/**
|
||||
* Places a character
|
||||
*/
|
||||
public boolean placeFlagHasCharacter;
|
||||
/**
|
||||
* Defines a character to be moved
|
||||
*/
|
||||
public boolean placeFlagMove;
|
||||
/**
|
||||
* Depth of character
|
||||
*/
|
||||
@SWFType(BasicType.UI16)
|
||||
public int depth;
|
||||
/**
|
||||
* If PlaceFlagHasCharacter, ID of character to place
|
||||
*/
|
||||
@SWFType(BasicType.UI16)
|
||||
@Conditional("placeFlagHasCharacter")
|
||||
public int characterId;
|
||||
/**
|
||||
* If PlaceFlagHasMatrix, Transform matrix data
|
||||
*/
|
||||
@Conditional("placeFlagHasMatrix")
|
||||
public MATRIX matrix;
|
||||
/**
|
||||
* If PlaceFlagHasColorTransform, Color transform data
|
||||
*/
|
||||
@Conditional("placeFlagHasColorTransform")
|
||||
public CXFORMWITHALPHA colorTransform;
|
||||
/**
|
||||
* If PlaceFlagHasRatio, ratio
|
||||
*/
|
||||
@SWFType(BasicType.UI16)
|
||||
@Conditional("placeFlagHasRatio")
|
||||
public int ratio;
|
||||
/**
|
||||
* If PlaceFlagHasName, Name of character
|
||||
*/
|
||||
@Conditional("placeFlagHasName")
|
||||
public String name;
|
||||
/**
|
||||
* If PlaceFlagHasClipDepth, Clip depth
|
||||
*/
|
||||
@Conditional("placeFlagHasClipDepth")
|
||||
public int clipDepth;
|
||||
/**
|
||||
* @since SWF 5 If PlaceFlagHasClipActions, Clip Actions Data
|
||||
*/
|
||||
@Conditional("placeFlagHasClipActions")
|
||||
@Internal //TODO: make editable
|
||||
public CLIPACTIONS clipActions;
|
||||
public static final int ID = 26;
|
||||
|
||||
@Override
|
||||
public int getClipDepth() {
|
||||
if (placeFlagHasClipDepth) {
|
||||
return clipDepth;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FILTER> getFilters() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets data bytes
|
||||
*
|
||||
* @return Bytes of data
|
||||
*/
|
||||
@Override
|
||||
public byte[] getData() {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
OutputStream os = baos;
|
||||
if (Configuration.debugCopy.get()) {
|
||||
os = new CopyOutputStream(os, new ByteArrayInputStream(getOriginalData().getRangeData()));
|
||||
}
|
||||
SWFOutputStream sos = new SWFOutputStream(os, getVersion());
|
||||
try {
|
||||
sos.writeUB(1, placeFlagHasClipActions ? 1 : 0);
|
||||
sos.writeUB(1, placeFlagHasClipDepth ? 1 : 0);
|
||||
sos.writeUB(1, placeFlagHasName ? 1 : 0);
|
||||
sos.writeUB(1, placeFlagHasRatio ? 1 : 0);
|
||||
sos.writeUB(1, placeFlagHasColorTransform ? 1 : 0);
|
||||
sos.writeUB(1, placeFlagHasMatrix ? 1 : 0);
|
||||
sos.writeUB(1, placeFlagHasCharacter ? 1 : 0);
|
||||
sos.writeUB(1, placeFlagMove ? 1 : 0);
|
||||
sos.writeUI16(depth);
|
||||
if (placeFlagHasCharacter) {
|
||||
sos.writeUI16(characterId);
|
||||
}
|
||||
if (placeFlagHasMatrix) {
|
||||
sos.writeMatrix(matrix);
|
||||
}
|
||||
if (placeFlagHasColorTransform) {
|
||||
sos.writeCXFORMWITHALPHA(colorTransform);
|
||||
}
|
||||
if (placeFlagHasRatio) {
|
||||
sos.writeUI16(ratio);
|
||||
}
|
||||
if (placeFlagHasName) {
|
||||
sos.writeString(name);
|
||||
}
|
||||
if (placeFlagHasClipDepth) {
|
||||
sos.writeUI16(clipDepth);
|
||||
}
|
||||
if (placeFlagHasClipActions) {
|
||||
sos.writeCLIPACTIONS(clipActions);
|
||||
}
|
||||
sos.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
public PlaceObject2Tag(SWF swf, boolean placeFlagHasClipActions, boolean placeFlagHasClipDepth, boolean placeFlagHasName, boolean placeFlagHasRatio, boolean placeFlagHasColorTransform, boolean placeFlagHasMatrix, boolean placeFlagHasCharacter, boolean placeFlagMove, int depth, int characterId, MATRIX matrix, CXFORMWITHALPHA colorTransform, int ratio, String name, int clipDepth, CLIPACTIONS clipActions) {
|
||||
super(swf, ID, "PlaceObject2", null);
|
||||
this.placeFlagHasClipActions = placeFlagHasClipActions;
|
||||
this.placeFlagHasClipDepth = placeFlagHasClipDepth;
|
||||
this.placeFlagHasName = placeFlagHasName;
|
||||
this.placeFlagHasRatio = placeFlagHasRatio;
|
||||
this.placeFlagHasColorTransform = placeFlagHasColorTransform;
|
||||
this.placeFlagHasMatrix = placeFlagHasMatrix;
|
||||
this.placeFlagHasCharacter = placeFlagHasCharacter;
|
||||
this.placeFlagMove = placeFlagMove;
|
||||
this.depth = depth;
|
||||
this.characterId = characterId;
|
||||
this.matrix = matrix;
|
||||
this.colorTransform = colorTransform;
|
||||
this.ratio = ratio;
|
||||
this.name = name;
|
||||
this.clipDepth = clipDepth;
|
||||
this.clipActions = clipActions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param sis
|
||||
* @param data
|
||||
* @throws IOException
|
||||
*/
|
||||
public PlaceObject2Tag(SWFInputStream sis, ByteArrayRange data) throws IOException {
|
||||
super(sis.getSwf(), ID, "PlaceObject2", data);
|
||||
placeFlagHasClipActions = sis.readUB(1, "placeFlagHasClipActions") == 1;
|
||||
placeFlagHasClipDepth = sis.readUB(1, "placeFlagHasClipDepth") == 1;
|
||||
placeFlagHasName = sis.readUB(1, "placeFlagHasName") == 1;
|
||||
placeFlagHasRatio = sis.readUB(1, "placeFlagHasRatio") == 1;
|
||||
placeFlagHasColorTransform = sis.readUB(1, "placeFlagHasColorTransform") == 1;
|
||||
placeFlagHasMatrix = sis.readUB(1, "placeFlagHasMatrix") == 1;
|
||||
placeFlagHasCharacter = sis.readUB(1, "placeFlagHasCharacter") == 1;
|
||||
placeFlagMove = sis.readUB(1, "placeFlagMove") == 1;
|
||||
|
||||
depth = sis.readUI16("depth");
|
||||
if (placeFlagHasCharacter) {
|
||||
characterId = sis.readUI16("characterId");
|
||||
}
|
||||
if (placeFlagHasMatrix) {
|
||||
matrix = sis.readMatrix("matrix");
|
||||
}
|
||||
if (placeFlagHasColorTransform) {
|
||||
colorTransform = sis.readCXFORMWITHALPHA("colorTransform");
|
||||
}
|
||||
if (placeFlagHasRatio) {
|
||||
ratio = sis.readUI16("ratio");
|
||||
}
|
||||
if (placeFlagHasName) {
|
||||
name = sis.readString("name");
|
||||
}
|
||||
if (placeFlagHasClipDepth) {
|
||||
clipDepth = sis.readUI16("clipDepth");
|
||||
}
|
||||
if (placeFlagHasClipActions) {
|
||||
clipActions = sis.readCLIPACTIONS(swf, this, "clipActions");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all sub-items
|
||||
*
|
||||
* @return List of sub-items
|
||||
*/
|
||||
@Override
|
||||
public List<ContainerItem> getSubItems() {
|
||||
List<ContainerItem> ret = new ArrayList<>();
|
||||
if (placeFlagHasClipActions) {
|
||||
ret.addAll(clipActions.clipActionRecords);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns number of sub-items
|
||||
*
|
||||
* @return Number of sub-items
|
||||
*/
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
if (!placeFlagHasClipActions) {
|
||||
return 0;
|
||||
}
|
||||
return clipActions.clipActionRecords.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getNeededCharacters(Set<Integer> needed) {
|
||||
if (placeFlagHasCharacter) {
|
||||
needed.add(characterId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeCharacter(int characterId) {
|
||||
// the place object tag will be removed
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCharacterId() {
|
||||
if (placeFlagHasCharacter) {
|
||||
return characterId;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDepth() {
|
||||
return depth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MATRIX getMatrix() {
|
||||
if (placeFlagHasMatrix) {
|
||||
return matrix;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInstanceName() {
|
||||
if (placeFlagHasName) {
|
||||
return name;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ColorTransform getColorTransform() {
|
||||
if (placeFlagHasColorTransform) {
|
||||
return colorTransform;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBlendMode() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cacheAsBitmap() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClassName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVisible() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RGBA getBackgroundColor() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean flagMove() {
|
||||
return placeFlagMove;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRatio() {
|
||||
if (!placeFlagHasRatio) {
|
||||
return -1;
|
||||
}
|
||||
return ratio;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInstanceName(String name) {
|
||||
placeFlagHasName = true;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClassName(String className) {
|
||||
//not supported
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (placeFlagHasName) {
|
||||
return super.toString() + " (" + name + ")";
|
||||
} else {
|
||||
return super.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CLIPACTIONS getClipActions() {
|
||||
if (placeFlagHasClipActions) {
|
||||
return clipActions;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,449 +1,448 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.tags;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.tags.base.ContainerItem;
|
||||
import com.jpexs.decompiler.flash.tags.base.Exportable;
|
||||
import com.jpexs.decompiler.flash.tags.base.NeedsCharacters;
|
||||
import com.jpexs.decompiler.flash.tags.gfx.DefineCompactedFont;
|
||||
import com.jpexs.decompiler.flash.tags.gfx.DefineExternalGradient;
|
||||
import com.jpexs.decompiler.flash.tags.gfx.DefineExternalImage;
|
||||
import com.jpexs.decompiler.flash.tags.gfx.DefineExternalImage2;
|
||||
import com.jpexs.decompiler.flash.tags.gfx.DefineExternalSound;
|
||||
import com.jpexs.decompiler.flash.tags.gfx.DefineExternalStreamSound;
|
||||
import com.jpexs.decompiler.flash.tags.gfx.DefineGradientMap;
|
||||
import com.jpexs.decompiler.flash.tags.gfx.DefineSubImage;
|
||||
import com.jpexs.decompiler.flash.tags.gfx.ExporterInfoTag;
|
||||
import com.jpexs.decompiler.flash.tags.gfx.FontTextureInfo;
|
||||
import com.jpexs.decompiler.flash.timeline.Timelined;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Internal;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Represents Tag inside SWF file
|
||||
*/
|
||||
public abstract class Tag implements NeedsCharacters, Exportable, ContainerItem, Serializable {
|
||||
|
||||
/**
|
||||
* Identifier of tag type
|
||||
*/
|
||||
protected int id;
|
||||
/**
|
||||
* If true, then Tag is written to the stream as longer than 0x3f even if it
|
||||
* is not
|
||||
*/
|
||||
@Internal
|
||||
public boolean forceWriteAsLong = false;
|
||||
protected String tagName;
|
||||
@Internal
|
||||
protected transient SWF swf;
|
||||
@Internal
|
||||
protected transient Timelined timelined;
|
||||
@Internal
|
||||
private boolean modified;
|
||||
/**
|
||||
* Original tag data
|
||||
*/
|
||||
@Internal
|
||||
private ByteArrayRange originalData;
|
||||
|
||||
public String getTagName() {
|
||||
return tagName;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return tagName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExportFileName() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns identifier of tag type
|
||||
*
|
||||
* @return Identifier of tag type
|
||||
*/
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SWF getSwf() {
|
||||
return swf;
|
||||
}
|
||||
|
||||
public void setSwf(SWF swf) {
|
||||
this.swf = swf;
|
||||
}
|
||||
|
||||
public Timelined getTimelined() {
|
||||
return timelined;
|
||||
}
|
||||
|
||||
public void setTimelined(Timelined timelined) {
|
||||
this.timelined = timelined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param swf The SWF
|
||||
* @param id Tag type identifier
|
||||
* @param name Tag name
|
||||
* @param data Original tag data
|
||||
*/
|
||||
public Tag(SWF swf, int id, String name, ByteArrayRange data) {
|
||||
this.id = id;
|
||||
this.tagName = name;
|
||||
this.originalData = data;
|
||||
this.swf = swf;
|
||||
if (swf == null) {
|
||||
throw new Error("swf parameter cannot be null.");
|
||||
}
|
||||
if (data == null) { // it is tag build by constructor
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static final Object lockObject = new Object();
|
||||
private static List<Integer> knownTagIds;
|
||||
private static List<Integer> requiredTagIds;
|
||||
|
||||
public static List<Integer> getKnownTags() {
|
||||
if (knownTagIds == null) {
|
||||
synchronized (lockObject) {
|
||||
if (knownTagIds == null) {
|
||||
List<Integer> tagIds = Arrays.asList(
|
||||
CSMTextSettingsTag.ID,
|
||||
DebugIDTag.ID,
|
||||
DefineBinaryDataTag.ID,
|
||||
DefineBitsJPEG2Tag.ID,
|
||||
DefineBitsJPEG3Tag.ID,
|
||||
DefineBitsJPEG4Tag.ID,
|
||||
DefineBitsLossless2Tag.ID,
|
||||
DefineBitsLosslessTag.ID,
|
||||
DefineBitsTag.ID,
|
||||
DefineButton2Tag.ID,
|
||||
DefineButtonCxformTag.ID,
|
||||
DefineButtonSoundTag.ID,
|
||||
DefineButtonTag.ID,
|
||||
DefineEditTextTag.ID,
|
||||
DefineFont2Tag.ID,
|
||||
DefineFont3Tag.ID,
|
||||
DefineFont4Tag.ID,
|
||||
DefineFontAlignZonesTag.ID,
|
||||
DefineFontInfo2Tag.ID,
|
||||
DefineFontInfoTag.ID,
|
||||
DefineFontNameTag.ID,
|
||||
DefineFontTag.ID,
|
||||
DefineMorphShape2Tag.ID,
|
||||
DefineMorphShapeTag.ID,
|
||||
DefineScalingGridTag.ID,
|
||||
DefineSceneAndFrameLabelDataTag.ID,
|
||||
DefineShape2Tag.ID,
|
||||
DefineShape3Tag.ID,
|
||||
DefineShape4Tag.ID,
|
||||
DefineShapeTag.ID,
|
||||
DefineSoundTag.ID,
|
||||
DefineSpriteTag.ID,
|
||||
DefineText2Tag.ID,
|
||||
DefineTextTag.ID,
|
||||
DefineVideoStreamTag.ID,
|
||||
DoABCDefineTag.ID,
|
||||
DoABCTag.ID,
|
||||
DoActionTag.ID,
|
||||
DoInitActionTag.ID,
|
||||
EnableDebugger2Tag.ID,
|
||||
EnableDebuggerTag.ID,
|
||||
EnableTelemetryTag.ID,
|
||||
EndTag.ID,
|
||||
ExportAssetsTag.ID,
|
||||
FileAttributesTag.ID,
|
||||
FrameLabelTag.ID,
|
||||
ImportAssets2Tag.ID,
|
||||
ImportAssetsTag.ID,
|
||||
JPEGTablesTag.ID,
|
||||
MetadataTag.ID,
|
||||
PlaceObject2Tag.ID,
|
||||
PlaceObject3Tag.ID,
|
||||
PlaceObject4Tag.ID,
|
||||
PlaceObjectTag.ID,
|
||||
ProductInfoTag.ID,
|
||||
ProtectTag.ID,
|
||||
RemoveObject2Tag.ID,
|
||||
RemoveObjectTag.ID,
|
||||
ScriptLimitsTag.ID,
|
||||
SetBackgroundColorTag.ID,
|
||||
SetTabIndexTag.ID,
|
||||
ShowFrameTag.ID,
|
||||
SoundStreamBlockTag.ID,
|
||||
SoundStreamHead2Tag.ID,
|
||||
SoundStreamHeadTag.ID,
|
||||
StartSound2Tag.ID,
|
||||
StartSoundTag.ID,
|
||||
SymbolClassTag.ID,
|
||||
VideoFrameTag.ID,
|
||||
DefineCompactedFont.ID,
|
||||
DefineExternalGradient.ID,
|
||||
DefineExternalImage.ID,
|
||||
DefineExternalImage2.ID,
|
||||
DefineExternalSound.ID,
|
||||
DefineExternalStreamSound.ID,
|
||||
DefineGradientMap.ID,
|
||||
DefineSubImage.ID,
|
||||
ExporterInfoTag.ID,
|
||||
FontTextureInfo.ID);
|
||||
knownTagIds = tagIds;
|
||||
}
|
||||
}
|
||||
}
|
||||
return knownTagIds;
|
||||
}
|
||||
|
||||
public static List<Integer> getRequiredTags() {
|
||||
if (requiredTagIds == null) {
|
||||
synchronized (lockObject) {
|
||||
if (requiredTagIds == null) {
|
||||
List<Integer> tagIds = Arrays.asList(
|
||||
DefineBinaryDataTag.ID,
|
||||
DefineBitsJPEG2Tag.ID,
|
||||
DefineBitsJPEG3Tag.ID,
|
||||
DefineBitsJPEG4Tag.ID,
|
||||
DefineBitsLossless2Tag.ID,
|
||||
DefineBitsLosslessTag.ID,
|
||||
DefineBitsTag.ID,
|
||||
DefineButton2Tag.ID,
|
||||
DefineButtonCxformTag.ID,
|
||||
DefineButtonSoundTag.ID,
|
||||
DefineButtonTag.ID,
|
||||
DefineEditTextTag.ID,
|
||||
DefineFont2Tag.ID,
|
||||
DefineFont3Tag.ID,
|
||||
DefineFont4Tag.ID,
|
||||
DefineFontAlignZonesTag.ID,
|
||||
DefineFontInfo2Tag.ID,
|
||||
DefineFontInfoTag.ID,
|
||||
DefineFontNameTag.ID,
|
||||
DefineFontTag.ID,
|
||||
DefineMorphShape2Tag.ID,
|
||||
DefineMorphShapeTag.ID,
|
||||
DefineScalingGridTag.ID,
|
||||
DefineSceneAndFrameLabelDataTag.ID,
|
||||
DefineShape2Tag.ID,
|
||||
DefineShape3Tag.ID,
|
||||
DefineShape4Tag.ID,
|
||||
DefineShapeTag.ID,
|
||||
DefineSoundTag.ID,
|
||||
DefineSpriteTag.ID,
|
||||
DefineText2Tag.ID,
|
||||
DefineTextTag.ID,
|
||||
DefineVideoStreamTag.ID,
|
||||
DoABCDefineTag.ID,
|
||||
DoABCTag.ID,
|
||||
DoActionTag.ID,
|
||||
DoInitActionTag.ID,
|
||||
ShowFrameTag.ID);
|
||||
requiredTagIds = tagIds;
|
||||
}
|
||||
}
|
||||
}
|
||||
return requiredTagIds;
|
||||
}
|
||||
|
||||
public int getVersion() {
|
||||
if (swf == null) {
|
||||
return SWF.DEFAULT_VERSION;
|
||||
}
|
||||
return swf.version;
|
||||
}
|
||||
|
||||
protected byte[] getHeader(byte[] data) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try {
|
||||
|
||||
SWFOutputStream sos = new SWFOutputStream(baos, swf.version);
|
||||
int tagLength = data.length;
|
||||
int tagID = getId();
|
||||
int tagIDLength = (tagID << 6);
|
||||
if ((tagLength <= 62) && (!forceWriteAsLong)) {
|
||||
tagIDLength += tagLength;
|
||||
sos.writeUI16(tagIDLength);
|
||||
} else {
|
||||
tagIDLength += 0x3f;
|
||||
sos.writeUI16(tagIDLength);
|
||||
sos.writeSI32(tagLength);
|
||||
}
|
||||
} catch (IOException iex) {
|
||||
}
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
public static byte[] getTagHeader(int tagIDTagLength, long tagLength, boolean writeLong, int version) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try {
|
||||
|
||||
SWFOutputStream sos = new SWFOutputStream(baos, version);
|
||||
sos.writeUI16(tagIDTagLength);
|
||||
if (writeLong) {
|
||||
sos.writeSI32(tagLength);
|
||||
}
|
||||
} catch (IOException iex) {
|
||||
}
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes Tag value to the stream
|
||||
*
|
||||
* @param sos SWF output stream
|
||||
* @throws IOException
|
||||
*/
|
||||
public void writeTag(SWFOutputStream sos) throws IOException {
|
||||
if (isModified()) {
|
||||
byte[] newData = getData();
|
||||
byte[] newHeaderData = getHeader(newData);
|
||||
sos.write(newHeaderData);
|
||||
sos.write(newData);
|
||||
} else {
|
||||
sos.write(originalData.array, originalData.pos, originalData.length);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns string representation of the object
|
||||
*
|
||||
* @return String representation of the object
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets data bytes
|
||||
*
|
||||
* @return Bytes of data
|
||||
*/
|
||||
public byte[] getData() {
|
||||
return getOriginalData();
|
||||
}
|
||||
|
||||
public final ByteArrayRange getOriginalRange() {
|
||||
return originalData;
|
||||
}
|
||||
|
||||
public final byte[] getOriginalData() {
|
||||
if (originalData == null) {
|
||||
return new byte[0];
|
||||
}
|
||||
// todo honfika: do not copy data
|
||||
int dataLength = getOriginalDataLength();
|
||||
byte[] data = new byte[dataLength];
|
||||
System.arraycopy(originalData.array, (int) (originalData.pos + originalData.length - dataLength), data, 0, dataLength);
|
||||
return data;
|
||||
}
|
||||
|
||||
public final int getOriginalDataLength() {
|
||||
if (originalData == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return originalData.length - (isLongOriginal() ? 6 : 2);
|
||||
}
|
||||
|
||||
private final boolean isLongOriginal() {
|
||||
int shortLength = originalData.array[(int) originalData.pos] & 0x003F;
|
||||
return shortLength == 0x3f;
|
||||
}
|
||||
|
||||
public boolean hasSubTags() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public List<Tag> getSubTags() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public long getPos() {
|
||||
return originalData.pos;
|
||||
}
|
||||
|
||||
public long getDataPos() {
|
||||
return originalData.pos + (isLongOriginal() ? 6 : 2);
|
||||
}
|
||||
|
||||
public void setModified(boolean value) {
|
||||
modified = value;
|
||||
}
|
||||
|
||||
public void createOriginalData() {
|
||||
byte[] data = getData();
|
||||
byte[] headerData = getHeader(data);
|
||||
byte[] tagData = new byte[data.length + headerData.length];
|
||||
System.arraycopy(headerData, 0, tagData, 0, headerData.length);
|
||||
System.arraycopy(data, 0, tagData, headerData.length, data.length);
|
||||
originalData = new ByteArrayRange(tagData, 0, tagData.length);
|
||||
}
|
||||
|
||||
public boolean isModified() {
|
||||
return modified;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getNeededCharacters(Set<Integer> needed) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeCharacter(int characterId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void getNeededCharactersDeep(Set<Integer> needed) {
|
||||
Set<Integer> visited = new HashSet<>();
|
||||
Set<Integer> needed2 = new HashSet<>();
|
||||
getNeededCharacters(needed2);
|
||||
|
||||
while (visited.size() != needed2.size()) {
|
||||
for (Integer characterId : needed2) {
|
||||
if (!visited.contains(characterId)) {
|
||||
visited.add(characterId);
|
||||
if (swf.characters.containsKey(characterId)) {
|
||||
swf.characters.get(characterId).getNeededCharacters(needed2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Integer characterId : needed2) {
|
||||
if (swf.characters.containsKey(characterId)) {
|
||||
needed.add(characterId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.tags;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.tags.base.ContainerItem;
|
||||
import com.jpexs.decompiler.flash.tags.base.Exportable;
|
||||
import com.jpexs.decompiler.flash.tags.base.NeedsCharacters;
|
||||
import com.jpexs.decompiler.flash.tags.gfx.DefineCompactedFont;
|
||||
import com.jpexs.decompiler.flash.tags.gfx.DefineExternalGradient;
|
||||
import com.jpexs.decompiler.flash.tags.gfx.DefineExternalImage;
|
||||
import com.jpexs.decompiler.flash.tags.gfx.DefineExternalImage2;
|
||||
import com.jpexs.decompiler.flash.tags.gfx.DefineExternalSound;
|
||||
import com.jpexs.decompiler.flash.tags.gfx.DefineExternalStreamSound;
|
||||
import com.jpexs.decompiler.flash.tags.gfx.DefineGradientMap;
|
||||
import com.jpexs.decompiler.flash.tags.gfx.DefineSubImage;
|
||||
import com.jpexs.decompiler.flash.tags.gfx.ExporterInfoTag;
|
||||
import com.jpexs.decompiler.flash.tags.gfx.FontTextureInfo;
|
||||
import com.jpexs.decompiler.flash.timeline.Timelined;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Internal;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Represents Tag inside SWF file
|
||||
*/
|
||||
public abstract class Tag implements NeedsCharacters, Exportable, ContainerItem, Serializable {
|
||||
|
||||
/**
|
||||
* Identifier of tag type
|
||||
*/
|
||||
protected int id;
|
||||
/**
|
||||
* If true, then Tag is written to the stream as longer than 0x3f even if it
|
||||
* is not
|
||||
*/
|
||||
@Internal
|
||||
public boolean forceWriteAsLong = false;
|
||||
protected String tagName;
|
||||
@Internal
|
||||
protected transient SWF swf;
|
||||
@Internal
|
||||
protected transient Timelined timelined;
|
||||
@Internal
|
||||
private boolean modified;
|
||||
/**
|
||||
* Original tag data
|
||||
*/
|
||||
@Internal
|
||||
private ByteArrayRange originalRange;
|
||||
|
||||
public String getTagName() {
|
||||
return tagName;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return tagName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExportFileName() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns identifier of tag type
|
||||
*
|
||||
* @return Identifier of tag type
|
||||
*/
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SWF getSwf() {
|
||||
return swf;
|
||||
}
|
||||
|
||||
public void setSwf(SWF swf) {
|
||||
this.swf = swf;
|
||||
}
|
||||
|
||||
public Timelined getTimelined() {
|
||||
return timelined;
|
||||
}
|
||||
|
||||
public void setTimelined(Timelined timelined) {
|
||||
this.timelined = timelined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param swf The SWF
|
||||
* @param id Tag type identifier
|
||||
* @param name Tag name
|
||||
* @param data Original tag data
|
||||
*/
|
||||
public Tag(SWF swf, int id, String name, ByteArrayRange data) {
|
||||
this.id = id;
|
||||
this.tagName = name;
|
||||
this.originalRange = data;
|
||||
this.swf = swf;
|
||||
if (swf == null) {
|
||||
throw new Error("swf parameter cannot be null.");
|
||||
}
|
||||
if (data == null) { // it is tag build by constructor
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static final Object lockObject = new Object();
|
||||
private static List<Integer> knownTagIds;
|
||||
private static List<Integer> requiredTagIds;
|
||||
|
||||
public static List<Integer> getKnownTags() {
|
||||
if (knownTagIds == null) {
|
||||
synchronized (lockObject) {
|
||||
if (knownTagIds == null) {
|
||||
List<Integer> tagIds = Arrays.asList(
|
||||
CSMTextSettingsTag.ID,
|
||||
DebugIDTag.ID,
|
||||
DefineBinaryDataTag.ID,
|
||||
DefineBitsJPEG2Tag.ID,
|
||||
DefineBitsJPEG3Tag.ID,
|
||||
DefineBitsJPEG4Tag.ID,
|
||||
DefineBitsLossless2Tag.ID,
|
||||
DefineBitsLosslessTag.ID,
|
||||
DefineBitsTag.ID,
|
||||
DefineButton2Tag.ID,
|
||||
DefineButtonCxformTag.ID,
|
||||
DefineButtonSoundTag.ID,
|
||||
DefineButtonTag.ID,
|
||||
DefineEditTextTag.ID,
|
||||
DefineFont2Tag.ID,
|
||||
DefineFont3Tag.ID,
|
||||
DefineFont4Tag.ID,
|
||||
DefineFontAlignZonesTag.ID,
|
||||
DefineFontInfo2Tag.ID,
|
||||
DefineFontInfoTag.ID,
|
||||
DefineFontNameTag.ID,
|
||||
DefineFontTag.ID,
|
||||
DefineMorphShape2Tag.ID,
|
||||
DefineMorphShapeTag.ID,
|
||||
DefineScalingGridTag.ID,
|
||||
DefineSceneAndFrameLabelDataTag.ID,
|
||||
DefineShape2Tag.ID,
|
||||
DefineShape3Tag.ID,
|
||||
DefineShape4Tag.ID,
|
||||
DefineShapeTag.ID,
|
||||
DefineSoundTag.ID,
|
||||
DefineSpriteTag.ID,
|
||||
DefineText2Tag.ID,
|
||||
DefineTextTag.ID,
|
||||
DefineVideoStreamTag.ID,
|
||||
DoABCDefineTag.ID,
|
||||
DoABCTag.ID,
|
||||
DoActionTag.ID,
|
||||
DoInitActionTag.ID,
|
||||
EnableDebugger2Tag.ID,
|
||||
EnableDebuggerTag.ID,
|
||||
EnableTelemetryTag.ID,
|
||||
EndTag.ID,
|
||||
ExportAssetsTag.ID,
|
||||
FileAttributesTag.ID,
|
||||
FrameLabelTag.ID,
|
||||
ImportAssets2Tag.ID,
|
||||
ImportAssetsTag.ID,
|
||||
JPEGTablesTag.ID,
|
||||
MetadataTag.ID,
|
||||
PlaceObject2Tag.ID,
|
||||
PlaceObject3Tag.ID,
|
||||
PlaceObject4Tag.ID,
|
||||
PlaceObjectTag.ID,
|
||||
ProductInfoTag.ID,
|
||||
ProtectTag.ID,
|
||||
RemoveObject2Tag.ID,
|
||||
RemoveObjectTag.ID,
|
||||
ScriptLimitsTag.ID,
|
||||
SetBackgroundColorTag.ID,
|
||||
SetTabIndexTag.ID,
|
||||
ShowFrameTag.ID,
|
||||
SoundStreamBlockTag.ID,
|
||||
SoundStreamHead2Tag.ID,
|
||||
SoundStreamHeadTag.ID,
|
||||
StartSound2Tag.ID,
|
||||
StartSoundTag.ID,
|
||||
SymbolClassTag.ID,
|
||||
VideoFrameTag.ID,
|
||||
DefineCompactedFont.ID,
|
||||
DefineExternalGradient.ID,
|
||||
DefineExternalImage.ID,
|
||||
DefineExternalImage2.ID,
|
||||
DefineExternalSound.ID,
|
||||
DefineExternalStreamSound.ID,
|
||||
DefineGradientMap.ID,
|
||||
DefineSubImage.ID,
|
||||
ExporterInfoTag.ID,
|
||||
FontTextureInfo.ID);
|
||||
knownTagIds = tagIds;
|
||||
}
|
||||
}
|
||||
}
|
||||
return knownTagIds;
|
||||
}
|
||||
|
||||
public static List<Integer> getRequiredTags() {
|
||||
if (requiredTagIds == null) {
|
||||
synchronized (lockObject) {
|
||||
if (requiredTagIds == null) {
|
||||
List<Integer> tagIds = Arrays.asList(
|
||||
DefineBinaryDataTag.ID,
|
||||
DefineBitsJPEG2Tag.ID,
|
||||
DefineBitsJPEG3Tag.ID,
|
||||
DefineBitsJPEG4Tag.ID,
|
||||
DefineBitsLossless2Tag.ID,
|
||||
DefineBitsLosslessTag.ID,
|
||||
DefineBitsTag.ID,
|
||||
DefineButton2Tag.ID,
|
||||
DefineButtonCxformTag.ID,
|
||||
DefineButtonSoundTag.ID,
|
||||
DefineButtonTag.ID,
|
||||
DefineEditTextTag.ID,
|
||||
DefineFont2Tag.ID,
|
||||
DefineFont3Tag.ID,
|
||||
DefineFont4Tag.ID,
|
||||
DefineFontAlignZonesTag.ID,
|
||||
DefineFontInfo2Tag.ID,
|
||||
DefineFontInfoTag.ID,
|
||||
DefineFontNameTag.ID,
|
||||
DefineFontTag.ID,
|
||||
DefineMorphShape2Tag.ID,
|
||||
DefineMorphShapeTag.ID,
|
||||
DefineScalingGridTag.ID,
|
||||
DefineSceneAndFrameLabelDataTag.ID,
|
||||
DefineShape2Tag.ID,
|
||||
DefineShape3Tag.ID,
|
||||
DefineShape4Tag.ID,
|
||||
DefineShapeTag.ID,
|
||||
DefineSoundTag.ID,
|
||||
DefineSpriteTag.ID,
|
||||
DefineText2Tag.ID,
|
||||
DefineTextTag.ID,
|
||||
DefineVideoStreamTag.ID,
|
||||
DoABCDefineTag.ID,
|
||||
DoABCTag.ID,
|
||||
DoActionTag.ID,
|
||||
DoInitActionTag.ID,
|
||||
ShowFrameTag.ID);
|
||||
requiredTagIds = tagIds;
|
||||
}
|
||||
}
|
||||
}
|
||||
return requiredTagIds;
|
||||
}
|
||||
|
||||
public int getVersion() {
|
||||
if (swf == null) {
|
||||
return SWF.DEFAULT_VERSION;
|
||||
}
|
||||
return swf.version;
|
||||
}
|
||||
|
||||
protected byte[] getHeader(byte[] data) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try {
|
||||
|
||||
SWFOutputStream sos = new SWFOutputStream(baos, swf.version);
|
||||
int tagLength = data.length;
|
||||
int tagID = getId();
|
||||
int tagIDLength = (tagID << 6);
|
||||
if ((tagLength <= 62) && (!forceWriteAsLong)) {
|
||||
tagIDLength += tagLength;
|
||||
sos.writeUI16(tagIDLength);
|
||||
} else {
|
||||
tagIDLength += 0x3f;
|
||||
sos.writeUI16(tagIDLength);
|
||||
sos.writeSI32(tagLength);
|
||||
}
|
||||
} catch (IOException iex) {
|
||||
}
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
public static byte[] getTagHeader(int tagIDTagLength, long tagLength, boolean writeLong, int version) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try {
|
||||
|
||||
SWFOutputStream sos = new SWFOutputStream(baos, version);
|
||||
sos.writeUI16(tagIDTagLength);
|
||||
if (writeLong) {
|
||||
sos.writeSI32(tagLength);
|
||||
}
|
||||
} catch (IOException iex) {
|
||||
}
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes Tag value to the stream
|
||||
*
|
||||
* @param sos SWF output stream
|
||||
* @throws IOException
|
||||
*/
|
||||
public void writeTag(SWFOutputStream sos) throws IOException {
|
||||
if (isModified()) {
|
||||
byte[] newData = getData();
|
||||
byte[] newHeaderData = getHeader(newData);
|
||||
sos.write(newHeaderData);
|
||||
sos.write(newData);
|
||||
} else {
|
||||
sos.write(originalRange.array, originalRange.pos, originalRange.length);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns string representation of the object
|
||||
*
|
||||
* @return String representation of the object
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets data bytes
|
||||
*
|
||||
* @return Bytes of data
|
||||
*/
|
||||
public byte[] getData() {
|
||||
return getOriginalData().getRangeData();
|
||||
}
|
||||
|
||||
public final ByteArrayRange getOriginalRange() {
|
||||
return originalRange;
|
||||
}
|
||||
|
||||
public final ByteArrayRange getOriginalData() {
|
||||
if (originalRange == null) {
|
||||
return new ByteArrayRange();
|
||||
}
|
||||
|
||||
int dataLength = getOriginalDataLength();
|
||||
int pos = (int) (originalRange.pos + originalRange.length - dataLength);
|
||||
return new ByteArrayRange(originalRange.array, pos, dataLength);
|
||||
}
|
||||
|
||||
public final int getOriginalDataLength() {
|
||||
if (originalRange == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return originalRange.length - (isLongOriginal() ? 6 : 2);
|
||||
}
|
||||
|
||||
private final boolean isLongOriginal() {
|
||||
int shortLength = originalRange.array[(int) originalRange.pos] & 0x003F;
|
||||
return shortLength == 0x3f;
|
||||
}
|
||||
|
||||
public boolean hasSubTags() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public List<Tag> getSubTags() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public long getPos() {
|
||||
return originalRange.pos;
|
||||
}
|
||||
|
||||
public long getDataPos() {
|
||||
return originalRange.pos + (isLongOriginal() ? 6 : 2);
|
||||
}
|
||||
|
||||
public void setModified(boolean value) {
|
||||
modified = value;
|
||||
}
|
||||
|
||||
public void createOriginalData() {
|
||||
byte[] data = getData();
|
||||
byte[] headerData = getHeader(data);
|
||||
byte[] tagData = new byte[data.length + headerData.length];
|
||||
System.arraycopy(headerData, 0, tagData, 0, headerData.length);
|
||||
System.arraycopy(data, 0, tagData, headerData.length, data.length);
|
||||
originalRange = new ByteArrayRange(tagData, 0, tagData.length);
|
||||
}
|
||||
|
||||
public boolean isModified() {
|
||||
return modified;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getNeededCharacters(Set<Integer> needed) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeCharacter(int characterId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void getNeededCharactersDeep(Set<Integer> needed) {
|
||||
Set<Integer> visited = new HashSet<>();
|
||||
Set<Integer> needed2 = new HashSet<>();
|
||||
getNeededCharacters(needed2);
|
||||
|
||||
while (visited.size() != needed2.size()) {
|
||||
for (Integer characterId : needed2) {
|
||||
if (!visited.contains(characterId)) {
|
||||
visited.add(characterId);
|
||||
if (swf.characters.containsKey(characterId)) {
|
||||
swf.characters.get(characterId).getNeededCharacters(needed2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Integer characterId : needed2) {
|
||||
if (swf.characters.containsKey(characterId)) {
|
||||
needed.add(characterId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,28 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.tags.base;
|
||||
|
||||
import com.jpexs.decompiler.flash.types.RECT;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public interface BoundedTag {
|
||||
|
||||
public RECT getRect();
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.tags.base;
|
||||
|
||||
import com.jpexs.decompiler.flash.types.RECT;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public interface BoundedTag {
|
||||
|
||||
public RECT getRect(Set<BoundedTag> added);
|
||||
}
|
||||
|
||||
@@ -45,8 +45,10 @@ import java.awt.font.GlyphVector;
|
||||
import java.awt.geom.Area;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -280,12 +282,12 @@ public abstract class FontTag extends CharacterTag implements AloneTag, Drawable
|
||||
|
||||
@Override
|
||||
public Shape getOutline(int frame, int time, int ratio, DepthState stateUnderCursor, int mouseButton, Matrix transformation) {
|
||||
RECT r = getRect();
|
||||
RECT r = getRect(new HashSet<BoundedTag>());
|
||||
return new Area(new Rectangle(r.Xmin, r.Ymin, r.getWidth(), r.getHeight()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public RECT getRect() {
|
||||
public RECT getRect(Set<BoundedTag> added) {
|
||||
return new RECT(0, (int) (previewSize * SWF.unitDivisor), 0, (int) (previewSize * SWF.unitDivisor));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,188 +1,190 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.tags.base;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.shape.BitmapExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.shape.CanvasShapeExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.shape.SVGShapeExporter;
|
||||
import com.jpexs.decompiler.flash.timeline.DepthState;
|
||||
import com.jpexs.decompiler.flash.types.ColorTransform;
|
||||
import com.jpexs.decompiler.flash.types.FILLSTYLE;
|
||||
import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY;
|
||||
import com.jpexs.decompiler.flash.types.LINESTYLE;
|
||||
import com.jpexs.decompiler.flash.types.LINESTYLEARRAY;
|
||||
import com.jpexs.decompiler.flash.types.MATRIX;
|
||||
import com.jpexs.decompiler.flash.types.RECT;
|
||||
import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import com.jpexs.helpers.SerializableImage;
|
||||
import java.awt.Color;
|
||||
import java.awt.Shape;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public abstract class ImageTag extends CharacterTag implements DrawableTag {
|
||||
|
||||
public ImageTag(SWF swf, int id, String name, ByteArrayRange data) {
|
||||
super(swf, id, name, data);
|
||||
}
|
||||
|
||||
public abstract InputStream getImageData();
|
||||
|
||||
public abstract SerializableImage getImage();
|
||||
|
||||
public abstract void setImage(byte[] data) throws IOException;
|
||||
|
||||
public abstract String getImageFormat();
|
||||
|
||||
public boolean importSupported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static String getImageFormat(byte[] data) {
|
||||
if (SWF.hasErrorHeader(data)) {
|
||||
return "jpg";
|
||||
}
|
||||
if (data.length > 2 && ((data[0] & 0xff) == 0xff) && ((data[1] & 0xff) == 0xd8)) {
|
||||
return "jpg";
|
||||
}
|
||||
if (data.length > 6 && ((data[0] & 0xff) == 0x47) && ((data[1] & 0xff) == 0x49) && ((data[2] & 0xff) == 0x46) && ((data[3] & 0xff) == 0x38) && ((data[4] & 0xff) == 0x39) && ((data[5] & 0xff) == 0x61)) {
|
||||
return "gif";
|
||||
}
|
||||
|
||||
if (data.length > 8 && ((data[0] & 0xff) == 0x89) && ((data[1] & 0xff) == 0x50) && ((data[2] & 0xff) == 0x4e) && ((data[3] & 0xff) == 0x47) && ((data[4] & 0xff) == 0x0d) && ((data[5] & 0xff) == 0x0a) && ((data[6] & 0xff) == 0x1a) && ((data[7] & 0xff) == 0x0a)) {
|
||||
return "png";
|
||||
}
|
||||
|
||||
return "unk";
|
||||
}
|
||||
|
||||
protected static int max255(float val) {
|
||||
if (val > 255) {
|
||||
return 255;
|
||||
}
|
||||
return (int) val;
|
||||
}
|
||||
|
||||
protected static Color intToColor(int val) {
|
||||
return new Color(val & 0xff, (val >> 8) & 0xff, (val >> 16) & 0xff, (val >> 24) & 0xff);
|
||||
}
|
||||
|
||||
protected static int colorToInt(Color c) {
|
||||
return (c.getAlpha() << 24) | (c.getBlue() << 16) | (c.getGreen() << 8) | c.getRed();
|
||||
}
|
||||
|
||||
protected static Color multiplyAlpha(Color c) {
|
||||
float multiplier = c.getAlpha() == 0 ? 0 : 255.0f / c.getAlpha();
|
||||
return new Color(max255(c.getRed() * multiplier), max255(c.getGreen() * multiplier), max255(c.getBlue() * multiplier), c.getAlpha());
|
||||
}
|
||||
|
||||
private SHAPEWITHSTYLE getShape() {
|
||||
SHAPEWITHSTYLE shape = new SHAPEWITHSTYLE();
|
||||
shape.fillStyles = new FILLSTYLEARRAY();
|
||||
shape.fillStyles.fillStyles = new FILLSTYLE[1];
|
||||
FILLSTYLE fillStyle = new FILLSTYLE();
|
||||
fillStyle.fillStyleType = FILLSTYLE.REPEATING_BITMAP;
|
||||
fillStyle.bitmapId = getCharacterId();
|
||||
MATRIX matrix = new MATRIX();
|
||||
matrix.hasScale = true;
|
||||
matrix.scaleX = ((int) SWF.unitDivisor) << 16;
|
||||
matrix.scaleY = matrix.scaleX;
|
||||
fillStyle.bitmapMatrix = matrix;
|
||||
shape.fillStyles.fillStyles[0] = fillStyle;
|
||||
|
||||
shape.lineStyles = new LINESTYLEARRAY();
|
||||
shape.lineStyles.lineStyles = new LINESTYLE[0];
|
||||
shape.shapeRecords = new ArrayList<>();
|
||||
StyleChangeRecord style = new StyleChangeRecord();
|
||||
style.stateFillStyle0 = true;
|
||||
style.fillStyle0 = 1;
|
||||
style.stateMoveTo = true;
|
||||
shape.shapeRecords.add(style);
|
||||
RECT rect = getRect();
|
||||
StraightEdgeRecord top = new StraightEdgeRecord();
|
||||
top.generalLineFlag = true;
|
||||
top.deltaX = rect.getWidth();
|
||||
StraightEdgeRecord right = new StraightEdgeRecord();
|
||||
right.generalLineFlag = true;
|
||||
right.deltaY = rect.getHeight();
|
||||
StraightEdgeRecord bottom = new StraightEdgeRecord();
|
||||
bottom.generalLineFlag = true;
|
||||
bottom.deltaX = -rect.getWidth();
|
||||
StraightEdgeRecord left = new StraightEdgeRecord();
|
||||
left.generalLineFlag = true;
|
||||
left.deltaY = -rect.getHeight();
|
||||
shape.shapeRecords.add(top);
|
||||
shape.shapeRecords.add(right);
|
||||
shape.shapeRecords.add(bottom);
|
||||
shape.shapeRecords.add(left);
|
||||
shape.shapeRecords.add(new EndShapeRecord());
|
||||
return shape;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RECT getRect() {
|
||||
SerializableImage image = getImage();
|
||||
int widthInTwips = (int) (image.getWidth() * SWF.unitDivisor);
|
||||
int heightInTwips = (int) (image.getHeight() * SWF.unitDivisor);
|
||||
return new RECT(0, widthInTwips, 0, heightInTwips);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toImage(int frame, int time, int ratio, DepthState stateUnderCursor, int mouseButton, SerializableImage image, Matrix transformation, ColorTransform colorTransform) {
|
||||
BitmapExporter.export(swf, getShape(), null, image, transformation, colorTransform);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level) throws IOException {
|
||||
SVGShapeExporter shapeExporter = new SVGShapeExporter(swf, getShape(), exporter, null, colorTransform);
|
||||
shapeExporter.export();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toHtmlCanvas(double unitDivisor) {
|
||||
CanvasShapeExporter cse = new CanvasShapeExporter(null, unitDivisor, swf, getShape(), new ColorTransform(), 0, 0);
|
||||
cse.export();
|
||||
return cse.getShapeData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumFrames() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleFrame() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Shape getOutline(int frame, int time, int ratio, DepthState stateUnderCursor, int mouseButton, Matrix transformation) {
|
||||
return transformation.toTransform().createTransformedShape(getShape().getOutline());
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.tags.base;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.shape.BitmapExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.shape.CanvasShapeExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.shape.SVGShapeExporter;
|
||||
import com.jpexs.decompiler.flash.timeline.DepthState;
|
||||
import com.jpexs.decompiler.flash.types.ColorTransform;
|
||||
import com.jpexs.decompiler.flash.types.FILLSTYLE;
|
||||
import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY;
|
||||
import com.jpexs.decompiler.flash.types.LINESTYLE;
|
||||
import com.jpexs.decompiler.flash.types.LINESTYLEARRAY;
|
||||
import com.jpexs.decompiler.flash.types.MATRIX;
|
||||
import com.jpexs.decompiler.flash.types.RECT;
|
||||
import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import com.jpexs.helpers.SerializableImage;
|
||||
import java.awt.Color;
|
||||
import java.awt.Shape;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public abstract class ImageTag extends CharacterTag implements DrawableTag {
|
||||
|
||||
public ImageTag(SWF swf, int id, String name, ByteArrayRange data) {
|
||||
super(swf, id, name, data);
|
||||
}
|
||||
|
||||
public abstract InputStream getImageData();
|
||||
|
||||
public abstract SerializableImage getImage();
|
||||
|
||||
public abstract void setImage(byte[] data) throws IOException;
|
||||
|
||||
public abstract String getImageFormat();
|
||||
|
||||
public boolean importSupported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static String getImageFormat(byte[] data) {
|
||||
if (SWF.hasErrorHeader(data)) {
|
||||
return "jpg";
|
||||
}
|
||||
if (data.length > 2 && ((data[0] & 0xff) == 0xff) && ((data[1] & 0xff) == 0xd8)) {
|
||||
return "jpg";
|
||||
}
|
||||
if (data.length > 6 && ((data[0] & 0xff) == 0x47) && ((data[1] & 0xff) == 0x49) && ((data[2] & 0xff) == 0x46) && ((data[3] & 0xff) == 0x38) && ((data[4] & 0xff) == 0x39) && ((data[5] & 0xff) == 0x61)) {
|
||||
return "gif";
|
||||
}
|
||||
|
||||
if (data.length > 8 && ((data[0] & 0xff) == 0x89) && ((data[1] & 0xff) == 0x50) && ((data[2] & 0xff) == 0x4e) && ((data[3] & 0xff) == 0x47) && ((data[4] & 0xff) == 0x0d) && ((data[5] & 0xff) == 0x0a) && ((data[6] & 0xff) == 0x1a) && ((data[7] & 0xff) == 0x0a)) {
|
||||
return "png";
|
||||
}
|
||||
|
||||
return "unk";
|
||||
}
|
||||
|
||||
protected static int max255(float val) {
|
||||
if (val > 255) {
|
||||
return 255;
|
||||
}
|
||||
return (int) val;
|
||||
}
|
||||
|
||||
protected static Color intToColor(int val) {
|
||||
return new Color(val & 0xff, (val >> 8) & 0xff, (val >> 16) & 0xff, (val >> 24) & 0xff);
|
||||
}
|
||||
|
||||
protected static int colorToInt(Color c) {
|
||||
return (c.getAlpha() << 24) | (c.getBlue() << 16) | (c.getGreen() << 8) | c.getRed();
|
||||
}
|
||||
|
||||
protected static Color multiplyAlpha(Color c) {
|
||||
float multiplier = c.getAlpha() == 0 ? 0 : 255.0f / c.getAlpha();
|
||||
return new Color(max255(c.getRed() * multiplier), max255(c.getGreen() * multiplier), max255(c.getBlue() * multiplier), c.getAlpha());
|
||||
}
|
||||
|
||||
private SHAPEWITHSTYLE getShape() {
|
||||
SHAPEWITHSTYLE shape = new SHAPEWITHSTYLE();
|
||||
shape.fillStyles = new FILLSTYLEARRAY();
|
||||
shape.fillStyles.fillStyles = new FILLSTYLE[1];
|
||||
FILLSTYLE fillStyle = new FILLSTYLE();
|
||||
fillStyle.fillStyleType = FILLSTYLE.REPEATING_BITMAP;
|
||||
fillStyle.bitmapId = getCharacterId();
|
||||
MATRIX matrix = new MATRIX();
|
||||
matrix.hasScale = true;
|
||||
matrix.scaleX = ((int) SWF.unitDivisor) << 16;
|
||||
matrix.scaleY = matrix.scaleX;
|
||||
fillStyle.bitmapMatrix = matrix;
|
||||
shape.fillStyles.fillStyles[0] = fillStyle;
|
||||
|
||||
shape.lineStyles = new LINESTYLEARRAY();
|
||||
shape.lineStyles.lineStyles = new LINESTYLE[0];
|
||||
shape.shapeRecords = new ArrayList<>();
|
||||
StyleChangeRecord style = new StyleChangeRecord();
|
||||
style.stateFillStyle0 = true;
|
||||
style.fillStyle0 = 1;
|
||||
style.stateMoveTo = true;
|
||||
shape.shapeRecords.add(style);
|
||||
RECT rect = getRect(new HashSet<BoundedTag>());
|
||||
StraightEdgeRecord top = new StraightEdgeRecord();
|
||||
top.generalLineFlag = true;
|
||||
top.deltaX = rect.getWidth();
|
||||
StraightEdgeRecord right = new StraightEdgeRecord();
|
||||
right.generalLineFlag = true;
|
||||
right.deltaY = rect.getHeight();
|
||||
StraightEdgeRecord bottom = new StraightEdgeRecord();
|
||||
bottom.generalLineFlag = true;
|
||||
bottom.deltaX = -rect.getWidth();
|
||||
StraightEdgeRecord left = new StraightEdgeRecord();
|
||||
left.generalLineFlag = true;
|
||||
left.deltaY = -rect.getHeight();
|
||||
shape.shapeRecords.add(top);
|
||||
shape.shapeRecords.add(right);
|
||||
shape.shapeRecords.add(bottom);
|
||||
shape.shapeRecords.add(left);
|
||||
shape.shapeRecords.add(new EndShapeRecord());
|
||||
return shape;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RECT getRect(Set<BoundedTag> added) {
|
||||
SerializableImage image = getImage();
|
||||
int widthInTwips = (int) (image.getWidth() * SWF.unitDivisor);
|
||||
int heightInTwips = (int) (image.getHeight() * SWF.unitDivisor);
|
||||
return new RECT(0, widthInTwips, 0, heightInTwips);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toImage(int frame, int time, int ratio, DepthState stateUnderCursor, int mouseButton, SerializableImage image, Matrix transformation, ColorTransform colorTransform) {
|
||||
BitmapExporter.export(swf, getShape(), null, image, transformation, colorTransform);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level) throws IOException {
|
||||
SVGShapeExporter shapeExporter = new SVGShapeExporter(swf, getShape(), exporter, null, colorTransform);
|
||||
shapeExporter.export();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toHtmlCanvas(double unitDivisor) {
|
||||
CanvasShapeExporter cse = new CanvasShapeExporter(null, unitDivisor, swf, getShape(), new ColorTransform(), 0, 0);
|
||||
cse.export();
|
||||
return cse.getShapeData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumFrames() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleFrame() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Shape getOutline(int frame, int time, int ratio, DepthState stateUnderCursor, int mouseButton, Matrix transformation) {
|
||||
return transformation.toTransform().createTransformedShape(getShape().getOutline());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ import com.jpexs.decompiler.flash.SWF;
|
||||
*/
|
||||
public class HeaderItem implements TreeItem {
|
||||
|
||||
private SWF swf;
|
||||
private final SWF swf;
|
||||
|
||||
public HeaderItem(SWF swf) {
|
||||
this.swf = swf;
|
||||
|
||||
@@ -54,6 +54,7 @@ import com.jpexs.decompiler.flash.tags.StartSoundTag;
|
||||
import com.jpexs.decompiler.flash.tags.SymbolClassTag;
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ASMSource;
|
||||
import com.jpexs.decompiler.flash.tags.base.BoundedTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ButtonTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.FontTag;
|
||||
@@ -114,6 +115,7 @@ import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
@@ -1072,7 +1074,7 @@ public class XFLConverter {
|
||||
ret += " symbolType=\"graphic\" loop=\"loop\"";
|
||||
} else if (tag instanceof DefineSpriteTag) {
|
||||
DefineSpriteTag sprite = (DefineSpriteTag) tag;
|
||||
RECT spriteRect = sprite.getRect();
|
||||
RECT spriteRect = sprite.getRect(new HashSet<BoundedTag>());
|
||||
double centerPoint3DX = twipToPixel(matrix.translateX + spriteRect.getWidth() / 2);
|
||||
double centerPoint3DY = twipToPixel(matrix.translateY + spriteRect.getHeight() / 2);
|
||||
ret += " centerPoint3DX=\"" + centerPoint3DX + "\" centerPoint3DY=\"" + centerPoint3DY + "\"";
|
||||
|
||||
@@ -26,6 +26,10 @@ public class ByteArrayRange {
|
||||
public final int pos;
|
||||
public final int length;
|
||||
|
||||
public ByteArrayRange() {
|
||||
this(new byte[0]);
|
||||
}
|
||||
|
||||
public ByteArrayRange(byte[] array) {
|
||||
this.array = array;
|
||||
this.pos = 0;
|
||||
|
||||
Reference in New Issue
Block a user