From 1bd050440273034883ed992f1a349512f7d79bf2 Mon Sep 17 00:00:00 2001 From: honfika Date: Fri, 25 Jul 2014 22:12:46 +0200 Subject: [PATCH] better handling of corrupt swf files --- src/com/jpexs/decompiler/flash/SWF.java | 10 +- .../decompiler/flash/SWFInputStream.java | 49 +- .../flash/exporters/MorphShapeExporter.java | 3 +- .../flash/exporters/ShapeExporter.java | 5 +- .../flash/exporters/TextExporter.java | 262 ++-- .../flash/gui/GenericTagTreePanel.java | 5 +- .../decompiler/flash/gui/ImagePanel.java | 5 +- .../jpexs/decompiler/flash/gui/MainPanel.java | 20 +- .../decompiler/flash/gui/PreviewImage.java | 3 +- .../decompiler/flash/gui/PreviewPanel.java | 4 +- .../flash/tags/DefineButton2Tag.java | 27 +- .../flash/tags/DefineButtonTag.java | 27 +- .../flash/tags/DefineEditTextTag.java | 6 +- .../decompiler/flash/tags/DefineFont3Tag.java | 2 +- .../flash/tags/DefineMorphShape2Tag.java | 3 +- .../flash/tags/DefineMorphShapeTag.java | 3 +- .../flash/tags/DefineShape2Tag.java | 3 +- .../flash/tags/DefineShape3Tag.java | 3 +- .../flash/tags/DefineShape4Tag.java | 3 +- .../decompiler/flash/tags/DefineShapeTag.java | 3 +- .../flash/tags/DefineSpriteTag.java | 20 +- .../decompiler/flash/tags/DefineText2Tag.java | 6 +- .../decompiler/flash/tags/DefineTextTag.java | 6 +- .../flash/tags/DefineVideoStreamTag.java | 3 +- .../decompiler/flash/tags/DoABCDefineTag.java | 2 +- .../jpexs/decompiler/flash/tags/DoABCTag.java | 2 +- .../decompiler/flash/tags/DoActionTag.java | 2 +- .../flash/tags/PlaceObject2Tag.java | 804 ++++++------- .../flash/tags/PlaceObject3Tag.java | 1060 ++++++++-------- .../flash/tags/PlaceObject4Tag.java | 1066 ++++++++--------- src/com/jpexs/decompiler/flash/tags/Tag.java | 897 +++++++------- .../flash/tags/base/BoundedTag.java | 57 +- .../decompiler/flash/tags/base/FontTag.java | 6 +- .../decompiler/flash/tags/base/ImageTag.java | 378 +++--- .../flash/treeitems/HeaderItem.java | 2 +- .../decompiler/flash/xfl/XFLConverter.java | 4 +- src/com/jpexs/helpers/ByteArrayRange.java | 4 + 37 files changed, 2416 insertions(+), 2349 deletions(-) diff --git a/src/com/jpexs/decompiler/flash/SWF.java b/src/com/jpexs/decompiler/flash/SWF.java index d7092e87b..461ed19a7 100644 --- a/src/com/jpexs/decompiler/flash/SWF.java +++ b/src/com/jpexs/decompiler/flash/SWF.java @@ -868,7 +868,7 @@ public final class SWF implements TreeItem, Timelined { } @Override - public RECT getRect() { + public RECT getRect(Set 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()); 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()); 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()); 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)); diff --git a/src/com/jpexs/decompiler/flash/SWFInputStream.java b/src/com/jpexs/decompiler/flash/SWFInputStream.java index b475db83c..1cc9ab493 100644 --- a/src/com/jpexs/decompiler/flash/SWFInputStream.java +++ b/src/com/jpexs/decompiler/flash/SWFInputStream.java @@ -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 { - 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 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 future = executor.submit(new TagResolutionTask(tag, di, level, parallel, skipUnusualTags, gfx)); + Future 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"); diff --git a/src/com/jpexs/decompiler/flash/exporters/MorphShapeExporter.java b/src/com/jpexs/decompiler/flash/exporters/MorphShapeExporter.java index e7231ecff..c41c2cfe7 100644 --- a/src/com/jpexs/decompiler/flash/exporters/MorphShapeExporter.java +++ b/src/com/jpexs/decompiler/flash/exporters/MorphShapeExporter.java @@ -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())); SVGExporter exporter = new SVGExporter(rect); mst.toSVG(exporter, -2, new CXFORMWITHALPHA(), 0); fos.write(Utf8Helper.getBytes(exporter.getSVG())); diff --git a/src/com/jpexs/decompiler/flash/exporters/ShapeExporter.java b/src/com/jpexs/decompiler/flash/exporters/ShapeExporter.java index a6d9c7455..ba49a03e6 100644 --- a/src/com/jpexs/decompiler/flash/exporters/ShapeExporter.java +++ b/src/com/jpexs/decompiler/flash/exporters/ShapeExporter.java @@ -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())); 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()); int newWidth = (int) (rect.getWidth() / SWF.unitDivisor); int newHeight = (int) (rect.getHeight() / SWF.unitDivisor); SerializableImage img = new SerializableImage(newWidth, newHeight, SerializableImage.TYPE_INT_ARGB); diff --git a/src/com/jpexs/decompiler/flash/exporters/TextExporter.java b/src/com/jpexs/decompiler/flash/exporters/TextExporter.java index 7515aac4b..81eb623e6 100644 --- a/src/com/jpexs/decompiler/flash/exporters/TextExporter.java +++ b/src/com/jpexs/decompiler/flash/exporters/TextExporter.java @@ -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 . - */ -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 exportTexts(AbortRetryIgnoreHandler handler, String outdir, List tags, final TextExportSettings settings) throws IOException { - List 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 . + */ +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 exportTexts(AbortRetryIgnoreHandler handler, String outdir, List tags, final TextExportSettings settings) throws IOException { + List 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())); + 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; + } +} diff --git a/src/com/jpexs/decompiler/flash/gui/GenericTagTreePanel.java b/src/com/jpexs/decompiler/flash/gui/GenericTagTreePanel.java index e0111fe25..dc17f3364 100644 --- a/src/com/jpexs/decompiler/flash/gui/GenericTagTreePanel.java +++ b/src/com/jpexs/decompiler/flash/gui/GenericTagTreePanel.java @@ -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); diff --git a/src/com/jpexs/decompiler/flash/gui/ImagePanel.java b/src/com/jpexs/decompiler/flash/gui/ImagePanel.java index 06baf0f70..7cefef044 100644 --- a/src/com/jpexs/decompiler/flash/gui/ImagePanel.java +++ b/src/com/jpexs/decompiler/flash/gui/ImagePanel.java @@ -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()); 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()); if (rect == null) { //??? Why? rect = new RECT(0, 0, 1, 1); } diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index 6639557b3..bd7e2e443 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -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()); 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(), ((CharacterTag) tag).getCharacterId(), getRect()); + tim = new Timeline(tag.getSwf(), new ArrayList(), ((CharacterTag) tag).getCharacterId(), getRect(new HashSet())); 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()); 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 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); } }; } diff --git a/src/com/jpexs/decompiler/flash/gui/PreviewImage.java b/src/com/jpexs/decompiler/flash/gui/PreviewImage.java index 775665d68..4bfd708ee 100644 --- a/src/com/jpexs/decompiler/flash/gui/PreviewImage.java +++ b/src/com/jpexs/decompiler/flash/gui/PreviewImage.java @@ -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()); width = (int) (rect.getWidth() / SWF.unitDivisor) + 1; height = (int) (rect.getHeight() / SWF.unitDivisor) + 1; m.translate(-rect.Xmin, -rect.Ymin); diff --git a/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java b/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java index f24ddd64c..36ab9fc2c 100644 --- a/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java @@ -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()); 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()); mat.translateX = -r.Xmin; mat.translateY = -r.Ymin; mat.translateX = mat.translateX + width / 2 - r.getWidth() / 2; diff --git a/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java b/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java index ebbae3fbe..562ea661e 100644 --- a/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java +++ b/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java @@ -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 rectCache = Cache.getInstance(true); @Override - public RECT getRect() { + public RECT getRect(Set 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(), buttonId, getRect()); + timeline = new Timeline(swf, new ArrayList(), buttonId, getRect(new HashSet())); int maxDepth = 0; Frame frameUp = new Frame(timeline); diff --git a/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java b/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java index 6f0b49e5a..6d298d6a1 100644 --- a/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java +++ b/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java @@ -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 rectCache = Cache.getInstance(true); @Override - public RECT getRect() { + public RECT getRect(Set 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(), buttonId, getRect()); + timeline = new Timeline(swf, new ArrayList(), buttonId, getRect(new HashSet())); ColorTransform clrTrans = null; for (Tag t : swf.tags) { diff --git a/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java b/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java index 1435ee1fe..4c8c33084 100644 --- a/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java +++ b/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java @@ -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 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()), getTextMatrix(), transformation, colorTransform); } if (hasText) { DynamicTextModel textModel = new DynamicTextModel(); diff --git a/src/com/jpexs/decompiler/flash/tags/DefineFont3Tag.java b/src/com/jpexs/decompiler/flash/tags/DefineFont3Tag.java index c81c9bb1f..cd52280ef 100644 --- a/src/com/jpexs/decompiler/flash/tags/DefineFont3Tag.java +++ b/src/com/jpexs/decompiler/flash/tags/DefineFont3Tag.java @@ -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 offsetTable = new ArrayList<>(); diff --git a/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java b/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java index 6d86ebf43..869c6dc51 100644 --- a/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java +++ b/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java @@ -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 added) { RECT rect = new RECT(); rect.Xmin = Math.min(startBounds.Xmin, endBounds.Xmin); rect.Ymin = Math.min(startBounds.Ymin, endBounds.Ymin); diff --git a/src/com/jpexs/decompiler/flash/tags/DefineMorphShapeTag.java b/src/com/jpexs/decompiler/flash/tags/DefineMorphShapeTag.java index 6cb12b907..4b8fa9ad3 100644 --- a/src/com/jpexs/decompiler/flash/tags/DefineMorphShapeTag.java +++ b/src/com/jpexs/decompiler/flash/tags/DefineMorphShapeTag.java @@ -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 added) { RECT rect = new RECT(); rect.Xmin = Math.min(startBounds.Xmin, endBounds.Xmin); rect.Ymin = Math.min(startBounds.Ymin, endBounds.Ymin); diff --git a/src/com/jpexs/decompiler/flash/tags/DefineShape2Tag.java b/src/com/jpexs/decompiler/flash/tags/DefineShape2Tag.java index b54518ae0..1c84b53a2 100644 --- a/src/com/jpexs/decompiler/flash/tags/DefineShape2Tag.java +++ b/src/com/jpexs/decompiler/flash/tags/DefineShape2Tag.java @@ -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 added) { return shapeBounds; } diff --git a/src/com/jpexs/decompiler/flash/tags/DefineShape3Tag.java b/src/com/jpexs/decompiler/flash/tags/DefineShape3Tag.java index 5cf55a854..0e65c53a5 100644 --- a/src/com/jpexs/decompiler/flash/tags/DefineShape3Tag.java +++ b/src/com/jpexs/decompiler/flash/tags/DefineShape3Tag.java @@ -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 added) { return shapeBounds; } diff --git a/src/com/jpexs/decompiler/flash/tags/DefineShape4Tag.java b/src/com/jpexs/decompiler/flash/tags/DefineShape4Tag.java index ebd8efd7a..689faa45a 100644 --- a/src/com/jpexs/decompiler/flash/tags/DefineShape4Tag.java +++ b/src/com/jpexs/decompiler/flash/tags/DefineShape4Tag.java @@ -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 added) { return shapeBounds; } diff --git a/src/com/jpexs/decompiler/flash/tags/DefineShapeTag.java b/src/com/jpexs/decompiler/flash/tags/DefineShapeTag.java index b481a22e2..dd5c08c36 100644 --- a/src/com/jpexs/decompiler/flash/tags/DefineShapeTag.java +++ b/src/com/jpexs/decompiler/flash/tags/DefineShapeTag.java @@ -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 added) { return shapeBounds; } diff --git a/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java b/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java index b3caaf9d9..3030d6efa 100644 --- a/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java +++ b/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java @@ -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())); } return timeline; } @@ -99,14 +99,18 @@ public class DefineSpriteTag extends CharacterTag implements Container, Drawable return spriteId; } - private RECT getCharacterBounds(Set characters) { + private RECT getCharacterBounds(Set characters, Set 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 rectCache = Cache.getInstance(true); @Override - public RECT getRect() { + public RECT getRect(Set 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 depthMap = new HashMap<>(); boolean foundSomething = false; @@ -156,7 +160,7 @@ public class DefineSpriteTag extends CharacterTag implements Container, Drawable } Set 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 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 { diff --git a/src/com/jpexs/decompiler/flash/tags/DefineText2Tag.java b/src/com/jpexs/decompiler/flash/tags/DefineText2Tag.java index 3ee9024a9..1e957cca1 100644 --- a/src/com/jpexs/decompiler/flash/tags/DefineText2Tag.java +++ b/src/com/jpexs/decompiler/flash/tags/DefineText2Tag.java @@ -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 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()), getTextMatrix(), colorTransform); } @Override diff --git a/src/com/jpexs/decompiler/flash/tags/DefineTextTag.java b/src/com/jpexs/decompiler/flash/tags/DefineTextTag.java index 93dfee67c..7b6d49632 100644 --- a/src/com/jpexs/decompiler/flash/tags/DefineTextTag.java +++ b/src/com/jpexs/decompiler/flash/tags/DefineTextTag.java @@ -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 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()), getTextMatrix(), colorTransform); } @Override diff --git a/src/com/jpexs/decompiler/flash/tags/DefineVideoStreamTag.java b/src/com/jpexs/decompiler/flash/tags/DefineVideoStreamTag.java index 23bd6f715..09889adf4 100644 --- a/src/com/jpexs/decompiler/flash/tags/DefineVideoStreamTag.java +++ b/src/com/jpexs/decompiler/flash/tags/DefineVideoStreamTag.java @@ -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 added) { return new RECT(0, (int) (SWF.unitDivisor * width), 0, (int) (SWF.unitDivisor * height)); } } diff --git a/src/com/jpexs/decompiler/flash/tags/DoABCDefineTag.java b/src/com/jpexs/decompiler/flash/tags/DoABCDefineTag.java index 8e16c6e3b..c43a9fe31 100644 --- a/src/com/jpexs/decompiler/flash/tags/DoABCDefineTag.java +++ b/src/com/jpexs/decompiler/flash/tags/DoABCDefineTag.java @@ -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); diff --git a/src/com/jpexs/decompiler/flash/tags/DoABCTag.java b/src/com/jpexs/decompiler/flash/tags/DoABCTag.java index e1d615ce9..12f9305ad 100644 --- a/src/com/jpexs/decompiler/flash/tags/DoABCTag.java +++ b/src/com/jpexs/decompiler/flash/tags/DoABCTag.java @@ -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); diff --git a/src/com/jpexs/decompiler/flash/tags/DoActionTag.java b/src/com/jpexs/decompiler/flash/tags/DoActionTag.java index 18933674d..c61843256 100644 --- a/src/com/jpexs/decompiler/flash/tags/DoActionTag.java +++ b/src/com/jpexs/decompiler/flash/tags/DoActionTag.java @@ -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(); } /** diff --git a/src/com/jpexs/decompiler/flash/tags/PlaceObject2Tag.java b/src/com/jpexs/decompiler/flash/tags/PlaceObject2Tag.java index 9c68d415d..95e06cd46 100644 --- a/src/com/jpexs/decompiler/flash/tags/PlaceObject2Tag.java +++ b/src/com/jpexs/decompiler/flash/tags/PlaceObject2Tag.java @@ -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 . - */ -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 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 getSubItems() { - List 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 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 . + */ +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 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 getSubItems() { + List 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 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; + } + } +} diff --git a/src/com/jpexs/decompiler/flash/tags/PlaceObject3Tag.java b/src/com/jpexs/decompiler/flash/tags/PlaceObject3Tag.java index 2e1584a6d..451907f52 100644 --- a/src/com/jpexs/decompiler/flash/tags/PlaceObject3Tag.java +++ b/src/com/jpexs/decompiler/flash/tags/PlaceObject3Tag.java @@ -1,530 +1,530 @@ -/* - * 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 . - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.EndOfStreamException; -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.Reserved; -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 PlaceObject3Tag 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; - /** - * Has class name or character ID of bitmap to place. If - * PlaceFlagHasClassName, use ClassName. If PlaceFlagHasCharacter, use - * CharacterId - */ - public boolean placeFlagHasImage; - /** - * Has class name of object to place - */ - public boolean placeFlagHasClassName; - /** - * Enables bitmap caching - */ - public boolean placeFlagHasCacheAsBitmap; - /** - * Has blend mode - */ - public boolean placeFlagHasBlendMode; - /** - * Has filter list - */ - public boolean placeFlagHasFilterList; - /** - * Has opaque background. SWF 11 and higher. - */ - public boolean placeFlagOpaqueBackground; - /** - * Has visibility flag. SWF 11 and higher. - */ - public boolean placeFlagHasVisible; - /** - * Depth of character - */ - @SWFType(BasicType.UI16) - public int depth; - /** - * If PlaceFlagHasClassName or (PlaceFlagHasImage and - * PlaceFlagHasCharacter), Name of the class to place - */ - @Conditional("placeFlagHasClassName") - public String className; - /** - * 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 - */ - @SWFType(BasicType.UI16) - @Conditional("placeFlagHasClipDepth") - public int clipDepth; - /** - * If PlaceFlagHasFilterList, List of filters on this object - */ - @Conditional("placeFlagHasFilterList") - public List surfaceFilterList; - /** - * If PlaceFlagHasBlendMode, Blend mode - */ - @SWFType(BasicType.UI8) - @Conditional("placeFlagHasBlendMode") - public int blendMode; - /** - * If PlaceFlagHasCacheAsBitmap, 0 = Bitmap cache disabled, 1-255 = Bitmap - * cache enabled - */ - @SWFType(BasicType.UI8) - @Conditional("placeFlagHasCacheAsBitmap") - public int bitmapCache; - /** - * @since SWF 5 If PlaceFlagHasClipActions, Clip Actions Data - */ - @Conditional(value = "placeFlagHasClipActions", minSwfVersion = 5) - @Internal //TODO: make editable - public CLIPACTIONS clipActions; - /** - * If PlaceFlagHasVisible, 0 = Place invisible, 1 = Place visible - */ - @Conditional("placeFlagHasVisible") - public int visible; - /** - * If PlaceFlagHasVisible, Background color - */ - @Conditional("placeFlagOpaqueBackground") - public RGBA backgroundColor; - // FIXME bug found in ecoDrive.swf, - @Internal - private boolean bitmapCacheBug; - @Reserved - public boolean reserved; - public static final int ID = 70; - - @Override - public List getFilters() { - if (placeFlagHasFilterList) { - return surfaceFilterList; - } else { - return null; - } - } - - @Override - public int getClipDepth() { - if (placeFlagHasClipDepth) { - return clipDepth; - } - return -1; - } - - /** - * 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.writeUB(1, reserved ? 1 : 0); - sos.writeUB(1, placeFlagOpaqueBackground ? 1 : 0); //SWF11 - sos.writeUB(1, placeFlagHasVisible ? 1 : 0); //SWF11 - sos.writeUB(1, placeFlagHasImage ? 1 : 0); - sos.writeUB(1, placeFlagHasClassName ? 1 : 0); - sos.writeUB(1, placeFlagHasCacheAsBitmap ? 1 : 0); - sos.writeUB(1, placeFlagHasBlendMode ? 1 : 0); - sos.writeUB(1, placeFlagHasFilterList ? 1 : 0); - sos.writeUI16(depth); - - if (placeFlagHasClassName) { - sos.writeString(className); - } - 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 (placeFlagHasFilterList) { - sos.writeFILTERLIST(surfaceFilterList); - } - if (placeFlagHasBlendMode) { - sos.writeUI8(blendMode); - } - if (placeFlagHasCacheAsBitmap) { - if (!bitmapCacheBug) { - sos.writeUI8(bitmapCache); - } - } - if (placeFlagHasVisible) { - sos.writeUI8(visible); - } - if (placeFlagOpaqueBackground) { - sos.writeRGBA(backgroundColor); - } - if (placeFlagHasClipActions) { - sos.writeCLIPACTIONS(clipActions); - } - sos.close(); - } catch (IOException ex) { - } - return baos.toByteArray(); - } - - /** - * Constructor - * - * @param sis - * @param data - * @throws IOException - */ - public PlaceObject3Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "PlaceObject3", 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; - reserved = sis.readUB(1, "reserved") == 1; - placeFlagOpaqueBackground = sis.readUB(1, "placeFlagOpaqueBackground") == 1; //SWF11 - placeFlagHasVisible = sis.readUB(1, "placeFlagHasVisible") == 1; //SWF11 - placeFlagHasImage = sis.readUB(1, "placeFlagHasImage") == 1; - placeFlagHasClassName = sis.readUB(1, "placeFlagHasClassName") == 1; - placeFlagHasCacheAsBitmap = sis.readUB(1, "placeFlagHasCacheAsBitmap") == 1; - placeFlagHasBlendMode = sis.readUB(1, "placeFlagHasBlendMode") == 1; - placeFlagHasFilterList = sis.readUB(1, "placeFlagHasFilterList") == 1; - - depth = sis.readUI16("depth"); - if (placeFlagHasClassName) { - className = sis.readString("className"); - } - 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 (placeFlagHasFilterList) { - surfaceFilterList = sis.readFILTERLIST("surfaceFilterList"); - } - if (placeFlagHasBlendMode) { - blendMode = sis.readUI8("blendMode"); - } - bitmapCacheBug = false; - if (placeFlagHasCacheAsBitmap) { - try { - bitmapCache = sis.readUI8("bitmapCache"); - } catch (EndOfStreamException eex) { - bitmapCacheBug = true; - bitmapCache = 1; - } - } - - if (placeFlagHasVisible) { - visible = sis.readUI8("visible"); - } - if (placeFlagOpaqueBackground) { - backgroundColor = sis.readRGBA("backgroundColor"); - } - - if (placeFlagHasClipActions) { - clipActions = sis.readCLIPACTIONS(swf, this, "clipActions"); - } - } - - /** - * Returns all sub-items - * - * @return List of sub-items - */ - @Override - public List getSubItems() { - List 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 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 blendMode; - } - - @Override - public String getClassName() { - if (placeFlagHasClassName) { - return className; - } - return null; - } - - @Override - public boolean cacheAsBitmap() { - return placeFlagHasCacheAsBitmap; - } - - @Override - public boolean isVisible() { - if (placeFlagHasVisible) { - return visible == 1; - } - return true; - } - - @Override - public RGBA getBackgroundColor() { - if (placeFlagOpaqueBackground) { - return backgroundColor; - } - 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) { - placeFlagHasClassName = true; - this.className = className; - } - - @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 . + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.EndOfStreamException; +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.Reserved; +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 PlaceObject3Tag 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; + /** + * Has class name or character ID of bitmap to place. If + * PlaceFlagHasClassName, use ClassName. If PlaceFlagHasCharacter, use + * CharacterId + */ + public boolean placeFlagHasImage; + /** + * Has class name of object to place + */ + public boolean placeFlagHasClassName; + /** + * Enables bitmap caching + */ + public boolean placeFlagHasCacheAsBitmap; + /** + * Has blend mode + */ + public boolean placeFlagHasBlendMode; + /** + * Has filter list + */ + public boolean placeFlagHasFilterList; + /** + * Has opaque background. SWF 11 and higher. + */ + public boolean placeFlagOpaqueBackground; + /** + * Has visibility flag. SWF 11 and higher. + */ + public boolean placeFlagHasVisible; + /** + * Depth of character + */ + @SWFType(BasicType.UI16) + public int depth; + /** + * If PlaceFlagHasClassName or (PlaceFlagHasImage and + * PlaceFlagHasCharacter), Name of the class to place + */ + @Conditional("placeFlagHasClassName") + public String className; + /** + * 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 + */ + @SWFType(BasicType.UI16) + @Conditional("placeFlagHasClipDepth") + public int clipDepth; + /** + * If PlaceFlagHasFilterList, List of filters on this object + */ + @Conditional("placeFlagHasFilterList") + public List surfaceFilterList; + /** + * If PlaceFlagHasBlendMode, Blend mode + */ + @SWFType(BasicType.UI8) + @Conditional("placeFlagHasBlendMode") + public int blendMode; + /** + * If PlaceFlagHasCacheAsBitmap, 0 = Bitmap cache disabled, 1-255 = Bitmap + * cache enabled + */ + @SWFType(BasicType.UI8) + @Conditional("placeFlagHasCacheAsBitmap") + public int bitmapCache; + /** + * @since SWF 5 If PlaceFlagHasClipActions, Clip Actions Data + */ + @Conditional(value = "placeFlagHasClipActions", minSwfVersion = 5) + @Internal //TODO: make editable + public CLIPACTIONS clipActions; + /** + * If PlaceFlagHasVisible, 0 = Place invisible, 1 = Place visible + */ + @Conditional("placeFlagHasVisible") + public int visible; + /** + * If PlaceFlagHasVisible, Background color + */ + @Conditional("placeFlagOpaqueBackground") + public RGBA backgroundColor; + // FIXME bug found in ecoDrive.swf, + @Internal + private boolean bitmapCacheBug; + @Reserved + public boolean reserved; + public static final int ID = 70; + + @Override + public List getFilters() { + if (placeFlagHasFilterList) { + return surfaceFilterList; + } else { + return null; + } + } + + @Override + public int getClipDepth() { + if (placeFlagHasClipDepth) { + return clipDepth; + } + return -1; + } + + /** + * 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.writeUB(1, reserved ? 1 : 0); + sos.writeUB(1, placeFlagOpaqueBackground ? 1 : 0); //SWF11 + sos.writeUB(1, placeFlagHasVisible ? 1 : 0); //SWF11 + sos.writeUB(1, placeFlagHasImage ? 1 : 0); + sos.writeUB(1, placeFlagHasClassName ? 1 : 0); + sos.writeUB(1, placeFlagHasCacheAsBitmap ? 1 : 0); + sos.writeUB(1, placeFlagHasBlendMode ? 1 : 0); + sos.writeUB(1, placeFlagHasFilterList ? 1 : 0); + sos.writeUI16(depth); + + if (placeFlagHasClassName) { + sos.writeString(className); + } + 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 (placeFlagHasFilterList) { + sos.writeFILTERLIST(surfaceFilterList); + } + if (placeFlagHasBlendMode) { + sos.writeUI8(blendMode); + } + if (placeFlagHasCacheAsBitmap) { + if (!bitmapCacheBug) { + sos.writeUI8(bitmapCache); + } + } + if (placeFlagHasVisible) { + sos.writeUI8(visible); + } + if (placeFlagOpaqueBackground) { + sos.writeRGBA(backgroundColor); + } + if (placeFlagHasClipActions) { + sos.writeCLIPACTIONS(clipActions); + } + sos.close(); + } catch (IOException ex) { + } + return baos.toByteArray(); + } + + /** + * Constructor + * + * @param sis + * @param data + * @throws IOException + */ + public PlaceObject3Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, "PlaceObject3", 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; + reserved = sis.readUB(1, "reserved") == 1; + placeFlagOpaqueBackground = sis.readUB(1, "placeFlagOpaqueBackground") == 1; //SWF11 + placeFlagHasVisible = sis.readUB(1, "placeFlagHasVisible") == 1; //SWF11 + placeFlagHasImage = sis.readUB(1, "placeFlagHasImage") == 1; + placeFlagHasClassName = sis.readUB(1, "placeFlagHasClassName") == 1; + placeFlagHasCacheAsBitmap = sis.readUB(1, "placeFlagHasCacheAsBitmap") == 1; + placeFlagHasBlendMode = sis.readUB(1, "placeFlagHasBlendMode") == 1; + placeFlagHasFilterList = sis.readUB(1, "placeFlagHasFilterList") == 1; + + depth = sis.readUI16("depth"); + if (placeFlagHasClassName) { + className = sis.readString("className"); + } + 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 (placeFlagHasFilterList) { + surfaceFilterList = sis.readFILTERLIST("surfaceFilterList"); + } + if (placeFlagHasBlendMode) { + blendMode = sis.readUI8("blendMode"); + } + bitmapCacheBug = false; + if (placeFlagHasCacheAsBitmap) { + try { + bitmapCache = sis.readUI8("bitmapCache"); + } catch (EndOfStreamException eex) { + bitmapCacheBug = true; + bitmapCache = 1; + } + } + + if (placeFlagHasVisible) { + visible = sis.readUI8("visible"); + } + if (placeFlagOpaqueBackground) { + backgroundColor = sis.readRGBA("backgroundColor"); + } + + if (placeFlagHasClipActions) { + clipActions = sis.readCLIPACTIONS(swf, this, "clipActions"); + } + } + + /** + * Returns all sub-items + * + * @return List of sub-items + */ + @Override + public List getSubItems() { + List 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 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 blendMode; + } + + @Override + public String getClassName() { + if (placeFlagHasClassName) { + return className; + } + return null; + } + + @Override + public boolean cacheAsBitmap() { + return placeFlagHasCacheAsBitmap; + } + + @Override + public boolean isVisible() { + if (placeFlagHasVisible) { + return visible == 1; + } + return true; + } + + @Override + public RGBA getBackgroundColor() { + if (placeFlagOpaqueBackground) { + return backgroundColor; + } + 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) { + placeFlagHasClassName = true; + this.className = className; + } + + @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; + } + } +} diff --git a/src/com/jpexs/decompiler/flash/tags/PlaceObject4Tag.java b/src/com/jpexs/decompiler/flash/tags/PlaceObject4Tag.java index a32fa9dd1..23e1a1167 100644 --- a/src/com/jpexs/decompiler/flash/tags/PlaceObject4Tag.java +++ b/src/com/jpexs/decompiler/flash/tags/PlaceObject4Tag.java @@ -1,533 +1,533 @@ -/* - * 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 . - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.EndOfStreamException; -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.Reserved; -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; - -/** - * Same as PlaceObject3Tag except additional AMF data - * - * @author JPEXS - */ -public class PlaceObject4Tag 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; - /** - * Has class name or character ID of bitmap to place. If - * PlaceFlagHasClassName, use ClassName. If PlaceFlagHasCharacter, use - * CharacterId - */ - public boolean placeFlagHasImage; - /** - * Has class name of object to place - */ - public boolean placeFlagHasClassName; - /** - * Enables bitmap caching - */ - public boolean placeFlagHasCacheAsBitmap; - /** - * Has blend mode - */ - public boolean placeFlagHasBlendMode; - /** - * Has filter list - */ - public boolean placeFlagHasFilterList; - /** - * Has opaque background. SWF 11 and higher. - */ - public boolean placeFlagOpaqueBackground; - /** - * Has visibility flag. SWF 11 and higher. - */ - public boolean placeFlagHasVisible; - /** - * Depth of character - */ - @SWFType(BasicType.UI16) - public int depth; - /** - * If PlaceFlagHasClassName or (PlaceFlagHasImage and - * PlaceFlagHasCharacter), Name of the class to place - */ - @Conditional("placeFlagHasClassName") - public String className; - /** - * 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 - */ - @SWFType(BasicType.UI16) - @Conditional("placeFlagHasClipDepth") - public int clipDepth; - /** - * If PlaceFlagHasFilterList, List of filters on this object - */ - @Conditional("placeFlagHasFilterList") - public List surfaceFilterList; - /** - * If PlaceFlagHasBlendMode, Blend mode - */ - @SWFType(BasicType.UI8) - @Conditional("placeFlagHasBlendMode") - public int blendMode; - /** - * If PlaceFlagHasCacheAsBitmap, 0 = Bitmap cache disabled, 1-255 = Bitmap - * cache enabled - */ - @SWFType(BasicType.UI8) - @Conditional("placeFlagHasCacheAsBitmap") - public int bitmapCache; - /** - * @since SWF 5 If PlaceFlagHasClipActions, Clip Actions Data - */ - @Conditional(value = "placeFlagHasClipActions", minSwfVersion = 5) - @Internal //TODO: make editable - public CLIPACTIONS clipActions; - /** - * If PlaceFlagHasVisible, 0 = Place invisible, 1 = Place visible - */ - @Conditional("placeFlagHasVisible") - public int visible; - /** - * If PlaceFlagHasVisible, Background color - */ - @Conditional("placeFlagOpaqueBackground") - public RGBA backgroundColor; - // FIXME bug found in ecoDrive.swf, - @Internal - private boolean bitmapCacheBug; - @Reserved - public boolean reserved; - - public static final int ID = 94; - public byte[] amfData; //TODO: Parse AMF data? - - @Override - public List getFilters() { - if (placeFlagHasFilterList) { - return surfaceFilterList; - } else { - return null; - } - } - - @Override - public int getClipDepth() { - if (placeFlagHasClipDepth) { - return clipDepth; - } - return -1; - } - - /** - * 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.writeUB(1, reserved ? 1 : 0); - sos.writeUB(1, placeFlagOpaqueBackground ? 1 : 0); //SWF11 - sos.writeUB(1, placeFlagHasVisible ? 1 : 0); //SWF11 - sos.writeUB(1, placeFlagHasImage ? 1 : 0); - sos.writeUB(1, placeFlagHasClassName ? 1 : 0); - sos.writeUB(1, placeFlagHasCacheAsBitmap ? 1 : 0); - sos.writeUB(1, placeFlagHasBlendMode ? 1 : 0); - sos.writeUB(1, placeFlagHasFilterList ? 1 : 0); - sos.writeUI16(depth); - - if (placeFlagHasClassName) { - sos.writeString(className); - } - 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 (placeFlagHasFilterList) { - sos.writeFILTERLIST(surfaceFilterList); - } - if (placeFlagHasBlendMode) { - sos.writeUI8(blendMode); - } - if (placeFlagHasCacheAsBitmap) { - if (!bitmapCacheBug) { - sos.writeUI8(bitmapCache); - } - } - if (placeFlagHasVisible) { - sos.writeUI8(visible); - } - if (placeFlagOpaqueBackground) { - sos.writeRGBA(backgroundColor); - } - if (placeFlagHasClipActions) { - sos.writeCLIPACTIONS(clipActions); - } - sos.close(); - } catch (IOException ex) { - } - return baos.toByteArray(); - } - - /** - * Constructor - * - * @param sis - * @param data - * @throws IOException - */ - public PlaceObject4Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "PlaceObject4", 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; - reserved = sis.readUB(1, "reserved") == 1; - placeFlagOpaqueBackground = sis.readUB(1, "placeFlagOpaqueBackground") == 1; //SWF11 - placeFlagHasVisible = sis.readUB(1, "placeFlagHasVisible") == 1; //SWF11 - placeFlagHasImage = sis.readUB(1, "placeFlagHasImage") == 1; - placeFlagHasClassName = sis.readUB(1, "placeFlagHasClassName") == 1; - placeFlagHasCacheAsBitmap = sis.readUB(1, "placeFlagHasCacheAsBitmap") == 1; - placeFlagHasBlendMode = sis.readUB(1, "placeFlagHasBlendMode") == 1; - placeFlagHasFilterList = sis.readUB(1, "placeFlagHasFilterList") == 1; - - depth = sis.readUI16("depth"); - if (placeFlagHasClassName) { - className = sis.readString("className"); - } - 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 (placeFlagHasFilterList) { - surfaceFilterList = sis.readFILTERLIST("surfaceFilterList"); - } - if (placeFlagHasBlendMode) { - blendMode = sis.readUI8("blendMode"); - } - bitmapCacheBug = false; - if (placeFlagHasCacheAsBitmap) { - try { - bitmapCache = sis.readUI8("bitmapCache"); - } catch (EndOfStreamException eex) { - bitmapCacheBug = true; - bitmapCache = 1; - } - } - - if (placeFlagHasVisible) { - visible = sis.readUI8("visible"); - } - if (placeFlagOpaqueBackground) { - backgroundColor = sis.readRGBA("backgroundColor"); - } - - if (placeFlagHasClipActions) { - clipActions = sis.readCLIPACTIONS(swf, this, "clipActions"); - } - amfData = sis.readBytesEx(sis.available(), "amfData"); - } - - /** - * Returns all sub-items - * - * @return List of sub-items - */ - @Override - public List getSubItems() { - List 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 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 blendMode; - } - - @Override - public String getClassName() { - if (placeFlagHasClassName) { - return className; - } - return null; - } - - @Override - public boolean cacheAsBitmap() { - return placeFlagHasCacheAsBitmap; - } - - @Override - public boolean isVisible() { - if (placeFlagHasVisible) { - return visible == 1; - } - return true; - } - - @Override - public RGBA getBackgroundColor() { - if (placeFlagOpaqueBackground) { - return backgroundColor; - } - 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) { - placeFlagHasClassName = true; - this.className = className; - } - - @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 . + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.EndOfStreamException; +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.Reserved; +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; + +/** + * Same as PlaceObject3Tag except additional AMF data + * + * @author JPEXS + */ +public class PlaceObject4Tag 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; + /** + * Has class name or character ID of bitmap to place. If + * PlaceFlagHasClassName, use ClassName. If PlaceFlagHasCharacter, use + * CharacterId + */ + public boolean placeFlagHasImage; + /** + * Has class name of object to place + */ + public boolean placeFlagHasClassName; + /** + * Enables bitmap caching + */ + public boolean placeFlagHasCacheAsBitmap; + /** + * Has blend mode + */ + public boolean placeFlagHasBlendMode; + /** + * Has filter list + */ + public boolean placeFlagHasFilterList; + /** + * Has opaque background. SWF 11 and higher. + */ + public boolean placeFlagOpaqueBackground; + /** + * Has visibility flag. SWF 11 and higher. + */ + public boolean placeFlagHasVisible; + /** + * Depth of character + */ + @SWFType(BasicType.UI16) + public int depth; + /** + * If PlaceFlagHasClassName or (PlaceFlagHasImage and + * PlaceFlagHasCharacter), Name of the class to place + */ + @Conditional("placeFlagHasClassName") + public String className; + /** + * 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 + */ + @SWFType(BasicType.UI16) + @Conditional("placeFlagHasClipDepth") + public int clipDepth; + /** + * If PlaceFlagHasFilterList, List of filters on this object + */ + @Conditional("placeFlagHasFilterList") + public List surfaceFilterList; + /** + * If PlaceFlagHasBlendMode, Blend mode + */ + @SWFType(BasicType.UI8) + @Conditional("placeFlagHasBlendMode") + public int blendMode; + /** + * If PlaceFlagHasCacheAsBitmap, 0 = Bitmap cache disabled, 1-255 = Bitmap + * cache enabled + */ + @SWFType(BasicType.UI8) + @Conditional("placeFlagHasCacheAsBitmap") + public int bitmapCache; + /** + * @since SWF 5 If PlaceFlagHasClipActions, Clip Actions Data + */ + @Conditional(value = "placeFlagHasClipActions", minSwfVersion = 5) + @Internal //TODO: make editable + public CLIPACTIONS clipActions; + /** + * If PlaceFlagHasVisible, 0 = Place invisible, 1 = Place visible + */ + @Conditional("placeFlagHasVisible") + public int visible; + /** + * If PlaceFlagHasVisible, Background color + */ + @Conditional("placeFlagOpaqueBackground") + public RGBA backgroundColor; + // FIXME bug found in ecoDrive.swf, + @Internal + private boolean bitmapCacheBug; + @Reserved + public boolean reserved; + + public static final int ID = 94; + public byte[] amfData; //TODO: Parse AMF data? + + @Override + public List getFilters() { + if (placeFlagHasFilterList) { + return surfaceFilterList; + } else { + return null; + } + } + + @Override + public int getClipDepth() { + if (placeFlagHasClipDepth) { + return clipDepth; + } + return -1; + } + + /** + * 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.writeUB(1, reserved ? 1 : 0); + sos.writeUB(1, placeFlagOpaqueBackground ? 1 : 0); //SWF11 + sos.writeUB(1, placeFlagHasVisible ? 1 : 0); //SWF11 + sos.writeUB(1, placeFlagHasImage ? 1 : 0); + sos.writeUB(1, placeFlagHasClassName ? 1 : 0); + sos.writeUB(1, placeFlagHasCacheAsBitmap ? 1 : 0); + sos.writeUB(1, placeFlagHasBlendMode ? 1 : 0); + sos.writeUB(1, placeFlagHasFilterList ? 1 : 0); + sos.writeUI16(depth); + + if (placeFlagHasClassName) { + sos.writeString(className); + } + 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 (placeFlagHasFilterList) { + sos.writeFILTERLIST(surfaceFilterList); + } + if (placeFlagHasBlendMode) { + sos.writeUI8(blendMode); + } + if (placeFlagHasCacheAsBitmap) { + if (!bitmapCacheBug) { + sos.writeUI8(bitmapCache); + } + } + if (placeFlagHasVisible) { + sos.writeUI8(visible); + } + if (placeFlagOpaqueBackground) { + sos.writeRGBA(backgroundColor); + } + if (placeFlagHasClipActions) { + sos.writeCLIPACTIONS(clipActions); + } + sos.close(); + } catch (IOException ex) { + } + return baos.toByteArray(); + } + + /** + * Constructor + * + * @param sis + * @param data + * @throws IOException + */ + public PlaceObject4Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, "PlaceObject4", 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; + reserved = sis.readUB(1, "reserved") == 1; + placeFlagOpaqueBackground = sis.readUB(1, "placeFlagOpaqueBackground") == 1; //SWF11 + placeFlagHasVisible = sis.readUB(1, "placeFlagHasVisible") == 1; //SWF11 + placeFlagHasImage = sis.readUB(1, "placeFlagHasImage") == 1; + placeFlagHasClassName = sis.readUB(1, "placeFlagHasClassName") == 1; + placeFlagHasCacheAsBitmap = sis.readUB(1, "placeFlagHasCacheAsBitmap") == 1; + placeFlagHasBlendMode = sis.readUB(1, "placeFlagHasBlendMode") == 1; + placeFlagHasFilterList = sis.readUB(1, "placeFlagHasFilterList") == 1; + + depth = sis.readUI16("depth"); + if (placeFlagHasClassName) { + className = sis.readString("className"); + } + 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 (placeFlagHasFilterList) { + surfaceFilterList = sis.readFILTERLIST("surfaceFilterList"); + } + if (placeFlagHasBlendMode) { + blendMode = sis.readUI8("blendMode"); + } + bitmapCacheBug = false; + if (placeFlagHasCacheAsBitmap) { + try { + bitmapCache = sis.readUI8("bitmapCache"); + } catch (EndOfStreamException eex) { + bitmapCacheBug = true; + bitmapCache = 1; + } + } + + if (placeFlagHasVisible) { + visible = sis.readUI8("visible"); + } + if (placeFlagOpaqueBackground) { + backgroundColor = sis.readRGBA("backgroundColor"); + } + + if (placeFlagHasClipActions) { + clipActions = sis.readCLIPACTIONS(swf, this, "clipActions"); + } + amfData = sis.readBytesEx(sis.available(), "amfData"); + } + + /** + * Returns all sub-items + * + * @return List of sub-items + */ + @Override + public List getSubItems() { + List 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 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 blendMode; + } + + @Override + public String getClassName() { + if (placeFlagHasClassName) { + return className; + } + return null; + } + + @Override + public boolean cacheAsBitmap() { + return placeFlagHasCacheAsBitmap; + } + + @Override + public boolean isVisible() { + if (placeFlagHasVisible) { + return visible == 1; + } + return true; + } + + @Override + public RGBA getBackgroundColor() { + if (placeFlagOpaqueBackground) { + return backgroundColor; + } + 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) { + placeFlagHasClassName = true; + this.className = className; + } + + @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; + } + } +} diff --git a/src/com/jpexs/decompiler/flash/tags/Tag.java b/src/com/jpexs/decompiler/flash/tags/Tag.java index 7c01411c6..50981f219 100644 --- a/src/com/jpexs/decompiler/flash/tags/Tag.java +++ b/src/com/jpexs/decompiler/flash/tags/Tag.java @@ -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 . - */ -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 knownTagIds; - private static List requiredTagIds; - - public static List getKnownTags() { - if (knownTagIds == null) { - synchronized (lockObject) { - if (knownTagIds == null) { - List 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 getRequiredTags() { - if (requiredTagIds == null) { - synchronized (lockObject) { - if (requiredTagIds == null) { - List 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 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 needed) { - } - - @Override - public boolean removeCharacter(int characterId) { - return false; - } - - public void getNeededCharactersDeep(Set needed) { - Set visited = new HashSet<>(); - Set 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 . + */ +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 knownTagIds; + private static List requiredTagIds; + + public static List getKnownTags() { + if (knownTagIds == null) { + synchronized (lockObject) { + if (knownTagIds == null) { + List 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 getRequiredTags() { + if (requiredTagIds == null) { + synchronized (lockObject) { + if (requiredTagIds == null) { + List 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 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 needed) { + } + + @Override + public boolean removeCharacter(int characterId) { + return false; + } + + public void getNeededCharactersDeep(Set needed) { + Set visited = new HashSet<>(); + Set 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); + } + } + } +} diff --git a/src/com/jpexs/decompiler/flash/tags/base/BoundedTag.java b/src/com/jpexs/decompiler/flash/tags/base/BoundedTag.java index fb2422f0b..c67199f68 100644 --- a/src/com/jpexs/decompiler/flash/tags/base/BoundedTag.java +++ b/src/com/jpexs/decompiler/flash/tags/base/BoundedTag.java @@ -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 . - */ -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 . + */ +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 added); +} diff --git a/src/com/jpexs/decompiler/flash/tags/base/FontTag.java b/src/com/jpexs/decompiler/flash/tags/base/FontTag.java index cb4dcb72a..2de2edb60 100644 --- a/src/com/jpexs/decompiler/flash/tags/base/FontTag.java +++ b/src/com/jpexs/decompiler/flash/tags/base/FontTag.java @@ -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()); return new Area(new Rectangle(r.Xmin, r.Ymin, r.getWidth(), r.getHeight())); } @Override - public RECT getRect() { + public RECT getRect(Set added) { return new RECT(0, (int) (previewSize * SWF.unitDivisor), 0, (int) (previewSize * SWF.unitDivisor)); } diff --git a/src/com/jpexs/decompiler/flash/tags/base/ImageTag.java b/src/com/jpexs/decompiler/flash/tags/base/ImageTag.java index 38210dbae..eaefc15fc 100644 --- a/src/com/jpexs/decompiler/flash/tags/base/ImageTag.java +++ b/src/com/jpexs/decompiler/flash/tags/base/ImageTag.java @@ -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 . - */ -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 . + */ +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()); + 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 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()); + } +} diff --git a/src/com/jpexs/decompiler/flash/treeitems/HeaderItem.java b/src/com/jpexs/decompiler/flash/treeitems/HeaderItem.java index 0baefd1ff..fb82f70da 100644 --- a/src/com/jpexs/decompiler/flash/treeitems/HeaderItem.java +++ b/src/com/jpexs/decompiler/flash/treeitems/HeaderItem.java @@ -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; diff --git a/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java b/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java index 8134f3fd2..1de47d401 100644 --- a/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java +++ b/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java @@ -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()); double centerPoint3DX = twipToPixel(matrix.translateX + spriteRect.getWidth() / 2); double centerPoint3DY = twipToPixel(matrix.translateY + spriteRect.getHeight() / 2); ret += " centerPoint3DX=\"" + centerPoint3DX + "\" centerPoint3DY=\"" + centerPoint3DY + "\""; diff --git a/src/com/jpexs/helpers/ByteArrayRange.java b/src/com/jpexs/helpers/ByteArrayRange.java index 239357001..e8d327eb3 100644 --- a/src/com/jpexs/helpers/ByteArrayRange.java +++ b/src/com/jpexs/helpers/ByteArrayRange.java @@ -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;