diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFInputStream.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFInputStream.java index cf0b9a471..dc0d13438 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFInputStream.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFInputStream.java @@ -2650,7 +2650,7 @@ public class SWFInputStream implements AutoCloseable { for (int i = 0; i < lineStyleCount; i++) { ret.lineStyles[i] = readLINESTYLE(shapeNum, "lineStyle"); } - } else if (shapeNum == 4) { + } else { ret.lineStyles = new LINESTYLE2[lineStyleCount]; for (int i = 0; i < lineStyleCount; i++) { ret.lineStyles[i] = readLINESTYLE2(shapeNum, "lineStyle"); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFOutputStream.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFOutputStream.java index 19ec08358..08df1bf8b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFOutputStream.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFOutputStream.java @@ -1314,7 +1314,7 @@ public class SWFOutputStream extends OutputStream { for (int i = 0; i < lineStyleCount; i++) { writeLINESTYLE(value.lineStyles[i], shapeNum); } - } else if (shapeNum == 4) { + } else { lineStyleCount = value.lineStyles.length; if (lineStyleCount >= 0xff) { writeUI8(0xff); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/SwfXmlImporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/SwfXmlImporter.java index 1ba208bc3..50b753fdf 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/SwfXmlImporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/SwfXmlImporter.java @@ -243,7 +243,7 @@ public class SwfXmlImporter { Map tags = new HashMap<>(); Map knownTags = Tag.getKnownClasses(); for (Integer key : knownTags.keySet()) { - Class cls = knownTags.get(key).cls; + Class cls = knownTags.get(key).getCls(); if (!ReflectionTools.canInstantiate(cls)) { System.err.println("Can't instantiate: " + cls.getName()); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/CSMTextSettingsTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/CSMTextSettingsTag.java index 7fb77be19..4b945de23 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/CSMTextSettingsTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/CSMTextSettingsTag.java @@ -34,6 +34,10 @@ import java.io.OutputStream; */ public class CSMTextSettingsTag extends Tag implements CharacterIdTag { + public static final int ID = 74; + + public static final String NAME = "CSMTextSettings"; + @SWFType(BasicType.UI16) public int textID; @@ -57,34 +61,6 @@ public class CSMTextSettingsTag extends Tag implements CharacterIdTag { @SWFType(BasicType.UI8) public int reserved2; - public static final int ID = 74; - - public static final String NAME = "CSMTextSettings"; - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(textID); - sos.writeUB(2, useFlashType); - sos.writeUB(3, gridFit); - sos.writeUB(3, reserved); - sos.writeFLOAT(thickness); //F32 = FLOAT - sos.writeFLOAT(sharpness); //F32 = FLOAT - sos.writeUI8(reserved2); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - /** * Constructor * @@ -117,6 +93,30 @@ public class CSMTextSettingsTag extends Tag implements CharacterIdTag { reserved2 = sis.readUI8("reserved2"); //reserved } + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(textID); + sos.writeUB(2, useFlashType); + sos.writeUB(3, gridFit); + sos.writeUB(3, reserved); + sos.writeFLOAT(thickness); //F32 = FLOAT + sos.writeFLOAT(sharpness); //F32 = FLOAT + sos.writeUI8(reserved2); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + @Override public int getCharacterId() { return textID; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DebugIDTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DebugIDTag.java index fdaada60c..7f303952f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DebugIDTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DebugIDTag.java @@ -32,30 +32,12 @@ import java.io.OutputStream; */ public class DebugIDTag extends Tag { - @SWFType(value = BasicType.UI8, count = 16) - public byte[] debugId; - public static final int ID = 63; public static final String NAME = "DebugID"; - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.write(debugId); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } + @SWFType(value = BasicType.UI8, count = 16) + public byte[] debugId; /** * Constructor @@ -83,4 +65,22 @@ public class DebugIDTag extends Tag { public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { debugId = sis.readBytesEx(16, "debugId"); } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.write(debugId); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBinaryDataTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBinaryDataTag.java index b528302d2..3a75e341a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBinaryDataTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBinaryDataTag.java @@ -40,6 +40,10 @@ import java.util.Arrays; */ public class DefineBinaryDataTag extends CharacterTag { + public static final int ID = 87; + + public static final String NAME = "DefineBinaryData"; + @SWFType(BasicType.UI16) public int tag; @@ -49,10 +53,6 @@ public class DefineBinaryDataTag extends CharacterTag { @SWFType(BasicType.UI32) public long reserved; - public static final int ID = 87; - - public static final String NAME = "DefineBinaryData"; - @Internal public SWF innerSwf; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG2Tag.java index 475b2aacc..a19bee961 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG2Tag.java @@ -41,16 +41,16 @@ import java.util.logging.Logger; */ public class DefineBitsJPEG2Tag extends ImageTag implements AloneTag { + public static final int ID = 21; + + public static final String NAME = "DefineBitsJPEG2"; + @SWFType(BasicType.UI16) public int characterID; @SWFType(BasicType.UI8) public ByteArrayRange imageData; - public static final int ID = 21; - - public static final String NAME = "DefineBitsJPEG2"; - @Override public int getCharacterId() { return characterID; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG3Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG3Tag.java index 6abc27702..f39e6a85a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG3Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG3Tag.java @@ -42,6 +42,10 @@ import java.util.logging.Logger; */ public class DefineBitsJPEG3Tag extends ImageTag implements AloneTag { + public static final int ID = 35; + + public static final String NAME = "DefineBitsJPEG3"; + @SWFType(BasicType.UI16) public int characterID; @@ -51,10 +55,6 @@ public class DefineBitsJPEG3Tag extends ImageTag implements AloneTag { @SWFType(BasicType.UI8) public byte[] bitmapAlphaData; - public static final int ID = 35; - - public static final String NAME = "DefineBitsJPEG3"; - @Override public int getCharacterId() { return characterID; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG4Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG4Tag.java index 301d091e2..192556a9a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG4Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG4Tag.java @@ -42,6 +42,10 @@ import java.util.logging.Logger; */ public class DefineBitsJPEG4Tag extends ImageTag implements AloneTag { + public static final int ID = 90; + + public static final String NAME = "DefineBitsJPEG4"; + @SWFType(BasicType.UI16) public int characterID; @@ -54,10 +58,6 @@ public class DefineBitsJPEG4Tag extends ImageTag implements AloneTag { @SWFType(BasicType.UI8) public ByteArrayRange bitmapAlphaData; - public static final int ID = 90; - - public static final String NAME = "DefineBitsJPEG4"; - @Override public int getCharacterId() { return characterID; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsLossless2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsLossless2Tag.java index 5b3442def..0a4fa9302 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsLossless2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsLossless2Tag.java @@ -48,6 +48,10 @@ import java.util.zip.InflaterInputStream; */ public class DefineBitsLossless2Tag extends ImageTag implements AloneTag { + public static final int ID = 36; + + public static final String NAME = "DefineBitsLossless2"; + @SWFType(BasicType.UI16) public int characterID; @@ -79,10 +83,6 @@ public class DefineBitsLossless2Tag extends ImageTag implements AloneTag { @Internal private boolean decompressed = false; - public static final int ID = 36; - - public static final String NAME = "DefineBitsLossless2"; - @Override public int getCharacterId() { return characterID; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsLosslessTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsLosslessTag.java index 09214081a..b1df0f32a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsLosslessTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsLosslessTag.java @@ -48,6 +48,10 @@ import java.util.zip.InflaterInputStream; */ public class DefineBitsLosslessTag extends ImageTag implements AloneTag { + public static final int ID = 20; + + public static final String NAME = "DefineBitsLossless"; + @SWFType(BasicType.UI16) public int characterID; @@ -81,10 +85,6 @@ public class DefineBitsLosslessTag extends ImageTag implements AloneTag { @Internal private boolean decompressed = false; - public static final int ID = 20; - - public static final String NAME = "DefineBitsLossless"; - private byte[] createEmptyImage() { try { BITMAPDATA bitmapData = new BITMAPDATA(); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsTag.java index d04d47b21..a75c4ef5a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsTag.java @@ -39,16 +39,16 @@ import java.util.logging.Logger; */ public class DefineBitsTag extends ImageTag implements TagChangedListener { + public static final int ID = 6; + + public static final String NAME = "DefineBits"; + @SWFType(BasicType.UI16) public int characterID; @SWFType(BasicType.UI8) public ByteArrayRange jpegData; - public static final int ID = 6; - - public static final String NAME = "DefineBits"; - @Override public void setImage(byte[] data) { throw new UnsupportedOperationException("Set image is not supported for DefineBits"); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java index 760075f1d..b28f555c2 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java @@ -53,6 +53,10 @@ import java.util.Set; */ public class DefineButton2Tag extends ButtonTag implements ASMSourceContainer { + public static final int ID = 34; + + public static final String NAME = "DefineButton2"; + /** * ID for this character */ @@ -78,10 +82,6 @@ public class DefineButton2Tag extends ButtonTag implements ASMSourceContainer { */ public List actions = new ArrayList<>(); - public static final int ID = 34; - - public static final String NAME = "DefineButton2"; - private Timeline timeline; private boolean isSingleFrameInitialized; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonCxformTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonCxformTag.java index 993d55fea..e32cae329 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonCxformTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonCxformTag.java @@ -34,15 +34,15 @@ import java.io.OutputStream; */ public class DefineButtonCxformTag extends Tag implements CharacterIdTag { + public static final int ID = 23; + + public static final String NAME = "DefineButtonCxform"; + @SWFType(BasicType.UI16) public int buttonId; public CXFORM buttonColorTransform; - public static final int ID = 23; - - public static final String NAME = "DefineButtonCxform"; - /** * Gets data bytes * diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonSoundTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonSoundTag.java index cdbb04eb0..111013af8 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonSoundTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonSoundTag.java @@ -34,6 +34,10 @@ import java.io.OutputStream; */ public class DefineButtonSoundTag extends Tag implements CharacterIdTag { + public static final int ID = 17; + + public static final String NAME = "DefineButtonSound"; + @SWFType(BasicType.UI16) public int buttonId; @@ -57,10 +61,6 @@ public class DefineButtonSoundTag extends Tag implements CharacterIdTag { public SOUNDINFO buttonSoundInfo3; - public static final int ID = 17; - - public static final String NAME = "DefineButtonSound"; - @Override public int getCharacterId() { return buttonId; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java index 138762ec9..690b63595 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java @@ -61,6 +61,10 @@ import java.util.logging.Logger; */ public class DefineButtonTag extends ButtonTag implements ASMSource { + public static final int ID = 7; + + public static final String NAME = "DefineButton"; + /** * ID for this character */ @@ -79,10 +83,6 @@ public class DefineButtonTag extends ButtonTag implements ASMSource { @HideInRawEdit public ByteArrayRange actionBytes; - public static final int ID = 7; - - public static final String NAME = "DefineButton"; - @Override public int getCharacterId() { return buttonId; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java index 782a2d45f..0502dfcd6 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java @@ -83,6 +83,10 @@ import org.xml.sax.helpers.DefaultHandler; */ public class DefineEditTextTag extends TextTag { + public static final int ID = 37; + + public static final String NAME = "DefineEditText"; + @SWFType(BasicType.UI16) public int characterID; @@ -163,10 +167,6 @@ public class DefineEditTextTag extends TextTag { @Conditional("hasText") public String initialText; - public static final int ID = 37; - - public static final String NAME = "DefineEditText"; - @Override public RECT getBounds() { return bounds; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont2Tag.java index 75613ba01..064c14acb 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont2Tag.java @@ -43,6 +43,10 @@ import java.util.List; */ public class DefineFont2Tag extends FontTag { + public static final int ID = 48; + + public static final String NAME = "DefineFont2"; + @SWFType(BasicType.UI16) public int fontId; @@ -93,10 +97,6 @@ public class DefineFont2Tag extends FontTag { @Conditional("fontFlagsHasLayout") public List fontKerningTable; - public static final int ID = 48; - - public static final String NAME = "DefineFont2"; - @Override public boolean isSmall() { return fontFlagsSmallText; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont3Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont3Tag.java index a51368dcf..53123037a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont3Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont3Tag.java @@ -47,6 +47,10 @@ import java.util.List; */ public class DefineFont3Tag extends FontTag { + public static final int ID = 75; + + public static final String NAME = "DefineFont3"; + @SWFType(BasicType.UI16) public int fontId; @@ -97,10 +101,6 @@ public class DefineFont3Tag extends FontTag { @Conditional("fontFlagsHasLayout") public List fontKerningTable; - public static final int ID = 75; - - public static final String NAME = "DefineFont3"; - @Override public boolean isSmall() { return fontFlagsSmallText; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont4Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont4Tag.java index 416248103..20c5eaee3 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont4Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont4Tag.java @@ -34,6 +34,10 @@ import java.io.OutputStream; */ public class DefineFont4Tag extends CharacterTag { + public static final int ID = 91; + + public static final String NAME = "DefineFont4"; + @SWFType(BasicType.UI16) public int fontID; @@ -51,10 +55,6 @@ public class DefineFont4Tag extends CharacterTag { public byte[] fontData; - public static final int ID = 91; - - public static final String NAME = "DefineFont4"; - @Override public int getCharacterId() { return fontID; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontAlignZonesTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontAlignZonesTag.java index 9f2eea4a0..e7b7f8d04 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontAlignZonesTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontAlignZonesTag.java @@ -38,6 +38,10 @@ import java.util.List; */ public class DefineFontAlignZonesTag extends Tag implements CharacterIdTag { + public static final int ID = 73; + + public static final String NAME = "DefineFontAlignZones"; + @SWFType(BasicType.UI16) public int fontID; @@ -51,10 +55,6 @@ public class DefineFontAlignZonesTag extends Tag implements CharacterIdTag { @SWFArray(value = "zone", countField = "glyphCount") public List zoneTable; - public static final int ID = 73; - - public static final String NAME = "DefineFontAlignZones"; - /** * Constructor * diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfo2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfo2Tag.java index 5870d5cef..ccd01aacd 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfo2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfo2Tag.java @@ -38,6 +38,10 @@ import java.util.List; */ public class DefineFontInfo2Tag extends Tag implements CharacterIdTag { + public static final int ID = 62; + + public static final String NAME = "DefineFontInfo2"; + @SWFType(BasicType.UI16) public int fontID; @@ -64,10 +68,6 @@ public class DefineFontInfo2Tag extends Tag implements CharacterIdTag { @SWFType(BasicType.UI16) public List codeTable; - public static final int ID = 62; - - public static final String NAME = "DefineFontInfo2"; - /** * Gets data bytes * diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfoTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfoTag.java index 313b369a4..f36524440 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfoTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfoTag.java @@ -37,6 +37,10 @@ import java.util.List; */ public class DefineFontInfoTag extends Tag implements CharacterIdTag { + public static final int ID = 13; + + public static final String NAME = "DefineFontInfo"; + @SWFType(BasicType.UI16) public int fontId; @@ -61,10 +65,6 @@ public class DefineFontInfoTag extends Tag implements CharacterIdTag { @SWFType(value = BasicType.UI8, alternateValue = BasicType.UI16, alternateCondition = "fontFlagsWideCodes") public List codeTable; - public static final int ID = 13; - - public static final String NAME = "DefineFontInfo"; - /** * Gets data bytes * diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontNameTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontNameTag.java index b919a4c97..1260fa18d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontNameTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontNameTag.java @@ -33,6 +33,10 @@ import java.io.OutputStream; */ public class DefineFontNameTag extends Tag implements CharacterIdTag { + public static final int ID = 88; + + public static final String NAME = "DefineFontName"; + @SWFType(BasicType.UI16) public int fontId; @@ -40,10 +44,6 @@ public class DefineFontNameTag extends Tag implements CharacterIdTag { public String fontCopyright; - public static final int ID = 88; - - public static final String NAME = "DefineFontName"; - /** * Constructor * diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontTag.java index 43b683b58..392bbe879 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontTag.java @@ -39,6 +39,10 @@ import java.util.List; */ public class DefineFontTag extends FontTag { + public static final int ID = 10; + + public static final String NAME = "DefineFont"; + @SWFType(BasicType.UI16) public int fontId; @@ -50,10 +54,6 @@ public class DefineFontTag extends FontTag { @Internal private DefineFontInfo2Tag fontInfo2Tag = null; - public static final int ID = 10; - - public static final String NAME = "DefineFont"; - @Override public boolean isSmall() { return false; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java index 64e1f38a8..76965a9bf 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java @@ -40,6 +40,10 @@ import java.io.OutputStream; */ public class DefineMorphShape2Tag extends MorphShapeTag { + public static final int ID = 84; + + public static final String NAME = "DefineMorphShape2"; + public RECT startEdgeBounds; public RECT endEdgeBounds; @@ -52,10 +56,6 @@ public class DefineMorphShape2Tag extends MorphShapeTag { public boolean usesScalingStrokes; - public static final int ID = 84; - - public static final String NAME = "DefineMorphShape2"; - /** * Gets data bytes * diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineScalingGridTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineScalingGridTag.java index 5fd55cd89..093934949 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineScalingGridTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineScalingGridTag.java @@ -34,15 +34,15 @@ import java.io.OutputStream; */ public class DefineScalingGridTag extends Tag implements CharacterIdTag { + public static final int ID = 78; + + public static final String NAME = "DefineScalingGrid"; + @SWFType(BasicType.UI16) public int characterId; public RECT splitter; - public static final int ID = 78; - - public static final String NAME = "DefineScalingGrid"; - /** * Constructor * diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSceneAndFrameLabelDataTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSceneAndFrameLabelDataTag.java index 8351ca919..e66b8b5d5 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSceneAndFrameLabelDataTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSceneAndFrameLabelDataTag.java @@ -33,6 +33,10 @@ import java.io.OutputStream; */ public class DefineSceneAndFrameLabelDataTag extends Tag { + public static final int ID = 86; + + public static final String NAME = "DefineSceneAndFrameLabelData"; + @SWFType(value = BasicType.EncodedU32) @SWFArray(value = "offset", countField = "sceneCount") public long[] sceneOffsets; @@ -47,10 +51,6 @@ public class DefineSceneAndFrameLabelDataTag extends Tag { @SWFArray(countField = "frameLabelCount") public String[] frameNames; - public static final int ID = 86; - - public static final String NAME = "DefineSceneAndFrameLabelData"; - /** * Gets data bytes * diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShape2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShape2Tag.java index fe9b303e1..bbb158f96 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShape2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShape2Tag.java @@ -19,16 +19,12 @@ 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.tags.base.BoundedTag; import com.jpexs.decompiler.flash.tags.base.ShapeTag; import com.jpexs.decompiler.flash.types.RECT; import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE; import com.jpexs.helpers.ByteArrayRange; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; /** * @@ -40,57 +36,6 @@ public class DefineShape2Tag extends ShapeTag { public static final String NAME = "DefineShape2"; - private ByteArrayRange shapeData; - - @Override - public int getShapeNum() { - return 2; - } - - @Override - public SHAPEWITHSTYLE getShapes() { - if (shapes == null && shapeData != null) { - try { - SWFInputStream sis = new SWFInputStream(swf, shapeData.getArray(), 0, shapeData.getPos() + shapeData.getLength()); - sis.seek(shapeData.getPos()); - shapes = sis.readSHAPEWITHSTYLE(getShapeNum(), false, "shapes"); - shapeData = null; // not needed anymore, give it to GC - } catch (IOException ex) { - Logger.getLogger(DefineShape2Tag.class.getName()).log(Level.SEVERE, null, ex); - } - } - - return shapes; - } - - @Override - public void getNeededCharacters(Set needed) { - getShapes().getNeededCharacters(needed); - } - - @Override - public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { - boolean modified = getShapes().replaceCharacter(oldCharacterId, newCharacterId); - if (modified) { - setModified(true); - } - return modified; - } - - @Override - public boolean removeCharacter(int characterId) { - boolean modified = getShapes().removeCharacter(characterId); - if (modified) { - setModified(true); - } - return modified; - } - - @Override - public RECT getRect(Set added) { - return shapeBounds; - } - /** * Constructor * @@ -139,22 +84,7 @@ public class DefineShape2Tag extends ShapeTag { } @Override - public int getNumFrames() { - return 1; - } - - @Override - public boolean isSingleFrame() { - return true; - } - - @Override - public int getCharacterId() { - return shapeId; - } - - @Override - public void setCharacterId(int characterId) { - this.shapeId = characterId; + public int getShapeNum() { + return 2; } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShape3Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShape3Tag.java index 40aa56fe3..21819d97c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShape3Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShape3Tag.java @@ -19,17 +19,12 @@ 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.tags.base.BoundedTag; import com.jpexs.decompiler.flash.tags.base.ShapeTag; import com.jpexs.decompiler.flash.types.RECT; import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE; import com.jpexs.helpers.ByteArrayRange; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.OutputStream; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; /** * @@ -41,57 +36,6 @@ public class DefineShape3Tag extends ShapeTag { public static final String NAME = "DefineShape3"; - private ByteArrayRange shapeData; - - @Override - public int getShapeNum() { - return 3; - } - - @Override - public SHAPEWITHSTYLE getShapes() { - if (shapes == null && shapeData != null) { - try { - SWFInputStream sis = new SWFInputStream(swf, shapeData.getArray(), 0, shapeData.getPos() + shapeData.getLength()); - sis.seek(shapeData.getPos()); - shapes = sis.readSHAPEWITHSTYLE(3, false, "shapes"); - shapeData = null; // not needed anymore, give it to GC - } catch (IOException ex) { - Logger.getLogger(DefineShape3Tag.class.getName()).log(Level.SEVERE, null, ex); - } - } - - return shapes; - } - - @Override - public void getNeededCharacters(Set needed) { - getShapes().getNeededCharacters(needed); - } - - @Override - public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { - boolean modified = getShapes().replaceCharacter(oldCharacterId, newCharacterId); - if (modified) { - setModified(true); - } - return modified; - } - - @Override - public boolean removeCharacter(int characterId) { - boolean modified = getShapes().removeCharacter(characterId); - if (modified) { - setModified(true); - } - return modified; - } - - @Override - public RECT getRect(Set added) { - return shapeBounds; - } - /** * Constructor * @@ -114,7 +58,7 @@ public class DefineShape3Tag extends ShapeTag { shapeId = sis.readUI16("shapeId"); shapeBounds = sis.readRECT("shapeBounds"); if (!lazy) { - shapes = sis.readSHAPEWITHSTYLE(3, false, "shapes"); + shapes = sis.readSHAPEWITHSTYLE(getShapeNum(), false, "shapes"); } else { shapeData = new ByteArrayRange(data.getArray(), (int) sis.getPos(), sis.available()); } @@ -128,12 +72,11 @@ public class DefineShape3Tag extends ShapeTag { @Override public byte[] getData() { ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + SWFOutputStream sos = new SWFOutputStream(baos, getVersion()); try { sos.writeUI16(shapeId); sos.writeRECT(shapeBounds); - sos.writeSHAPEWITHSTYLE(getShapes(), 3); + sos.writeSHAPEWITHSTYLE(getShapes(), getShapeNum()); } catch (IOException e) { throw new Error("This should never happen.", e); } @@ -141,22 +84,7 @@ public class DefineShape3Tag extends ShapeTag { } @Override - public int getNumFrames() { - return 1; - } - - @Override - public boolean isSingleFrame() { - return true; - } - - @Override - public int getCharacterId() { - return shapeId; - } - - @Override - public void setCharacterId(int characterId) { - this.shapeId = characterId; + public int getShapeNum() { + return 3; } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShape4Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShape4Tag.java index 38596a0b3..d19eead3a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShape4Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShape4Tag.java @@ -19,7 +19,6 @@ 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.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; @@ -29,10 +28,6 @@ import com.jpexs.decompiler.flash.types.annotations.SWFType; import com.jpexs.helpers.ByteArrayRange; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.OutputStream; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; /** * @@ -40,6 +35,10 @@ import java.util.logging.Logger; */ public class DefineShape4Tag extends ShapeTag { + public static final int ID = 83; + + public static final String NAME = "DefineShape4"; + public RECT edgeBounds; @Reserved @@ -52,61 +51,6 @@ public class DefineShape4Tag extends ShapeTag { public boolean usesScalingStrokes; - public static final int ID = 83; - - public static final String NAME = "DefineShape4"; - - private ByteArrayRange shapeData; - - @Override - public int getShapeNum() { - return 4; - } - - @Override - public SHAPEWITHSTYLE getShapes() { - if (shapes == null && shapeData != null) { - try { - SWFInputStream sis = new SWFInputStream(swf, shapeData.getArray(), 0, shapeData.getPos() + shapeData.getLength()); - sis.seek(shapeData.getPos()); - shapes = sis.readSHAPEWITHSTYLE(4, false, "shapes"); - shapeData = null; // not needed anymore, give it to GC - } catch (IOException ex) { - Logger.getLogger(DefineShape4Tag.class.getName()).log(Level.SEVERE, null, ex); - } - } - - return shapes; - } - - @Override - public void getNeededCharacters(Set needed) { - getShapes().getNeededCharacters(needed); - } - - @Override - public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { - boolean modified = getShapes().replaceCharacter(oldCharacterId, newCharacterId); - if (modified) { - setModified(true); - } - return modified; - } - - @Override - public boolean removeCharacter(int characterId) { - boolean modified = getShapes().removeCharacter(characterId); - if (modified) { - setModified(true); - } - return modified; - } - - @Override - public RECT getRect(Set added) { - return shapeBounds; - } - /** * Constructor * @@ -135,7 +79,7 @@ public class DefineShape4Tag extends ShapeTag { usesNonScalingStrokes = sis.readUB(1, "usesNonScalingStrokes") == 1; usesScalingStrokes = sis.readUB(1, "usesScalingStrokes") == 1; if (!lazy) { - shapes = sis.readSHAPEWITHSTYLE(4, false, "shapes"); + shapes = sis.readSHAPEWITHSTYLE(getShapeNum(), false, "shapes"); } else { shapeData = new ByteArrayRange(data.getArray(), (int) sis.getPos(), sis.available()); } @@ -149,8 +93,7 @@ public class DefineShape4Tag extends ShapeTag { @Override public byte[] getData() { ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + SWFOutputStream sos = new SWFOutputStream(baos, getVersion()); try { sos.writeUI16(shapeId); sos.writeRECT(shapeBounds); @@ -159,7 +102,7 @@ public class DefineShape4Tag extends ShapeTag { sos.writeUB(1, usesFillWindingRule ? 1 : 0); sos.writeUB(1, usesNonScalingStrokes ? 1 : 0); sos.writeUB(1, usesScalingStrokes ? 1 : 0); - sos.writeSHAPEWITHSTYLE(getShapes(), 4); + sos.writeSHAPEWITHSTYLE(getShapes(), getShapeNum()); } catch (IOException e) { throw new Error("This should never happen.", e); } @@ -167,22 +110,7 @@ public class DefineShape4Tag extends ShapeTag { } @Override - public int getNumFrames() { - return 1; - } - - @Override - public boolean isSingleFrame() { - return true; - } - - @Override - public int getCharacterId() { - return shapeId; - } - - @Override - public void setCharacterId(int characterId) { - this.shapeId = characterId; + public int getShapeNum() { + return 4; } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShapeTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShapeTag.java index 51a24d983..12248b987 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShapeTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShapeTag.java @@ -19,16 +19,12 @@ 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.tags.base.BoundedTag; import com.jpexs.decompiler.flash.tags.base.ShapeTag; import com.jpexs.decompiler.flash.types.RECT; import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE; import com.jpexs.helpers.ByteArrayRange; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; /** * @@ -40,57 +36,6 @@ public class DefineShapeTag extends ShapeTag { public static final String NAME = "DefineShape"; - private ByteArrayRange shapeData; - - @Override - public int getShapeNum() { - return 1; - } - - @Override - public SHAPEWITHSTYLE getShapes() { - if (shapes == null && shapeData != null) { - try { - SWFInputStream sis = new SWFInputStream(swf, shapeData.getArray(), 0, shapeData.getPos() + shapeData.getLength()); - sis.seek(shapeData.getPos()); - shapes = sis.readSHAPEWITHSTYLE(getShapeNum(), false, "shapes"); - shapeData = null; // not needed anymore, give it to GC - } catch (IOException ex) { - Logger.getLogger(DefineShapeTag.class.getName()).log(Level.SEVERE, null, ex); - } - } - - return shapes; - } - - @Override - public void getNeededCharacters(Set needed) { - getShapes().getNeededCharacters(needed); - } - - @Override - public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { - boolean modified = getShapes().replaceCharacter(oldCharacterId, newCharacterId); - if (modified) { - setModified(true); - } - return modified; - } - - @Override - public boolean removeCharacter(int characterId) { - boolean modified = getShapes().removeCharacter(characterId); - if (modified) { - setModified(true); - } - return modified; - } - - @Override - public RECT getRect(Set added) { - return shapeBounds; - } - /** * Constructor * @@ -139,22 +84,7 @@ public class DefineShapeTag extends ShapeTag { } @Override - public int getNumFrames() { + public int getShapeNum() { return 1; } - - @Override - public boolean isSingleFrame() { - return true; - } - - @Override - public int getCharacterId() { - return shapeId; - } - - @Override - public void setCharacterId(int characterId) { - this.shapeId = characterId; - } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSoundTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSoundTag.java index dfc32c0dd..3d61c0f76 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSoundTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSoundTag.java @@ -47,6 +47,10 @@ import javax.sound.sampled.UnsupportedAudioFileException; */ public class DefineSoundTag extends CharacterTag implements SoundTag { + public static final int ID = 14; + + public static final String NAME = "DefineSound"; + @SWFType(BasicType.UI16) public int soundId; @@ -65,10 +69,6 @@ public class DefineSoundTag extends CharacterTag implements SoundTag { public ByteArrayRange soundData; - public static final int ID = 14; - - public static final String NAME = "DefineSound"; - @Override public int getCharacterId() { return soundId; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java index d8924ad8d..64d82dd46 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java @@ -58,6 +58,10 @@ import java.util.Set; */ public class DefineSpriteTag extends CharacterTag implements DrawableTag, Timelined { + public static final int ID = 39; + + public static final String NAME = "DefineSprite"; + /** * Character ID of sprite */ @@ -77,10 +81,6 @@ public class DefineSpriteTag extends CharacterTag implements DrawableTag, Timeli public boolean hasEndTag; - public static final int ID = 39; - - public static final String NAME = "DefineSprite"; - private Timeline timeline; private boolean isSingleFrameInitialized; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineVideoStreamTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineVideoStreamTag.java index 951a00ae0..2cd617b24 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineVideoStreamTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineVideoStreamTag.java @@ -37,6 +37,10 @@ import java.util.Set; */ public class DefineVideoStreamTag extends CharacterTag implements BoundedTag { + public static final int ID = 60; + + public static final String NAME = "DefineVideoStream"; + @SWFType(BasicType.UI16) public int characterID; @@ -69,45 +73,6 @@ public class DefineVideoStreamTag extends CharacterTag implements BoundedTag { public static final int CODEC_VP6_ALPHA = 5; - public static final int ID = 60; - - public static final String NAME = "DefineVideoStream"; - - @Override - public int getCharacterId() { - return characterID; - } - - @Override - public void setCharacterId(int characterId) { - this.characterID = characterId; - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(characterID); - sos.writeUI16(numFrames); - sos.writeUI16(width); - sos.writeUI16(height); - sos.writeUB(4, reserved); - sos.writeUB(3, videoFlagsDeblocking); - sos.writeUB(1, videoFlagsSmoothing ? 1 : 0); - sos.writeUI8(codecID); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - /** * Constructor * @@ -142,6 +107,41 @@ public class DefineVideoStreamTag extends CharacterTag implements BoundedTag { codecID = sis.readUI8("codecID"); } + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(characterID); + sos.writeUI16(numFrames); + sos.writeUI16(width); + sos.writeUI16(height); + sos.writeUB(4, reserved); + sos.writeUB(3, videoFlagsDeblocking); + sos.writeUB(1, videoFlagsSmoothing ? 1 : 0); + sos.writeUI8(codecID); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + @Override + public int getCharacterId() { + return characterID; + } + + @Override + public void setCharacterId(int characterId) { + this.characterID = characterId; + } + @Override public RECT getRect() { return getRect(null); // parameter not used diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoABCDefineTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoABCDefineTag.java index 313a0c57c..e83689b84 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoABCDefineTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoABCDefineTag.java @@ -41,6 +41,10 @@ import java.io.OutputStream; */ public class DoABCDefineTag extends Tag implements ABCContainerTag { + public static final int ID = 82; + + public static final String NAME = "DoABCDefine"; + /** * ActionScript 3 bytecodes */ @@ -62,20 +66,6 @@ public class DoABCDefineTag extends Tag implements ABCContainerTag { */ public String name; - public static final int ID = 82; - - public static final String NAME = "DoABCDefine"; - - @Override - public ABC getABC() { - return abc; - } - - @Override - public String getName() { - return super.getName() + " (" + name + ")"; - } - /** * Constructor * @@ -134,6 +124,16 @@ public class DoABCDefineTag extends Tag implements ABCContainerTag { } } + @Override + public ABC getABC() { + return abc; + } + + @Override + public String getName() { + return super.getName() + " (" + name + ")"; + } + @Override public int compareTo(ABCContainerTag o) { if (o instanceof DoABCDefineTag) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoABCTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoABCTag.java index 255c781e2..d40764c53 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoABCTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoABCTag.java @@ -39,6 +39,10 @@ import java.io.OutputStream; */ public class DoABCTag extends Tag implements ABCContainerTag { + public static final int ID = 72; + + public static final String NAME = "DoABC"; + /** * ActionScript 3 bytecodes */ @@ -46,15 +50,6 @@ public class DoABCTag extends Tag implements ABCContainerTag { @SWFField private ABC abc; - public static final int ID = 72; - - public static final String NAME = "DoABC"; - - @Override - public ABC getABC() { - return abc; - } - /** * Constructor * @@ -107,6 +102,11 @@ public class DoABCTag extends Tag implements ABCContainerTag { } } + @Override + public ABC getABC() { + return abc; + } + @Override public int compareTo(ABCContainerTag o) { return 0; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoActionTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoActionTag.java index b2dd8a27f..d71570a0b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoActionTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoActionTag.java @@ -42,6 +42,10 @@ import java.util.logging.Logger; */ public class DoActionTag extends Tag implements ASMSource { + public static final int ID = 12; + + public static final String NAME = "DoAction"; + /** * List of actions to perform */ @@ -49,10 +53,6 @@ public class DoActionTag extends Tag implements ASMSource { @HideInRawEdit public ByteArrayRange actionBytes; - public static final int ID = 12; - - public static final String NAME = "DoAction"; - /** * Constructor * @@ -62,6 +62,17 @@ public class DoActionTag extends Tag implements ASMSource { super(swf, ID, NAME, null); } + /** + * Constructor + * + * @param swf + * @param data + */ + public DoActionTag(SWF swf, ByteArrayRange data) { + super(swf, ID, NAME, data); + actionBytes = ByteArrayRange.EMPTY; + } + /** * Constructor * @@ -79,17 +90,6 @@ public class DoActionTag extends Tag implements ASMSource { actionBytes = sis.readByteRangeEx(sis.available(), "actionBytes"); } - /** - * Constructor - * - * @param swf - * @param data - */ - public DoActionTag(SWF swf, ByteArrayRange data) { - super(swf, ID, NAME, data); - actionBytes = ByteArrayRange.EMPTY; - } - /** * Gets data bytes * diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoInitActionTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoInitActionTag.java index 464e0b468..26f16bd5a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoInitActionTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoInitActionTag.java @@ -45,6 +45,10 @@ import java.util.logging.Logger; */ public class DoInitActionTag extends Tag implements CharacterIdTag, ASMSource { + public static final int ID = 59; + + public static final String NAME = "DoInitAction"; + /** * Identifier of Sprite */ @@ -58,10 +62,6 @@ public class DoInitActionTag extends Tag implements CharacterIdTag, ASMSource { @HideInRawEdit public ByteArrayRange actionBytes; - public static final int ID = 59; - - public static final String NAME = "DoInitAction"; - /** * Constructor * diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/EnableDebugger2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/EnableDebugger2Tag.java index fe382b6ab..2f258d003 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/EnableDebugger2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/EnableDebugger2Tag.java @@ -34,6 +34,10 @@ import java.io.OutputStream; */ public class EnableDebugger2Tag extends Tag { + public static final int ID = 64; + + public static final String NAME = "EnableDebugger2"; + @Reserved @SWFType(BasicType.UI16) public int reserved; @@ -43,30 +47,6 @@ public class EnableDebugger2Tag extends Tag { */ public String passwordHash; - public static final int ID = 64; - - public static final String NAME = "EnableDebugger2"; - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(reserved); - sos.writeString(passwordHash); - - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - /** * Constructor * @@ -94,4 +74,24 @@ public class EnableDebugger2Tag extends Tag { reserved = sis.readUI16("reserved"); passwordHash = sis.readString("passwordHash"); } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(reserved); + sos.writeString(passwordHash); + + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/EnableDebuggerTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/EnableDebuggerTag.java index d0fed05a3..282b0bb18 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/EnableDebuggerTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/EnableDebuggerTag.java @@ -31,34 +31,14 @@ import java.io.OutputStream; */ public class EnableDebuggerTag extends Tag { - /** - * MD5 hash of password - */ - public String passwordHash; - public static final int ID = 58; public static final String NAME = "EnableDebugger"; /** - * Gets data bytes - * - * @return Bytes of data + * MD5 hash of password */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - if (passwordHash != null) { - sos.writeString(passwordHash); - } - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } + public String passwordHash; /** * Constructor @@ -86,4 +66,24 @@ public class EnableDebuggerTag extends Tag { public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { passwordHash = sis.readString("passwordHash"); } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + if (passwordHash != null) { + sos.writeString(passwordHash); + } + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/EnableTelemetryTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/EnableTelemetryTag.java index 77240b236..3846bba3c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/EnableTelemetryTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/EnableTelemetryTag.java @@ -47,27 +47,6 @@ public class EnableTelemetryTag extends Tag { @SWFType(value = BasicType.UI8, count = 32) public byte[] passwordHash; - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUB(16, reserved); - if (passwordHash != null) { - sos.write(passwordHash); - } - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - /** * Constructor * @@ -97,4 +76,25 @@ public class EnableTelemetryTag extends Tag { passwordHash = sis.readBytesEx(32, "passwordHash"); } } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUB(16, reserved); + if (passwordHash != null) { + sos.write(passwordHash); + } + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/EndTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/EndTag.java index 75c7c296c..bdcbd2f52 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/EndTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/EndTag.java @@ -28,16 +28,6 @@ import java.io.IOException; */ public class EndTag extends Tag { - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - return new byte[0]; - } - public static final int ID = 0; public static final String NAME = "End"; @@ -66,4 +56,14 @@ public class EndTag extends Tag { @Override public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + return new byte[0]; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ExportAssetsTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ExportAssetsTag.java index a1b24b629..c04f19624 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ExportAssetsTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ExportAssetsTag.java @@ -37,6 +37,10 @@ import java.util.List; */ public class ExportAssetsTag extends SymbolClassTypeTag { + public static final int ID = 56; + + public static final String NAME = "ExportAssets"; + /** * HashMap with assets */ @@ -47,10 +51,6 @@ public class ExportAssetsTag extends SymbolClassTypeTag { @SWFArray(value = "name", countField = "count") public List names; - public static final int ID = 56; - - public static final String NAME = "ExportAssets"; - /** * Constructor * diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/FileAttributesTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/FileAttributesTag.java index ba8e84763..bca593d46 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/FileAttributesTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/FileAttributesTag.java @@ -29,6 +29,10 @@ import java.io.OutputStream; public class FileAttributesTag extends Tag { + public static final int ID = 69; + + public static final String NAME = "FileAttributes"; + public boolean useDirectBlit; public boolean useGPU; @@ -51,10 +55,6 @@ public class FileAttributesTag extends Tag { @Reserved public int reserved3; - public static final int ID = 69; - - public static final String NAME = "FileAttributes"; - /** * Constructor * diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/FrameLabelTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/FrameLabelTag.java index 1172eca45..771fe0d01 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/FrameLabelTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/FrameLabelTag.java @@ -26,21 +26,13 @@ import java.io.OutputStream; public class FrameLabelTag extends Tag { - public String name; - - public boolean namedAnchor = false; - public static final int ID = 43; public static final String NAME = "FrameLabel"; - public String getLabelName() { - return name; - } + public String name; - public boolean isNamedAnchor() { - return namedAnchor; - } + public boolean namedAnchor = false; /** * Constructor @@ -87,4 +79,12 @@ public class FrameLabelTag extends Tag { } return baos.toByteArray(); } + + public String getLabelName() { + return name; + } + + public boolean isNamedAnchor() { + return namedAnchor; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ImportAssets2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ImportAssets2Tag.java index 087b32898..0eb0676c1 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ImportAssets2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ImportAssets2Tag.java @@ -40,6 +40,10 @@ import java.util.Map; */ public class ImportAssets2Tag extends Tag implements ImportTag { + public static final int ID = 71; + + public static final String NAME = "ImportAssets2"; + public String url; @Reserved @@ -60,10 +64,6 @@ public class ImportAssets2Tag extends Tag implements ImportTag { @SWFArray(value = "name", countField = "count") public List names; - public static final int ID = 71; - - public static final String NAME = "ImportAssets2"; - /** * Constructor * diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ImportAssetsTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ImportAssetsTag.java index c5f1086ce..4626871f8 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ImportAssetsTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ImportAssetsTag.java @@ -39,6 +39,10 @@ import java.util.Map; */ public class ImportAssetsTag extends Tag implements ImportTag { + public static final int ID = 57; + + public static final String NAME = "ImportAssets"; + public String url; /** @@ -51,10 +55,6 @@ public class ImportAssetsTag extends Tag implements ImportTag { @SWFArray(value = "name", countField = "count") public List names; - public static final int ID = 57; - - public static final String NAME = "ImportAssets"; - /** * Constructor * diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/MetadataTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/MetadataTag.java index f138f7443..c6aa3baee 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/MetadataTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/MetadataTag.java @@ -27,13 +27,13 @@ import java.io.OutputStream; public class MetadataTag extends Tag { - @Multiline - public String xmlMetadata; - public static final int ID = 77; public static final String NAME = "Metadata"; + @Multiline + public String xmlMetadata; + /** * Constructor * diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject2Tag.java index 09a0d1f9a..ee939dd26 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject2Tag.java @@ -50,6 +50,10 @@ import java.util.Set; */ public class PlaceObject2Tag extends PlaceObjectTypeTag implements ASMSourceContainer { + public static final int ID = 26; + + public static final String NAME = "PlaceObject2"; + /** * @since SWF 5 Has clip actions (sprite characters only) */ @@ -141,74 +145,6 @@ public class PlaceObject2Tag extends PlaceObjectTypeTag implements ASMSourceCont @HideInRawEdit //TODO: make editable public CLIPACTIONS clipActions; - public static final int ID = 26; - - public static final String NAME = "PlaceObject2"; - - @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) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - /** * Constructor * @@ -285,6 +221,70 @@ public class PlaceObject2Tag extends PlaceObjectTypeTag implements ASMSourceCont } } + /** + * 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) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + @Override + public int getClipDepth() { + if (placeFlagHasClipDepth) { + return clipDepth; + } + return -1; + } + + @Override + public List getFilters() { + return null; + } + /** * Returns all sub-items * diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject3Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject3Tag.java index eaf13f95b..dc8da668d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject3Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject3Tag.java @@ -53,6 +53,10 @@ import java.util.Set; */ public class PlaceObject3Tag extends PlaceObjectTypeTag implements ASMSourceContainer { + public static final int ID = 70; + + public static final String NAME = "PlaceObject3"; + /** * @since SWF 5 has clip actions (sprite characters only) */ @@ -229,107 +233,6 @@ public class PlaceObject3Tag extends PlaceObjectTypeTag implements ASMSourceCont @Reserved public boolean reserved; - public static final int ID = 70; - - public static final String NAME = "PlaceObject3"; - - @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 e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - /** * Constructor * @@ -420,6 +323,103 @@ public class PlaceObject3Tag extends PlaceObjectTypeTag implements ASMSourceCont } } + /** + * 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 e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + @Override + public List getFilters() { + if (placeFlagHasFilterList) { + return surfaceFilterList; + } else { + return null; + } + } + + @Override + public int getClipDepth() { + if (placeFlagHasClipDepth) { + return clipDepth; + } + return -1; + } + /** * Returns all sub-items * diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject4Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject4Tag.java index 2d13e115f..b922a5b29 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject4Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject4Tag.java @@ -53,6 +53,10 @@ import java.util.Set; */ public class PlaceObject4Tag extends PlaceObjectTypeTag implements ASMSourceContainer { + public static final int ID = 94; + + public static final String NAME = "PlaceObject4"; + /** * @since SWF 5 has clip actions (sprite characters only) */ @@ -229,109 +233,8 @@ public class PlaceObject4Tag extends PlaceObjectTypeTag implements ASMSourceCont @Reserved public boolean reserved; - public static final int ID = 94; - - public static final String NAME = "PlaceObject4"; - 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 e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - /** * Constructor * @@ -423,6 +326,103 @@ public class PlaceObject4Tag extends PlaceObjectTypeTag implements ASMSourceCont amfData = sis.readBytesEx(sis.available(), "amfData"); } + /** + * 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 e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + @Override + public List getFilters() { + if (placeFlagHasFilterList) { + return surfaceFilterList; + } else { + return null; + } + } + + @Override + public int getClipDepth() { + if (placeFlagHasClipDepth) { + return clipDepth; + } + return -1; + } + /** * Returns all sub-items * diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObjectTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObjectTag.java index 1eede5249..24ed5ced2 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObjectTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObjectTag.java @@ -43,41 +43,48 @@ import java.util.Set; */ public class PlaceObjectTag extends PlaceObjectTypeTag { - /** - * ID of character to place - */ - @SWFType(BasicType.UI16) - public int characterId; - - /** - * Depth of character - */ - @SWFType(BasicType.UI16) - public int depth; - - /** - * Transform matrix data - */ - public MATRIX matrix; - - /** - * Color transform data - */ - @Optional - public CXFORM colorTransform; - public static final int ID = 4; public static final String NAME = "PlaceObject"; - @Override - public List getFilters() { - return null; + /** + * Constructor + * + * @param swf + */ + public PlaceObjectTag(SWF swf) { + super(swf, ID, NAME, null); + matrix = new MATRIX(); + } + + public PlaceObjectTag(SWF swf, int characterId, int depth, MATRIX matrix, CXFORM colorTransform) { + super(swf, ID, NAME, null); + this.characterId = characterId; + this.depth = depth; + this.matrix = matrix; + this.colorTransform = colorTransform; + } + + /** + * Constructor + * + * @param sis + * @param data + * @throws IOException + */ + public PlaceObjectTag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); } @Override - public int getClipDepth() { - return -1; + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + characterId = sis.readUI16("characterId"); + depth = sis.readUI16("depth"); + matrix = sis.readMatrix("matrix"); + if (sis.available() > 0) { + colorTransform = sis.readCXFORM("colorTransform"); + } } /** @@ -104,43 +111,36 @@ public class PlaceObjectTag extends PlaceObjectTypeTag { } /** - * Constructor - * - * @param swf + * ID of character to place */ - public PlaceObjectTag(SWF swf) { - super(swf, ID, NAME, null); - matrix = new MATRIX(); - } + @SWFType(BasicType.UI16) + public int characterId; /** - * Constructor - * - * @param sis - * @param data - * @throws IOException + * Depth of character */ - public PlaceObjectTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, NAME, data); - readData(sis, data, 0, false, false, false); + @SWFType(BasicType.UI16) + public int depth; + + /** + * Transform matrix data + */ + public MATRIX matrix; + + /** + * Color transform data + */ + @Optional + public CXFORM colorTransform; + + @Override + public List getFilters() { + return null; } @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - characterId = sis.readUI16("characterId"); - depth = sis.readUI16("depth"); - matrix = sis.readMatrix("matrix"); - if (sis.available() > 0) { - colorTransform = sis.readCXFORM("colorTransform"); - } - } - - public PlaceObjectTag(SWF swf, int characterId, int depth, MATRIX matrix, CXFORM colorTransform) { - super(swf, ID, NAME, null); - this.characterId = characterId; - this.depth = depth; - this.matrix = matrix; - this.colorTransform = colorTransform; + public int getClipDepth() { + return -1; } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ProductInfoTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ProductInfoTag.java index 4c25c7103..e17342251 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ProductInfoTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ProductInfoTag.java @@ -28,6 +28,10 @@ import java.io.OutputStream; public class ProductInfoTag extends Tag { + public static final int ID = 41; + + public static final String NAME = "ProductInfo"; + @SWFType(BasicType.UI32) public long productID; @@ -52,10 +56,6 @@ public class ProductInfoTag extends Tag { @SWFType(BasicType.UI32) public long compilationDateHigh; - public static final int ID = 41; - - public static final String NAME = "ProductInfo"; - /** * Constructor * diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ProtectTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ProtectTag.java index fde991ecd..bc943b1cb 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ProtectTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ProtectTag.java @@ -31,34 +31,14 @@ import java.io.OutputStream; */ public class ProtectTag extends Tag { - /** - * MD5 hash of password - */ - public String passwordHash; - public static final int ID = 24; public static final String NAME = "Protect"; /** - * Gets data bytes - * - * @return Bytes of data + * MD5 hash of password */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - if (!"".equals(passwordHash)) { - sos.writeString(passwordHash); - } - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } + public String passwordHash; /** * Constructor @@ -90,4 +70,24 @@ public class ProtectTag extends Tag { passwordHash = ""; } } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + if (!"".equals(passwordHash)) { + sos.writeString(passwordHash); + } + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/RemoveObject2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/RemoveObject2Tag.java index 14146345c..3e3697306 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/RemoveObject2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/RemoveObject2Tag.java @@ -27,15 +27,19 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; +/** + * + * @author JPEXS + */ public class RemoveObject2Tag extends RemoveTag { - @SWFType(BasicType.UI16) - public int depth; - public static final int ID = 28; public static final String NAME = "RemoveObject2"; + @SWFType(BasicType.UI16) + public int depth; + /** * Constructor * @@ -45,6 +49,13 @@ public class RemoveObject2Tag extends RemoveTag { super(swf, ID, NAME, null); } + /** + * Constructor + * + * @param sis + * @param data + * @throws IOException + */ public RemoveObject2Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { super(sis.getSwf(), ID, NAME, data); readData(sis, data, 0, false, false, false); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/RemoveObjectTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/RemoveObjectTag.java index 85d255d00..d9fb6837d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/RemoveObjectTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/RemoveObjectTag.java @@ -35,6 +35,10 @@ import java.io.OutputStream; */ public class RemoveObjectTag extends RemoveTag implements CharacterIdTag { + public static final int ID = 5; + + public static final String NAME = "RemoveObject"; + /** * ID of character to place */ @@ -47,29 +51,6 @@ public class RemoveObjectTag extends RemoveTag implements CharacterIdTag { @SWFType(BasicType.UI16) public int depth; - public static final int ID = 5; - - public static final String NAME = "RemoveObject"; - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(characterId); - sos.writeUI16(depth); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - /** * Constructor * @@ -98,6 +79,25 @@ public class RemoveObjectTag extends RemoveTag implements CharacterIdTag { depth = sis.readUI16("depth"); } + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(characterId); + sos.writeUI16(depth); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + @Override public int getDepth() { return depth; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ScriptLimitsTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ScriptLimitsTag.java index 68205ed03..a061aaea4 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ScriptLimitsTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ScriptLimitsTag.java @@ -28,16 +28,16 @@ import java.io.OutputStream; public class ScriptLimitsTag extends Tag { + public static final int ID = 65; + + public static final String NAME = "ScriptLimits"; + @SWFType(BasicType.UI16) public int maxRecursionDepth; @SWFType(BasicType.UI16) public int scriptTimeoutSeconds; - public static final int ID = 65; - - public static final String NAME = "ScriptLimits"; - /** * Constructor * diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SetBackgroundColorTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SetBackgroundColorTag.java index 991e4b9fe..397df1da5 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SetBackgroundColorTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SetBackgroundColorTag.java @@ -26,12 +26,12 @@ import java.io.IOException; public class SetBackgroundColorTag extends Tag { - public RGB backgroundColor; - public static final int ID = 9; public static final String NAME = "SetBackgroundColor"; + public RGB backgroundColor; + /** * Constructor * diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SetTabIndexTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SetTabIndexTag.java index 050f4b1a1..016b7e19f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SetTabIndexTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SetTabIndexTag.java @@ -33,6 +33,10 @@ import java.io.OutputStream; */ public class SetTabIndexTag extends Tag { + public static final int ID = 66; + + public static final String NAME = "SetTabIndex"; + /** * Depth of character */ @@ -45,29 +49,6 @@ public class SetTabIndexTag extends Tag { @SWFType(BasicType.UI16) public int tabIndex; - public static final int ID = 66; - - public static final String NAME = "SetTabIndex"; - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(depth); - sos.writeUI16(tabIndex); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - /** * Constructor * @@ -94,4 +75,23 @@ public class SetTabIndexTag extends Tag { depth = sis.readUI16("depth"); tabIndex = sis.readUI16("tabIndex"); } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(depth); + sos.writeUI16(tabIndex); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHead2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHead2Tag.java index 958ecac6e..1a99488e9 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHead2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHead2Tag.java @@ -41,6 +41,10 @@ import java.util.List; */ public class SoundStreamHead2Tag extends Tag implements SoundStreamHeadTypeTag { + public static final int ID = 45; + + public static final String NAME = "SoundStreamHead2"; + @Reserved @SWFType(value = BasicType.UB, count = 4) public int reserved; @@ -72,9 +76,71 @@ public class SoundStreamHead2Tag extends Tag implements SoundStreamHeadTypeTag { @Internal private int virtualCharacterId = 0; - public static final int ID = 45; + /** + * Constructor + * + * @param swf + */ + public SoundStreamHead2Tag(SWF swf) { + super(swf, ID, NAME, null); + } - public static final String NAME = "SoundStreamHead2"; + /** + * Constructor + * + * @param sis + * @param data + * @throws IOException + */ + public SoundStreamHead2Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + reserved = (int) sis.readUB(4, "reserved"); + playBackSoundRate = (int) sis.readUB(2, "playBackSoundRate"); + playBackSoundSize = sis.readUB(1, "playBackSoundSize") == 1; + playBackSoundType = sis.readUB(1, "playBackSoundType") == 1; + streamSoundCompression = (int) sis.readUB(4, "streamSoundCompression"); + streamSoundRate = (int) sis.readUB(2, "streamSoundRate"); + streamSoundSize = sis.readUB(1, "streamSoundSize") == 1; + streamSoundType = sis.readUB(1, "streamSoundType") == 1; + streamSoundSampleCount = sis.readUI16("streamSoundSampleCount"); + if (streamSoundCompression == 2) { + latencySeek = sis.readSI16("latencySeek"); + } + } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUB(4, reserved); + sos.writeUB(2, playBackSoundRate); + sos.writeUB(1, playBackSoundSize ? 1 : 0); + sos.writeUB(1, playBackSoundType ? 1 : 0); + sos.writeUB(4, streamSoundCompression); + sos.writeUB(2, streamSoundRate); + sos.writeUB(1, streamSoundSize ? 1 : 0); + sos.writeUB(1, streamSoundType ? 1 : 0); + sos.writeUI16(streamSoundSampleCount); + if (streamSoundCompression == 2) { + sos.writeSI16(latencySeek); + } + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } @Override public int getCharacterId() { @@ -116,72 +182,6 @@ public class SoundStreamHead2Tag extends Tag implements SoundStreamHeadTypeTag { virtualCharacterId = ch; } - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUB(4, reserved); - sos.writeUB(2, playBackSoundRate); - sos.writeUB(1, playBackSoundSize ? 1 : 0); - sos.writeUB(1, playBackSoundType ? 1 : 0); - sos.writeUB(4, streamSoundCompression); - sos.writeUB(2, streamSoundRate); - sos.writeUB(1, streamSoundSize ? 1 : 0); - sos.writeUB(1, streamSoundType ? 1 : 0); - sos.writeUI16(streamSoundSampleCount); - if (streamSoundCompression == 2) { - sos.writeSI16(latencySeek); - } - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - - /** - * Constructor - * - * @param swf - */ - public SoundStreamHead2Tag(SWF swf) { - super(swf, ID, NAME, null); - } - - /** - * Constructor - * - * @param sis - * @param data - * @throws IOException - */ - public SoundStreamHead2Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, NAME, data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - reserved = (int) sis.readUB(4, "reserved"); - playBackSoundRate = (int) sis.readUB(2, "playBackSoundRate"); - playBackSoundSize = sis.readUB(1, "playBackSoundSize") == 1; - playBackSoundType = sis.readUB(1, "playBackSoundType") == 1; - streamSoundCompression = (int) sis.readUB(4, "streamSoundCompression"); - streamSoundRate = (int) sis.readUB(2, "streamSoundRate"); - streamSoundSize = sis.readUB(1, "streamSoundSize") == 1; - streamSoundType = sis.readUB(1, "streamSoundType") == 1; - streamSoundSampleCount = sis.readUI16("streamSoundSampleCount"); - if (streamSoundCompression == 2) { - latencySeek = sis.readSI16("latencySeek"); - } - } - @Override public int getSoundFormatId() { return streamSoundCompression; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHeadTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHeadTag.java index 22c1e44fe..b5196791f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHeadTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHeadTag.java @@ -41,6 +41,10 @@ import java.util.List; */ public class SoundStreamHeadTag extends Tag implements SoundStreamHeadTypeTag { + public static final int ID = 18; + + public static final String NAME = "SoundStreamHead"; + @Reserved @SWFType(value = BasicType.UB, count = 4) public int reserved; @@ -71,9 +75,71 @@ public class SoundStreamHeadTag extends Tag implements SoundStreamHeadTypeTag { @Internal private int virtualCharacterId = 0; - public static final int ID = 18; + /** + * Constructor + * + * @param swf + */ + public SoundStreamHeadTag(SWF swf) { + super(swf, ID, NAME, null); + } - public static final String NAME = "SoundStreamHead"; + /** + * Constructor + * + * @param sis + * @param data + * @throws IOException + */ + public SoundStreamHeadTag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + reserved = (int) sis.readUB(4, "reserved"); + playBackSoundRate = (int) sis.readUB(2, "playBackSoundRate"); + playBackSoundSize = sis.readUB(1, "playBackSoundSize") == 1; + playBackSoundType = sis.readUB(1, "playBackSoundType") == 1; + streamSoundCompression = (int) sis.readUB(4, "streamSoundCompression"); + streamSoundRate = (int) sis.readUB(2, "streamSoundRate"); + streamSoundSize = sis.readUB(1, "streamSoundSize") == 1; + streamSoundType = sis.readUB(1, "streamSoundType") == 1; + streamSoundSampleCount = sis.readUI16("streamSoundSampleCount"); + if (streamSoundCompression == 2) { + latencySeek = sis.readSI16("latencySeek"); + } + } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUB(4, reserved); + sos.writeUB(2, playBackSoundRate); + sos.writeUB(1, playBackSoundSize ? 1 : 0); + sos.writeUB(1, playBackSoundType ? 1 : 0); + sos.writeUB(4, streamSoundCompression); + sos.writeUB(2, streamSoundRate); + sos.writeUB(1, streamSoundSize ? 1 : 0); + sos.writeUB(1, streamSoundType ? 1 : 0); + sos.writeUI16(streamSoundSampleCount); + if (streamSoundCompression == 2) { + sos.writeSI16(latencySeek); + } + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } @Override public String getExportFormat() { @@ -115,72 +181,6 @@ public class SoundStreamHeadTag extends Tag implements SoundStreamHeadTypeTag { return streamSoundSampleCount; } - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUB(4, reserved); - sos.writeUB(2, playBackSoundRate); - sos.writeUB(1, playBackSoundSize ? 1 : 0); - sos.writeUB(1, playBackSoundType ? 1 : 0); - sos.writeUB(4, streamSoundCompression); - sos.writeUB(2, streamSoundRate); - sos.writeUB(1, streamSoundSize ? 1 : 0); - sos.writeUB(1, streamSoundType ? 1 : 0); - sos.writeUI16(streamSoundSampleCount); - if (streamSoundCompression == 2) { - sos.writeSI16(latencySeek); - } - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - - /** - * Constructor - * - * @param swf - */ - public SoundStreamHeadTag(SWF swf) { - super(swf, ID, NAME, null); - } - - /** - * Constructor - * - * @param sis - * @param data - * @throws IOException - */ - public SoundStreamHeadTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, NAME, data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - reserved = (int) sis.readUB(4, "reserved"); - playBackSoundRate = (int) sis.readUB(2, "playBackSoundRate"); - playBackSoundSize = sis.readUB(1, "playBackSoundSize") == 1; - playBackSoundType = sis.readUB(1, "playBackSoundType") == 1; - streamSoundCompression = (int) sis.readUB(4, "streamSoundCompression"); - streamSoundRate = (int) sis.readUB(2, "streamSoundRate"); - streamSoundSize = sis.readUB(1, "streamSoundSize") == 1; - streamSoundType = sis.readUB(1, "streamSoundType") == 1; - streamSoundSampleCount = sis.readUI16("streamSoundSampleCount"); - if (streamSoundCompression == 2) { - latencySeek = sis.readSI16("latencySeek"); - } - } - @Override public int getSoundFormatId() { return streamSoundCompression; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/StartSound2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/StartSound2Tag.java index d2e4f832f..ede2dd95c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/StartSound2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/StartSound2Tag.java @@ -31,32 +31,13 @@ import java.io.OutputStream; */ public class StartSound2Tag extends Tag { - public String soundClassName; - - public SOUNDINFO soundInfo; - public static final int ID = 89; public static final String NAME = "StartSound2"; - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeString(soundClassName); - sos.writeSOUNDINFO(soundInfo); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } + public String soundClassName; + + public SOUNDINFO soundInfo; /** * Constructor @@ -86,4 +67,23 @@ public class StartSound2Tag extends Tag { soundClassName = sis.readString("soundClassName"); soundInfo = sis.readSOUNDINFO("soundInfo"); } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeString(soundClassName); + sos.writeSOUNDINFO(soundInfo); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/StartSoundTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/StartSoundTag.java index 6d7b5c2e5..606ea7a18 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/StartSoundTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/StartSoundTag.java @@ -34,33 +34,14 @@ import java.io.OutputStream; */ public class StartSoundTag extends Tag { - @SWFType(BasicType.UI16) - public int soundId; - - public SOUNDINFO soundInfo; - public static final int ID = 15; public static final String NAME = "StartSound"; - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(soundId); - sos.writeSOUNDINFO(soundInfo); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } + @SWFType(BasicType.UI16) + public int soundId; + + public SOUNDINFO soundInfo; /** * Constructor @@ -89,4 +70,23 @@ public class StartSoundTag extends Tag { soundId = sis.readUI16("soundId"); soundInfo = sis.readSOUNDINFO("soundInfo"); } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(soundId); + sos.writeSOUNDINFO(soundInfo); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SymbolClassTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SymbolClassTag.java index cf23f3c59..a2d4b0ac6 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SymbolClassTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SymbolClassTag.java @@ -32,6 +32,10 @@ import java.util.List; public class SymbolClassTag extends SymbolClassTypeTag { + public static final int ID = 76; + + public static final String NAME = "SymbolClass"; + @SWFType(value = BasicType.UI16) @SWFArray(value = "tag", countField = "numSymbols") public List tags; @@ -39,10 +43,6 @@ public class SymbolClassTag extends SymbolClassTypeTag { @SWFArray(value = "name", countField = "numSymbols") public List names; - public static final int ID = 76; - - public static final String NAME = "SymbolClass"; - /** * Constructor * diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/Tag.java index d4746c062..7af8c82e0 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/Tag.java @@ -83,6 +83,27 @@ public abstract class Tag implements NeedsCharacters, Exportable, Serializable { private final HashSet listeners = new HashSet<>(); + /** + * 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; + } + } + public String getTagName() { return tagName; } @@ -134,27 +155,6 @@ public abstract class Tag implements NeedsCharacters, Exportable, Serializable { 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; - } - } - public abstract void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException, InterruptedException; private static final Object lockObject = new Object(); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/TagInfo.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/TagInfo.java index 762c83af5..d640c588f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/TagInfo.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/TagInfo.java @@ -22,15 +22,27 @@ package com.jpexs.decompiler.flash.tags; */ public class TagInfo { - public int id; + private final int id; - public Class cls; + private final Class cls; - public String name; + private final String name; public TagInfo(int id, Class cls, String name) { this.id = id; this.cls = cls; this.name = name; } + + public int getId() { + return id; + } + + public Class getCls() { + return cls; + } + + public String getName() { + return name; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/VideoFrameTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/VideoFrameTag.java index 28f9538e7..16c411201 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/VideoFrameTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/VideoFrameTag.java @@ -34,6 +34,10 @@ import java.io.OutputStream; */ public class VideoFrameTag extends Tag implements CharacterIdTag { + public static final int ID = 61; + + public static final String NAME = "VideoFrame"; + @SWFType(BasicType.UI16) public int streamID; @@ -42,30 +46,6 @@ public class VideoFrameTag extends Tag implements CharacterIdTag { public ByteArrayRange videoData; - public static final int ID = 61; - - public static final String NAME = "VideoFrame"; - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(streamID); - sos.writeUI16(frameNum); - sos.write(videoData); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - /** * Constructor * @@ -95,6 +75,26 @@ public class VideoFrameTag extends Tag implements CharacterIdTag { videoData = sis.readByteRangeEx(sis.available(), "videoData"); //TODO: Parse video packets } + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(streamID); + sos.writeUI16(frameNum); + sos.write(videoData); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + @Override public int getCharacterId() { return streamID; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ShapeTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ShapeTag.java index 9b75094ec..6a3f3b473 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ShapeTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ShapeTag.java @@ -1,159 +1,210 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags.base; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.configuration.Configuration; -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.PathExporter; -import com.jpexs.decompiler.flash.exporters.shape.SVGShapeExporter; -import com.jpexs.decompiler.flash.helpers.LazyObject; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.ColorTransform; -import com.jpexs.decompiler.flash.types.RECT; -import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.helpers.ByteArrayRange; -import com.jpexs.helpers.SerializableImage; -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.Shape; -import java.awt.geom.AffineTransform; -import java.awt.geom.GeneralPath; -import java.awt.geom.PathIterator; -import java.io.IOException; -import java.util.List; -import java.util.Set; - -/** - * - * @author JPEXS - */ -public abstract class ShapeTag extends CharacterTag implements DrawableTag, LazyObject { - - @SWFType(BasicType.UI16) - public int shapeId; - - public RECT shapeBounds; - - public SHAPEWITHSTYLE shapes; - - private final int markerSize = 10; - - public ShapeTag(SWF swf, int id, String name, ByteArrayRange data) { - super(swf, id, name, data); - } - - public abstract SHAPEWITHSTYLE getShapes(); - - @Override - public void load() { - getShapes(); - } - - public abstract int getShapeNum(); - - @Override - public RECT getRect() { - return getRect(null); // parameter not used - } - - @Override - public int getUsedParameters() { - return 0; - } - - @Override - public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation) { - return transformation.toTransform().createTransformedShape(getShapes().getOutline()); - } - - @Override - public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, Matrix transformation, ColorTransform colorTransform) { - BitmapExporter.export(swf, getShapes(), null, image, transformation, colorTransform); - if (Configuration.debugMode.get()) { // show control points - List paths = PathExporter.export(getShapes()); - double[] coords = new double[6]; - AffineTransform at = transformation.toTransform(); - at.preConcatenate(AffineTransform.getScaleInstance(1 / SWF.unitDivisor, 1 / SWF.unitDivisor)); - - // get the graphics from the inner image object, because it creates a new Graphics object - Graphics2D graphics = (Graphics2D) image.getBufferedImage().getGraphics(); - graphics.setPaint(Color.black); - for (GeneralPath path : paths) { - PathIterator iterator = path.getPathIterator(at); - while (!iterator.isDone()) { - int type = iterator.currentSegment(coords); - double x = coords[0]; - double y = coords[1]; - switch (type) { - case PathIterator.SEG_MOVETO: - graphics.drawRect((int) (x - markerSize / 2), (int) (y - markerSize / 2), markerSize, markerSize); - break; - case PathIterator.SEG_LINETO: - graphics.drawRect((int) (x - markerSize / 2), (int) (y - markerSize / 2), markerSize, markerSize); - break; - case PathIterator.SEG_QUADTO: - graphics.drawRect((int) (x - markerSize / 2), (int) (y - markerSize / 2), markerSize, markerSize); - x = coords[2]; - y = coords[3]; - graphics.drawRect((int) (x - markerSize / 2), (int) (y - markerSize / 2), markerSize, markerSize); - break; - case PathIterator.SEG_CUBICTO: - System.out.print("CUBICTO NOT SUPPORTED. "); - break; - case PathIterator.SEG_CLOSE: - System.out.print("CLOSE NOT SUPPORTED. "); - break; - } - iterator.next(); - } - } - } - } - - @Override - public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, double zoom) throws IOException { - SVGShapeExporter shapeExporter = new SVGShapeExporter(swf, getShapes(), exporter, null, colorTransform, zoom); - shapeExporter.export(); - } - - @Override - public String toHtmlCanvas(double unitDivisor) { - CanvasShapeExporter cse = new CanvasShapeExporter(null, unitDivisor, swf, getShapes(), new ColorTransform(), 0, 0); - cse.export(); - return cse.getShapeData(); - } - - @Override - public void getNeededCharacters(Set needed) { - getShapes().getNeededCharacters(needed); - } - - @Override - public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { - return getShapes().replaceCharacter(oldCharacterId, newCharacterId); - } - - @Override - public boolean removeCharacter(int characterId) { - return getShapes().removeCharacter(characterId); - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags.base; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.configuration.Configuration; +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.PathExporter; +import com.jpexs.decompiler.flash.exporters.shape.SVGShapeExporter; +import com.jpexs.decompiler.flash.helpers.LazyObject; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.ColorTransform; +import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.helpers.ByteArrayRange; +import com.jpexs.helpers.SerializableImage; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.GeneralPath; +import java.awt.geom.PathIterator; +import java.io.IOException; +import java.util.List; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author JPEXS + */ +public abstract class ShapeTag extends CharacterTag implements DrawableTag, LazyObject { + + @SWFType(BasicType.UI16) + public int shapeId; + + public RECT shapeBounds; + + public SHAPEWITHSTYLE shapes; + + protected ByteArrayRange shapeData; + + private final int markerSize = 10; + + public ShapeTag(SWF swf, int id, String name, ByteArrayRange data) { + super(swf, id, name, data); + } + + @Override + public void load() { + getShapes(); + } + + public abstract int getShapeNum(); + + public SHAPEWITHSTYLE getShapes() { + if (shapes == null && shapeData != null) { + try { + SWFInputStream sis = new SWFInputStream(swf, shapeData.getArray(), 0, shapeData.getPos() + shapeData.getLength()); + sis.seek(shapeData.getPos()); + shapes = sis.readSHAPEWITHSTYLE(getShapeNum(), false, "shapes"); + shapeData = null; // not needed anymore, give it to GC + } catch (IOException ex) { + Logger.getLogger(ShapeTag.class.getName()).log(Level.SEVERE, null, ex); + } + } + + return shapes; + } + + @Override + public void getNeededCharacters(Set needed) { + getShapes().getNeededCharacters(needed); + } + + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + boolean modified = getShapes().replaceCharacter(oldCharacterId, newCharacterId); + if (modified) { + setModified(true); + } + return modified; + } + + @Override + public boolean removeCharacter(int characterId) { + boolean modified = getShapes().removeCharacter(characterId); + if (modified) { + setModified(true); + } + return modified; + } + + @Override + public RECT getRect(Set added) { + return shapeBounds; + } + + @Override + public RECT getRect() { + return getRect(null); // parameter not used + } + + @Override + public int getUsedParameters() { + return 0; + } + + @Override + public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation) { + return transformation.toTransform().createTransformedShape(getShapes().getOutline()); + } + + @Override + public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, Matrix transformation, ColorTransform colorTransform) { + BitmapExporter.export(swf, getShapes(), null, image, transformation, colorTransform); + if (Configuration.debugMode.get()) { // show control points + List paths = PathExporter.export(getShapes()); + double[] coords = new double[6]; + AffineTransform at = transformation.toTransform(); + at.preConcatenate(AffineTransform.getScaleInstance(1 / SWF.unitDivisor, 1 / SWF.unitDivisor)); + + // get the graphics from the inner image object, because it creates a new Graphics object + Graphics2D graphics = (Graphics2D) image.getBufferedImage().getGraphics(); + graphics.setPaint(Color.black); + for (GeneralPath path : paths) { + PathIterator iterator = path.getPathIterator(at); + while (!iterator.isDone()) { + int type = iterator.currentSegment(coords); + double x = coords[0]; + double y = coords[1]; + switch (type) { + case PathIterator.SEG_MOVETO: + graphics.drawRect((int) (x - markerSize / 2), (int) (y - markerSize / 2), markerSize, markerSize); + break; + case PathIterator.SEG_LINETO: + graphics.drawRect((int) (x - markerSize / 2), (int) (y - markerSize / 2), markerSize, markerSize); + break; + case PathIterator.SEG_QUADTO: + graphics.drawRect((int) (x - markerSize / 2), (int) (y - markerSize / 2), markerSize, markerSize); + x = coords[2]; + y = coords[3]; + graphics.drawRect((int) (x - markerSize / 2), (int) (y - markerSize / 2), markerSize, markerSize); + break; + case PathIterator.SEG_CUBICTO: + System.out.print("CUBICTO NOT SUPPORTED. "); + break; + case PathIterator.SEG_CLOSE: + System.out.print("CLOSE NOT SUPPORTED. "); + break; + } + iterator.next(); + } + } + } + } + + @Override + public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, double zoom) throws IOException { + SVGShapeExporter shapeExporter = new SVGShapeExporter(swf, getShapes(), exporter, null, colorTransform, zoom); + shapeExporter.export(); + } + + @Override + public String toHtmlCanvas(double unitDivisor) { + CanvasShapeExporter cse = new CanvasShapeExporter(null, unitDivisor, swf, getShapes(), new ColorTransform(), 0, 0); + cse.export(); + return cse.getShapeData(); + } + + @Override + public int getNumFrames() { + return 1; + } + + @Override + public boolean isSingleFrame() { + return true; + } + + @Override + public int getCharacterId() { + return shapeId; + } + + @Override + public void setCharacterId(int characterId) { + this.shapeId = characterId; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/SHAPEWITHSTYLE.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/SHAPEWITHSTYLE.java index 113311b57..c24aede2d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/SHAPEWITHSTYLE.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/SHAPEWITHSTYLE.java @@ -1,82 +1,82 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.types; - -import com.jpexs.decompiler.flash.tags.base.NeedsCharacters; -import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord; -import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Set; - -/** - * - * @author JPEXS - */ -public class SHAPEWITHSTYLE extends SHAPE implements NeedsCharacters, Serializable { - - public FILLSTYLEARRAY fillStyles; - - public LINESTYLEARRAY lineStyles; - - @Override - public void getNeededCharacters(Set needed) { - fillStyles.getNeededCharacters(needed); - lineStyles.getNeededCharacters(needed); - for (SHAPERECORD r : shapeRecords) { - r.getNeededCharacters(needed); - } - } - - @Override - public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { - boolean modified = false; - modified |= fillStyles.replaceCharacter(oldCharacterId, newCharacterId); - modified |= lineStyles.replaceCharacter(oldCharacterId, newCharacterId); - for (SHAPERECORD r : shapeRecords) { - modified |= r.replaceCharacter(oldCharacterId, newCharacterId); - } - return modified; - } - - @Override - public boolean removeCharacter(int characterId) { - boolean modified = false; - modified |= fillStyles.removeCharacter(characterId); - modified |= lineStyles.removeCharacter(characterId); - for (SHAPERECORD r : shapeRecords) { - modified |= r.removeCharacter(characterId); - } - return modified; - } - - public static SHAPEWITHSTYLE createEmpty(int shapeNum) { - SHAPEWITHSTYLE ret = new SHAPEWITHSTYLE(); - ret.shapeRecords = new ArrayList<>(); - ret.shapeRecords.add(new EndShapeRecord()); - ret.fillStyles = new FILLSTYLEARRAY(); - ret.fillStyles.fillStyles = new FILLSTYLE[0]; - ret.lineStyles = new LINESTYLEARRAY(); - if ((shapeNum == 1 || shapeNum == 2 || shapeNum == 3)) { - ret.lineStyles.lineStyles = new LINESTYLE[0]; - } else if (shapeNum == 4) { - ret.lineStyles.lineStyles = new LINESTYLE2[0]; - } - - return ret; - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.types; + +import com.jpexs.decompiler.flash.tags.base.NeedsCharacters; +import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord; +import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Set; + +/** + * + * @author JPEXS + */ +public class SHAPEWITHSTYLE extends SHAPE implements NeedsCharacters, Serializable { + + public FILLSTYLEARRAY fillStyles; + + public LINESTYLEARRAY lineStyles; + + @Override + public void getNeededCharacters(Set needed) { + fillStyles.getNeededCharacters(needed); + lineStyles.getNeededCharacters(needed); + for (SHAPERECORD r : shapeRecords) { + r.getNeededCharacters(needed); + } + } + + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + boolean modified = false; + modified |= fillStyles.replaceCharacter(oldCharacterId, newCharacterId); + modified |= lineStyles.replaceCharacter(oldCharacterId, newCharacterId); + for (SHAPERECORD r : shapeRecords) { + modified |= r.replaceCharacter(oldCharacterId, newCharacterId); + } + return modified; + } + + @Override + public boolean removeCharacter(int characterId) { + boolean modified = false; + modified |= fillStyles.removeCharacter(characterId); + modified |= lineStyles.removeCharacter(characterId); + for (SHAPERECORD r : shapeRecords) { + modified |= r.removeCharacter(characterId); + } + return modified; + } + + public static SHAPEWITHSTYLE createEmpty(int shapeNum) { + SHAPEWITHSTYLE ret = new SHAPEWITHSTYLE(); + ret.shapeRecords = new ArrayList<>(); + ret.shapeRecords.add(new EndShapeRecord()); + ret.fillStyles = new FILLSTYLEARRAY(); + ret.fillStyles.fillStyles = new FILLSTYLE[0]; + ret.lineStyles = new LINESTYLEARRAY(); + if (shapeNum <= 3) { + ret.lineStyles.lineStyles = new LINESTYLE[0]; + } else { + ret.lineStyles.lineStyles = new LINESTYLE2[0]; + } + + return ret; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java index e082c795c..f87eafbf2 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java @@ -1,3434 +1,3434 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.xfl; - -import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler; -import com.jpexs.decompiler.flash.RetryTask; -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFCompression; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.action.Action; -import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.decompiler.flash.exporters.MovieExporter; -import com.jpexs.decompiler.flash.exporters.SoundExporter; -import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; -import com.jpexs.decompiler.flash.exporters.modes.MovieExportMode; -import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; -import com.jpexs.decompiler.flash.exporters.modes.SoundExportMode; -import com.jpexs.decompiler.flash.exporters.settings.ScriptExportSettings; -import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter; -import com.jpexs.decompiler.flash.helpers.ImageHelper; -import com.jpexs.decompiler.flash.tags.CSMTextSettingsTag; -import com.jpexs.decompiler.flash.tags.DefineButton2Tag; -import com.jpexs.decompiler.flash.tags.DefineButtonCxformTag; -import com.jpexs.decompiler.flash.tags.DefineButtonTag; -import com.jpexs.decompiler.flash.tags.DefineEditTextTag; -import com.jpexs.decompiler.flash.tags.DefineFontNameTag; -import com.jpexs.decompiler.flash.tags.DefineSoundTag; -import com.jpexs.decompiler.flash.tags.DefineSpriteTag; -import com.jpexs.decompiler.flash.tags.DefineText2Tag; -import com.jpexs.decompiler.flash.tags.DefineTextTag; -import com.jpexs.decompiler.flash.tags.DefineVideoStreamTag; -import com.jpexs.decompiler.flash.tags.DoActionTag; -import com.jpexs.decompiler.flash.tags.DoInitActionTag; -import com.jpexs.decompiler.flash.tags.ExportAssetsTag; -import com.jpexs.decompiler.flash.tags.FileAttributesTag; -import com.jpexs.decompiler.flash.tags.FrameLabelTag; -import com.jpexs.decompiler.flash.tags.SetBackgroundColorTag; -import com.jpexs.decompiler.flash.tags.ShowFrameTag; -import com.jpexs.decompiler.flash.tags.SoundStreamBlockTag; -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.ButtonTag; -import com.jpexs.decompiler.flash.tags.base.CharacterTag; -import com.jpexs.decompiler.flash.tags.base.FontTag; -import com.jpexs.decompiler.flash.tags.base.ImageTag; -import com.jpexs.decompiler.flash.tags.base.MorphShapeTag; -import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag; -import com.jpexs.decompiler.flash.tags.base.RemoveTag; -import com.jpexs.decompiler.flash.tags.base.ShapeTag; -import com.jpexs.decompiler.flash.tags.base.SoundStreamHeadTypeTag; -import com.jpexs.decompiler.flash.tags.base.SoundTag; -import com.jpexs.decompiler.flash.tags.base.TextTag; -import com.jpexs.decompiler.flash.tags.font.CharacterRanges; -import com.jpexs.decompiler.flash.types.BUTTONCONDACTION; -import com.jpexs.decompiler.flash.types.BUTTONRECORD; -import com.jpexs.decompiler.flash.types.CLIPACTIONRECORD; -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.FILLSTYLE; -import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY; -import com.jpexs.decompiler.flash.types.FOCALGRADIENT; -import com.jpexs.decompiler.flash.types.GRADIENT; -import com.jpexs.decompiler.flash.types.GRADRECORD; -import com.jpexs.decompiler.flash.types.LINESTYLE; -import com.jpexs.decompiler.flash.types.LINESTYLE2; -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.RGB; -import com.jpexs.decompiler.flash.types.RGBA; -import com.jpexs.decompiler.flash.types.SOUNDENVELOPE; -import com.jpexs.decompiler.flash.types.TEXTRECORD; -import com.jpexs.decompiler.flash.types.filters.BEVELFILTER; -import com.jpexs.decompiler.flash.types.filters.BLURFILTER; -import com.jpexs.decompiler.flash.types.filters.COLORMATRIXFILTER; -import com.jpexs.decompiler.flash.types.filters.DROPSHADOWFILTER; -import com.jpexs.decompiler.flash.types.filters.FILTER; -import com.jpexs.decompiler.flash.types.filters.GLOWFILTER; -import com.jpexs.decompiler.flash.types.filters.GRADIENTBEVELFILTER; -import com.jpexs.decompiler.flash.types.filters.GRADIENTGLOWFILTER; -import com.jpexs.decompiler.flash.types.shaperecords.CurvedEdgeRecord; -import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD; -import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord; -import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord; -import com.jpexs.decompiler.flash.types.sound.MP3FRAME; -import com.jpexs.decompiler.flash.types.sound.MP3SOUNDDATA; -import com.jpexs.decompiler.flash.types.sound.SoundFormat; -import com.jpexs.helpers.Path; -import com.jpexs.helpers.SerializableImage; -import com.jpexs.helpers.utf8.Utf8Helper; -import java.awt.Font; -import java.awt.Point; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.StringReader; -import java.io.StringWriter; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.Stack; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; -import javax.xml.parsers.SAXParserFactory; -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Source; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.TransformerFactoryConfigurationError; -import javax.xml.transform.stream.StreamResult; -import javax.xml.transform.stream.StreamSource; -import org.xml.sax.Attributes; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; -import org.xml.sax.SAXParseException; -import org.xml.sax.XMLReader; -import org.xml.sax.helpers.DefaultHandler; -import org.xml.sax.helpers.XMLReaderFactory; - -/** - * - * @author JPEXS - */ -public class XFLConverter { - - public static final int KEY_MODE_NORMAL = 9728; - - public static final int KEY_MODE_CLASSIC_TWEEN = 22017; - - public static final int KEY_MODE_SHAPE_TWEEN = 17922; - - public static final int KEY_MODE_MOTION_TWEEN = 8195; - - public static final int KEY_MODE_SHAPE_LAYERS = 8192; - - private static final Random random = new Random(123); // predictable random - - private XFLConverter() { - } - - public static String convertShapeEdge(MATRIX mat, SHAPERECORD record, int x, int y) { - if (record instanceof StyleChangeRecord) { - StyleChangeRecord scr = (StyleChangeRecord) record; - Point p = new Point(scr.moveDeltaX, scr.moveDeltaY); - //p = mat.apply(p); - if (scr.stateMoveTo) { - return "! " + p.x + " " + p.y; - } - return ""; - } - if (record instanceof StraightEdgeRecord) { - StraightEdgeRecord ser = (StraightEdgeRecord) record; - if (ser.generalLineFlag || ser.vertLineFlag) { - y += ser.deltaY; - } - if (ser.generalLineFlag || (!ser.vertLineFlag)) { - x += ser.deltaX; - } - Point p = new Point(x, y); - //p = mat.apply(p); - return "| " + p.x + " " + p.y; - } - if (record instanceof CurvedEdgeRecord) { - CurvedEdgeRecord cer = (CurvedEdgeRecord) record; - int controlX = cer.controlDeltaX + x; - int controlY = cer.controlDeltaY + y; - int anchorX = cer.anchorDeltaX + controlX; - int anchorY = cer.anchorDeltaY + controlY; - Point control = new Point(controlX, controlY); - //control = mat.apply(control); - Point anchor = new Point(anchorX, anchorY); - //anchor = mat.apply(anchor); - return "[ " + control.x + " " + control.y + " " + anchor.x + " " + anchor.y; - } - return ""; - } - - public static String convertShapeEdges(int startX, int startY, MATRIX mat, List records) { - StringBuilder ret = new StringBuilder(); - int x = startX; - int y = startY; - ret.append("!").append(startX).append(" ").append(startY); - for (SHAPERECORD rec : records) { - ret.append(convertShapeEdge(mat, rec, x, y)); - x = rec.changeX(x); - y = rec.changeY(y); - } - return ret.toString(); - } - - public static String convertLineStyle(LINESTYLE ls, int shapeNum) { - return "" - + "" - + "" - + "" - + ""; - } - - public static String convertLineStyle(HashMap characters, LINESTYLE2 ls, int shapeNum) { - StringBuilder ret = new StringBuilder(); - StringBuilder params = new StringBuilder(); - if (ls.pixelHintingFlag) { - params.append(" pixelHinting=\"true\""); - } - if (ls.width == 1) { - params.append(" solidStyle=\"hairline\""); - } - if ((!ls.noHScaleFlag) && (!ls.noVScaleFlag)) { - params.append(" scaleMode=\"normal\""); - } else if ((!ls.noHScaleFlag) && ls.noVScaleFlag) { - params.append(" scaleMode=\"horizontal\""); - } else if (ls.noHScaleFlag && (!ls.noVScaleFlag)) { - params.append(" scaleMode=\"vertical\""); - } - - switch (ls.endCapStyle) { //What about endCapStyle? - case LINESTYLE2.NO_CAP: - params.append(" caps=\"none\""); - break; - case LINESTYLE2.SQUARE_CAP: - params.append(" caps=\"square\""); - break; - } - switch (ls.joinStyle) { - case LINESTYLE2.BEVEL_JOIN: - params.append(" joints=\"bevel\""); - break; - case LINESTYLE2.MITER_JOIN: - params.append(" joints=\"miter\""); - float miterLimitFactor = toFloat(ls.miterLimitFactor); - if (miterLimitFactor != 3.0f) { - params.append(" miterLimit=\"").append(miterLimitFactor).append("\""); - } - break; - } - - ret.append(""); - ret.append(""); - - if (!ls.hasFillFlag) { - RGBA color = (RGBA) ls.color; - ret.append(""); - } else { - ret.append(convertFillStyle(null/* FIXME */, characters, ls.fillType, shapeNum)); - } - ret.append(""); - ret.append(""); - return ret.toString(); - } - - private static float toFloat(int i) { - return ((float) i) / (1 << 16); - } - - public static String convertFillStyle(MATRIX mat, HashMap characters, FILLSTYLE fs, int shapeNum) { - /* todo: use matrix - if (mat == null) { - mat = new MATRIX(); - }*/ - StringBuilder ret = new StringBuilder(); - //ret += ""; - switch (fs.fillStyleType) { - case FILLSTYLE.SOLID: - ret.append("= 3) { - ret.append(" alpha=\"").append(((RGBA) fs.color).getAlphaFloat()).append("\""); - } - ret.append(" />"); - break; - case FILLSTYLE.REPEATING_BITMAP: - case FILLSTYLE.CLIPPED_BITMAP: - case FILLSTYLE.NON_SMOOTHED_REPEATING_BITMAP: - case FILLSTYLE.NON_SMOOTHED_CLIPPED_BITMAP: - ret.append(""; - } - ret.append("\""); - - if ((fs.fillStyleType == FILLSTYLE.CLIPPED_BITMAP) || (fs.fillStyleType == FILLSTYLE.NON_SMOOTHED_CLIPPED_BITMAP)) { - ret.append(" bitmapIsClipped=\"true\""); - } - - ret.append(">"); - ret.append("").append(convertMatrix(fs.bitmapMatrix)).append(""); - ret.append(""); - break; - case FILLSTYLE.LINEAR_GRADIENT: - case FILLSTYLE.RADIAL_GRADIENT: - case FILLSTYLE.FOCAL_RADIAL_GRADIENT: - - if (fs.fillStyleType == FILLSTYLE.LINEAR_GRADIENT) { - ret.append(""); - - ret.append("").append(convertMatrix(fs.gradientMatrix)).append(""); - GRADRECORD[] records; - if (fs.fillStyleType == FILLSTYLE.FOCAL_RADIAL_GRADIENT) { - records = fs.gradient.gradientRecords; - } else { - records = fs.gradient.gradientRecords; - } - for (GRADRECORD rec : records) { - ret.append("= 3) { - ret.append(" alpha=\"").append(((RGBA) rec.color).getAlphaFloat()).append("\""); - } - ret.append(" ratio=\"").append(rec.getRatioFloat()).append("\""); - ret.append(" />"); - } - if (fs.fillStyleType == FILLSTYLE.LINEAR_GRADIENT) { - ret.append(""); - } else { - ret.append(""); - } - break; - } - //ret += ""; - return ret.toString(); - } - - public static String convertMatrix(MATRIX m) { - return convertMatrix(new Matrix(m)); - } - - public static String convertMatrix(Matrix m) { - StringBuilder ret = new StringBuilder(); - if (m == null) { - m = new Matrix(); - } - ret.append(""); - return ret.toString(); - } - /* - public static String convertShape(HashMap characters, MATRIX mat, int shapeNum, SHAPE shape) { - return convertShape(characters, mat, shapeNum, shape.shapeRecords); - } - - public static String convertShape(HashMap characters, MATRIX mat, int shapeNum, SHAPEWITHSTYLE shape,boolean morphShape) { - return convertShape(characters, mat, shapeNum, shape.shapeRecords, shape.fillStyles, shape.lineStyles, morphShape); - } - - public static String convertShape(HashMap characters, MATRIX mat, ShapeTag shape, boolean morphShape) { - return convertShape(characters, mat, shape.getShapeNum(), shape.getShapes(),morphShape); - } - - public static String convertShape(HashMap characters, MATRIX mat, int shapeNum, List shapeRecords,boolean useLayers) { - return convertShape(characters, mat, shapeNum, shapeRecords, null, null, false,true); - }*/ - - private static boolean shapeHasMultiLayers(HashMap characters, MATRIX mat, int shapeNum, List shapeRecords, FILLSTYLEARRAY fillStyles, LINESTYLEARRAY lineStyles) { - List layers = getShapeLayers(characters, mat, shapeNum, shapeRecords, fillStyles, lineStyles, false); - return layers.size() > 1; - } - - public static String convertShape(HashMap characters, MATRIX mat, int shapeNum, List shapeRecords, FILLSTYLEARRAY fillStyles, LINESTYLEARRAY lineStyles, boolean morphshape, boolean useLayers) { - StringBuilder ret = new StringBuilder(); - List layers = getShapeLayers(characters, mat, shapeNum, shapeRecords, fillStyles, lineStyles, morphshape); - if (layers.size() == 1 && !useLayers) { - ret.append(layers.get(0)); - } else { - int layer = 1; - for (int l = layers.size() - 1; l >= 0; l--) { - ret.append(""); //color=\"#4FFF4F\" - ret.append(""); - ret.append(""); - ret.append(""); - ret.append(layers.get(l)); - ret.append(""); - ret.append(""); - ret.append(""); - ret.append(""); - } - } - return ret.toString(); - } - - /** - * Remove bugs in shape: - * - * ... straightrecord straightrecord stylechange straightrecord (-2,0) <-- - * merge this with previous stylegchange - * - * @param shapeRecords - * @return - */ - private static List smoothShape(List shapeRecords) { - List ret = new ArrayList<>(shapeRecords); - - for (int i = 1; i < ret.size() - 1; i++) { - if (ret.get(i) instanceof StraightEdgeRecord && (ret.get(i - 1) instanceof StyleChangeRecord) && (ret.get(i + 1) instanceof StyleChangeRecord)) { - StraightEdgeRecord ser = (StraightEdgeRecord) ret.get(i); - StyleChangeRecord scr = (StyleChangeRecord) ret.get(i - 1); - StyleChangeRecord scr2 = (StyleChangeRecord) ret.get(i + 1); - if ((!scr.stateMoveTo && !scr.stateNewStyles) && Math.abs(ser.deltaX) < 5 && Math.abs(ser.deltaY) < 5) { - if (i >= 2) { - SHAPERECORD rbef = ret.get(i - 2); - if (rbef instanceof StraightEdgeRecord) { - StraightEdgeRecord ser_b = (StraightEdgeRecord) rbef; - ser_b.generalLineFlag = true; - ser_b.deltaX = ser.changeX(ser_b.deltaX); - ser_b.deltaY = ser.changeY(ser_b.deltaY); - } else if (rbef instanceof CurvedEdgeRecord) { - CurvedEdgeRecord cer_b = (CurvedEdgeRecord) rbef; - cer_b.anchorDeltaX = ser.changeX(cer_b.anchorDeltaX); - cer_b.anchorDeltaY = ser.changeY(cer_b.anchorDeltaY); - } else { - //??? - } - if (i >= 2) { - ret.remove(i - 1); - ret.remove(i - 1); - if (scr.stateFillStyle0 && !scr2.stateFillStyle0) { - scr2.stateFillStyle0 = true; - scr2.fillStyle0 = scr.fillStyle0; - } - if (scr.stateFillStyle1 && !scr2.stateFillStyle1) { - scr2.stateFillStyle1 = true; - scr2.fillStyle1 = scr.fillStyle1; - } - if (scr.stateLineStyle && !scr2.stateLineStyle) { - scr2.stateLineStyle = true; - scr2.lineStyle = scr.lineStyle; - } - i -= 2; - } - - } - } - } - - } - return ret; - } - - public static List getShapeLayers(HashMap characters, MATRIX mat, int shapeNum, List shapeRecords, FILLSTYLEARRAY fillStyles, LINESTYLEARRAY lineStyles, boolean morphshape) { - if (mat == null) { - mat = new MATRIX(); - } - shapeRecords = smoothShape(shapeRecords); - List edges = new ArrayList<>(); - int lineStyleCount = 0; - int fillStyle0 = -1; - int fillStyle1 = -1; - int strokeStyle = -1; - String fillsStr = ""; - String strokesStr = ""; - fillsStr += ""; - strokesStr += ""; - List layers = new ArrayList<>(); - String currentLayer = ""; - - int fillStyleCount = 0; - if (fillStyles != null) { - for (FILLSTYLE fs : fillStyles.fillStyles) { - fillsStr += ""; - fillsStr += convertFillStyle(mat, characters, fs, shapeNum); - fillsStr += ""; - fillStyleCount++; - } - } - if (lineStyles != null) { - if ((shapeNum == 4) && (lineStyles.lineStyles != null)) { //(shapeNum == 4) { - for (int l = 0; l < lineStyles.lineStyles.length; l++) { - strokesStr += ""; - strokesStr += convertLineStyle(characters, (LINESTYLE2) lineStyles.lineStyles[l], shapeNum); - strokesStr += ""; - lineStyleCount++; - } - } else if (lineStyles.lineStyles != null) { - for (int l = 0; l < lineStyles.lineStyles.length; l++) { - strokesStr += ""; - strokesStr += convertLineStyle(lineStyles.lineStyles[l], shapeNum); - strokesStr += ""; - lineStyleCount++; - } - } - } - - fillsStr += ""; - strokesStr += ""; - - int layer = 1; - - if ((fillStyleCount > 0) || (lineStyleCount > 0)) { - currentLayer += ""; - currentLayer += fillsStr; - currentLayer += strokesStr; - currentLayer += ""; - } - int x = 0; - int y = 0; - int startEdgeX = 0; - int startEdgeY = 0; - - LINESTYLEARRAY actualLinestyles = lineStyles; - int strokeStyleOrig = 0; - fillStyleCount = fillStyles.fillStyles.length; - for (SHAPERECORD edge : shapeRecords) { - if (edge instanceof StyleChangeRecord) { - StyleChangeRecord scr = (StyleChangeRecord) edge; - boolean styleChange = false; - int lastFillStyle1 = fillStyle1; - int lastFillStyle0 = fillStyle0; - int lastStrokeStyle = strokeStyle; - if (scr.stateNewStyles) { - fillsStr = ""; - strokesStr = ""; - if (fillStyleCount > 0 || lineStyleCount > 0) { - - if ((fillStyle0 > 0) || (fillStyle1 > 0) || (strokeStyle > 0)) { - - boolean empty = false; - if ((fillStyle0 <= 0) && (fillStyle1 <= 0) && (strokeStyle > 0) && morphshape) { - if (shapeNum == 4) { - if (strokeStyleOrig > 0) { - if (!((LINESTYLE2) actualLinestyles.lineStyles[strokeStyleOrig]).hasFillFlag) { - RGBA color = (RGBA) actualLinestyles.lineStyles[strokeStyleOrig].color; - if (color.alpha == 0 && color.red == 0 && color.green == 0 && color.blue == 0) { - empty = true; - } - } - } - } - } - if (!empty) { - currentLayer += " -1) { - currentLayer += " fillStyle0=\"" + fillStyle0 + "\""; - } - if (fillStyle1 > -1) { - currentLayer += " fillStyle1=\"" + fillStyle1 + "\""; - } - if (strokeStyle > -1) { - currentLayer += " strokeStyle=\"" + strokeStyle + "\""; - } - currentLayer += " edges=\"" + convertShapeEdges(startEdgeX, startEdgeY, mat, edges) + "\" />"; - } - } - - currentLayer += ""; - currentLayer += ""; - if (!currentLayer.contains("")) { //no empty layers, TODO:handle this better - layers.add(currentLayer); - } - currentLayer = ""; - } - - currentLayer += ""; - //ret += convertShape(characters, null, shape); - for (int f = 0; f < scr.fillStyles.fillStyles.length; f++) { - fillsStr += ""; - fillsStr += convertFillStyle(mat, characters, scr.fillStyles.fillStyles[f], shapeNum); - fillsStr += ""; - fillStyleCount++; - } - - lineStyleCount = 0; - if (shapeNum == 4) { - for (int l = 0; l < scr.lineStyles.lineStyles.length; l++) { - strokesStr += ""; - strokesStr += convertLineStyle(characters, (LINESTYLE2) scr.lineStyles.lineStyles[l], shapeNum); - strokesStr += ""; - lineStyleCount++; - } - } else { - for (int l = 0; l < scr.lineStyles.lineStyles.length; l++) { - strokesStr += ""; - strokesStr += convertLineStyle(scr.lineStyles.lineStyles[l], shapeNum); - strokesStr += ""; - lineStyleCount++; - } - } - fillsStr += ""; - strokesStr += ""; - currentLayer += fillsStr; - currentLayer += strokesStr; - currentLayer += ""; - actualLinestyles = scr.lineStyles; - } - if (scr.stateFillStyle0) { - int fillStyle0_new = scr.fillStyle0;// == 0 ? 0 : fillStylesMap.get(fillStyleCount - lastFillStyleCount + scr.fillStyle0 - 1) + 1; - if (morphshape) { //??? - fillStyle1 = fillStyle0_new; - } else { - fillStyle0 = fillStyle0_new; - } - styleChange = true; - } - if (scr.stateFillStyle1) { - int fillStyle1_new = scr.fillStyle1;// == 0 ? 0 : fillStylesMap.get(fillStyleCount - lastFillStyleCount + scr.fillStyle1 - 1) + 1; - if (morphshape) { - fillStyle0 = fillStyle1_new; - } else { - fillStyle1 = fillStyle1_new; - } - styleChange = true; - } - if (scr.stateLineStyle) { - strokeStyle = scr.lineStyle;// == 0 ? 0 : lineStyleCount - lastLineStyleCount + scr.lineStyle; - strokeStyleOrig = scr.lineStyle - 1; - styleChange = true; - } - if (!edges.isEmpty()) { - if ((fillStyle0 > 0) || (fillStyle1 > 0) || (strokeStyle > 0)) { - boolean empty = false; - if ((fillStyle0 <= 0) && (fillStyle1 <= 0) && (strokeStyle > 0) && morphshape) { - if (shapeNum == 4) { - if (strokeStyleOrig > 0) { - if (!((LINESTYLE2) actualLinestyles.lineStyles[strokeStyleOrig]).hasFillFlag) { - RGBA color = (RGBA) actualLinestyles.lineStyles[strokeStyleOrig].color; - if (color.alpha == 0 && color.red == 0 && color.green == 0 && color.blue == 0) { - empty = true; - } - } - } - } - } - if (!empty) { - currentLayer += " -1) { - currentLayer += " fillStyle0=\"" + lastFillStyle0 + "\""; - } - if (fillStyle1 > -1) { - currentLayer += " fillStyle1=\"" + lastFillStyle1 + "\""; - } - if (strokeStyle > -1) { - currentLayer += " strokeStyle=\"" + lastStrokeStyle + "\""; - } - currentLayer += " edges=\"" + convertShapeEdges(startEdgeX, startEdgeY, mat, edges) + "\" />"; - } - - startEdgeX = x; - startEdgeY = y; - } - edges.clear(); - } - } - edges.add(edge); - x = edge.changeX(x); - y = edge.changeY(y); - } - if (!edges.isEmpty()) { - if ((fillStyle0 > 0) || (fillStyle1 > 0) || (strokeStyle > 0)) { - - boolean empty = false; - if ((fillStyle0 <= 0) && (fillStyle1 <= 0) && (strokeStyle > 0) && morphshape) { - if (shapeNum == 4) { - if (strokeStyleOrig > 0) { - if (!((LINESTYLE2) actualLinestyles.lineStyles[strokeStyleOrig]).hasFillFlag) { - RGBA color = (RGBA) actualLinestyles.lineStyles[strokeStyleOrig].color; - if (color.alpha == 0 && color.red == 0 && color.green == 0 && color.blue == 0) { - empty = true; - } - } - } - } - } - if (!empty) { - currentLayer += " -1) { - currentLayer += " fillStyle0=\"" + fillStyle0 + "\""; - } - if (fillStyle1 > -1) { - currentLayer += " fillStyle1=\"" + fillStyle1 + "\""; - } - if (strokeStyle > -1) { - currentLayer += " strokeStyle=\"" + strokeStyle + "\""; - } - currentLayer += " edges=\"" + convertShapeEdges(startEdgeX, startEdgeY, mat, edges) + "\" />"; - } - } - } - edges.clear(); - fillsStr += ""; - strokesStr += ""; - if (!currentLayer.isEmpty()) { - currentLayer += ""; - currentLayer += ""; - - if (!currentLayer.contains("")) { //no empty layers, TODO:handle this better - layers.add(currentLayer); - } - } - return layers; - } - - private static int getLayerCount(List tags) { - int maxDepth = 0; - for (Tag t : tags) { - if (t instanceof PlaceObjectTypeTag) { - int d = ((PlaceObjectTypeTag) t).getDepth(); - if (d > maxDepth) { - maxDepth = d; - } - int cd = ((PlaceObjectTypeTag) t).getClipDepth(); - if (cd > maxDepth) { - maxDepth = cd; - } - } - } - return maxDepth; - } - - private static void walkShapeUsages(List timeLineTags, HashMap characters, HashMap usages) { - for (Tag t : timeLineTags) { - if (t instanceof DefineSpriteTag) { - DefineSpriteTag sprite = (DefineSpriteTag) t; - walkShapeUsages(sprite.subTags, characters, usages); - } - if (t instanceof PlaceObjectTypeTag) { - PlaceObjectTypeTag po = (PlaceObjectTypeTag) t; - int ch = po.getCharacterId(); - if (ch > -1) { - if (!usages.containsKey(ch)) { - usages.put(ch, 0); - } - int usageCount = usages.get(ch); - if (po.getInstanceName() != null) { - usageCount++; - } - if (po.getColorTransform() != null) { - usageCount++; - } - if (po.cacheAsBitmap()) { - usageCount++; - } - MATRIX mat = po.getMatrix(); - if (mat != null) { - if (!mat.isEmpty()) { - usageCount++; - } - } - usages.put(ch, usageCount + 1); - } - } - } - } - - private static List getNonLibraryShapes(List tags, HashMap characters) { - HashMap usages = new HashMap<>(); - walkShapeUsages(tags, characters, usages); - List ret = new ArrayList<>(); - for (int ch : usages.keySet()) { - if (usages.get(ch) < 2) { - if (characters.get(ch) instanceof ShapeTag) { - ShapeTag shp = (ShapeTag) characters.get(ch); - if (!shapeHasMultiLayers(characters, null, shp.getShapeNum(), shp.getShapes().shapeRecords, shp.getShapes().fillStyles, shp.getShapes().lineStyles)) { - ret.add(ch); - } - } - - } - } - return ret; - } - - private static HashMap getCharacters(List tags) { - HashMap ret = new HashMap<>(); - int maxId = 0; - for (Tag t : tags) { - if (t instanceof CharacterTag) { - CharacterTag ct = (CharacterTag) t; - if (ct.getCharacterId() > maxId) { - maxId = ct.getCharacterId(); - } - } - } - for (Tag t : tags) { - if (t instanceof SoundStreamHeadTypeTag) { - SoundStreamHeadTypeTag ssh = (SoundStreamHeadTypeTag) t; - ssh.setVirtualCharacterId(++maxId); - } - if (t instanceof CharacterTag) { - CharacterTag ct = (CharacterTag) t; - ret.put(ct.getCharacterId(), ct); - } - } - return ret; - } - - private static final String[] BLENDMODES = { - null, - null, - "layer", - "multiply", - "screen", - "lighten", - "darken", - "difference", - "add", - "subtract", - "invert", - "alpha", - "erase", - "overlay", - "hardligh" - }; - - private static double radToDeg(double rad) { - return rad * 180 / Math.PI; - } - - private static String doubleToString(double d, int precision) { - double m = Math.pow(10, precision); - d = Math.round(d * m) / m; - return doubleToString(d); - } - - private static String doubleToString(double d) { - String ds = "" + d; - if (ds.endsWith(".0")) { - ds = ds.substring(0, ds.length() - 2); - } - return ds; - } - - public static String convertFilter(FILTER filter) { - StringBuilder ret = new StringBuilder(); - if (filter instanceof DROPSHADOWFILTER) { - DROPSHADOWFILTER dsf = (DROPSHADOWFILTER) filter; - ret.append(""); - } else if (filter instanceof BLURFILTER) { - BLURFILTER bf = (BLURFILTER) filter; - ret.append(""); - } else if (filter instanceof GLOWFILTER) { - GLOWFILTER gf = (GLOWFILTER) filter; - ret.append(""); - } else if (filter instanceof BEVELFILTER) { - BEVELFILTER bf = (BEVELFILTER) filter; - ret.append(""); - } else if (filter instanceof GRADIENTGLOWFILTER) { - GRADIENTGLOWFILTER ggf = (GRADIENTGLOWFILTER) filter; - ret.append(""); - for (int g = 0; g < ggf.gradientColors.length; g++) { - RGBA gc = ggf.gradientColors[g]; - ret.append(""); - } - ret.append(""); - } else if (filter instanceof GRADIENTBEVELFILTER) { - GRADIENTBEVELFILTER gbf = (GRADIENTBEVELFILTER) filter; - ret.append(""); - for (int g = 0; g < gbf.gradientColors.length; g++) { - RGBA gc = gbf.gradientColors[g]; - ret.append(""); - } - ret.append(""); - } else if (filter instanceof COLORMATRIXFILTER) { - COLORMATRIXFILTER cmf = (COLORMATRIXFILTER) filter; - ret.append(convertAdjustColorFilter(cmf)); - } - return ret.toString(); - } - - public static String convertSymbolInstance(String name, MATRIX matrix, ColorTransform colorTransform, boolean cacheAsBitmap, int blendMode, List filters, boolean isVisible, RGBA backgroundColor, CLIPACTIONS clipActions, CharacterTag tag, HashMap characters, List tags, FLAVersion flaVersion) { - StringBuilder ret = new StringBuilder(); - if (matrix == null) { - matrix = new MATRIX(); - } - if (tag instanceof DefineButtonTag) { - DefineButtonTag bt = (DefineButtonTag) tag; - for (Tag t : tags) { - if (t instanceof DefineButtonCxformTag) { - DefineButtonCxformTag bcx = (DefineButtonCxformTag) t; - if (bcx.buttonId == bt.buttonId) { - colorTransform = bcx.buttonColorTransform; - } - } - } - } - - ret.append("= FLAVersion.CS5_5.ordinal()) { - ret.append(" isVisible=\"false\""); - } - ret.append(">"); - ret.append(""); - ret.append(convertMatrix(matrix)); - ret.append(""); - ret.append(""); - - if (backgroundColor != null) { - ret.append(""); - } - if (colorTransform != null) { - ret.append(""); - } - if (filters != null) { - ret.append(""); - for (FILTER f : filters) { - ret.append(convertFilter(f)); - } - ret.append(""); - } - if (tag instanceof DefineButtonTag) { - ret.append(""); - } - if (tag instanceof DefineButton2Tag) { - DefineButton2Tag db2 = (DefineButton2Tag) tag; - if (!db2.actions.isEmpty()) { - ret.append(""); - } - } - if (clipActions != null) { - ret.append(""); - } - ret.append(""); - return ret.toString(); - } - - private static String convertActionScript(ASMSource as) { - HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), false); - try { - Action.actionsToSource(as, as.getActions(), as.toString(), writer); - } catch (InterruptedException ex) { - Logger.getLogger(XFLConverter.class.getName()).log(Level.SEVERE, null, ex); - } - return writer.toString(); - } - - private static long getTimestamp() { - return new Date().getTime() / 1000; - } - - public static String convertLibrary(SWF swf, Map characterVariables, Map characterClasses, List nonLibraryShapes, String backgroundColor, List tags, HashMap characters, HashMap files, HashMap datfiles, FLAVersion flaVersion) { - - //TODO: Imported assets - //linkageImportForRS="true" linkageIdentifier="xxx" linkageURL="yyy.swf" - StringBuilder ret = new StringBuilder(); - List media = new ArrayList<>(); - List symbols = new ArrayList<>(); - for (int ch : characters.keySet()) { - CharacterTag symbol = characters.get(ch); - if ((symbol instanceof ShapeTag) && nonLibraryShapes.contains(symbol.getCharacterId())) { - continue; //shapes with 1 ocurrence and single layer are not added to library - } - if ((symbol instanceof ShapeTag) || (symbol instanceof DefineSpriteTag) || (symbol instanceof ButtonTag)) { - StringBuilder symbolStr = new StringBuilder(); - - symbolStr.append(""); - symbolStr.append(""); - String itemIcon = null; - if (symbol instanceof ButtonTag) { - itemIcon = "0"; - symbolStr.append(""); - symbolStr.append(""); - - ButtonTag button = (ButtonTag) symbol; - List records = button.getRecords(); - - int maxDepth = 0; - for (BUTTONRECORD rec : records) { - if (rec.placeDepth > maxDepth) { - maxDepth = rec.placeDepth; - } - } - for (int i = maxDepth; i >= 1; i--) { - symbolStr.append(""); - symbolStr.append(""); - int lastFrame = 0; - loopframes: - for (int frame = 1; frame <= 4; frame++) { - for (BUTTONRECORD rec : records) { - if (rec.placeDepth == i) { - boolean ok = false; - switch (frame) { - case 1: - ok = rec.buttonStateUp; - break; - case 2: - ok = rec.buttonStateOver; - break; - case 3: - ok = rec.buttonStateDown; - break; - case 4: - ok = rec.buttonStateHitTest; - break; - } - if (!ok) { - continue; - } - CXFORMWITHALPHA colorTransformAlpha = null; - int blendMode = 0; - List filters = new ArrayList<>(); - if (button instanceof DefineButton2Tag) { - colorTransformAlpha = rec.colorTransform; - if (rec.buttonHasBlendMode) { - blendMode = rec.blendMode; - } - if (rec.buttonHasFilterList) { - filters = rec.filterList; - } - } - CharacterTag character = characters.get(rec.characterId); - MATRIX matrix = rec.placeMatrix; - String recCharStr; - if (character instanceof TextTag) { - recCharStr = convertText(null, (TextTag) character, matrix, filters, null); - } else if (character instanceof DefineVideoStreamTag) { - recCharStr = convertVideoInstance(null, matrix, (DefineVideoStreamTag) character, null); - } else { - recCharStr = convertSymbolInstance(null, matrix, colorTransformAlpha, false, blendMode, filters, true, null, null, characters.get(rec.characterId), characters, tags, flaVersion); - } - int duration = frame - lastFrame; - lastFrame = frame; - if (duration > 0) { - if (duration > 1) { - symbolStr.append(""); - symbolStr.append(""); - symbolStr.append(""); - symbolStr.append(""); - } - symbolStr.append(""); - symbolStr.append(""); - symbolStr.append(recCharStr); - symbolStr.append(""); - symbolStr.append(""); - } - } - } - } - symbolStr.append(""); - symbolStr.append(""); - } - symbolStr.append(""); - symbolStr.append(""); - } else if (symbol instanceof DefineSpriteTag) { - DefineSpriteTag sprite = (DefineSpriteTag) symbol; - if (sprite.subTags.isEmpty()) { //probably AS2 class - continue; - } - symbolStr.append(convertTimeline(sprite.spriteId, nonLibraryShapes, backgroundColor, tags, sprite.getSubTags(), characters, "Symbol " + symbol.getCharacterId(), flaVersion, files)); - } else if (symbol instanceof ShapeTag) { - itemIcon = "1"; - ShapeTag shape = (ShapeTag) symbol; - symbolStr.append(""); - symbolStr.append(""); - symbolStr.append(convertShape(characters, null, shape.getShapeNum(), shape.getShapes().shapeRecords, shape.getShapes().fillStyles, shape.getShapes().lineStyles, false, true)); - symbolStr.append(""); - symbolStr.append(""); - } - symbolStr.append(""); - symbolStr.append(""); - String symbolStr2 = prettyFormatXML(symbolStr.toString()); - String symbolFile = "Symbol " + symbol.getCharacterId() + ".xml"; - files.put(symbolFile, Utf8Helper.getBytes(symbolStr2)); - String symbLinkStr = ""; - symbLinkStr += "= FLAVersion.CS5_5.ordinal()) { - symbLinkStr += " lastModified=\"" + getTimestamp() + "\""; - //TODO: itemID=\"518de416-00000341\" - } - symbLinkStr += "/>"; - symbols.add(symbLinkStr); - } else if (symbol instanceof ImageTag) { - ImageTag imageTag = (ImageTag) symbol; - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - SerializableImage image = imageTag.getImage(); - // do not store the image in cache during xfl conversion - imageTag.clearCache(); - String format = imageTag.getImageFormat(); - ImageHelper.write(image.getBufferedImage(), format.toUpperCase(), baos); - String symbolFile = "bitmap" + symbol.getCharacterId() + "." + imageTag.getImageFormat(); - files.put(symbolFile, baos.toByteArray()); - String mediaLinkStr = "\n"; - media.add(mediaLinkStr); - - } else if ((symbol instanceof SoundStreamHeadTypeTag) || (symbol instanceof DefineSoundTag)) { - int soundFormat = 0; - int soundRate = 0; - boolean soundType = false; - boolean soundSize = false; - long soundSampleCount = 0; - byte[] soundData = new byte[0]; - int[] rateMap = {5, 11, 22, 44}; - String exportFormat = "flv"; - if (symbol instanceof SoundStreamHeadTypeTag) { - SoundStreamHeadTypeTag sstream = (SoundStreamHeadTypeTag) symbol; - soundFormat = sstream.getSoundFormatId(); - soundRate = sstream.getSoundRate(); - soundType = sstream.getSoundType(); - soundSize = sstream.getSoundSize(); - soundSampleCount = sstream.getSoundSampleCount(); - boolean found = false; - for (Tag t : tags) { - if (found && (t instanceof SoundStreamBlockTag)) { - SoundStreamBlockTag bl = (SoundStreamBlockTag) t; - soundData = bl.streamSoundData.getRangeData(); - break; - } - if (t == symbol) { - found = true; - } - } - } else if (symbol instanceof DefineSoundTag) { - DefineSoundTag sound = (DefineSoundTag) symbol; - soundFormat = sound.soundFormat; - soundRate = sound.soundRate; - soundType = sound.soundType; - soundData = sound.soundData.getRangeData(); - soundSize = sound.soundSize; - soundSampleCount = sound.soundSampleCount; - } - int format = 0; - int bits = 0; - if ((soundFormat == SoundFormat.FORMAT_ADPCM) - || (soundFormat == SoundFormat.FORMAT_UNCOMPRESSED_LITTLE_ENDIAN) - || (soundFormat == SoundFormat.FORMAT_UNCOMPRESSED_NATIVE_ENDIAN)) { - exportFormat = "wav"; - if (soundType) { //stereo - format += 1; - } - switch (soundRate) { - case 0: - format += 2; - break; - case 1: - format += 6; - break; - case 2: - format += 10; - break; - case 3: - format += 14; - break; - } - } - if (soundFormat == SoundFormat.FORMAT_SPEEX) { - bits = 18; - } - if (soundFormat == SoundFormat.FORMAT_ADPCM) { - exportFormat = "wav"; - try { - SWFInputStream sis = new SWFInputStream(swf, soundData); - int adpcmCodeSize = (int) sis.readUB(2, "adpcmCodeSize"); - bits = 2 + adpcmCodeSize; - } catch (IOException ex) { - Logger.getLogger(XFLConverter.class.getName()).log(Level.SEVERE, null, ex); - } - } - if (soundFormat == SoundFormat.FORMAT_MP3) { - exportFormat = "mp3"; - if (!soundType) { //mono - format += 1; - } - format += 4; //quality best - try { - MP3SOUNDDATA s = new MP3SOUNDDATA(new SWFInputStream(swf, soundData), false); - //sis.readSI16(); - //MP3FRAME frame = new MP3FRAME(sis); - MP3FRAME frame = s.frames.get(0); - int bitRate = frame.getBitRate(); - - switch (bitRate) { - case 8: - bits = 6; - break; - case 16: - bits = 7; - break; - case 20: - bits = 8; - break; - case 24: - bits = 9; - break; - case 32: - bits = 10; - break; - case 48: - bits = 11; - break; - case 56: - bits = 12; - break; - case 64: - bits = 13; - break; - case 80: - bits = 14; - break; - case 112: - bits = 15; - break; - case 128: - bits = 16; - break; - case 160: - bits = 17; - break; - - } - } catch (IOException ex) { - Logger.getLogger(XFLConverter.class.getName()).log(Level.SEVERE, null, ex); - } - } - SoundTag st = (SoundTag) symbol; - SoundFormat fmt = st.getSoundFormat(); - byte[] data = new byte[0]; - try { - data = new SoundExporter().exportSound(st, SoundExportMode.MP3_WAV); - } catch (IOException ex) { - Logger.getLogger(XFLConverter.class.getName()).log(Level.SEVERE, null, ex); - } - - String symbolFile = "sound" + symbol.getCharacterId() + "." + exportFormat; - files.put(symbolFile, data); - String mediaLinkStr = ""; - //Use the dat file, otherwise it does not work - datfiles.put(datFileName, new byte[]{ //Magic numbers, if anybody knows why, please tell me - (byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xA0, (byte) 0x00, (byte) 0x00, - (byte) 0x00, (byte) 0x78, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00, - (byte) 0x00, (byte) 0x01, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x00, (byte) 0x59, (byte) 0x40, (byte) 0x18, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xFF, (byte) 0xFE, (byte) 0xFF, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 - }); - } else { - files.put(symbolFile, data); - mediaLinkStr = ""); - for (String m : media) { - ret.append(m); - } - ret.append(""); - } - if (!symbols.isEmpty()) { - ret.append(""); - for (String s : symbols) { - ret.append(s); - } - ret.append(""); - } - return ret.toString(); - } - - private static String prettyFormatXML(String input) { - int indent = 5; - try { - Source xmlInput = new StreamSource(new StringReader(input)); - StringWriter stringWriter = new StringWriter(); - StreamResult xmlOutput = new StreamResult(stringWriter); - TransformerFactory transformerFactory = TransformerFactory.newInstance(); - transformerFactory.setAttribute("indent-number", indent); - Transformer transformer = transformerFactory.newTransformer(); - transformer.setOutputProperty(OutputKeys.INDENT, "yes"); - transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); - transformer.transform(xmlInput, xmlOutput); - return xmlOutput.getWriter().toString(); - } catch (TransformerFactoryConfigurationError | IllegalArgumentException | TransformerException e) { - System.err.println(input); - Logger.getLogger(XFLConverter.class.getName()).log(Level.SEVERE, "Pretty print error", e); - return input; - } - } - - private static String convertFrame(boolean shapeTween, HashMap characters, List tags, SoundStreamHeadTypeTag soundStreamHead, StartSoundTag startSound, int frame, int duration, String actionScript, String elements, HashMap files) { - StringBuilder ret = new StringBuilder(); - DefineSoundTag sound = null; - if (startSound != null) { - for (Tag t : tags) { - if (t instanceof DefineSoundTag) { - DefineSoundTag s = (DefineSoundTag) t; - if (s.soundId == startSound.soundId) { - sound = s; - break; - } - } - } - } - - ret.append(" 1) { - ret.append(" duration=\"").append(duration).append("\""); - } - if (shapeTween) { - ret.append(" tweenType=\"shape\" keyMode=\"").append(KEY_MODE_SHAPE_TWEEN).append("\""); - } else { - ret.append(" keyMode=\"").append(KEY_MODE_NORMAL).append("\""); - } - String soundEnvelopeStr = ""; - if (soundStreamHead != null && startSound == null) { - String soundName = "sound" + soundStreamHead.getCharacterId() + "." + soundStreamHead.getExportFormat(); - ret.append(" soundName=\"").append(soundName).append("\""); - ret.append(" soundSync=\"stream\""); - soundEnvelopeStr += ""; - soundEnvelopeStr += ""; - soundEnvelopeStr += ""; - } - if (startSound != null && sound != null) { - String soundName = "sound" + sound.soundId + "." + sound.getExportFormat(); - ret.append(" soundName=\"").append(soundName).append("\""); - if (startSound.soundInfo.hasInPoint) { - ret.append(" inPoint44=\"").append(startSound.soundInfo.inPoint).append("\""); - } - if (startSound.soundInfo.hasOutPoint) { - ret.append(" outPoint44=\"").append(startSound.soundInfo.outPoint).append("\""); - } - if (startSound.soundInfo.hasLoops) { - if (startSound.soundInfo.loopCount == 32767) { - ret.append(" soundLoopMode=\"loop\""); - } - ret.append(" soundLoop=\"").append(startSound.soundInfo.loopCount).append("\""); - } - - if (startSound.soundInfo.syncStop) { - ret.append(" soundSync=\"stop\""); - } else if (startSound.soundInfo.syncNoMultiple) { - ret.append(" soundSync=\"start\""); - } - soundEnvelopeStr += ""; - if (startSound.soundInfo.hasEnvelope) { - SOUNDENVELOPE[] envelopeRecords = startSound.soundInfo.envelopeRecords; - for (SOUNDENVELOPE env : envelopeRecords) { - soundEnvelopeStr += ""; - } - - if (envelopeRecords.length == 1 - && envelopeRecords[0].leftLevel == 32768 - && envelopeRecords[0].pos44 == 0 - && envelopeRecords[0].rightLevel == 0) { - ret.append(" soundEffect=\"left channel\""); - } else if (envelopeRecords.length == 1 - && envelopeRecords[0].leftLevel == 0 - && envelopeRecords[0].pos44 == 0 - && envelopeRecords[0].rightLevel == 32768) { - ret.append(" soundEffect=\"right channel\""); - } else if (envelopeRecords.length == 2 - && envelopeRecords[0].leftLevel == 32768 - && envelopeRecords[0].pos44 == 0 - && envelopeRecords[0].rightLevel == 0 - && envelopeRecords[1].leftLevel == 0 - && envelopeRecords[1].pos44 == sound.soundSampleCount - && envelopeRecords[1].rightLevel == 32768) { - ret.append(" soundEffect=\"fade left to right\""); - } else if (envelopeRecords.length == 2 - && envelopeRecords[0].leftLevel == 0 - && envelopeRecords[0].pos44 == 0 - && envelopeRecords[0].rightLevel == 32768 - && envelopeRecords[1].leftLevel == 32768 - && envelopeRecords[1].pos44 == sound.soundSampleCount - && envelopeRecords[1].rightLevel == 0) { - ret.append(" soundEffect=\"fade right to left\""); - } else { - ret.append(" soundEffect=\"custom\""); - } - //TODO: fade in, fade out - - } else { - soundEnvelopeStr += ""; - } - soundEnvelopeStr += ""; - } - ret.append(">"); - - ret.append(soundEnvelopeStr); - if (!actionScript.isEmpty()) { - ret.append(""); - } - ret.append(""); - ret.append(elements); - ret.append(""); - ret.append(""); - return ret.toString(); - } - - private static String convertVideoInstance(String instanceName, MATRIX matrix, DefineVideoStreamTag video, CLIPACTIONS clipActions) { - StringBuilder ret = new StringBuilder(); - ret.append(""); - ret.append(""); - ret.append(convertMatrix(matrix)); - ret.append(""); - ret.append(""); - ret.append(""); - ret.append(""); - ret.append(""); - return ret.toString(); - } - - private static String convertFrames(String prevStr, String afterStr, List nonLibraryShapes, List tags, List timelineTags, HashMap characters, int depth, FLAVersion flaVersion, HashMap files) { - StringBuilder ret = new StringBuilder(); - prevStr += ""; - int frame = -1; - String elements = ""; - String lastElements = ""; - - int duration = 1; - - CharacterTag character = null; - MATRIX matrix = null; - String instanceName = null; - ColorTransform colorTransForm = null; - boolean cacheAsBitmap = false; - int blendMode = 0; - List filters = new ArrayList<>(); - boolean isVisible = true; - RGBA backGroundColor = null; - CLIPACTIONS clipActions = null; - int characterId = -1; - int ratio = -1; - boolean shapeTween = false; - boolean lastShapeTween = false; - MorphShapeTag shapeTweener = null; - - for (Tag t : timelineTags) { - if (t instanceof PlaceObjectTypeTag) { - PlaceObjectTypeTag po = (PlaceObjectTypeTag) t; - if (po.getDepth() == depth) { - int newCharId = po.getCharacterId(); - if (newCharId == -1) { - newCharId = characterId; - } - characterId = newCharId; - if (characters.containsKey(characterId)) { - character = characters.get(characterId); - if (po.flagMove()) { - MATRIX matrix2 = po.getMatrix(); - if (matrix2 != null) { - matrix = matrix2; - } - String instanceName2 = po.getInstanceName(); - if (instanceName2 != null) { - instanceName = instanceName2; - } - ColorTransform colorTransForm2 = po.getColorTransform(); - if (colorTransForm2 != null) { - colorTransForm = colorTransForm2; - } - - CLIPACTIONS clipActions2 = po.getClipActions(); - if (clipActions2 != null) { - clipActions = clipActions2; - } - if (po.cacheAsBitmap()) { - cacheAsBitmap = true; - } - int blendMode2 = po.getBlendMode(); - if (blendMode2 > 0) { - blendMode = blendMode2; - } - List filters2 = po.getFilters(); - if (filters2 != null) { - filters = filters2; - } - int ratio2 = po.getRatio(); - if (ratio2 > -1) { - ratio = ratio2; - } - } else { - matrix = po.getMatrix(); - instanceName = po.getInstanceName(); - colorTransForm = po.getColorTransform(); - cacheAsBitmap = po.cacheAsBitmap(); - blendMode = po.getBlendMode(); - filters = po.getFilters(); - ratio = po.getRatio(); - clipActions = po.getClipActions(); - } - - } - } - } - - if (t instanceof RemoveTag) { - RemoveTag rt = (RemoveTag) t; - if (rt.getDepth() == depth) { - if (shapeTween && character != null) { - MorphShapeTag m = (MorphShapeTag) character; - shapeTweener = m; - shapeTween = false; - } - character = null; - matrix = null; - instanceName = null; - colorTransForm = null; - cacheAsBitmap = false; - blendMode = 0; - filters = new ArrayList<>(); - isVisible = true; - backGroundColor = null; - characterId = -1; - clipActions = null; - } - } - - if (t instanceof ShowFrameTag) { - elements = ""; - - if ((character instanceof ShapeTag) && (nonLibraryShapes.contains(characterId) || shapeTweener != null)) { - ShapeTag shape = (ShapeTag) character; - elements += convertShape(characters, matrix, shape.getShapeNum(), shape.getShapes().shapeRecords, shape.getShapes().fillStyles, shape.getShapes().lineStyles, false, false); - shapeTween = false; - shapeTweener = null; - } else if (character != null) { - if (character instanceof MorphShapeTag) { - MorphShapeTag m = (MorphShapeTag) character; - elements += convertShape(characters, matrix, 3, m.getStartEdges().shapeRecords, m.getFillStyles().getStartFillStyles(), m.getLineStyles().getStartLineStyles(m.getShapeNum()), true, false); - shapeTween = true; - } else { - shapeTween = false; - if (character instanceof TextTag) { - elements += convertText(instanceName, (TextTag) character, matrix, filters, clipActions); - } else if (character instanceof DefineVideoStreamTag) { - elements += convertVideoInstance(instanceName, matrix, (DefineVideoStreamTag) character, clipActions); - } else { - elements += convertSymbolInstance(instanceName, matrix, colorTransForm, cacheAsBitmap, blendMode, filters, isVisible, backGroundColor, clipActions, character, characters, tags, flaVersion); - } - } - } - - frame++; - if (!elements.equals(lastElements) && frame > 0) { - ret.append(convertFrame(lastShapeTween, characters, tags, null, null, frame - duration, duration, "", lastElements, files)); - duration = 1; - } else if (frame == 0) { - duration = 1; - } else { - duration++; - } - - lastShapeTween = shapeTween; - lastElements = elements; - } - } - if (!lastElements.isEmpty()) { - frame++; - ret.append(convertFrame(lastShapeTween, characters, tags, null, null, (frame - duration < 0 ? 0 : frame - duration), duration, "", lastElements, files)); - } - afterStr = "" + afterStr; - String retStr = ret.toString(); - if (!retStr.isEmpty()) { - retStr = prevStr + retStr + afterStr; - } - return retStr; - } - - public static String convertFonts(List tags) { - StringBuilder ret = new StringBuilder(); - for (Tag t : tags) { - if (t instanceof FontTag) { - FontTag font = (FontTag) t; - int fontId = font.getFontId(); - String fontName = null; - for (Tag t2 : tags) { - if (t2 instanceof DefineFontNameTag) { - if (((DefineFontNameTag) t2).fontId == fontId) { - fontName = ((DefineFontNameTag) t2).fontName; - } - } - } - if (fontName == null) { - fontName = font.getFontNameIntag(); - } - int fontStyle = font.getFontStyle(); - String installedFont; - if ((installedFont = FontTag.isFontFamilyInstalled(fontName)) != null) { - fontName = new Font(installedFont, fontStyle, 10).getPSName(); - } - String embedRanges = ""; - - String fontChars = font.getCharacters(tags); - if ("".equals(fontChars)) { - continue; - } - String embeddedCharacters = fontChars; - embeddedCharacters = embeddedCharacters.replace("\u00A0", ""); //nonbreak space - embeddedCharacters = embeddedCharacters.replace(".", ""); - boolean hasAllRanges = false; - for (int r = 0; r < CharacterRanges.rangeCount(); r++) { - int[] codes = CharacterRanges.rangeCodes(r); - boolean hasAllInRange = true; - for (int i = 0; i < codes.length; i++) { - if (!fontChars.contains("" + (char) codes[i])) { - hasAllInRange = false; - break; - } - } - if (hasAllInRange) { - //remove all found characters - for (int i = 0; i < codes.length; i++) { - embeddedCharacters = embeddedCharacters.replace("" + (char) codes[i], ""); - } - if (!"".equals(embedRanges)) { - embedRanges += "|"; - } - embedRanges += (r + 1); - } else { - hasAllRanges = false; - } - } - if (hasAllRanges) { - embedRanges = "9999"; - } - ret.append(""); - } - - } - - String retStr = ret.toString(); - if (!retStr.isEmpty()) { - retStr = "" + retStr + ""; - } - - return retStr; - } - - public static String convertActionScriptLayer(int spriteId, List tags, List timeLineTags, String backgroundColor) { - StringBuilder ret = new StringBuilder(); - - String script = ""; - int duration = 0; - int frame = 0; - for (Tag t : tags) { - if (t instanceof DoInitActionTag) { - DoInitActionTag dia = (DoInitActionTag) t; - if (dia.spriteId == spriteId) { - script += convertActionScript(dia); - } - } - } - if (!script.isEmpty()) { - script = "#initclip\r\n" + script + "#endinitclip\r\n"; - } - for (Tag t : timeLineTags) { - if (t instanceof DoActionTag) { - DoActionTag da = (DoActionTag) t; - script += convertActionScript(da); - } - if (t instanceof ShowFrameTag) { - - if (script.isEmpty()) { - duration++; - } else { - if (duration > 0) { - ret.append(" 1) { - ret.append(" duration=\"").append(duration).append("\""); - } - ret.append(" keyMode=\"").append(KEY_MODE_NORMAL).append("\">"); - ret.append(""); - ret.append(""); - ret.append(""); - } - ret.append(""); - ret.append(""); - ret.append(""); - ret.append(""); - ret.append(""); - script = ""; - duration = 0; - } - frame++; - } - } - String retStr = ret.toString(); - if (!retStr.isEmpty()) { - retStr = "" - + "" - + retStr - + "" - + ""; - } - return retStr; - } - - public static String convertLabelsLayer(int spriteId, List tags, List timeLineTags, String backgroundColor) { - StringBuilder ret = new StringBuilder(); - int duration = 0; - int frame = 0; - String frameLabel = ""; - boolean isAnchor = false; - for (Tag t : timeLineTags) { - if (t instanceof FrameLabelTag) { - FrameLabelTag fl = (FrameLabelTag) t; - frameLabel = fl.getLabelName(); - isAnchor = fl.isNamedAnchor(); - } - if (t instanceof ShowFrameTag) { - - if (frameLabel.isEmpty()) { - duration++; - } else { - if (duration > 0) { - ret.append(" 1) { - ret.append(" duration=\"").append(duration).append("\""); - } - ret.append(" keyMode=\"").append(KEY_MODE_NORMAL).append("\">"); - ret.append(""); - ret.append(""); - ret.append(""); - } - ret.append(""); - ret.append(""); - ret.append(""); - ret.append(""); - frameLabel = ""; - duration = 0; - } - frame++; - } - } - String retStr = ret.toString(); - if (!retStr.isEmpty()) { - retStr = "" - + "" - + retStr - + "" - + ""; - } - return retStr; - } - - public static String convertSoundLayer(int layerIndex, String backgroundColor, HashMap characters, List tags, List timeLineTags, HashMap files) { - StringBuilder ret = new StringBuilder(); - StartSoundTag lastStartSound = null; - SoundStreamHeadTypeTag lastSoundStreamHead = null; - StartSoundTag startSound = null; - SoundStreamHeadTypeTag soundStreamHead = null; - int duration = 1; - int frame = 0; - for (Tag t : timeLineTags) { - if (t instanceof StartSoundTag) { - startSound = (StartSoundTag) t; - - for (Tag ta : tags) { - if (ta instanceof DefineSoundTag) { - DefineSoundTag s = (DefineSoundTag) ta; - if (s.soundId == startSound.soundId) { - if (!files.containsKey("sound" + s.soundId + "." + s.getExportFormat())) { //Sound was not exported - startSound = null; // ignore - } - break; - } - } - } - - } - if (t instanceof SoundStreamHeadTypeTag) { - soundStreamHead = (SoundStreamHeadTypeTag) t; - if (!files.containsKey("sound" + soundStreamHead.getCharacterId() + "." + soundStreamHead.getExportFormat())) { //Sound was not exported - soundStreamHead = null; // ignore - } - } - if (t instanceof ShowFrameTag) { - if (soundStreamHead != null || startSound != null) { - if (lastSoundStreamHead != null || lastStartSound != null) { - ret.append(convertFrame(false, characters, tags, lastSoundStreamHead, lastStartSound, frame, duration, "", "", files)); - } - frame += duration; - duration = 1; - lastSoundStreamHead = soundStreamHead; - lastStartSound = startSound; - soundStreamHead = null; - startSound = null; - } else { - duration++; - } - } - } - if (lastSoundStreamHead != null || lastStartSound != null) { - if (frame < 0) { - frame = 0; - duration = 1; - } - ret.append(convertFrame(false, characters, tags, lastSoundStreamHead, lastStartSound, frame, duration, "", "", files)); - } - String retStr = ret.toString(); - if (!retStr.isEmpty()) { - retStr = "" - + "" + retStr + "" - + ""; - } - return retStr; - } - - private static String randomOutlineColor() { - RGB outlineColor = new RGB(); - do { - outlineColor.red = random.nextInt(256); - outlineColor.green = random.nextInt(256); - outlineColor.blue = random.nextInt(256); - } while ((outlineColor.red + outlineColor.green + outlineColor.blue) / 3 < 128); - return outlineColor.toHexRGB(); - } - - public static String convertTimeline(int spriteId, List nonLibraryShapes, String backgroundColor, List tags, List timelineTags, HashMap characters, String name, FLAVersion flaVersion, HashMap files) { - StringBuilder ret = new StringBuilder(); - ret.append(""); - ret.append(""); - - String labelsLayer = convertLabelsLayer(spriteId, tags, timelineTags, backgroundColor); - ret.append(labelsLayer); - String scriptLayer = convertActionScriptLayer(spriteId, tags, timelineTags, backgroundColor); - ret.append(scriptLayer); - - int index = 0; - - if (!labelsLayer.isEmpty()) { - index++; - } - - if (!scriptLayer.isEmpty()) { - index++; - } - - int layerCount = getLayerCount(timelineTags); - Stack parentLayers = new Stack<>(); - - for (int d = layerCount; d >= 1; d--, index++) { - for (Tag t : timelineTags) { - if (t instanceof PlaceObjectTypeTag) { - PlaceObjectTypeTag po = (PlaceObjectTypeTag) t; - if (po.getClipDepth() == d) { - for (int m = po.getDepth(); m < po.getClipDepth(); m++) { - parentLayers.push(index); - } - - ret.append(""); - ret.append(convertFrames("", "", nonLibraryShapes, tags, timelineTags, characters, po.getDepth(), flaVersion, files)); - ret.append(""); - index++; - break; - } - } - } - - boolean hasClipDepth = false; - for (Tag t : timelineTags) { - if (t instanceof PlaceObjectTypeTag) { - PlaceObjectTypeTag po = (PlaceObjectTypeTag) t; - if (po.getDepth() == d) { - if (po.getClipDepth() != -1) { - hasClipDepth = true; - break; - } - } - } - } - if (hasClipDepth) { - index--; - continue; - } - int parentLayer = -1; - if (!parentLayers.isEmpty()) { - parentLayer = parentLayers.pop(); - } - String layerPrev = ""; - - layerPrev += ""); - ret.append(""); - return ret.toString(); - } - - private static void writeFile(AbortRetryIgnoreHandler handler, final byte[] data, final String file) throws IOException { - new RetryTask(() -> { - try (FileOutputStream fos = new FileOutputStream(file)) { - fos.write(data); - } - }, handler).run(); - } - - private static Map getCharacterClasses(List tags) { - Map ret = new HashMap<>(); - for (Tag t : tags) { - if (t instanceof SymbolClassTag) { - SymbolClassTag sc = (SymbolClassTag) t; - for (int i = 0; i < sc.tags.size(); i++) { - if (!ret.containsKey(sc.tags.get(i)) && !ret.containsValue(sc.names.get(i))) { - ret.put(sc.tags.get(i), sc.names.get(i)); - } - } - } - } - return ret; - } - - private static Map getCharacterVariables(List tags) { - Map ret = new HashMap<>(); - for (Tag t : tags) { - if (t instanceof ExportAssetsTag) { - ExportAssetsTag ea = (ExportAssetsTag) t; - for (int i = 0; i < ea.tags.size(); i++) { - if (!ret.containsKey(ea.tags.get(i))) { - ret.put(ea.tags.get(i), ea.names.get(i)); - } - } - } - } - return ret; - } - - public static String convertText(String instanceName, TextTag tag, MATRIX m, List filters, CLIPACTIONS clipActions) { - StringBuilder ret = new StringBuilder(); - - if (m == null) { - m = new MATRIX(); - } - Matrix matrix = new Matrix(m); - CSMTextSettingsTag csmts = null; - String filterStr = ""; - if (filters != null) { - filterStr += ""; - for (FILTER f : filters) { - filterStr += convertFilter(f); - } - filterStr += ""; - } - - SWF swf = tag.getSwf(); - for (Tag t : swf.tags) { - if (t instanceof CSMTextSettingsTag) { - CSMTextSettingsTag c = (CSMTextSettingsTag) t; - if (c.textID == tag.getCharacterId()) { - csmts = c; - break; - } - } - } - - String fontRenderingMode = "standard"; - String antiAlias = ""; - if (csmts != null) { - if (csmts.thickness == 0 & csmts.sharpness == 0) { - fontRenderingMode = null; - } else { - fontRenderingMode = "customThicknessSharpness"; - } - antiAlias = " antiAliasSharpness=\"" + doubleToString(csmts.sharpness) + "\" antiAliasThickness=\"" + doubleToString(csmts.thickness) + "\""; - } - String matStr = ""; - matStr += ""; - String left = ""; - RECT bounds = tag.getBounds(); - if ((tag instanceof DefineTextTag) || (tag instanceof DefineText2Tag)) { - MATRIX textMatrix = tag.getTextMatrix(); - left = " left=\"" + doubleToString((textMatrix.translateX) / SWF.unitDivisor) + "\""; - } - matStr += convertMatrix(matrix); - matStr += ""; - if ((tag instanceof DefineTextTag) || (tag instanceof DefineText2Tag)) { - List textRecords = new ArrayList<>(); - if (tag instanceof DefineTextTag) { - textRecords = ((DefineTextTag) tag).textRecords; - } else if (tag instanceof DefineText2Tag) { - textRecords = ((DefineText2Tag) tag).textRecords; - } - - for (TEXTRECORD rec : textRecords) { - if (rec.styleFlagsHasFont) { - FontTag ft = swf.getFont(rec.fontId); - if (ft != null && ft.isSmall()) { - fontRenderingMode = "bitmap"; - break; - } - } - } - - ret.append(" attrs = TextTag.getTextRecordsAttributes(textRecords, swf); - - ret.append(" width=\"").append(tag.getBounds().getWidth() / 2).append("\" height=\"").append(tag.getBounds().getHeight()).append("\" autoExpand=\"true\" isSelectable=\"false\">"); - ret.append(matStr); - - ret.append(""); - int fontId = -1; - FontTag font = null; - String fontName = null; - String psFontName = null; - int textHeight = -1; - RGB textColor = null; - RGBA textColorA = null; - boolean newline = false; - boolean firstRun = true; - @SuppressWarnings("unchecked") - List leftMargins = (List) attrs.get("allLeftMargins"); - @SuppressWarnings("unchecked") - List letterSpacings = (List) attrs.get("allLetterSpacings"); - for (int r = 0; r < textRecords.size(); r++) { - TEXTRECORD rec = textRecords.get(r); - if (rec.styleFlagsHasColor) { - if (tag instanceof DefineTextTag) { - textColor = rec.textColor; - } else { - textColorA = rec.textColorA; - } - } - if (rec.styleFlagsHasFont) { - fontId = rec.fontId; - fontName = null; - textHeight = rec.textHeight; - font = swf.getFont(fontId); - for (Tag t : swf.tags) { - if (t instanceof DefineFontNameTag) { - if (((DefineFontNameTag) t).fontId == fontId) { - fontName = ((DefineFontNameTag) t).fontName; - } - } - } - if ((fontName == null) && (font != null)) { - fontName = font.getFontNameIntag(); - } - int fontStyle = 0; - if (font != null) { - fontStyle = font.getFontStyle(); - } - String installedFont; - if ((installedFont = FontTag.isFontFamilyInstalled(fontName)) != null) { - psFontName = new Font(installedFont, fontStyle, 10).getPSName(); - } else { - psFontName = fontName; - } - } - newline = false; - if (!firstRun && rec.styleFlagsHasYOffset) { - newline = true; - } - firstRun = false; - if (font != null) { - ret.append(""); - ret.append("").append(xmlString((newline ? "\r" : "") + rec.getText(font))).append(""); - ret.append(""); - - ret.append(""); - - ret.append(""); - ret.append(""); - } - } - ret.append(""); - ret.append(filterStr); - ret.append(""); - } else if (tag instanceof DefineEditTextTag) { - DefineEditTextTag det = (DefineEditTextTag) tag; - String tagName; - FontTag ft = swf.getFont(det.fontId); - if (ft != null && ft.isSmall()) { - fontRenderingMode = "bitmap"; - } - if (!det.useOutlines) { - fontRenderingMode = "device"; - } - if (det.wasStatic) { - tagName = "DOMStaticText"; - } else if (det.readOnly) { - tagName = "DOMDynamicText"; - } else { - tagName = "DOMInputText"; - } - ret.append("<").append(tagName); - if (fontRenderingMode != null) { - ret.append(" fontRenderingMode=\"").append(fontRenderingMode).append("\""); - } - if (instanceName != null) { - ret.append(" name=\"").append(xmlString(instanceName)).append("\""); - } - ret.append(antiAlias); - double width = twipToPixel(bounds.getWidth()); - double height = twipToPixel(bounds.getHeight()); - //There is usually 4px difference between width/height and XML width/height - //If somebody knows what that means, tell me - double padding = 2; - width -= 2 * padding; - height -= 2 * padding; - if (det.hasLayout) { - width -= twipToPixel(det.rightMargin); - width -= twipToPixel(det.leftMargin); - } - ret.append(" width=\"").append(width).append("\""); - ret.append(" height=\"").append(height).append("\""); - if (det.border) { - ret.append(" border=\"true\""); - } - if (det.html) { - ret.append(" renderAsHTML=\"true\""); - } - if (det.noSelect) { - ret.append(" isSelectable=\"false\""); - } - if (det.multiline && det.wordWrap) { - ret.append(" lineType=\"multiline\""); - } else if (det.multiline && (!det.wordWrap)) { - ret.append(" lineType=\"multiline no wrap\""); - } else if (det.password) { - ret.append(" lineType=\"password\""); - } - if (det.hasMaxLength) { - ret.append(" maxCharacters=\"").append(det.maxLength).append("\""); - } - if (!det.variableName.isEmpty()) { - ret.append(" variableName=\"").append(det.variableName).append("\""); - } - ret.append(">"); - ret.append(matStr); - ret.append(""); - String txt = ""; - if (det.hasText) { - txt = det.initialText; - } - - if (det.html) { - ret.append(convertHTMLText(swf.tags, det, txt)); - } else { - ret.append(""); - ret.append("").append(xmlString(txt)).append(""); - int leftMargin = -1; - int rightMargin = -1; - int indent = -1; - int lineSpacing = -1; - String alignment = null; - boolean italic = false; - boolean bold = false; - String fontFace = null; - int size = -1; - RGBA textColor = null; - if (det.hasTextColor) { - textColor = det.textColor; - } - if (det.hasFont) { - String fontName = null; - for (Tag u : swf.tags) { - if (u instanceof DefineFontNameTag) { - if (((DefineFontNameTag) u).fontId == det.fontId) { - fontName = ((DefineFontNameTag) u).fontName; - } - } - if (fontName != null && ft != null) { - break; - } - } - if (ft != null) { - if (fontName == null) { - fontName = ft.getFontNameIntag(); - } - italic = ft.isItalic(); - bold = ft.isBold(); - size = det.fontHeight; - fontFace = fontName; - String installedFont = null; - if ((installedFont = FontTag.isFontFamilyInstalled(fontName)) != null) { - fontName = installedFont; - fontFace = new Font(installedFont, (italic ? Font.ITALIC : 0) | (bold ? Font.BOLD : 0) | (!italic && !bold ? Font.PLAIN : 0), size < 0 ? 10 : size).getPSName(); - } - - } - } - if (det.hasLayout) { - leftMargin = det.leftMargin; - rightMargin = det.rightMargin; - indent = det.indent; - lineSpacing = det.leading; - String[] alignNames = {"left", "right", "center", "justify"}; - if (det.align < alignNames.length) { - alignment = alignNames[det.align]; - } else { - alignment = "unknown"; - } - } - ret.append(""); - ret.append(" -1) { - ret.append(" indent=\"").append(twipToPixel(indent)).append("\""); - } - if (leftMargin > -1) { - ret.append(" leftMargin=\"").append(twipToPixel(leftMargin)).append("\""); - } - if (lineSpacing > -1) { - ret.append(" lineSpacing=\"").append(twipToPixel(lineSpacing)).append("\""); - } - if (rightMargin > -1) { - ret.append(" rightMargin=\"").append(twipToPixel(rightMargin)).append("\""); - } - if (size > -1) { - ret.append(" size=\"").append(twipToPixel(size)).append("\""); - ret.append(" bitmapSize=\"").append(size).append("\""); - } - if (fontFace != null) { - ret.append(" face=\"").append(fontFace).append("\""); - } - if (textColor != null) { - ret.append(" fillColor=\"").append(textColor.toHexRGB()).append("\" alpha=\"").append(textColor.getAlphaFloat()).append("\""); - } - ret.append("/>"); - ret.append(""); - ret.append(""); - } - ret.append(""); - ret.append(filterStr); - ret.append(""); - } - return ret.toString(); - } - - public static void convertSWF(AbortRetryIgnoreHandler handler, SWF swf, String swfFileName, String outfile, boolean compressed, String generator, String generatorVerName, String generatorVersion, boolean parallel, FLAVersion flaVersion) throws IOException { - - FileAttributesTag fa = swf.getFileAttributes(); - - boolean useAS3 = false; - boolean useNetwork = false; - if (fa != null) { - useAS3 = fa.actionScript3; - useNetwork = fa.useNetwork; - } - - if (!useAS3 && flaVersion.minASVersion() > 2) { - throw new IllegalArgumentException("FLA version " + flaVersion + " does not support AS1/2"); - } - File file = new File(outfile); - File outDir = file.getParentFile(); - Path.createDirectorySafe(outDir); - StringBuilder domDocument = new StringBuilder(); - String baseName = swfFileName; - File f = new File(baseName); - baseName = f.getName(); - if (baseName.contains(".")) { - baseName = baseName.substring(0, baseName.lastIndexOf('.')); - } - final HashMap files = new HashMap<>(); - final HashMap datfiles = new HashMap<>(); - HashMap characters = getCharacters(swf.tags); - List nonLibraryShapes = getNonLibraryShapes(swf.tags, characters); - Map characterClasses = getCharacterClasses(swf.tags); - Map characterVariables = getCharacterVariables(swf.tags); - - String backgroundColor = "#ffffff"; - for (Tag t : swf.tags) { - if (t instanceof SetBackgroundColorTag) { - SetBackgroundColorTag sbc = (SetBackgroundColorTag) t; - backgroundColor = sbc.backgroundColor.toHexRGB(); - } - } - domDocument.append(""); - domDocument.append(convertFonts(swf.tags)); - domDocument.append(convertLibrary(swf, characterVariables, characterClasses, nonLibraryShapes, backgroundColor, swf.tags, characters, files, datfiles, flaVersion)); - domDocument.append(""); - domDocument.append(convertTimeline(0, nonLibraryShapes, backgroundColor, swf.tags, swf.tags, characters, "Scene 1", flaVersion, files)); - domDocument.append(""); - domDocument.append(""); - String domDocumentStr = prettyFormatXML(domDocument.toString()); - - for (Tag t : swf.tags) { - if (t instanceof DoInitActionTag) { - DoInitActionTag dia = (DoInitActionTag) t; - int chid = dia.getCharacterId(); - if (characters.containsKey(chid)) { - if (characters.get(chid) instanceof DefineSpriteTag) { - DefineSpriteTag sprite = (DefineSpriteTag) characters.get(chid); - if (sprite.subTags.isEmpty()) { - String data = convertActionScript(dia); - String expName = dia.getSwf().getExportName(dia.spriteId); - expName = expName != null ? expName : "_unk_"; - String expPath = expName; - final String prefix = "__Packages."; - if (expPath.startsWith(prefix)) { - expPath = expPath.substring(prefix.length()); - } - String expDir = ""; - if (expPath.contains(".")) { - expDir = expPath.substring(0, expPath.lastIndexOf('.')); - expDir = expDir.replace(".", File.separator); - } - expPath = expPath.replace(".", File.separator); - File cdir = new File(outDir.getAbsolutePath() + File.separator + expDir); - Path.createDirectorySafe(cdir); - writeFile(handler, Utf8Helper.getBytes(data), outDir.getAbsolutePath() + File.separator + expPath + ".as"); - } - } - } - } - } - - int flaSwfVersion = swf.version > flaVersion.maxSwfVersion() ? flaVersion.maxSwfVersion() : swf.version; - boolean greaterThanCC = flaVersion.ordinal() >= FLAVersion.CC.ordinal(); - StringBuilder publishSettings = new StringBuilder(); - publishSettings.append("\n"); - publishSettings.append("\n"); - publishSettings.append(" \n"); - publishSettings.append(" 1\n"); - publishSettings.append(" 1\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 1\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 0\n"); - publishSettings.append(greaterThanCC ? " 0\n" : " 0\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 1\n"); - publishSettings.append(" 1\n"); - publishSettings.append(" 1\n"); - publishSettings.append(" 1\n"); - publishSettings.append(" 1\n"); - publishSettings.append(" 1\n"); - publishSettings.append(" 1\n"); - publishSettings.append(greaterThanCC ? " 1\n" : " 1\n"); - publishSettings.append(" 1\n"); - publishSettings.append(" 1\n"); - publishSettings.append(" ").append(baseName).append(".swf\n"); - publishSettings.append(" ").append(baseName).append(".exe\n"); - publishSettings.append(" ").append(baseName).append(".app\n"); - publishSettings.append(" ").append(baseName).append(".html\n"); - publishSettings.append(" ").append(baseName).append(".gif\n"); - publishSettings.append(" ").append(baseName).append(".jpg\n"); - publishSettings.append(" ").append(baseName).append(".png\n"); - publishSettings.append(greaterThanCC ? " 1\n" : " 1\n"); - publishSettings.append(" ").append(baseName).append(".smil\n"); - publishSettings.append(" ").append(baseName).append(".swc\n"); - publishSettings.append(" \n"); - publishSettings.append(" \n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 12,0,0,0;11,2,0,0;11,1,0,0;10,3,0,0;10,2,153,0;10,1,52,0;9,0,124,0;8,0,24,0;7,0,14,0;6,0,79,0;5,0,58,0;4,0,32,0;3,0,8,0;2,0,1,12;1,0,0,1;\n"); - publishSettings.append(" 1\n"); - publishSettings.append(" 1\n"); - publishSettings.append(" ").append(baseName).append("_content.html\n"); - publishSettings.append(" ").append(baseName).append("_alternate.html\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" \n"); - publishSettings.append(" ").append(width).append("\n"); - publishSettings.append(" ").append(height).append("\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 1\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 1\n"); - publishSettings.append(" 1\n"); - publishSettings.append(" 4\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 1\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" \n"); - publishSettings.append(" 1\n"); - publishSettings.append(" \n"); - publishSettings.append(" \n"); - publishSettings.append(" \n"); - publishSettings.append(" \n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 80\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 7\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 7\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" ").append(flaSwfVersion).append("\n"); - publishSettings.append(" ").append(FLAVersion.swfVersionToPlayer(flaSwfVersion)).append("\n"); - publishSettings.append(" ").append(useAS3 ? "3" : "2").append("\n"); - publishSettings.append(" 1\n"); - publishSettings.append(" \n"); - publishSettings.append(" .\n"); - publishSettings.append(" CONFIG::FLASH_AUTHORING="true";\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" \n"); - publishSettings.append(" ").append(swf.compression == SWFCompression.NONE ? "0" : "1").append("\n"); - publishSettings.append(" ").append(swf.compression == SWFCompression.LZMA ? "1" : "0").append("\n"); - publishSettings.append(" 1\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" ").append(useNetwork ? 1 : 0).append("\n"); - publishSettings.append(" ").append(xmlString(characterClasses.containsKey(0) ? characterClasses.get(0) : "")).append("\n"); - publishSettings.append(" 2\n"); - publishSettings.append(" 4\n"); - publishSettings.append(" 4096\n"); - publishSettings.append(" AS3\n"); - publishSettings.append(" 1\n"); - publishSettings.append(" 1\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 15\n"); - publishSettings.append(" 1\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 4102\n"); - publishSettings.append(" rsl\n"); - publishSettings.append(" wrap\n"); - publishSettings.append(" $(AppConfig)/ActionScript 3.0/rsls/loader_animation.swf\n"); - if (greaterThanCC) { - publishSettings.append(" \n"); - publishSettings.append(" \n"); - publishSettings.append(" $(AppConfig)/ActionScript 3.0/libs\n"); - publishSettings.append(" merge\n"); - publishSettings.append(" \n"); - publishSettings.append(" \n"); - publishSettings.append(" $(FlexSDK)/frameworks/libs/flex.swc\n"); - publishSettings.append(" merge\n"); - publishSettings.append(" textLayout_2.0.0.232.swz\n"); - publishSettings.append(" \n"); - publishSettings.append(" \n"); - publishSettings.append(" $(FlexSDK)/frameworks/libs/core.swc\n"); - publishSettings.append(" merge\n"); - publishSettings.append(" textLayout_2.0.0.232.swz\n"); - publishSettings.append(" \n"); - publishSettings.append(" \n"); - publishSettings.append(" \n"); - publishSettings.append(" "); - } else { - publishSettings.append(" \n"); - publishSettings.append(" \n"); - publishSettings.append(" $(AppConfig)/ActionScript 3.0/libs\n"); - publishSettings.append(" merge\n"); - publishSettings.append(" \n"); - publishSettings.append(" \n"); - publishSettings.append(" $(AppConfig)/ActionScript 3.0/libs/11.0/textLayout.swc\n"); - publishSettings.append(" rsl\n"); - publishSettings.append(" http://fpdownload.adobe.com/pub/swz/tlf/2.0.0.232/textLayout_2.0.0.232.swz\n"); - publishSettings.append(" http://fpdownload.adobe.com/pub/swz/crossdomain.xml\n"); - publishSettings.append(" textLayout_2.0.0.232.swz\n"); - publishSettings.append(" \n"); - publishSettings.append(" \n"); - publishSettings.append(" \n"); - publishSettings.append(" \n"); - publishSettings.append(" $(AppConfig)/ActionScript 3.0/libs/11.0/textLayout.swc\n"); - publishSettings.append(" \n"); - publishSettings.append(" http://fpdownload.adobe.com/pub/swz/tlf/2.0.0.232/textLayout_2.0.0.232.swz\n"); - publishSettings.append(" http://fpdownload.adobe.com/pub/swz/crossdomain.xml\n"); - publishSettings.append(" textLayout_2.0.0.232.swz\n"); - publishSettings.append(" \n"); - publishSettings.append(" \n"); - } - publishSettings.append(" \n"); - publishSettings.append(" \n"); - publishSettings.append(" ").append(width).append("\n"); - publishSettings.append(" ").append(height).append("\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 4718592\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 80\n"); - publishSettings.append(" 1\n"); - publishSettings.append(" \n"); - publishSettings.append(" \n"); - publishSettings.append(" 1\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 1\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 100000\n"); - publishSettings.append(" 1\n"); - publishSettings.append(" 1\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 1\n"); - publishSettings.append(" \n"); - publishSettings.append(" \n"); - publishSettings.append(" ").append(width).append("\n"); - publishSettings.append(" ").append(height).append("\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 1\n"); - publishSettings.append(" 1\n"); - publishSettings.append(" \n"); - publishSettings.append(" 1\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 1\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" \n"); - publishSettings.append(" 128\n"); - publishSettings.append(" \n"); - publishSettings.append(" \n"); - publishSettings.append(" 255\n"); - publishSettings.append(" \n"); - publishSettings.append(" \n"); - publishSettings.append(" \n"); - publishSettings.append(" ").append(width).append("\n"); - publishSettings.append(" ").append(height).append("\n"); - publishSettings.append(" 1\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 1\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 1\n"); - publishSettings.append(" \n"); - publishSettings.append(" \n"); - publishSettings.append(" \n"); - publishSettings.append(" 24-bit with Alpha\n"); - publishSettings.append(" 255\n"); - publishSettings.append(" \n"); - publishSettings.append(" \n"); - if (!greaterThanCC) { - publishSettings.append(" \n"); - publishSettings.append(" ").append(width).append("\n"); - publishSettings.append(" ").append(height).append("\n"); - publishSettings.append(" 1\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" \n"); - publishSettings.append(" \n"); - publishSettings.append(" 00000000\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 0\n"); - publishSettings.append(" 1\n"); - publishSettings.append(" \n"); - } - publishSettings.append("\n"); - publishSettings.append(""); - String publishSettingsStr = publishSettings.toString(); - - if (compressed) { - final String domDocumentF = domDocumentStr; - final String publishSettingsF = publishSettingsStr; - final String outfileF = outfile; - new RetryTask(() -> { - try (ZipOutputStream out = new ZipOutputStream(new FileOutputStream(outfileF))) { - out.putNextEntry(new ZipEntry("DOMDocument.xml")); - out.write(Utf8Helper.getBytes(domDocumentF)); - out.putNextEntry(new ZipEntry("PublishSettings.xml")); - out.write(Utf8Helper.getBytes(publishSettingsF)); - for (String fileName : files.keySet()) { - out.putNextEntry(new ZipEntry("LIBRARY/" + fileName)); - out.write(files.get(fileName)); - } - for (String fileName : datfiles.keySet()) { - out.putNextEntry(new ZipEntry("bin/" + fileName)); - out.write(datfiles.get(fileName)); - } - } - }, handler).run(); - - } else { - Path.createDirectorySafe(outDir); - writeFile(handler, Utf8Helper.getBytes(domDocumentStr), outDir.getAbsolutePath() + File.separator + "DOMDocument.xml"); - writeFile(handler, Utf8Helper.getBytes(publishSettingsStr), outDir.getAbsolutePath() + File.separator + "PublishSettings.xml"); - File libraryDir = new File(outDir.getAbsolutePath() + File.separator + "LIBRARY"); - libraryDir.mkdir(); - File binDir = new File(outDir.getAbsolutePath() + File.separator + "bin"); - binDir.mkdir(); - for (String fileName : files.keySet()) { - writeFile(handler, files.get(fileName), libraryDir.getAbsolutePath() + File.separator + fileName); - } - for (String fileName : datfiles.keySet()) { - writeFile(handler, datfiles.get(fileName), binDir.getAbsolutePath() + File.separator + fileName); - } - writeFile(handler, Utf8Helper.getBytes("PROXY-CS5"), outfile); - } - if (useAS3) { - try { - ScriptExportSettings scriptExportSettings = new ScriptExportSettings(ScriptExportMode.AS, false); - swf.exportActionScript(handler, Path.combine(outDir.getAbsolutePath(), "scripts"), scriptExportSettings, parallel, null); - } catch (Exception ex) { - Logger.getLogger(XFLConverter.class.getName()).log(Level.SEVERE, "Error during ActionScript3 export", ex); - } - } - } - - private static int normHue(double h) { - if (Double.isNaN(h)) { - h = -Math.PI; - } - int ret = (int) Math.round(h * 180 / Math.PI); - while (ret > 180) { - ret -= 360; - } - while (ret < -180) { - ret += 360; - } - return ret; - } - - private static int normBrightness(double b) { - if (Double.isNaN(b)) { - b = -100; - } - return (int) Math.round(b); - } - - private static int normSaturation(double s) { - if (Double.isNaN(s)) { - return -100; - } else if (s == 1) { - return 0; - } else if (s - 1 < 0) { - return (int) Math.round((s - 1) * 100); - } else { - return (int) Math.round(((s - 1) * 100) / 3); - } - } - - private static int normContrast(double c) { - double[] ctrMap = { - // 0 1 2 3 4 5 6 7 8 9 - /*0*/0, 0.01, 0.02, 0.04, 0.05, 0.06, 0.07, 0.08, 0.1, 0.11, - /*1*/ 0.12, 0.14, 0.15, 0.16, 0.17, 0.18, 0.20, 0.21, 0.22, 0.24, - /*2*/ 0.25, 0.27, 0.28, 0.30, 0.32, 0.34, 0.36, 0.38, 0.40, 0.42, - /*3*/ 0.44, 0.46, 0.48, 0.5, 0.53, 0.56, 0.59, 0.62, 0.65, 0.68, - /*4*/ 0.71, 0.74, 0.77, 0.80, 0.83, 0.86, 0.89, 0.92, 0.95, 0.98, - /*5*/ 1.0, 1.06, 1.12, 1.18, 1.24, 1.30, 1.36, 1.42, 1.48, 1.54, - /*6*/ 1.60, 1.66, 1.72, 1.78, 1.84, 1.90, 1.96, 2.0, 2.12, 2.25, - /*7*/ 2.37, 2.50, 2.62, 2.75, 2.87, 3.0, 3.2, 3.4, 3.6, 3.8, - /*8*/ 4.0, 4.3, 4.7, 4.9, 5.0, 5.5, 6.0, 6.5, 6.8, 7.0, - /*9*/ 7.3, 7.5, 7.8, 8.0, 8.4, 8.7, 9.0, 9.4, 9.6, 9.8, - /*10*/ 10.0}; - if (c == 127) { - return 0; - } else if (c - 127 < 0) { - return (int) Math.round((c - 127) * 100.0 / 127.0); - } else { - c = (c - 127) / 127; - for (int i = 0; i < ctrMap.length; i++) { - if (ctrMap[i] >= c) { - return i; - } - } - } - return ctrMap.length - 1; - } - - private static boolean sameDouble(double a, double b) { - final double EPSILON = 0.00001; - return a == b ? true : Math.abs(a - b) < EPSILON; - } - - public static String convertAdjustColorFilter(COLORMATRIXFILTER filter) { - float[][] matrix = new float[5][5]; - int index = 0; - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 5; j++) { - matrix[j][i] = filter.matrix[index]; - index++; - } - } - double a11 = matrix[0][0], a12 = matrix[0][1], a13 = matrix[0][2], - a21 = matrix[1][0], a22 = matrix[1][1], a23 = matrix[1][2], - a31 = matrix[2][0], a32 = matrix[2][1], a33 = matrix[2][2], - a41 = matrix[4][0]; - - double b, c, h, s; - b = (24872168661075.0 * a11 * a11 - 151430415740925.0 * a12 + 341095051289483.0 * a12 * a12 - 15302094789450.0 * a13 + 82428663495404.0 * a12 * a13 - - 4592294873812.0 * a13 * a13 + 43556251470.0 * Math.sqrt(216225 * a11 * a11 + 332369 * a12 * a12 - 397828 * a12 * a13 + 281684 * a13 * a13 - - 930 * a11 * (287 * a12 + 178 * a13)) + 2384730956550.0 * a12 * a41 + 240977870700.0 * a13 * a41 - - 685925220 * Math.sqrt(216225 * a11 * a11 + 332369 * a12 * a12 - 397828 * a12 * a13 + 281684 * a13 * a13 - 930 * a11 * (287 * a12 + 178 * a13)) - * a41 + 465 * a11 * (466201717582.0 * a12 + 55756962908.0 * a13 + 764132175 * (-127 + 2 * a41))) - / (391687695450.0 * a11 * a11 + 5371575610858.0 * a12 * a12 + 1298089188904.0 * a12 * a13 - 72319604312.0 * a13 * a13 - + 1860 * a11 * (1835439833 * a12 + 219515602 * a13)); - c = (127 * (495225 * a11 + 1661845 * a12 + 167930 * a13 - + 478 * Math.sqrt(216225 * a11 * a11 + 332369 * a12 * a12 - 397828 * a12 * a13 + 281684 * a13 * a13 - 930 * a11 * (287 * a12 + 178 * a13)))) - / 717495; - h = 2 * (Math.atan((-465 * a11 + 287 * a12 + 178 * a13 + Math.sqrt(216225 * a11 * a11 + 332369 * a12 * a12 - 397828 * a12 * a13 + 281684 * a13 * a13 - - 930 * a11 * (287 * a12 + 178 * a13))) / (500. * (a12 - a13))) + Math.PI/*+ Pi*C(1)*/); - s = (1543 * (-103355550 * a11 * a11 - 158872382 * a12 * a12 + 190161784 * a12 * a13 - 134644952 * a13 * a13 - + 1661845 * a12 * Math.sqrt(216225 * a11 * a11 + 332369 * a12 * a12 - 397828 * a12 * a13 + 281684 * a13 * a13 - - 930 * a11 * (287 * a12 + 178 * a13)) + 167930 * a13 - * Math.sqrt(216225 * a11 * a11 + 332369 * a12 * a12 - 397828 * a12 * a13 + 281684 * a13 * a13 - 930 * a11 * (287 * a12 + 178 * a13)) - + 465 * a11 * (274372 * a12 + 170168 * a13 + 1065 * Math.sqrt(216225 * a11 * a11 + 332369 * a12 * a12 - 397828 * a12 * a13 - + 281684 * a13 * a13 - 930 * a11 * (287 * a12 + 178 * a13))))) - / (195843847725.0 * a11 * a11 + 2685787805429.0 * a12 * a12 + 649044594452.0 * a12 * a13 - 36159802156.0 * a13 * a13 - + 930 * a11 * (1835439833 * a12 + 219515602 * a13)); - - if (sameDouble(410 * a12, 1543 * a31) && sameDouble(410 * a12, 1543 * a32) && sameDouble(3047 * a12, 1543 * a21) && sameDouble(3047 * a12, 1543 * a23) - && sameDouble(a22, a11 + (1504 * a12) / 1543.) && sameDouble((1133 * a12) / 1543. + a33, a11) - /*&& (b == (195961 * a11 + 439039 * a12 + 1543 * (-127 + 2 * a41)) / (3086 * a11 + 6914 * a12)) - && (c == 127 * a11 + (439039 * a12) / 1543.) && (s == (1543 * (a11 - a12)) / (1543 * a11 + 3457 * a12)) - */ && !sameDouble(a11, a12) && !sameDouble(1543 * a11 + 3457 * a12, 0)) { - h = 0; - } - - return ""; - } - - private static String convertHTMLText(List tags, DefineEditTextTag det, String html) { - HTMLTextParser tparser = new HTMLTextParser(tags, det); - XMLReader parser; - try { - SAXParserFactory factory = SAXParserFactory.newInstance(); - parser = XMLReaderFactory.createXMLReader(); - parser.setContentHandler(tparser); - parser.setErrorHandler(tparser); - html = "\n" - + " \n" - + "]>" + html + ""; - try { - parser.parse(new InputSource(new StringReader(html))); - } catch (SAXParseException spe) { - System.out.println(html); - System.err.println(tparser.result); - } - } catch (SAXException | IOException e) { - Logger.getLogger(XFLConverter.class.getName()).log(Level.SEVERE, "Error while converting HTML", e); - } - return tparser.result; - } - - private static String xmlString(String s) { - return s.replace("<", "<").replace(">", ">").replace("\"", """).replace("&", "&").replace("\r\n", " ").replace("\r", " ").replace("\n", " "); - } - - private static double twipToPixel(double tw) { - return tw / SWF.unitDivisor; - } - - private static class HTMLTextParser extends DefaultHandler { - - public String result = ""; - - private String fontFace = ""; - - private String color = ""; - - private int size = -1; - - private int indent = -1; - - private int leftMargin = -1; - - private int rightMargin = -1; - - private int lineSpacing = -1; - - private double letterSpacing = -1; - - private String alignment = null; - - private final List tags; - - private boolean bold = false; - - private boolean italic = false; - - private boolean underline = false; - - private boolean li = false; - - private String url = null; - - private String target = null; - - @Override - public void error(SAXParseException e) throws SAXException { - } - - @Override - public void fatalError(SAXParseException e) throws SAXException { - } - - @Override - public void warning(SAXParseException e) throws SAXException { - } - - public HTMLTextParser(List tags, DefineEditTextTag det) { - if (det.hasFont) { - String fontName = null; - FontTag ft = null; - for (Tag u : tags) { - if (u instanceof DefineFontNameTag) { - if (((DefineFontNameTag) u).fontId == det.fontId) { - fontName = ((DefineFontNameTag) u).fontName; - } - } - if (u instanceof FontTag) { - if (((FontTag) u).getFontId() == det.fontId) { - ft = (FontTag) u; - } - } - if (fontName != null && ft != null) { - break; - } - } - if (ft != null) { - if (fontName == null) { - fontName = ft.getFontNameIntag(); - } - italic = ft.isItalic(); - bold = ft.isBold(); - size = det.fontHeight; - fontFace = new Font(fontName, (italic ? Font.ITALIC : 0) | (bold ? Font.BOLD : 0) | (!italic && !bold ? Font.PLAIN : 0), size < 0 ? 10 : size).getPSName(); - } - } - if (det.hasLayout) { - leftMargin = det.leftMargin; - rightMargin = det.rightMargin; - indent = det.indent; - lineSpacing = det.leading; - String[] alignNames = {"left", "right", "center", "justify"}; - if (det.align < alignNames.length) { - alignment = alignNames[det.align]; - } else { - alignment = "unknown"; - } - } - this.tags = tags; - } - - @Override - public void startDocument() throws SAXException { - } - - @Override - public void startElement(String uri, String localName, - String qName, Attributes attributes) throws SAXException { - switch (qName) { - case "a": - String href = attributes.getValue("href"); - if (href != null) { - url = href; - } - String t = attributes.getValue("target"); - if (t != null) { - target = t; - } - break; - case "b": - bold = true; - break; - case "i": - italic = true; - break; - case "u": - underline = true; - break; - case "li": - li = true; - break; - case "p": - String a = attributes.getValue("align"); - if (a != null) { - alignment = a; - } - if (!result.isEmpty()) { - putText("\r\n"); - } - break; - case "font": - //kerning ? - String ls = attributes.getValue("letterSpacing"); - if (ls != null) { - letterSpacing = Double.parseDouble(ls); - } - String s = attributes.getValue("size"); - if (s != null) { - size = Integer.parseInt(s); - } - String c = attributes.getValue("color"); - if (c != null) { - color = c; - } - String f = attributes.getValue("face"); - if (f != null) { - for (Tag tag : tags) { - if (tag instanceof FontTag) { - FontTag ft = (FontTag) tag; - String fontName = null; - if (f.equals(ft.getFontNameIntag())) { - for (Tag u : tags) { - if (u instanceof DefineFontNameTag) { - if (((DefineFontNameTag) u).fontId == ft.getFontId()) { - fontName = ((DefineFontNameTag) u).fontName; - } - } - } - if (fontName == null) { - fontName = ft.getFontNameIntag(); - } - String installedFont; - if ((installedFont = FontTag.isFontFamilyInstalled(fontName)) != null) { - fontFace = new Font(installedFont, (italic ? Font.ITALIC : 0) | (bold ? Font.BOLD : 0) | (!italic && !bold ? Font.PLAIN : 0), size < 0 ? 10 : size).getPSName(); - } else { - fontFace = fontName; - } - break; - } - } - } - } - break; - } - } - - @Override - public void endElement(String uri, String localName, - String qName) throws SAXException { - if (qName.equals("a")) { - url = null; - target = null; - } - if (qName.equals("b")) { - bold = false; - } - if (qName.equals("i")) { - italic = false; - } - if (qName.equals("u")) { - underline = false; - } - if (qName.equals("li")) { - li = false; - } - } - - private void putText(String txt) { - - result += ""; - result += "" + xmlString(txt) + ""; - result += ""; - result += " -1) { - result += " indent=\"" + twipToPixel(indent) + "\""; - } - if (leftMargin > -1) { - result += " leftMargin=\"" + twipToPixel(leftMargin) + "\""; - } - if (letterSpacing > -1) { - result += " letterSpacing=\"" + letterSpacing + "\""; - } - if (lineSpacing > -1) { - result += " lineSpacing=\"" + twipToPixel(lineSpacing) + "\""; - } - if (rightMargin > -1) { - result += " rightMargin=\"" + twipToPixel(rightMargin) + "\""; - } - if (size > -1) { - result += " size=\"" + size + "\""; - result += " bitmapSize=\"" + (size * 20) + "\""; - } - if (fontFace != null) { - result += " face=\"" + fontFace + "\""; - } - if (color != null) { - result += " fillColor=\"" + color + "\""; - } - if (url != null) { - result += " url=\"" + url + "\""; - } - if (target != null) { - result += " target=\"" + target + "\""; - } - result += "/>"; - result += ""; - result += ""; - } - - @Override - public void characters(char[] ch, int start, int length) - throws SAXException { - putText(new String(ch, start, length)); - - } - - @Override - public void endDocument() { - if (this.result.isEmpty()) { - putText(""); - } - } - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.xfl; + +import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler; +import com.jpexs.decompiler.flash.RetryTask; +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFCompression; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.action.Action; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.exporters.MovieExporter; +import com.jpexs.decompiler.flash.exporters.SoundExporter; +import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; +import com.jpexs.decompiler.flash.exporters.modes.MovieExportMode; +import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; +import com.jpexs.decompiler.flash.exporters.modes.SoundExportMode; +import com.jpexs.decompiler.flash.exporters.settings.ScriptExportSettings; +import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter; +import com.jpexs.decompiler.flash.helpers.ImageHelper; +import com.jpexs.decompiler.flash.tags.CSMTextSettingsTag; +import com.jpexs.decompiler.flash.tags.DefineButton2Tag; +import com.jpexs.decompiler.flash.tags.DefineButtonCxformTag; +import com.jpexs.decompiler.flash.tags.DefineButtonTag; +import com.jpexs.decompiler.flash.tags.DefineEditTextTag; +import com.jpexs.decompiler.flash.tags.DefineFontNameTag; +import com.jpexs.decompiler.flash.tags.DefineSoundTag; +import com.jpexs.decompiler.flash.tags.DefineSpriteTag; +import com.jpexs.decompiler.flash.tags.DefineText2Tag; +import com.jpexs.decompiler.flash.tags.DefineTextTag; +import com.jpexs.decompiler.flash.tags.DefineVideoStreamTag; +import com.jpexs.decompiler.flash.tags.DoActionTag; +import com.jpexs.decompiler.flash.tags.DoInitActionTag; +import com.jpexs.decompiler.flash.tags.ExportAssetsTag; +import com.jpexs.decompiler.flash.tags.FileAttributesTag; +import com.jpexs.decompiler.flash.tags.FrameLabelTag; +import com.jpexs.decompiler.flash.tags.SetBackgroundColorTag; +import com.jpexs.decompiler.flash.tags.ShowFrameTag; +import com.jpexs.decompiler.flash.tags.SoundStreamBlockTag; +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.ButtonTag; +import com.jpexs.decompiler.flash.tags.base.CharacterTag; +import com.jpexs.decompiler.flash.tags.base.FontTag; +import com.jpexs.decompiler.flash.tags.base.ImageTag; +import com.jpexs.decompiler.flash.tags.base.MorphShapeTag; +import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag; +import com.jpexs.decompiler.flash.tags.base.RemoveTag; +import com.jpexs.decompiler.flash.tags.base.ShapeTag; +import com.jpexs.decompiler.flash.tags.base.SoundStreamHeadTypeTag; +import com.jpexs.decompiler.flash.tags.base.SoundTag; +import com.jpexs.decompiler.flash.tags.base.TextTag; +import com.jpexs.decompiler.flash.tags.font.CharacterRanges; +import com.jpexs.decompiler.flash.types.BUTTONCONDACTION; +import com.jpexs.decompiler.flash.types.BUTTONRECORD; +import com.jpexs.decompiler.flash.types.CLIPACTIONRECORD; +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.FILLSTYLE; +import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY; +import com.jpexs.decompiler.flash.types.FOCALGRADIENT; +import com.jpexs.decompiler.flash.types.GRADIENT; +import com.jpexs.decompiler.flash.types.GRADRECORD; +import com.jpexs.decompiler.flash.types.LINESTYLE; +import com.jpexs.decompiler.flash.types.LINESTYLE2; +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.RGB; +import com.jpexs.decompiler.flash.types.RGBA; +import com.jpexs.decompiler.flash.types.SOUNDENVELOPE; +import com.jpexs.decompiler.flash.types.TEXTRECORD; +import com.jpexs.decompiler.flash.types.filters.BEVELFILTER; +import com.jpexs.decompiler.flash.types.filters.BLURFILTER; +import com.jpexs.decompiler.flash.types.filters.COLORMATRIXFILTER; +import com.jpexs.decompiler.flash.types.filters.DROPSHADOWFILTER; +import com.jpexs.decompiler.flash.types.filters.FILTER; +import com.jpexs.decompiler.flash.types.filters.GLOWFILTER; +import com.jpexs.decompiler.flash.types.filters.GRADIENTBEVELFILTER; +import com.jpexs.decompiler.flash.types.filters.GRADIENTGLOWFILTER; +import com.jpexs.decompiler.flash.types.shaperecords.CurvedEdgeRecord; +import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD; +import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord; +import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord; +import com.jpexs.decompiler.flash.types.sound.MP3FRAME; +import com.jpexs.decompiler.flash.types.sound.MP3SOUNDDATA; +import com.jpexs.decompiler.flash.types.sound.SoundFormat; +import com.jpexs.helpers.Path; +import com.jpexs.helpers.SerializableImage; +import com.jpexs.helpers.utf8.Utf8Helper; +import java.awt.Font; +import java.awt.Point; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.Stack; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; +import javax.xml.parsers.SAXParserFactory; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.TransformerFactoryConfigurationError; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; +import org.xml.sax.Attributes; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.DefaultHandler; +import org.xml.sax.helpers.XMLReaderFactory; + +/** + * + * @author JPEXS + */ +public class XFLConverter { + + public static final int KEY_MODE_NORMAL = 9728; + + public static final int KEY_MODE_CLASSIC_TWEEN = 22017; + + public static final int KEY_MODE_SHAPE_TWEEN = 17922; + + public static final int KEY_MODE_MOTION_TWEEN = 8195; + + public static final int KEY_MODE_SHAPE_LAYERS = 8192; + + private static final Random random = new Random(123); // predictable random + + private XFLConverter() { + } + + public static String convertShapeEdge(MATRIX mat, SHAPERECORD record, int x, int y) { + if (record instanceof StyleChangeRecord) { + StyleChangeRecord scr = (StyleChangeRecord) record; + Point p = new Point(scr.moveDeltaX, scr.moveDeltaY); + //p = mat.apply(p); + if (scr.stateMoveTo) { + return "! " + p.x + " " + p.y; + } + return ""; + } + if (record instanceof StraightEdgeRecord) { + StraightEdgeRecord ser = (StraightEdgeRecord) record; + if (ser.generalLineFlag || ser.vertLineFlag) { + y += ser.deltaY; + } + if (ser.generalLineFlag || (!ser.vertLineFlag)) { + x += ser.deltaX; + } + Point p = new Point(x, y); + //p = mat.apply(p); + return "| " + p.x + " " + p.y; + } + if (record instanceof CurvedEdgeRecord) { + CurvedEdgeRecord cer = (CurvedEdgeRecord) record; + int controlX = cer.controlDeltaX + x; + int controlY = cer.controlDeltaY + y; + int anchorX = cer.anchorDeltaX + controlX; + int anchorY = cer.anchorDeltaY + controlY; + Point control = new Point(controlX, controlY); + //control = mat.apply(control); + Point anchor = new Point(anchorX, anchorY); + //anchor = mat.apply(anchor); + return "[ " + control.x + " " + control.y + " " + anchor.x + " " + anchor.y; + } + return ""; + } + + public static String convertShapeEdges(int startX, int startY, MATRIX mat, List records) { + StringBuilder ret = new StringBuilder(); + int x = startX; + int y = startY; + ret.append("!").append(startX).append(" ").append(startY); + for (SHAPERECORD rec : records) { + ret.append(convertShapeEdge(mat, rec, x, y)); + x = rec.changeX(x); + y = rec.changeY(y); + } + return ret.toString(); + } + + public static String convertLineStyle(LINESTYLE ls, int shapeNum) { + return "" + + "" + + "" + + "" + + ""; + } + + public static String convertLineStyle(HashMap characters, LINESTYLE2 ls, int shapeNum) { + StringBuilder ret = new StringBuilder(); + StringBuilder params = new StringBuilder(); + if (ls.pixelHintingFlag) { + params.append(" pixelHinting=\"true\""); + } + if (ls.width == 1) { + params.append(" solidStyle=\"hairline\""); + } + if ((!ls.noHScaleFlag) && (!ls.noVScaleFlag)) { + params.append(" scaleMode=\"normal\""); + } else if ((!ls.noHScaleFlag) && ls.noVScaleFlag) { + params.append(" scaleMode=\"horizontal\""); + } else if (ls.noHScaleFlag && (!ls.noVScaleFlag)) { + params.append(" scaleMode=\"vertical\""); + } + + switch (ls.endCapStyle) { //What about endCapStyle? + case LINESTYLE2.NO_CAP: + params.append(" caps=\"none\""); + break; + case LINESTYLE2.SQUARE_CAP: + params.append(" caps=\"square\""); + break; + } + switch (ls.joinStyle) { + case LINESTYLE2.BEVEL_JOIN: + params.append(" joints=\"bevel\""); + break; + case LINESTYLE2.MITER_JOIN: + params.append(" joints=\"miter\""); + float miterLimitFactor = toFloat(ls.miterLimitFactor); + if (miterLimitFactor != 3.0f) { + params.append(" miterLimit=\"").append(miterLimitFactor).append("\""); + } + break; + } + + ret.append(""); + ret.append(""); + + if (!ls.hasFillFlag) { + RGBA color = (RGBA) ls.color; + ret.append(""); + } else { + ret.append(convertFillStyle(null/* FIXME */, characters, ls.fillType, shapeNum)); + } + ret.append(""); + ret.append(""); + return ret.toString(); + } + + private static float toFloat(int i) { + return ((float) i) / (1 << 16); + } + + public static String convertFillStyle(MATRIX mat, HashMap characters, FILLSTYLE fs, int shapeNum) { + /* todo: use matrix + if (mat == null) { + mat = new MATRIX(); + }*/ + StringBuilder ret = new StringBuilder(); + //ret += ""; + switch (fs.fillStyleType) { + case FILLSTYLE.SOLID: + ret.append("= 3) { + ret.append(" alpha=\"").append(((RGBA) fs.color).getAlphaFloat()).append("\""); + } + ret.append(" />"); + break; + case FILLSTYLE.REPEATING_BITMAP: + case FILLSTYLE.CLIPPED_BITMAP: + case FILLSTYLE.NON_SMOOTHED_REPEATING_BITMAP: + case FILLSTYLE.NON_SMOOTHED_CLIPPED_BITMAP: + ret.append(""; + } + ret.append("\""); + + if ((fs.fillStyleType == FILLSTYLE.CLIPPED_BITMAP) || (fs.fillStyleType == FILLSTYLE.NON_SMOOTHED_CLIPPED_BITMAP)) { + ret.append(" bitmapIsClipped=\"true\""); + } + + ret.append(">"); + ret.append("").append(convertMatrix(fs.bitmapMatrix)).append(""); + ret.append(""); + break; + case FILLSTYLE.LINEAR_GRADIENT: + case FILLSTYLE.RADIAL_GRADIENT: + case FILLSTYLE.FOCAL_RADIAL_GRADIENT: + + if (fs.fillStyleType == FILLSTYLE.LINEAR_GRADIENT) { + ret.append(""); + + ret.append("").append(convertMatrix(fs.gradientMatrix)).append(""); + GRADRECORD[] records; + if (fs.fillStyleType == FILLSTYLE.FOCAL_RADIAL_GRADIENT) { + records = fs.gradient.gradientRecords; + } else { + records = fs.gradient.gradientRecords; + } + for (GRADRECORD rec : records) { + ret.append("= 3) { + ret.append(" alpha=\"").append(((RGBA) rec.color).getAlphaFloat()).append("\""); + } + ret.append(" ratio=\"").append(rec.getRatioFloat()).append("\""); + ret.append(" />"); + } + if (fs.fillStyleType == FILLSTYLE.LINEAR_GRADIENT) { + ret.append(""); + } else { + ret.append(""); + } + break; + } + //ret += ""; + return ret.toString(); + } + + public static String convertMatrix(MATRIX m) { + return convertMatrix(new Matrix(m)); + } + + public static String convertMatrix(Matrix m) { + StringBuilder ret = new StringBuilder(); + if (m == null) { + m = new Matrix(); + } + ret.append(""); + return ret.toString(); + } + /* + public static String convertShape(HashMap characters, MATRIX mat, int shapeNum, SHAPE shape) { + return convertShape(characters, mat, shapeNum, shape.shapeRecords); + } + + public static String convertShape(HashMap characters, MATRIX mat, int shapeNum, SHAPEWITHSTYLE shape,boolean morphShape) { + return convertShape(characters, mat, shapeNum, shape.shapeRecords, shape.fillStyles, shape.lineStyles, morphShape); + } + + public static String convertShape(HashMap characters, MATRIX mat, ShapeTag shape, boolean morphShape) { + return convertShape(characters, mat, shape.getShapeNum(), shape.getShapes(),morphShape); + } + + public static String convertShape(HashMap characters, MATRIX mat, int shapeNum, List shapeRecords,boolean useLayers) { + return convertShape(characters, mat, shapeNum, shapeRecords, null, null, false,true); + }*/ + + private static boolean shapeHasMultiLayers(HashMap characters, MATRIX mat, int shapeNum, List shapeRecords, FILLSTYLEARRAY fillStyles, LINESTYLEARRAY lineStyles) { + List layers = getShapeLayers(characters, mat, shapeNum, shapeRecords, fillStyles, lineStyles, false); + return layers.size() > 1; + } + + public static String convertShape(HashMap characters, MATRIX mat, int shapeNum, List shapeRecords, FILLSTYLEARRAY fillStyles, LINESTYLEARRAY lineStyles, boolean morphshape, boolean useLayers) { + StringBuilder ret = new StringBuilder(); + List layers = getShapeLayers(characters, mat, shapeNum, shapeRecords, fillStyles, lineStyles, morphshape); + if (layers.size() == 1 && !useLayers) { + ret.append(layers.get(0)); + } else { + int layer = 1; + for (int l = layers.size() - 1; l >= 0; l--) { + ret.append(""); //color=\"#4FFF4F\" + ret.append(""); + ret.append(""); + ret.append(""); + ret.append(layers.get(l)); + ret.append(""); + ret.append(""); + ret.append(""); + ret.append(""); + } + } + return ret.toString(); + } + + /** + * Remove bugs in shape: + * + * ... straightrecord straightrecord stylechange straightrecord (-2,0) <-- + * merge this with previous stylegchange + * + * @param shapeRecords + * @return + */ + private static List smoothShape(List shapeRecords) { + List ret = new ArrayList<>(shapeRecords); + + for (int i = 1; i < ret.size() - 1; i++) { + if (ret.get(i) instanceof StraightEdgeRecord && (ret.get(i - 1) instanceof StyleChangeRecord) && (ret.get(i + 1) instanceof StyleChangeRecord)) { + StraightEdgeRecord ser = (StraightEdgeRecord) ret.get(i); + StyleChangeRecord scr = (StyleChangeRecord) ret.get(i - 1); + StyleChangeRecord scr2 = (StyleChangeRecord) ret.get(i + 1); + if ((!scr.stateMoveTo && !scr.stateNewStyles) && Math.abs(ser.deltaX) < 5 && Math.abs(ser.deltaY) < 5) { + if (i >= 2) { + SHAPERECORD rbef = ret.get(i - 2); + if (rbef instanceof StraightEdgeRecord) { + StraightEdgeRecord ser_b = (StraightEdgeRecord) rbef; + ser_b.generalLineFlag = true; + ser_b.deltaX = ser.changeX(ser_b.deltaX); + ser_b.deltaY = ser.changeY(ser_b.deltaY); + } else if (rbef instanceof CurvedEdgeRecord) { + CurvedEdgeRecord cer_b = (CurvedEdgeRecord) rbef; + cer_b.anchorDeltaX = ser.changeX(cer_b.anchorDeltaX); + cer_b.anchorDeltaY = ser.changeY(cer_b.anchorDeltaY); + } else { + //??? + } + if (i >= 2) { + ret.remove(i - 1); + ret.remove(i - 1); + if (scr.stateFillStyle0 && !scr2.stateFillStyle0) { + scr2.stateFillStyle0 = true; + scr2.fillStyle0 = scr.fillStyle0; + } + if (scr.stateFillStyle1 && !scr2.stateFillStyle1) { + scr2.stateFillStyle1 = true; + scr2.fillStyle1 = scr.fillStyle1; + } + if (scr.stateLineStyle && !scr2.stateLineStyle) { + scr2.stateLineStyle = true; + scr2.lineStyle = scr.lineStyle; + } + i -= 2; + } + + } + } + } + + } + return ret; + } + + public static List getShapeLayers(HashMap characters, MATRIX mat, int shapeNum, List shapeRecords, FILLSTYLEARRAY fillStyles, LINESTYLEARRAY lineStyles, boolean morphshape) { + if (mat == null) { + mat = new MATRIX(); + } + shapeRecords = smoothShape(shapeRecords); + List edges = new ArrayList<>(); + int lineStyleCount = 0; + int fillStyle0 = -1; + int fillStyle1 = -1; + int strokeStyle = -1; + String fillsStr = ""; + String strokesStr = ""; + fillsStr += ""; + strokesStr += ""; + List layers = new ArrayList<>(); + String currentLayer = ""; + + int fillStyleCount = 0; + if (fillStyles != null) { + for (FILLSTYLE fs : fillStyles.fillStyles) { + fillsStr += ""; + fillsStr += convertFillStyle(mat, characters, fs, shapeNum); + fillsStr += ""; + fillStyleCount++; + } + } + if (lineStyles != null) { + if (shapeNum <= 3 && lineStyles.lineStyles != null) { + for (int l = 0; l < lineStyles.lineStyles.length; l++) { + strokesStr += ""; + strokesStr += convertLineStyle(lineStyles.lineStyles[l], shapeNum); + strokesStr += ""; + lineStyleCount++; + } + } else if (lineStyles.lineStyles != null) { + for (int l = 0; l < lineStyles.lineStyles.length; l++) { + strokesStr += ""; + strokesStr += convertLineStyle(characters, (LINESTYLE2) lineStyles.lineStyles[l], shapeNum); + strokesStr += ""; + lineStyleCount++; + } + } + } + + fillsStr += ""; + strokesStr += ""; + + int layer = 1; + + if ((fillStyleCount > 0) || (lineStyleCount > 0)) { + currentLayer += ""; + currentLayer += fillsStr; + currentLayer += strokesStr; + currentLayer += ""; + } + int x = 0; + int y = 0; + int startEdgeX = 0; + int startEdgeY = 0; + + LINESTYLEARRAY actualLinestyles = lineStyles; + int strokeStyleOrig = 0; + fillStyleCount = fillStyles.fillStyles.length; + for (SHAPERECORD edge : shapeRecords) { + if (edge instanceof StyleChangeRecord) { + StyleChangeRecord scr = (StyleChangeRecord) edge; + boolean styleChange = false; + int lastFillStyle1 = fillStyle1; + int lastFillStyle0 = fillStyle0; + int lastStrokeStyle = strokeStyle; + if (scr.stateNewStyles) { + fillsStr = ""; + strokesStr = ""; + if (fillStyleCount > 0 || lineStyleCount > 0) { + + if ((fillStyle0 > 0) || (fillStyle1 > 0) || (strokeStyle > 0)) { + + boolean empty = false; + if ((fillStyle0 <= 0) && (fillStyle1 <= 0) && (strokeStyle > 0) && morphshape) { + if (shapeNum == 4) { + if (strokeStyleOrig > 0) { + if (!((LINESTYLE2) actualLinestyles.lineStyles[strokeStyleOrig]).hasFillFlag) { + RGBA color = (RGBA) actualLinestyles.lineStyles[strokeStyleOrig].color; + if (color.alpha == 0 && color.red == 0 && color.green == 0 && color.blue == 0) { + empty = true; + } + } + } + } + } + if (!empty) { + currentLayer += " -1) { + currentLayer += " fillStyle0=\"" + fillStyle0 + "\""; + } + if (fillStyle1 > -1) { + currentLayer += " fillStyle1=\"" + fillStyle1 + "\""; + } + if (strokeStyle > -1) { + currentLayer += " strokeStyle=\"" + strokeStyle + "\""; + } + currentLayer += " edges=\"" + convertShapeEdges(startEdgeX, startEdgeY, mat, edges) + "\" />"; + } + } + + currentLayer += ""; + currentLayer += ""; + if (!currentLayer.contains("")) { //no empty layers, TODO:handle this better + layers.add(currentLayer); + } + currentLayer = ""; + } + + currentLayer += ""; + //ret += convertShape(characters, null, shape); + for (int f = 0; f < scr.fillStyles.fillStyles.length; f++) { + fillsStr += ""; + fillsStr += convertFillStyle(mat, characters, scr.fillStyles.fillStyles[f], shapeNum); + fillsStr += ""; + fillStyleCount++; + } + + lineStyleCount = 0; + if (shapeNum <= 3) { + for (int l = 0; l < scr.lineStyles.lineStyles.length; l++) { + strokesStr += ""; + strokesStr += convertLineStyle(scr.lineStyles.lineStyles[l], shapeNum); + strokesStr += ""; + lineStyleCount++; + } + } else { + for (int l = 0; l < scr.lineStyles.lineStyles.length; l++) { + strokesStr += ""; + strokesStr += convertLineStyle(characters, (LINESTYLE2) scr.lineStyles.lineStyles[l], shapeNum); + strokesStr += ""; + lineStyleCount++; + } + } + fillsStr += ""; + strokesStr += ""; + currentLayer += fillsStr; + currentLayer += strokesStr; + currentLayer += ""; + actualLinestyles = scr.lineStyles; + } + if (scr.stateFillStyle0) { + int fillStyle0_new = scr.fillStyle0;// == 0 ? 0 : fillStylesMap.get(fillStyleCount - lastFillStyleCount + scr.fillStyle0 - 1) + 1; + if (morphshape) { //??? + fillStyle1 = fillStyle0_new; + } else { + fillStyle0 = fillStyle0_new; + } + styleChange = true; + } + if (scr.stateFillStyle1) { + int fillStyle1_new = scr.fillStyle1;// == 0 ? 0 : fillStylesMap.get(fillStyleCount - lastFillStyleCount + scr.fillStyle1 - 1) + 1; + if (morphshape) { + fillStyle0 = fillStyle1_new; + } else { + fillStyle1 = fillStyle1_new; + } + styleChange = true; + } + if (scr.stateLineStyle) { + strokeStyle = scr.lineStyle;// == 0 ? 0 : lineStyleCount - lastLineStyleCount + scr.lineStyle; + strokeStyleOrig = scr.lineStyle - 1; + styleChange = true; + } + if (!edges.isEmpty()) { + if ((fillStyle0 > 0) || (fillStyle1 > 0) || (strokeStyle > 0)) { + boolean empty = false; + if ((fillStyle0 <= 0) && (fillStyle1 <= 0) && (strokeStyle > 0) && morphshape) { + if (shapeNum == 4) { + if (strokeStyleOrig > 0) { + if (!((LINESTYLE2) actualLinestyles.lineStyles[strokeStyleOrig]).hasFillFlag) { + RGBA color = (RGBA) actualLinestyles.lineStyles[strokeStyleOrig].color; + if (color.alpha == 0 && color.red == 0 && color.green == 0 && color.blue == 0) { + empty = true; + } + } + } + } + } + if (!empty) { + currentLayer += " -1) { + currentLayer += " fillStyle0=\"" + lastFillStyle0 + "\""; + } + if (fillStyle1 > -1) { + currentLayer += " fillStyle1=\"" + lastFillStyle1 + "\""; + } + if (strokeStyle > -1) { + currentLayer += " strokeStyle=\"" + lastStrokeStyle + "\""; + } + currentLayer += " edges=\"" + convertShapeEdges(startEdgeX, startEdgeY, mat, edges) + "\" />"; + } + + startEdgeX = x; + startEdgeY = y; + } + edges.clear(); + } + } + edges.add(edge); + x = edge.changeX(x); + y = edge.changeY(y); + } + if (!edges.isEmpty()) { + if ((fillStyle0 > 0) || (fillStyle1 > 0) || (strokeStyle > 0)) { + + boolean empty = false; + if ((fillStyle0 <= 0) && (fillStyle1 <= 0) && (strokeStyle > 0) && morphshape) { + if (shapeNum == 4) { + if (strokeStyleOrig > 0) { + if (!((LINESTYLE2) actualLinestyles.lineStyles[strokeStyleOrig]).hasFillFlag) { + RGBA color = (RGBA) actualLinestyles.lineStyles[strokeStyleOrig].color; + if (color.alpha == 0 && color.red == 0 && color.green == 0 && color.blue == 0) { + empty = true; + } + } + } + } + } + if (!empty) { + currentLayer += " -1) { + currentLayer += " fillStyle0=\"" + fillStyle0 + "\""; + } + if (fillStyle1 > -1) { + currentLayer += " fillStyle1=\"" + fillStyle1 + "\""; + } + if (strokeStyle > -1) { + currentLayer += " strokeStyle=\"" + strokeStyle + "\""; + } + currentLayer += " edges=\"" + convertShapeEdges(startEdgeX, startEdgeY, mat, edges) + "\" />"; + } + } + } + edges.clear(); + fillsStr += ""; + strokesStr += ""; + if (!currentLayer.isEmpty()) { + currentLayer += ""; + currentLayer += ""; + + if (!currentLayer.contains("")) { //no empty layers, TODO:handle this better + layers.add(currentLayer); + } + } + return layers; + } + + private static int getLayerCount(List tags) { + int maxDepth = 0; + for (Tag t : tags) { + if (t instanceof PlaceObjectTypeTag) { + int d = ((PlaceObjectTypeTag) t).getDepth(); + if (d > maxDepth) { + maxDepth = d; + } + int cd = ((PlaceObjectTypeTag) t).getClipDepth(); + if (cd > maxDepth) { + maxDepth = cd; + } + } + } + return maxDepth; + } + + private static void walkShapeUsages(List timeLineTags, HashMap characters, HashMap usages) { + for (Tag t : timeLineTags) { + if (t instanceof DefineSpriteTag) { + DefineSpriteTag sprite = (DefineSpriteTag) t; + walkShapeUsages(sprite.subTags, characters, usages); + } + if (t instanceof PlaceObjectTypeTag) { + PlaceObjectTypeTag po = (PlaceObjectTypeTag) t; + int ch = po.getCharacterId(); + if (ch > -1) { + if (!usages.containsKey(ch)) { + usages.put(ch, 0); + } + int usageCount = usages.get(ch); + if (po.getInstanceName() != null) { + usageCount++; + } + if (po.getColorTransform() != null) { + usageCount++; + } + if (po.cacheAsBitmap()) { + usageCount++; + } + MATRIX mat = po.getMatrix(); + if (mat != null) { + if (!mat.isEmpty()) { + usageCount++; + } + } + usages.put(ch, usageCount + 1); + } + } + } + } + + private static List getNonLibraryShapes(List tags, HashMap characters) { + HashMap usages = new HashMap<>(); + walkShapeUsages(tags, characters, usages); + List ret = new ArrayList<>(); + for (int ch : usages.keySet()) { + if (usages.get(ch) < 2) { + if (characters.get(ch) instanceof ShapeTag) { + ShapeTag shp = (ShapeTag) characters.get(ch); + if (!shapeHasMultiLayers(characters, null, shp.getShapeNum(), shp.getShapes().shapeRecords, shp.getShapes().fillStyles, shp.getShapes().lineStyles)) { + ret.add(ch); + } + } + + } + } + return ret; + } + + private static HashMap getCharacters(List tags) { + HashMap ret = new HashMap<>(); + int maxId = 0; + for (Tag t : tags) { + if (t instanceof CharacterTag) { + CharacterTag ct = (CharacterTag) t; + if (ct.getCharacterId() > maxId) { + maxId = ct.getCharacterId(); + } + } + } + for (Tag t : tags) { + if (t instanceof SoundStreamHeadTypeTag) { + SoundStreamHeadTypeTag ssh = (SoundStreamHeadTypeTag) t; + ssh.setVirtualCharacterId(++maxId); + } + if (t instanceof CharacterTag) { + CharacterTag ct = (CharacterTag) t; + ret.put(ct.getCharacterId(), ct); + } + } + return ret; + } + + private static final String[] BLENDMODES = { + null, + null, + "layer", + "multiply", + "screen", + "lighten", + "darken", + "difference", + "add", + "subtract", + "invert", + "alpha", + "erase", + "overlay", + "hardligh" + }; + + private static double radToDeg(double rad) { + return rad * 180 / Math.PI; + } + + private static String doubleToString(double d, int precision) { + double m = Math.pow(10, precision); + d = Math.round(d * m) / m; + return doubleToString(d); + } + + private static String doubleToString(double d) { + String ds = "" + d; + if (ds.endsWith(".0")) { + ds = ds.substring(0, ds.length() - 2); + } + return ds; + } + + public static String convertFilter(FILTER filter) { + StringBuilder ret = new StringBuilder(); + if (filter instanceof DROPSHADOWFILTER) { + DROPSHADOWFILTER dsf = (DROPSHADOWFILTER) filter; + ret.append(""); + } else if (filter instanceof BLURFILTER) { + BLURFILTER bf = (BLURFILTER) filter; + ret.append(""); + } else if (filter instanceof GLOWFILTER) { + GLOWFILTER gf = (GLOWFILTER) filter; + ret.append(""); + } else if (filter instanceof BEVELFILTER) { + BEVELFILTER bf = (BEVELFILTER) filter; + ret.append(""); + } else if (filter instanceof GRADIENTGLOWFILTER) { + GRADIENTGLOWFILTER ggf = (GRADIENTGLOWFILTER) filter; + ret.append(""); + for (int g = 0; g < ggf.gradientColors.length; g++) { + RGBA gc = ggf.gradientColors[g]; + ret.append(""); + } + ret.append(""); + } else if (filter instanceof GRADIENTBEVELFILTER) { + GRADIENTBEVELFILTER gbf = (GRADIENTBEVELFILTER) filter; + ret.append(""); + for (int g = 0; g < gbf.gradientColors.length; g++) { + RGBA gc = gbf.gradientColors[g]; + ret.append(""); + } + ret.append(""); + } else if (filter instanceof COLORMATRIXFILTER) { + COLORMATRIXFILTER cmf = (COLORMATRIXFILTER) filter; + ret.append(convertAdjustColorFilter(cmf)); + } + return ret.toString(); + } + + public static String convertSymbolInstance(String name, MATRIX matrix, ColorTransform colorTransform, boolean cacheAsBitmap, int blendMode, List filters, boolean isVisible, RGBA backgroundColor, CLIPACTIONS clipActions, CharacterTag tag, HashMap characters, List tags, FLAVersion flaVersion) { + StringBuilder ret = new StringBuilder(); + if (matrix == null) { + matrix = new MATRIX(); + } + if (tag instanceof DefineButtonTag) { + DefineButtonTag bt = (DefineButtonTag) tag; + for (Tag t : tags) { + if (t instanceof DefineButtonCxformTag) { + DefineButtonCxformTag bcx = (DefineButtonCxformTag) t; + if (bcx.buttonId == bt.buttonId) { + colorTransform = bcx.buttonColorTransform; + } + } + } + } + + ret.append("= FLAVersion.CS5_5.ordinal()) { + ret.append(" isVisible=\"false\""); + } + ret.append(">"); + ret.append(""); + ret.append(convertMatrix(matrix)); + ret.append(""); + ret.append(""); + + if (backgroundColor != null) { + ret.append(""); + } + if (colorTransform != null) { + ret.append(""); + } + if (filters != null) { + ret.append(""); + for (FILTER f : filters) { + ret.append(convertFilter(f)); + } + ret.append(""); + } + if (tag instanceof DefineButtonTag) { + ret.append(""); + } + if (tag instanceof DefineButton2Tag) { + DefineButton2Tag db2 = (DefineButton2Tag) tag; + if (!db2.actions.isEmpty()) { + ret.append(""); + } + } + if (clipActions != null) { + ret.append(""); + } + ret.append(""); + return ret.toString(); + } + + private static String convertActionScript(ASMSource as) { + HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), false); + try { + Action.actionsToSource(as, as.getActions(), as.toString(), writer); + } catch (InterruptedException ex) { + Logger.getLogger(XFLConverter.class.getName()).log(Level.SEVERE, null, ex); + } + return writer.toString(); + } + + private static long getTimestamp() { + return new Date().getTime() / 1000; + } + + public static String convertLibrary(SWF swf, Map characterVariables, Map characterClasses, List nonLibraryShapes, String backgroundColor, List tags, HashMap characters, HashMap files, HashMap datfiles, FLAVersion flaVersion) { + + //TODO: Imported assets + //linkageImportForRS="true" linkageIdentifier="xxx" linkageURL="yyy.swf" + StringBuilder ret = new StringBuilder(); + List media = new ArrayList<>(); + List symbols = new ArrayList<>(); + for (int ch : characters.keySet()) { + CharacterTag symbol = characters.get(ch); + if ((symbol instanceof ShapeTag) && nonLibraryShapes.contains(symbol.getCharacterId())) { + continue; //shapes with 1 ocurrence and single layer are not added to library + } + if ((symbol instanceof ShapeTag) || (symbol instanceof DefineSpriteTag) || (symbol instanceof ButtonTag)) { + StringBuilder symbolStr = new StringBuilder(); + + symbolStr.append(""); + symbolStr.append(""); + String itemIcon = null; + if (symbol instanceof ButtonTag) { + itemIcon = "0"; + symbolStr.append(""); + symbolStr.append(""); + + ButtonTag button = (ButtonTag) symbol; + List records = button.getRecords(); + + int maxDepth = 0; + for (BUTTONRECORD rec : records) { + if (rec.placeDepth > maxDepth) { + maxDepth = rec.placeDepth; + } + } + for (int i = maxDepth; i >= 1; i--) { + symbolStr.append(""); + symbolStr.append(""); + int lastFrame = 0; + loopframes: + for (int frame = 1; frame <= 4; frame++) { + for (BUTTONRECORD rec : records) { + if (rec.placeDepth == i) { + boolean ok = false; + switch (frame) { + case 1: + ok = rec.buttonStateUp; + break; + case 2: + ok = rec.buttonStateOver; + break; + case 3: + ok = rec.buttonStateDown; + break; + case 4: + ok = rec.buttonStateHitTest; + break; + } + if (!ok) { + continue; + } + CXFORMWITHALPHA colorTransformAlpha = null; + int blendMode = 0; + List filters = new ArrayList<>(); + if (button instanceof DefineButton2Tag) { + colorTransformAlpha = rec.colorTransform; + if (rec.buttonHasBlendMode) { + blendMode = rec.blendMode; + } + if (rec.buttonHasFilterList) { + filters = rec.filterList; + } + } + CharacterTag character = characters.get(rec.characterId); + MATRIX matrix = rec.placeMatrix; + String recCharStr; + if (character instanceof TextTag) { + recCharStr = convertText(null, (TextTag) character, matrix, filters, null); + } else if (character instanceof DefineVideoStreamTag) { + recCharStr = convertVideoInstance(null, matrix, (DefineVideoStreamTag) character, null); + } else { + recCharStr = convertSymbolInstance(null, matrix, colorTransformAlpha, false, blendMode, filters, true, null, null, characters.get(rec.characterId), characters, tags, flaVersion); + } + int duration = frame - lastFrame; + lastFrame = frame; + if (duration > 0) { + if (duration > 1) { + symbolStr.append(""); + symbolStr.append(""); + symbolStr.append(""); + symbolStr.append(""); + } + symbolStr.append(""); + symbolStr.append(""); + symbolStr.append(recCharStr); + symbolStr.append(""); + symbolStr.append(""); + } + } + } + } + symbolStr.append(""); + symbolStr.append(""); + } + symbolStr.append(""); + symbolStr.append(""); + } else if (symbol instanceof DefineSpriteTag) { + DefineSpriteTag sprite = (DefineSpriteTag) symbol; + if (sprite.subTags.isEmpty()) { //probably AS2 class + continue; + } + symbolStr.append(convertTimeline(sprite.spriteId, nonLibraryShapes, backgroundColor, tags, sprite.getSubTags(), characters, "Symbol " + symbol.getCharacterId(), flaVersion, files)); + } else if (symbol instanceof ShapeTag) { + itemIcon = "1"; + ShapeTag shape = (ShapeTag) symbol; + symbolStr.append(""); + symbolStr.append(""); + symbolStr.append(convertShape(characters, null, shape.getShapeNum(), shape.getShapes().shapeRecords, shape.getShapes().fillStyles, shape.getShapes().lineStyles, false, true)); + symbolStr.append(""); + symbolStr.append(""); + } + symbolStr.append(""); + symbolStr.append(""); + String symbolStr2 = prettyFormatXML(symbolStr.toString()); + String symbolFile = "Symbol " + symbol.getCharacterId() + ".xml"; + files.put(symbolFile, Utf8Helper.getBytes(symbolStr2)); + String symbLinkStr = ""; + symbLinkStr += "= FLAVersion.CS5_5.ordinal()) { + symbLinkStr += " lastModified=\"" + getTimestamp() + "\""; + //TODO: itemID=\"518de416-00000341\" + } + symbLinkStr += "/>"; + symbols.add(symbLinkStr); + } else if (symbol instanceof ImageTag) { + ImageTag imageTag = (ImageTag) symbol; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + SerializableImage image = imageTag.getImage(); + // do not store the image in cache during xfl conversion + imageTag.clearCache(); + String format = imageTag.getImageFormat(); + ImageHelper.write(image.getBufferedImage(), format.toUpperCase(), baos); + String symbolFile = "bitmap" + symbol.getCharacterId() + "." + imageTag.getImageFormat(); + files.put(symbolFile, baos.toByteArray()); + String mediaLinkStr = "\n"; + media.add(mediaLinkStr); + + } else if ((symbol instanceof SoundStreamHeadTypeTag) || (symbol instanceof DefineSoundTag)) { + int soundFormat = 0; + int soundRate = 0; + boolean soundType = false; + boolean soundSize = false; + long soundSampleCount = 0; + byte[] soundData = new byte[0]; + int[] rateMap = {5, 11, 22, 44}; + String exportFormat = "flv"; + if (symbol instanceof SoundStreamHeadTypeTag) { + SoundStreamHeadTypeTag sstream = (SoundStreamHeadTypeTag) symbol; + soundFormat = sstream.getSoundFormatId(); + soundRate = sstream.getSoundRate(); + soundType = sstream.getSoundType(); + soundSize = sstream.getSoundSize(); + soundSampleCount = sstream.getSoundSampleCount(); + boolean found = false; + for (Tag t : tags) { + if (found && (t instanceof SoundStreamBlockTag)) { + SoundStreamBlockTag bl = (SoundStreamBlockTag) t; + soundData = bl.streamSoundData.getRangeData(); + break; + } + if (t == symbol) { + found = true; + } + } + } else if (symbol instanceof DefineSoundTag) { + DefineSoundTag sound = (DefineSoundTag) symbol; + soundFormat = sound.soundFormat; + soundRate = sound.soundRate; + soundType = sound.soundType; + soundData = sound.soundData.getRangeData(); + soundSize = sound.soundSize; + soundSampleCount = sound.soundSampleCount; + } + int format = 0; + int bits = 0; + if ((soundFormat == SoundFormat.FORMAT_ADPCM) + || (soundFormat == SoundFormat.FORMAT_UNCOMPRESSED_LITTLE_ENDIAN) + || (soundFormat == SoundFormat.FORMAT_UNCOMPRESSED_NATIVE_ENDIAN)) { + exportFormat = "wav"; + if (soundType) { //stereo + format += 1; + } + switch (soundRate) { + case 0: + format += 2; + break; + case 1: + format += 6; + break; + case 2: + format += 10; + break; + case 3: + format += 14; + break; + } + } + if (soundFormat == SoundFormat.FORMAT_SPEEX) { + bits = 18; + } + if (soundFormat == SoundFormat.FORMAT_ADPCM) { + exportFormat = "wav"; + try { + SWFInputStream sis = new SWFInputStream(swf, soundData); + int adpcmCodeSize = (int) sis.readUB(2, "adpcmCodeSize"); + bits = 2 + adpcmCodeSize; + } catch (IOException ex) { + Logger.getLogger(XFLConverter.class.getName()).log(Level.SEVERE, null, ex); + } + } + if (soundFormat == SoundFormat.FORMAT_MP3) { + exportFormat = "mp3"; + if (!soundType) { //mono + format += 1; + } + format += 4; //quality best + try { + MP3SOUNDDATA s = new MP3SOUNDDATA(new SWFInputStream(swf, soundData), false); + //sis.readSI16(); + //MP3FRAME frame = new MP3FRAME(sis); + MP3FRAME frame = s.frames.get(0); + int bitRate = frame.getBitRate(); + + switch (bitRate) { + case 8: + bits = 6; + break; + case 16: + bits = 7; + break; + case 20: + bits = 8; + break; + case 24: + bits = 9; + break; + case 32: + bits = 10; + break; + case 48: + bits = 11; + break; + case 56: + bits = 12; + break; + case 64: + bits = 13; + break; + case 80: + bits = 14; + break; + case 112: + bits = 15; + break; + case 128: + bits = 16; + break; + case 160: + bits = 17; + break; + + } + } catch (IOException ex) { + Logger.getLogger(XFLConverter.class.getName()).log(Level.SEVERE, null, ex); + } + } + SoundTag st = (SoundTag) symbol; + SoundFormat fmt = st.getSoundFormat(); + byte[] data = new byte[0]; + try { + data = new SoundExporter().exportSound(st, SoundExportMode.MP3_WAV); + } catch (IOException ex) { + Logger.getLogger(XFLConverter.class.getName()).log(Level.SEVERE, null, ex); + } + + String symbolFile = "sound" + symbol.getCharacterId() + "." + exportFormat; + files.put(symbolFile, data); + String mediaLinkStr = ""; + //Use the dat file, otherwise it does not work + datfiles.put(datFileName, new byte[]{ //Magic numbers, if anybody knows why, please tell me + (byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xA0, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x78, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x01, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x59, (byte) 0x40, (byte) 0x18, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xFF, (byte) 0xFE, (byte) 0xFF, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 + }); + } else { + files.put(symbolFile, data); + mediaLinkStr = ""); + for (String m : media) { + ret.append(m); + } + ret.append(""); + } + if (!symbols.isEmpty()) { + ret.append(""); + for (String s : symbols) { + ret.append(s); + } + ret.append(""); + } + return ret.toString(); + } + + private static String prettyFormatXML(String input) { + int indent = 5; + try { + Source xmlInput = new StreamSource(new StringReader(input)); + StringWriter stringWriter = new StringWriter(); + StreamResult xmlOutput = new StreamResult(stringWriter); + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + transformerFactory.setAttribute("indent-number", indent); + Transformer transformer = transformerFactory.newTransformer(); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); + transformer.transform(xmlInput, xmlOutput); + return xmlOutput.getWriter().toString(); + } catch (TransformerFactoryConfigurationError | IllegalArgumentException | TransformerException e) { + System.err.println(input); + Logger.getLogger(XFLConverter.class.getName()).log(Level.SEVERE, "Pretty print error", e); + return input; + } + } + + private static String convertFrame(boolean shapeTween, HashMap characters, List tags, SoundStreamHeadTypeTag soundStreamHead, StartSoundTag startSound, int frame, int duration, String actionScript, String elements, HashMap files) { + StringBuilder ret = new StringBuilder(); + DefineSoundTag sound = null; + if (startSound != null) { + for (Tag t : tags) { + if (t instanceof DefineSoundTag) { + DefineSoundTag s = (DefineSoundTag) t; + if (s.soundId == startSound.soundId) { + sound = s; + break; + } + } + } + } + + ret.append(" 1) { + ret.append(" duration=\"").append(duration).append("\""); + } + if (shapeTween) { + ret.append(" tweenType=\"shape\" keyMode=\"").append(KEY_MODE_SHAPE_TWEEN).append("\""); + } else { + ret.append(" keyMode=\"").append(KEY_MODE_NORMAL).append("\""); + } + String soundEnvelopeStr = ""; + if (soundStreamHead != null && startSound == null) { + String soundName = "sound" + soundStreamHead.getCharacterId() + "." + soundStreamHead.getExportFormat(); + ret.append(" soundName=\"").append(soundName).append("\""); + ret.append(" soundSync=\"stream\""); + soundEnvelopeStr += ""; + soundEnvelopeStr += ""; + soundEnvelopeStr += ""; + } + if (startSound != null && sound != null) { + String soundName = "sound" + sound.soundId + "." + sound.getExportFormat(); + ret.append(" soundName=\"").append(soundName).append("\""); + if (startSound.soundInfo.hasInPoint) { + ret.append(" inPoint44=\"").append(startSound.soundInfo.inPoint).append("\""); + } + if (startSound.soundInfo.hasOutPoint) { + ret.append(" outPoint44=\"").append(startSound.soundInfo.outPoint).append("\""); + } + if (startSound.soundInfo.hasLoops) { + if (startSound.soundInfo.loopCount == 32767) { + ret.append(" soundLoopMode=\"loop\""); + } + ret.append(" soundLoop=\"").append(startSound.soundInfo.loopCount).append("\""); + } + + if (startSound.soundInfo.syncStop) { + ret.append(" soundSync=\"stop\""); + } else if (startSound.soundInfo.syncNoMultiple) { + ret.append(" soundSync=\"start\""); + } + soundEnvelopeStr += ""; + if (startSound.soundInfo.hasEnvelope) { + SOUNDENVELOPE[] envelopeRecords = startSound.soundInfo.envelopeRecords; + for (SOUNDENVELOPE env : envelopeRecords) { + soundEnvelopeStr += ""; + } + + if (envelopeRecords.length == 1 + && envelopeRecords[0].leftLevel == 32768 + && envelopeRecords[0].pos44 == 0 + && envelopeRecords[0].rightLevel == 0) { + ret.append(" soundEffect=\"left channel\""); + } else if (envelopeRecords.length == 1 + && envelopeRecords[0].leftLevel == 0 + && envelopeRecords[0].pos44 == 0 + && envelopeRecords[0].rightLevel == 32768) { + ret.append(" soundEffect=\"right channel\""); + } else if (envelopeRecords.length == 2 + && envelopeRecords[0].leftLevel == 32768 + && envelopeRecords[0].pos44 == 0 + && envelopeRecords[0].rightLevel == 0 + && envelopeRecords[1].leftLevel == 0 + && envelopeRecords[1].pos44 == sound.soundSampleCount + && envelopeRecords[1].rightLevel == 32768) { + ret.append(" soundEffect=\"fade left to right\""); + } else if (envelopeRecords.length == 2 + && envelopeRecords[0].leftLevel == 0 + && envelopeRecords[0].pos44 == 0 + && envelopeRecords[0].rightLevel == 32768 + && envelopeRecords[1].leftLevel == 32768 + && envelopeRecords[1].pos44 == sound.soundSampleCount + && envelopeRecords[1].rightLevel == 0) { + ret.append(" soundEffect=\"fade right to left\""); + } else { + ret.append(" soundEffect=\"custom\""); + } + //TODO: fade in, fade out + + } else { + soundEnvelopeStr += ""; + } + soundEnvelopeStr += ""; + } + ret.append(">"); + + ret.append(soundEnvelopeStr); + if (!actionScript.isEmpty()) { + ret.append(""); + } + ret.append(""); + ret.append(elements); + ret.append(""); + ret.append(""); + return ret.toString(); + } + + private static String convertVideoInstance(String instanceName, MATRIX matrix, DefineVideoStreamTag video, CLIPACTIONS clipActions) { + StringBuilder ret = new StringBuilder(); + ret.append(""); + ret.append(""); + ret.append(convertMatrix(matrix)); + ret.append(""); + ret.append(""); + ret.append(""); + ret.append(""); + ret.append(""); + return ret.toString(); + } + + private static String convertFrames(String prevStr, String afterStr, List nonLibraryShapes, List tags, List timelineTags, HashMap characters, int depth, FLAVersion flaVersion, HashMap files) { + StringBuilder ret = new StringBuilder(); + prevStr += ""; + int frame = -1; + String elements = ""; + String lastElements = ""; + + int duration = 1; + + CharacterTag character = null; + MATRIX matrix = null; + String instanceName = null; + ColorTransform colorTransForm = null; + boolean cacheAsBitmap = false; + int blendMode = 0; + List filters = new ArrayList<>(); + boolean isVisible = true; + RGBA backGroundColor = null; + CLIPACTIONS clipActions = null; + int characterId = -1; + int ratio = -1; + boolean shapeTween = false; + boolean lastShapeTween = false; + MorphShapeTag shapeTweener = null; + + for (Tag t : timelineTags) { + if (t instanceof PlaceObjectTypeTag) { + PlaceObjectTypeTag po = (PlaceObjectTypeTag) t; + if (po.getDepth() == depth) { + int newCharId = po.getCharacterId(); + if (newCharId == -1) { + newCharId = characterId; + } + characterId = newCharId; + if (characters.containsKey(characterId)) { + character = characters.get(characterId); + if (po.flagMove()) { + MATRIX matrix2 = po.getMatrix(); + if (matrix2 != null) { + matrix = matrix2; + } + String instanceName2 = po.getInstanceName(); + if (instanceName2 != null) { + instanceName = instanceName2; + } + ColorTransform colorTransForm2 = po.getColorTransform(); + if (colorTransForm2 != null) { + colorTransForm = colorTransForm2; + } + + CLIPACTIONS clipActions2 = po.getClipActions(); + if (clipActions2 != null) { + clipActions = clipActions2; + } + if (po.cacheAsBitmap()) { + cacheAsBitmap = true; + } + int blendMode2 = po.getBlendMode(); + if (blendMode2 > 0) { + blendMode = blendMode2; + } + List filters2 = po.getFilters(); + if (filters2 != null) { + filters = filters2; + } + int ratio2 = po.getRatio(); + if (ratio2 > -1) { + ratio = ratio2; + } + } else { + matrix = po.getMatrix(); + instanceName = po.getInstanceName(); + colorTransForm = po.getColorTransform(); + cacheAsBitmap = po.cacheAsBitmap(); + blendMode = po.getBlendMode(); + filters = po.getFilters(); + ratio = po.getRatio(); + clipActions = po.getClipActions(); + } + + } + } + } + + if (t instanceof RemoveTag) { + RemoveTag rt = (RemoveTag) t; + if (rt.getDepth() == depth) { + if (shapeTween && character != null) { + MorphShapeTag m = (MorphShapeTag) character; + shapeTweener = m; + shapeTween = false; + } + character = null; + matrix = null; + instanceName = null; + colorTransForm = null; + cacheAsBitmap = false; + blendMode = 0; + filters = new ArrayList<>(); + isVisible = true; + backGroundColor = null; + characterId = -1; + clipActions = null; + } + } + + if (t instanceof ShowFrameTag) { + elements = ""; + + if ((character instanceof ShapeTag) && (nonLibraryShapes.contains(characterId) || shapeTweener != null)) { + ShapeTag shape = (ShapeTag) character; + elements += convertShape(characters, matrix, shape.getShapeNum(), shape.getShapes().shapeRecords, shape.getShapes().fillStyles, shape.getShapes().lineStyles, false, false); + shapeTween = false; + shapeTweener = null; + } else if (character != null) { + if (character instanceof MorphShapeTag) { + MorphShapeTag m = (MorphShapeTag) character; + elements += convertShape(characters, matrix, 3, m.getStartEdges().shapeRecords, m.getFillStyles().getStartFillStyles(), m.getLineStyles().getStartLineStyles(m.getShapeNum()), true, false); + shapeTween = true; + } else { + shapeTween = false; + if (character instanceof TextTag) { + elements += convertText(instanceName, (TextTag) character, matrix, filters, clipActions); + } else if (character instanceof DefineVideoStreamTag) { + elements += convertVideoInstance(instanceName, matrix, (DefineVideoStreamTag) character, clipActions); + } else { + elements += convertSymbolInstance(instanceName, matrix, colorTransForm, cacheAsBitmap, blendMode, filters, isVisible, backGroundColor, clipActions, character, characters, tags, flaVersion); + } + } + } + + frame++; + if (!elements.equals(lastElements) && frame > 0) { + ret.append(convertFrame(lastShapeTween, characters, tags, null, null, frame - duration, duration, "", lastElements, files)); + duration = 1; + } else if (frame == 0) { + duration = 1; + } else { + duration++; + } + + lastShapeTween = shapeTween; + lastElements = elements; + } + } + if (!lastElements.isEmpty()) { + frame++; + ret.append(convertFrame(lastShapeTween, characters, tags, null, null, (frame - duration < 0 ? 0 : frame - duration), duration, "", lastElements, files)); + } + afterStr = "" + afterStr; + String retStr = ret.toString(); + if (!retStr.isEmpty()) { + retStr = prevStr + retStr + afterStr; + } + return retStr; + } + + public static String convertFonts(List tags) { + StringBuilder ret = new StringBuilder(); + for (Tag t : tags) { + if (t instanceof FontTag) { + FontTag font = (FontTag) t; + int fontId = font.getFontId(); + String fontName = null; + for (Tag t2 : tags) { + if (t2 instanceof DefineFontNameTag) { + if (((DefineFontNameTag) t2).fontId == fontId) { + fontName = ((DefineFontNameTag) t2).fontName; + } + } + } + if (fontName == null) { + fontName = font.getFontNameIntag(); + } + int fontStyle = font.getFontStyle(); + String installedFont; + if ((installedFont = FontTag.isFontFamilyInstalled(fontName)) != null) { + fontName = new Font(installedFont, fontStyle, 10).getPSName(); + } + String embedRanges = ""; + + String fontChars = font.getCharacters(tags); + if ("".equals(fontChars)) { + continue; + } + String embeddedCharacters = fontChars; + embeddedCharacters = embeddedCharacters.replace("\u00A0", ""); //nonbreak space + embeddedCharacters = embeddedCharacters.replace(".", ""); + boolean hasAllRanges = false; + for (int r = 0; r < CharacterRanges.rangeCount(); r++) { + int[] codes = CharacterRanges.rangeCodes(r); + boolean hasAllInRange = true; + for (int i = 0; i < codes.length; i++) { + if (!fontChars.contains("" + (char) codes[i])) { + hasAllInRange = false; + break; + } + } + if (hasAllInRange) { + //remove all found characters + for (int i = 0; i < codes.length; i++) { + embeddedCharacters = embeddedCharacters.replace("" + (char) codes[i], ""); + } + if (!"".equals(embedRanges)) { + embedRanges += "|"; + } + embedRanges += (r + 1); + } else { + hasAllRanges = false; + } + } + if (hasAllRanges) { + embedRanges = "9999"; + } + ret.append(""); + } + + } + + String retStr = ret.toString(); + if (!retStr.isEmpty()) { + retStr = "" + retStr + ""; + } + + return retStr; + } + + public static String convertActionScriptLayer(int spriteId, List tags, List timeLineTags, String backgroundColor) { + StringBuilder ret = new StringBuilder(); + + String script = ""; + int duration = 0; + int frame = 0; + for (Tag t : tags) { + if (t instanceof DoInitActionTag) { + DoInitActionTag dia = (DoInitActionTag) t; + if (dia.spriteId == spriteId) { + script += convertActionScript(dia); + } + } + } + if (!script.isEmpty()) { + script = "#initclip\r\n" + script + "#endinitclip\r\n"; + } + for (Tag t : timeLineTags) { + if (t instanceof DoActionTag) { + DoActionTag da = (DoActionTag) t; + script += convertActionScript(da); + } + if (t instanceof ShowFrameTag) { + + if (script.isEmpty()) { + duration++; + } else { + if (duration > 0) { + ret.append(" 1) { + ret.append(" duration=\"").append(duration).append("\""); + } + ret.append(" keyMode=\"").append(KEY_MODE_NORMAL).append("\">"); + ret.append(""); + ret.append(""); + ret.append(""); + } + ret.append(""); + ret.append(""); + ret.append(""); + ret.append(""); + ret.append(""); + script = ""; + duration = 0; + } + frame++; + } + } + String retStr = ret.toString(); + if (!retStr.isEmpty()) { + retStr = "" + + "" + + retStr + + "" + + ""; + } + return retStr; + } + + public static String convertLabelsLayer(int spriteId, List tags, List timeLineTags, String backgroundColor) { + StringBuilder ret = new StringBuilder(); + int duration = 0; + int frame = 0; + String frameLabel = ""; + boolean isAnchor = false; + for (Tag t : timeLineTags) { + if (t instanceof FrameLabelTag) { + FrameLabelTag fl = (FrameLabelTag) t; + frameLabel = fl.getLabelName(); + isAnchor = fl.isNamedAnchor(); + } + if (t instanceof ShowFrameTag) { + + if (frameLabel.isEmpty()) { + duration++; + } else { + if (duration > 0) { + ret.append(" 1) { + ret.append(" duration=\"").append(duration).append("\""); + } + ret.append(" keyMode=\"").append(KEY_MODE_NORMAL).append("\">"); + ret.append(""); + ret.append(""); + ret.append(""); + } + ret.append(""); + ret.append(""); + ret.append(""); + ret.append(""); + frameLabel = ""; + duration = 0; + } + frame++; + } + } + String retStr = ret.toString(); + if (!retStr.isEmpty()) { + retStr = "" + + "" + + retStr + + "" + + ""; + } + return retStr; + } + + public static String convertSoundLayer(int layerIndex, String backgroundColor, HashMap characters, List tags, List timeLineTags, HashMap files) { + StringBuilder ret = new StringBuilder(); + StartSoundTag lastStartSound = null; + SoundStreamHeadTypeTag lastSoundStreamHead = null; + StartSoundTag startSound = null; + SoundStreamHeadTypeTag soundStreamHead = null; + int duration = 1; + int frame = 0; + for (Tag t : timeLineTags) { + if (t instanceof StartSoundTag) { + startSound = (StartSoundTag) t; + + for (Tag ta : tags) { + if (ta instanceof DefineSoundTag) { + DefineSoundTag s = (DefineSoundTag) ta; + if (s.soundId == startSound.soundId) { + if (!files.containsKey("sound" + s.soundId + "." + s.getExportFormat())) { //Sound was not exported + startSound = null; // ignore + } + break; + } + } + } + + } + if (t instanceof SoundStreamHeadTypeTag) { + soundStreamHead = (SoundStreamHeadTypeTag) t; + if (!files.containsKey("sound" + soundStreamHead.getCharacterId() + "." + soundStreamHead.getExportFormat())) { //Sound was not exported + soundStreamHead = null; // ignore + } + } + if (t instanceof ShowFrameTag) { + if (soundStreamHead != null || startSound != null) { + if (lastSoundStreamHead != null || lastStartSound != null) { + ret.append(convertFrame(false, characters, tags, lastSoundStreamHead, lastStartSound, frame, duration, "", "", files)); + } + frame += duration; + duration = 1; + lastSoundStreamHead = soundStreamHead; + lastStartSound = startSound; + soundStreamHead = null; + startSound = null; + } else { + duration++; + } + } + } + if (lastSoundStreamHead != null || lastStartSound != null) { + if (frame < 0) { + frame = 0; + duration = 1; + } + ret.append(convertFrame(false, characters, tags, lastSoundStreamHead, lastStartSound, frame, duration, "", "", files)); + } + String retStr = ret.toString(); + if (!retStr.isEmpty()) { + retStr = "" + + "" + retStr + "" + + ""; + } + return retStr; + } + + private static String randomOutlineColor() { + RGB outlineColor = new RGB(); + do { + outlineColor.red = random.nextInt(256); + outlineColor.green = random.nextInt(256); + outlineColor.blue = random.nextInt(256); + } while ((outlineColor.red + outlineColor.green + outlineColor.blue) / 3 < 128); + return outlineColor.toHexRGB(); + } + + public static String convertTimeline(int spriteId, List nonLibraryShapes, String backgroundColor, List tags, List timelineTags, HashMap characters, String name, FLAVersion flaVersion, HashMap files) { + StringBuilder ret = new StringBuilder(); + ret.append(""); + ret.append(""); + + String labelsLayer = convertLabelsLayer(spriteId, tags, timelineTags, backgroundColor); + ret.append(labelsLayer); + String scriptLayer = convertActionScriptLayer(spriteId, tags, timelineTags, backgroundColor); + ret.append(scriptLayer); + + int index = 0; + + if (!labelsLayer.isEmpty()) { + index++; + } + + if (!scriptLayer.isEmpty()) { + index++; + } + + int layerCount = getLayerCount(timelineTags); + Stack parentLayers = new Stack<>(); + + for (int d = layerCount; d >= 1; d--, index++) { + for (Tag t : timelineTags) { + if (t instanceof PlaceObjectTypeTag) { + PlaceObjectTypeTag po = (PlaceObjectTypeTag) t; + if (po.getClipDepth() == d) { + for (int m = po.getDepth(); m < po.getClipDepth(); m++) { + parentLayers.push(index); + } + + ret.append(""); + ret.append(convertFrames("", "", nonLibraryShapes, tags, timelineTags, characters, po.getDepth(), flaVersion, files)); + ret.append(""); + index++; + break; + } + } + } + + boolean hasClipDepth = false; + for (Tag t : timelineTags) { + if (t instanceof PlaceObjectTypeTag) { + PlaceObjectTypeTag po = (PlaceObjectTypeTag) t; + if (po.getDepth() == d) { + if (po.getClipDepth() != -1) { + hasClipDepth = true; + break; + } + } + } + } + if (hasClipDepth) { + index--; + continue; + } + int parentLayer = -1; + if (!parentLayers.isEmpty()) { + parentLayer = parentLayers.pop(); + } + String layerPrev = ""; + + layerPrev += ""); + ret.append(""); + return ret.toString(); + } + + private static void writeFile(AbortRetryIgnoreHandler handler, final byte[] data, final String file) throws IOException { + new RetryTask(() -> { + try (FileOutputStream fos = new FileOutputStream(file)) { + fos.write(data); + } + }, handler).run(); + } + + private static Map getCharacterClasses(List tags) { + Map ret = new HashMap<>(); + for (Tag t : tags) { + if (t instanceof SymbolClassTag) { + SymbolClassTag sc = (SymbolClassTag) t; + for (int i = 0; i < sc.tags.size(); i++) { + if (!ret.containsKey(sc.tags.get(i)) && !ret.containsValue(sc.names.get(i))) { + ret.put(sc.tags.get(i), sc.names.get(i)); + } + } + } + } + return ret; + } + + private static Map getCharacterVariables(List tags) { + Map ret = new HashMap<>(); + for (Tag t : tags) { + if (t instanceof ExportAssetsTag) { + ExportAssetsTag ea = (ExportAssetsTag) t; + for (int i = 0; i < ea.tags.size(); i++) { + if (!ret.containsKey(ea.tags.get(i))) { + ret.put(ea.tags.get(i), ea.names.get(i)); + } + } + } + } + return ret; + } + + public static String convertText(String instanceName, TextTag tag, MATRIX m, List filters, CLIPACTIONS clipActions) { + StringBuilder ret = new StringBuilder(); + + if (m == null) { + m = new MATRIX(); + } + Matrix matrix = new Matrix(m); + CSMTextSettingsTag csmts = null; + String filterStr = ""; + if (filters != null) { + filterStr += ""; + for (FILTER f : filters) { + filterStr += convertFilter(f); + } + filterStr += ""; + } + + SWF swf = tag.getSwf(); + for (Tag t : swf.tags) { + if (t instanceof CSMTextSettingsTag) { + CSMTextSettingsTag c = (CSMTextSettingsTag) t; + if (c.textID == tag.getCharacterId()) { + csmts = c; + break; + } + } + } + + String fontRenderingMode = "standard"; + String antiAlias = ""; + if (csmts != null) { + if (csmts.thickness == 0 & csmts.sharpness == 0) { + fontRenderingMode = null; + } else { + fontRenderingMode = "customThicknessSharpness"; + } + antiAlias = " antiAliasSharpness=\"" + doubleToString(csmts.sharpness) + "\" antiAliasThickness=\"" + doubleToString(csmts.thickness) + "\""; + } + String matStr = ""; + matStr += ""; + String left = ""; + RECT bounds = tag.getBounds(); + if ((tag instanceof DefineTextTag) || (tag instanceof DefineText2Tag)) { + MATRIX textMatrix = tag.getTextMatrix(); + left = " left=\"" + doubleToString((textMatrix.translateX) / SWF.unitDivisor) + "\""; + } + matStr += convertMatrix(matrix); + matStr += ""; + if ((tag instanceof DefineTextTag) || (tag instanceof DefineText2Tag)) { + List textRecords = new ArrayList<>(); + if (tag instanceof DefineTextTag) { + textRecords = ((DefineTextTag) tag).textRecords; + } else if (tag instanceof DefineText2Tag) { + textRecords = ((DefineText2Tag) tag).textRecords; + } + + for (TEXTRECORD rec : textRecords) { + if (rec.styleFlagsHasFont) { + FontTag ft = swf.getFont(rec.fontId); + if (ft != null && ft.isSmall()) { + fontRenderingMode = "bitmap"; + break; + } + } + } + + ret.append(" attrs = TextTag.getTextRecordsAttributes(textRecords, swf); + + ret.append(" width=\"").append(tag.getBounds().getWidth() / 2).append("\" height=\"").append(tag.getBounds().getHeight()).append("\" autoExpand=\"true\" isSelectable=\"false\">"); + ret.append(matStr); + + ret.append(""); + int fontId = -1; + FontTag font = null; + String fontName = null; + String psFontName = null; + int textHeight = -1; + RGB textColor = null; + RGBA textColorA = null; + boolean newline = false; + boolean firstRun = true; + @SuppressWarnings("unchecked") + List leftMargins = (List) attrs.get("allLeftMargins"); + @SuppressWarnings("unchecked") + List letterSpacings = (List) attrs.get("allLetterSpacings"); + for (int r = 0; r < textRecords.size(); r++) { + TEXTRECORD rec = textRecords.get(r); + if (rec.styleFlagsHasColor) { + if (tag instanceof DefineTextTag) { + textColor = rec.textColor; + } else { + textColorA = rec.textColorA; + } + } + if (rec.styleFlagsHasFont) { + fontId = rec.fontId; + fontName = null; + textHeight = rec.textHeight; + font = swf.getFont(fontId); + for (Tag t : swf.tags) { + if (t instanceof DefineFontNameTag) { + if (((DefineFontNameTag) t).fontId == fontId) { + fontName = ((DefineFontNameTag) t).fontName; + } + } + } + if ((fontName == null) && (font != null)) { + fontName = font.getFontNameIntag(); + } + int fontStyle = 0; + if (font != null) { + fontStyle = font.getFontStyle(); + } + String installedFont; + if ((installedFont = FontTag.isFontFamilyInstalled(fontName)) != null) { + psFontName = new Font(installedFont, fontStyle, 10).getPSName(); + } else { + psFontName = fontName; + } + } + newline = false; + if (!firstRun && rec.styleFlagsHasYOffset) { + newline = true; + } + firstRun = false; + if (font != null) { + ret.append(""); + ret.append("").append(xmlString((newline ? "\r" : "") + rec.getText(font))).append(""); + ret.append(""); + + ret.append(""); + + ret.append(""); + ret.append(""); + } + } + ret.append(""); + ret.append(filterStr); + ret.append(""); + } else if (tag instanceof DefineEditTextTag) { + DefineEditTextTag det = (DefineEditTextTag) tag; + String tagName; + FontTag ft = swf.getFont(det.fontId); + if (ft != null && ft.isSmall()) { + fontRenderingMode = "bitmap"; + } + if (!det.useOutlines) { + fontRenderingMode = "device"; + } + if (det.wasStatic) { + tagName = "DOMStaticText"; + } else if (det.readOnly) { + tagName = "DOMDynamicText"; + } else { + tagName = "DOMInputText"; + } + ret.append("<").append(tagName); + if (fontRenderingMode != null) { + ret.append(" fontRenderingMode=\"").append(fontRenderingMode).append("\""); + } + if (instanceName != null) { + ret.append(" name=\"").append(xmlString(instanceName)).append("\""); + } + ret.append(antiAlias); + double width = twipToPixel(bounds.getWidth()); + double height = twipToPixel(bounds.getHeight()); + //There is usually 4px difference between width/height and XML width/height + //If somebody knows what that means, tell me + double padding = 2; + width -= 2 * padding; + height -= 2 * padding; + if (det.hasLayout) { + width -= twipToPixel(det.rightMargin); + width -= twipToPixel(det.leftMargin); + } + ret.append(" width=\"").append(width).append("\""); + ret.append(" height=\"").append(height).append("\""); + if (det.border) { + ret.append(" border=\"true\""); + } + if (det.html) { + ret.append(" renderAsHTML=\"true\""); + } + if (det.noSelect) { + ret.append(" isSelectable=\"false\""); + } + if (det.multiline && det.wordWrap) { + ret.append(" lineType=\"multiline\""); + } else if (det.multiline && (!det.wordWrap)) { + ret.append(" lineType=\"multiline no wrap\""); + } else if (det.password) { + ret.append(" lineType=\"password\""); + } + if (det.hasMaxLength) { + ret.append(" maxCharacters=\"").append(det.maxLength).append("\""); + } + if (!det.variableName.isEmpty()) { + ret.append(" variableName=\"").append(det.variableName).append("\""); + } + ret.append(">"); + ret.append(matStr); + ret.append(""); + String txt = ""; + if (det.hasText) { + txt = det.initialText; + } + + if (det.html) { + ret.append(convertHTMLText(swf.tags, det, txt)); + } else { + ret.append(""); + ret.append("").append(xmlString(txt)).append(""); + int leftMargin = -1; + int rightMargin = -1; + int indent = -1; + int lineSpacing = -1; + String alignment = null; + boolean italic = false; + boolean bold = false; + String fontFace = null; + int size = -1; + RGBA textColor = null; + if (det.hasTextColor) { + textColor = det.textColor; + } + if (det.hasFont) { + String fontName = null; + for (Tag u : swf.tags) { + if (u instanceof DefineFontNameTag) { + if (((DefineFontNameTag) u).fontId == det.fontId) { + fontName = ((DefineFontNameTag) u).fontName; + } + } + if (fontName != null && ft != null) { + break; + } + } + if (ft != null) { + if (fontName == null) { + fontName = ft.getFontNameIntag(); + } + italic = ft.isItalic(); + bold = ft.isBold(); + size = det.fontHeight; + fontFace = fontName; + String installedFont = null; + if ((installedFont = FontTag.isFontFamilyInstalled(fontName)) != null) { + fontName = installedFont; + fontFace = new Font(installedFont, (italic ? Font.ITALIC : 0) | (bold ? Font.BOLD : 0) | (!italic && !bold ? Font.PLAIN : 0), size < 0 ? 10 : size).getPSName(); + } + + } + } + if (det.hasLayout) { + leftMargin = det.leftMargin; + rightMargin = det.rightMargin; + indent = det.indent; + lineSpacing = det.leading; + String[] alignNames = {"left", "right", "center", "justify"}; + if (det.align < alignNames.length) { + alignment = alignNames[det.align]; + } else { + alignment = "unknown"; + } + } + ret.append(""); + ret.append(" -1) { + ret.append(" indent=\"").append(twipToPixel(indent)).append("\""); + } + if (leftMargin > -1) { + ret.append(" leftMargin=\"").append(twipToPixel(leftMargin)).append("\""); + } + if (lineSpacing > -1) { + ret.append(" lineSpacing=\"").append(twipToPixel(lineSpacing)).append("\""); + } + if (rightMargin > -1) { + ret.append(" rightMargin=\"").append(twipToPixel(rightMargin)).append("\""); + } + if (size > -1) { + ret.append(" size=\"").append(twipToPixel(size)).append("\""); + ret.append(" bitmapSize=\"").append(size).append("\""); + } + if (fontFace != null) { + ret.append(" face=\"").append(fontFace).append("\""); + } + if (textColor != null) { + ret.append(" fillColor=\"").append(textColor.toHexRGB()).append("\" alpha=\"").append(textColor.getAlphaFloat()).append("\""); + } + ret.append("/>"); + ret.append(""); + ret.append(""); + } + ret.append(""); + ret.append(filterStr); + ret.append(""); + } + return ret.toString(); + } + + public static void convertSWF(AbortRetryIgnoreHandler handler, SWF swf, String swfFileName, String outfile, boolean compressed, String generator, String generatorVerName, String generatorVersion, boolean parallel, FLAVersion flaVersion) throws IOException { + + FileAttributesTag fa = swf.getFileAttributes(); + + boolean useAS3 = false; + boolean useNetwork = false; + if (fa != null) { + useAS3 = fa.actionScript3; + useNetwork = fa.useNetwork; + } + + if (!useAS3 && flaVersion.minASVersion() > 2) { + throw new IllegalArgumentException("FLA version " + flaVersion + " does not support AS1/2"); + } + File file = new File(outfile); + File outDir = file.getParentFile(); + Path.createDirectorySafe(outDir); + StringBuilder domDocument = new StringBuilder(); + String baseName = swfFileName; + File f = new File(baseName); + baseName = f.getName(); + if (baseName.contains(".")) { + baseName = baseName.substring(0, baseName.lastIndexOf('.')); + } + final HashMap files = new HashMap<>(); + final HashMap datfiles = new HashMap<>(); + HashMap characters = getCharacters(swf.tags); + List nonLibraryShapes = getNonLibraryShapes(swf.tags, characters); + Map characterClasses = getCharacterClasses(swf.tags); + Map characterVariables = getCharacterVariables(swf.tags); + + String backgroundColor = "#ffffff"; + for (Tag t : swf.tags) { + if (t instanceof SetBackgroundColorTag) { + SetBackgroundColorTag sbc = (SetBackgroundColorTag) t; + backgroundColor = sbc.backgroundColor.toHexRGB(); + } + } + domDocument.append(""); + domDocument.append(convertFonts(swf.tags)); + domDocument.append(convertLibrary(swf, characterVariables, characterClasses, nonLibraryShapes, backgroundColor, swf.tags, characters, files, datfiles, flaVersion)); + domDocument.append(""); + domDocument.append(convertTimeline(0, nonLibraryShapes, backgroundColor, swf.tags, swf.tags, characters, "Scene 1", flaVersion, files)); + domDocument.append(""); + domDocument.append(""); + String domDocumentStr = prettyFormatXML(domDocument.toString()); + + for (Tag t : swf.tags) { + if (t instanceof DoInitActionTag) { + DoInitActionTag dia = (DoInitActionTag) t; + int chid = dia.getCharacterId(); + if (characters.containsKey(chid)) { + if (characters.get(chid) instanceof DefineSpriteTag) { + DefineSpriteTag sprite = (DefineSpriteTag) characters.get(chid); + if (sprite.subTags.isEmpty()) { + String data = convertActionScript(dia); + String expName = dia.getSwf().getExportName(dia.spriteId); + expName = expName != null ? expName : "_unk_"; + String expPath = expName; + final String prefix = "__Packages."; + if (expPath.startsWith(prefix)) { + expPath = expPath.substring(prefix.length()); + } + String expDir = ""; + if (expPath.contains(".")) { + expDir = expPath.substring(0, expPath.lastIndexOf('.')); + expDir = expDir.replace(".", File.separator); + } + expPath = expPath.replace(".", File.separator); + File cdir = new File(outDir.getAbsolutePath() + File.separator + expDir); + Path.createDirectorySafe(cdir); + writeFile(handler, Utf8Helper.getBytes(data), outDir.getAbsolutePath() + File.separator + expPath + ".as"); + } + } + } + } + } + + int flaSwfVersion = swf.version > flaVersion.maxSwfVersion() ? flaVersion.maxSwfVersion() : swf.version; + boolean greaterThanCC = flaVersion.ordinal() >= FLAVersion.CC.ordinal(); + StringBuilder publishSettings = new StringBuilder(); + publishSettings.append("\n"); + publishSettings.append("\n"); + publishSettings.append(" \n"); + publishSettings.append(" 1\n"); + publishSettings.append(" 1\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 1\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 0\n"); + publishSettings.append(greaterThanCC ? " 0\n" : " 0\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 1\n"); + publishSettings.append(" 1\n"); + publishSettings.append(" 1\n"); + publishSettings.append(" 1\n"); + publishSettings.append(" 1\n"); + publishSettings.append(" 1\n"); + publishSettings.append(" 1\n"); + publishSettings.append(greaterThanCC ? " 1\n" : " 1\n"); + publishSettings.append(" 1\n"); + publishSettings.append(" 1\n"); + publishSettings.append(" ").append(baseName).append(".swf\n"); + publishSettings.append(" ").append(baseName).append(".exe\n"); + publishSettings.append(" ").append(baseName).append(".app\n"); + publishSettings.append(" ").append(baseName).append(".html\n"); + publishSettings.append(" ").append(baseName).append(".gif\n"); + publishSettings.append(" ").append(baseName).append(".jpg\n"); + publishSettings.append(" ").append(baseName).append(".png\n"); + publishSettings.append(greaterThanCC ? " 1\n" : " 1\n"); + publishSettings.append(" ").append(baseName).append(".smil\n"); + publishSettings.append(" ").append(baseName).append(".swc\n"); + publishSettings.append(" \n"); + publishSettings.append(" \n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 12,0,0,0;11,2,0,0;11,1,0,0;10,3,0,0;10,2,153,0;10,1,52,0;9,0,124,0;8,0,24,0;7,0,14,0;6,0,79,0;5,0,58,0;4,0,32,0;3,0,8,0;2,0,1,12;1,0,0,1;\n"); + publishSettings.append(" 1\n"); + publishSettings.append(" 1\n"); + publishSettings.append(" ").append(baseName).append("_content.html\n"); + publishSettings.append(" ").append(baseName).append("_alternate.html\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" \n"); + publishSettings.append(" ").append(width).append("\n"); + publishSettings.append(" ").append(height).append("\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 1\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 1\n"); + publishSettings.append(" 1\n"); + publishSettings.append(" 4\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 1\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" \n"); + publishSettings.append(" 1\n"); + publishSettings.append(" \n"); + publishSettings.append(" \n"); + publishSettings.append(" \n"); + publishSettings.append(" \n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 80\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 7\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 7\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" ").append(flaSwfVersion).append("\n"); + publishSettings.append(" ").append(FLAVersion.swfVersionToPlayer(flaSwfVersion)).append("\n"); + publishSettings.append(" ").append(useAS3 ? "3" : "2").append("\n"); + publishSettings.append(" 1\n"); + publishSettings.append(" \n"); + publishSettings.append(" .\n"); + publishSettings.append(" CONFIG::FLASH_AUTHORING="true";\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" \n"); + publishSettings.append(" ").append(swf.compression == SWFCompression.NONE ? "0" : "1").append("\n"); + publishSettings.append(" ").append(swf.compression == SWFCompression.LZMA ? "1" : "0").append("\n"); + publishSettings.append(" 1\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" ").append(useNetwork ? 1 : 0).append("\n"); + publishSettings.append(" ").append(xmlString(characterClasses.containsKey(0) ? characterClasses.get(0) : "")).append("\n"); + publishSettings.append(" 2\n"); + publishSettings.append(" 4\n"); + publishSettings.append(" 4096\n"); + publishSettings.append(" AS3\n"); + publishSettings.append(" 1\n"); + publishSettings.append(" 1\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 15\n"); + publishSettings.append(" 1\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 4102\n"); + publishSettings.append(" rsl\n"); + publishSettings.append(" wrap\n"); + publishSettings.append(" $(AppConfig)/ActionScript 3.0/rsls/loader_animation.swf\n"); + if (greaterThanCC) { + publishSettings.append(" \n"); + publishSettings.append(" \n"); + publishSettings.append(" $(AppConfig)/ActionScript 3.0/libs\n"); + publishSettings.append(" merge\n"); + publishSettings.append(" \n"); + publishSettings.append(" \n"); + publishSettings.append(" $(FlexSDK)/frameworks/libs/flex.swc\n"); + publishSettings.append(" merge\n"); + publishSettings.append(" textLayout_2.0.0.232.swz\n"); + publishSettings.append(" \n"); + publishSettings.append(" \n"); + publishSettings.append(" $(FlexSDK)/frameworks/libs/core.swc\n"); + publishSettings.append(" merge\n"); + publishSettings.append(" textLayout_2.0.0.232.swz\n"); + publishSettings.append(" \n"); + publishSettings.append(" \n"); + publishSettings.append(" \n"); + publishSettings.append(" "); + } else { + publishSettings.append(" \n"); + publishSettings.append(" \n"); + publishSettings.append(" $(AppConfig)/ActionScript 3.0/libs\n"); + publishSettings.append(" merge\n"); + publishSettings.append(" \n"); + publishSettings.append(" \n"); + publishSettings.append(" $(AppConfig)/ActionScript 3.0/libs/11.0/textLayout.swc\n"); + publishSettings.append(" rsl\n"); + publishSettings.append(" http://fpdownload.adobe.com/pub/swz/tlf/2.0.0.232/textLayout_2.0.0.232.swz\n"); + publishSettings.append(" http://fpdownload.adobe.com/pub/swz/crossdomain.xml\n"); + publishSettings.append(" textLayout_2.0.0.232.swz\n"); + publishSettings.append(" \n"); + publishSettings.append(" \n"); + publishSettings.append(" \n"); + publishSettings.append(" \n"); + publishSettings.append(" $(AppConfig)/ActionScript 3.0/libs/11.0/textLayout.swc\n"); + publishSettings.append(" \n"); + publishSettings.append(" http://fpdownload.adobe.com/pub/swz/tlf/2.0.0.232/textLayout_2.0.0.232.swz\n"); + publishSettings.append(" http://fpdownload.adobe.com/pub/swz/crossdomain.xml\n"); + publishSettings.append(" textLayout_2.0.0.232.swz\n"); + publishSettings.append(" \n"); + publishSettings.append(" \n"); + } + publishSettings.append(" \n"); + publishSettings.append(" \n"); + publishSettings.append(" ").append(width).append("\n"); + publishSettings.append(" ").append(height).append("\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 4718592\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 80\n"); + publishSettings.append(" 1\n"); + publishSettings.append(" \n"); + publishSettings.append(" \n"); + publishSettings.append(" 1\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 1\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 100000\n"); + publishSettings.append(" 1\n"); + publishSettings.append(" 1\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 1\n"); + publishSettings.append(" \n"); + publishSettings.append(" \n"); + publishSettings.append(" ").append(width).append("\n"); + publishSettings.append(" ").append(height).append("\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 1\n"); + publishSettings.append(" 1\n"); + publishSettings.append(" \n"); + publishSettings.append(" 1\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 1\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" \n"); + publishSettings.append(" 128\n"); + publishSettings.append(" \n"); + publishSettings.append(" \n"); + publishSettings.append(" 255\n"); + publishSettings.append(" \n"); + publishSettings.append(" \n"); + publishSettings.append(" \n"); + publishSettings.append(" ").append(width).append("\n"); + publishSettings.append(" ").append(height).append("\n"); + publishSettings.append(" 1\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 1\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 1\n"); + publishSettings.append(" \n"); + publishSettings.append(" \n"); + publishSettings.append(" \n"); + publishSettings.append(" 24-bit with Alpha\n"); + publishSettings.append(" 255\n"); + publishSettings.append(" \n"); + publishSettings.append(" \n"); + if (!greaterThanCC) { + publishSettings.append(" \n"); + publishSettings.append(" ").append(width).append("\n"); + publishSettings.append(" ").append(height).append("\n"); + publishSettings.append(" 1\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" \n"); + publishSettings.append(" \n"); + publishSettings.append(" 00000000\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 0\n"); + publishSettings.append(" 1\n"); + publishSettings.append(" \n"); + } + publishSettings.append("\n"); + publishSettings.append(""); + String publishSettingsStr = publishSettings.toString(); + + if (compressed) { + final String domDocumentF = domDocumentStr; + final String publishSettingsF = publishSettingsStr; + final String outfileF = outfile; + new RetryTask(() -> { + try (ZipOutputStream out = new ZipOutputStream(new FileOutputStream(outfileF))) { + out.putNextEntry(new ZipEntry("DOMDocument.xml")); + out.write(Utf8Helper.getBytes(domDocumentF)); + out.putNextEntry(new ZipEntry("PublishSettings.xml")); + out.write(Utf8Helper.getBytes(publishSettingsF)); + for (String fileName : files.keySet()) { + out.putNextEntry(new ZipEntry("LIBRARY/" + fileName)); + out.write(files.get(fileName)); + } + for (String fileName : datfiles.keySet()) { + out.putNextEntry(new ZipEntry("bin/" + fileName)); + out.write(datfiles.get(fileName)); + } + } + }, handler).run(); + + } else { + Path.createDirectorySafe(outDir); + writeFile(handler, Utf8Helper.getBytes(domDocumentStr), outDir.getAbsolutePath() + File.separator + "DOMDocument.xml"); + writeFile(handler, Utf8Helper.getBytes(publishSettingsStr), outDir.getAbsolutePath() + File.separator + "PublishSettings.xml"); + File libraryDir = new File(outDir.getAbsolutePath() + File.separator + "LIBRARY"); + libraryDir.mkdir(); + File binDir = new File(outDir.getAbsolutePath() + File.separator + "bin"); + binDir.mkdir(); + for (String fileName : files.keySet()) { + writeFile(handler, files.get(fileName), libraryDir.getAbsolutePath() + File.separator + fileName); + } + for (String fileName : datfiles.keySet()) { + writeFile(handler, datfiles.get(fileName), binDir.getAbsolutePath() + File.separator + fileName); + } + writeFile(handler, Utf8Helper.getBytes("PROXY-CS5"), outfile); + } + if (useAS3) { + try { + ScriptExportSettings scriptExportSettings = new ScriptExportSettings(ScriptExportMode.AS, false); + swf.exportActionScript(handler, Path.combine(outDir.getAbsolutePath(), "scripts"), scriptExportSettings, parallel, null); + } catch (Exception ex) { + Logger.getLogger(XFLConverter.class.getName()).log(Level.SEVERE, "Error during ActionScript3 export", ex); + } + } + } + + private static int normHue(double h) { + if (Double.isNaN(h)) { + h = -Math.PI; + } + int ret = (int) Math.round(h * 180 / Math.PI); + while (ret > 180) { + ret -= 360; + } + while (ret < -180) { + ret += 360; + } + return ret; + } + + private static int normBrightness(double b) { + if (Double.isNaN(b)) { + b = -100; + } + return (int) Math.round(b); + } + + private static int normSaturation(double s) { + if (Double.isNaN(s)) { + return -100; + } else if (s == 1) { + return 0; + } else if (s - 1 < 0) { + return (int) Math.round((s - 1) * 100); + } else { + return (int) Math.round(((s - 1) * 100) / 3); + } + } + + private static int normContrast(double c) { + double[] ctrMap = { + // 0 1 2 3 4 5 6 7 8 9 + /*0*/0, 0.01, 0.02, 0.04, 0.05, 0.06, 0.07, 0.08, 0.1, 0.11, + /*1*/ 0.12, 0.14, 0.15, 0.16, 0.17, 0.18, 0.20, 0.21, 0.22, 0.24, + /*2*/ 0.25, 0.27, 0.28, 0.30, 0.32, 0.34, 0.36, 0.38, 0.40, 0.42, + /*3*/ 0.44, 0.46, 0.48, 0.5, 0.53, 0.56, 0.59, 0.62, 0.65, 0.68, + /*4*/ 0.71, 0.74, 0.77, 0.80, 0.83, 0.86, 0.89, 0.92, 0.95, 0.98, + /*5*/ 1.0, 1.06, 1.12, 1.18, 1.24, 1.30, 1.36, 1.42, 1.48, 1.54, + /*6*/ 1.60, 1.66, 1.72, 1.78, 1.84, 1.90, 1.96, 2.0, 2.12, 2.25, + /*7*/ 2.37, 2.50, 2.62, 2.75, 2.87, 3.0, 3.2, 3.4, 3.6, 3.8, + /*8*/ 4.0, 4.3, 4.7, 4.9, 5.0, 5.5, 6.0, 6.5, 6.8, 7.0, + /*9*/ 7.3, 7.5, 7.8, 8.0, 8.4, 8.7, 9.0, 9.4, 9.6, 9.8, + /*10*/ 10.0}; + if (c == 127) { + return 0; + } else if (c - 127 < 0) { + return (int) Math.round((c - 127) * 100.0 / 127.0); + } else { + c = (c - 127) / 127; + for (int i = 0; i < ctrMap.length; i++) { + if (ctrMap[i] >= c) { + return i; + } + } + } + return ctrMap.length - 1; + } + + private static boolean sameDouble(double a, double b) { + final double EPSILON = 0.00001; + return a == b ? true : Math.abs(a - b) < EPSILON; + } + + public static String convertAdjustColorFilter(COLORMATRIXFILTER filter) { + float[][] matrix = new float[5][5]; + int index = 0; + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 5; j++) { + matrix[j][i] = filter.matrix[index]; + index++; + } + } + double a11 = matrix[0][0], a12 = matrix[0][1], a13 = matrix[0][2], + a21 = matrix[1][0], a22 = matrix[1][1], a23 = matrix[1][2], + a31 = matrix[2][0], a32 = matrix[2][1], a33 = matrix[2][2], + a41 = matrix[4][0]; + + double b, c, h, s; + b = (24872168661075.0 * a11 * a11 - 151430415740925.0 * a12 + 341095051289483.0 * a12 * a12 - 15302094789450.0 * a13 + 82428663495404.0 * a12 * a13 + - 4592294873812.0 * a13 * a13 + 43556251470.0 * Math.sqrt(216225 * a11 * a11 + 332369 * a12 * a12 - 397828 * a12 * a13 + 281684 * a13 * a13 + - 930 * a11 * (287 * a12 + 178 * a13)) + 2384730956550.0 * a12 * a41 + 240977870700.0 * a13 * a41 + - 685925220 * Math.sqrt(216225 * a11 * a11 + 332369 * a12 * a12 - 397828 * a12 * a13 + 281684 * a13 * a13 - 930 * a11 * (287 * a12 + 178 * a13)) + * a41 + 465 * a11 * (466201717582.0 * a12 + 55756962908.0 * a13 + 764132175 * (-127 + 2 * a41))) + / (391687695450.0 * a11 * a11 + 5371575610858.0 * a12 * a12 + 1298089188904.0 * a12 * a13 - 72319604312.0 * a13 * a13 + + 1860 * a11 * (1835439833 * a12 + 219515602 * a13)); + c = (127 * (495225 * a11 + 1661845 * a12 + 167930 * a13 + + 478 * Math.sqrt(216225 * a11 * a11 + 332369 * a12 * a12 - 397828 * a12 * a13 + 281684 * a13 * a13 - 930 * a11 * (287 * a12 + 178 * a13)))) + / 717495; + h = 2 * (Math.atan((-465 * a11 + 287 * a12 + 178 * a13 + Math.sqrt(216225 * a11 * a11 + 332369 * a12 * a12 - 397828 * a12 * a13 + 281684 * a13 * a13 + - 930 * a11 * (287 * a12 + 178 * a13))) / (500. * (a12 - a13))) + Math.PI/*+ Pi*C(1)*/); + s = (1543 * (-103355550 * a11 * a11 - 158872382 * a12 * a12 + 190161784 * a12 * a13 - 134644952 * a13 * a13 + + 1661845 * a12 * Math.sqrt(216225 * a11 * a11 + 332369 * a12 * a12 - 397828 * a12 * a13 + 281684 * a13 * a13 + - 930 * a11 * (287 * a12 + 178 * a13)) + 167930 * a13 + * Math.sqrt(216225 * a11 * a11 + 332369 * a12 * a12 - 397828 * a12 * a13 + 281684 * a13 * a13 - 930 * a11 * (287 * a12 + 178 * a13)) + + 465 * a11 * (274372 * a12 + 170168 * a13 + 1065 * Math.sqrt(216225 * a11 * a11 + 332369 * a12 * a12 - 397828 * a12 * a13 + + 281684 * a13 * a13 - 930 * a11 * (287 * a12 + 178 * a13))))) + / (195843847725.0 * a11 * a11 + 2685787805429.0 * a12 * a12 + 649044594452.0 * a12 * a13 - 36159802156.0 * a13 * a13 + + 930 * a11 * (1835439833 * a12 + 219515602 * a13)); + + if (sameDouble(410 * a12, 1543 * a31) && sameDouble(410 * a12, 1543 * a32) && sameDouble(3047 * a12, 1543 * a21) && sameDouble(3047 * a12, 1543 * a23) + && sameDouble(a22, a11 + (1504 * a12) / 1543.) && sameDouble((1133 * a12) / 1543. + a33, a11) + /*&& (b == (195961 * a11 + 439039 * a12 + 1543 * (-127 + 2 * a41)) / (3086 * a11 + 6914 * a12)) + && (c == 127 * a11 + (439039 * a12) / 1543.) && (s == (1543 * (a11 - a12)) / (1543 * a11 + 3457 * a12)) + */ && !sameDouble(a11, a12) && !sameDouble(1543 * a11 + 3457 * a12, 0)) { + h = 0; + } + + return ""; + } + + private static String convertHTMLText(List tags, DefineEditTextTag det, String html) { + HTMLTextParser tparser = new HTMLTextParser(tags, det); + XMLReader parser; + try { + SAXParserFactory factory = SAXParserFactory.newInstance(); + parser = XMLReaderFactory.createXMLReader(); + parser.setContentHandler(tparser); + parser.setErrorHandler(tparser); + html = "\n" + + " \n" + + "]>" + html + ""; + try { + parser.parse(new InputSource(new StringReader(html))); + } catch (SAXParseException spe) { + System.out.println(html); + System.err.println(tparser.result); + } + } catch (SAXException | IOException e) { + Logger.getLogger(XFLConverter.class.getName()).log(Level.SEVERE, "Error while converting HTML", e); + } + return tparser.result; + } + + private static String xmlString(String s) { + return s.replace("<", "<").replace(">", ">").replace("\"", """).replace("&", "&").replace("\r\n", " ").replace("\r", " ").replace("\n", " "); + } + + private static double twipToPixel(double tw) { + return tw / SWF.unitDivisor; + } + + private static class HTMLTextParser extends DefaultHandler { + + public String result = ""; + + private String fontFace = ""; + + private String color = ""; + + private int size = -1; + + private int indent = -1; + + private int leftMargin = -1; + + private int rightMargin = -1; + + private int lineSpacing = -1; + + private double letterSpacing = -1; + + private String alignment = null; + + private final List tags; + + private boolean bold = false; + + private boolean italic = false; + + private boolean underline = false; + + private boolean li = false; + + private String url = null; + + private String target = null; + + @Override + public void error(SAXParseException e) throws SAXException { + } + + @Override + public void fatalError(SAXParseException e) throws SAXException { + } + + @Override + public void warning(SAXParseException e) throws SAXException { + } + + public HTMLTextParser(List tags, DefineEditTextTag det) { + if (det.hasFont) { + String fontName = null; + FontTag ft = null; + for (Tag u : tags) { + if (u instanceof DefineFontNameTag) { + if (((DefineFontNameTag) u).fontId == det.fontId) { + fontName = ((DefineFontNameTag) u).fontName; + } + } + if (u instanceof FontTag) { + if (((FontTag) u).getFontId() == det.fontId) { + ft = (FontTag) u; + } + } + if (fontName != null && ft != null) { + break; + } + } + if (ft != null) { + if (fontName == null) { + fontName = ft.getFontNameIntag(); + } + italic = ft.isItalic(); + bold = ft.isBold(); + size = det.fontHeight; + fontFace = new Font(fontName, (italic ? Font.ITALIC : 0) | (bold ? Font.BOLD : 0) | (!italic && !bold ? Font.PLAIN : 0), size < 0 ? 10 : size).getPSName(); + } + } + if (det.hasLayout) { + leftMargin = det.leftMargin; + rightMargin = det.rightMargin; + indent = det.indent; + lineSpacing = det.leading; + String[] alignNames = {"left", "right", "center", "justify"}; + if (det.align < alignNames.length) { + alignment = alignNames[det.align]; + } else { + alignment = "unknown"; + } + } + this.tags = tags; + } + + @Override + public void startDocument() throws SAXException { + } + + @Override + public void startElement(String uri, String localName, + String qName, Attributes attributes) throws SAXException { + switch (qName) { + case "a": + String href = attributes.getValue("href"); + if (href != null) { + url = href; + } + String t = attributes.getValue("target"); + if (t != null) { + target = t; + } + break; + case "b": + bold = true; + break; + case "i": + italic = true; + break; + case "u": + underline = true; + break; + case "li": + li = true; + break; + case "p": + String a = attributes.getValue("align"); + if (a != null) { + alignment = a; + } + if (!result.isEmpty()) { + putText("\r\n"); + } + break; + case "font": + //kerning ? + String ls = attributes.getValue("letterSpacing"); + if (ls != null) { + letterSpacing = Double.parseDouble(ls); + } + String s = attributes.getValue("size"); + if (s != null) { + size = Integer.parseInt(s); + } + String c = attributes.getValue("color"); + if (c != null) { + color = c; + } + String f = attributes.getValue("face"); + if (f != null) { + for (Tag tag : tags) { + if (tag instanceof FontTag) { + FontTag ft = (FontTag) tag; + String fontName = null; + if (f.equals(ft.getFontNameIntag())) { + for (Tag u : tags) { + if (u instanceof DefineFontNameTag) { + if (((DefineFontNameTag) u).fontId == ft.getFontId()) { + fontName = ((DefineFontNameTag) u).fontName; + } + } + } + if (fontName == null) { + fontName = ft.getFontNameIntag(); + } + String installedFont; + if ((installedFont = FontTag.isFontFamilyInstalled(fontName)) != null) { + fontFace = new Font(installedFont, (italic ? Font.ITALIC : 0) | (bold ? Font.BOLD : 0) | (!italic && !bold ? Font.PLAIN : 0), size < 0 ? 10 : size).getPSName(); + } else { + fontFace = fontName; + } + break; + } + } + } + } + break; + } + } + + @Override + public void endElement(String uri, String localName, + String qName) throws SAXException { + if (qName.equals("a")) { + url = null; + target = null; + } + if (qName.equals("b")) { + bold = false; + } + if (qName.equals("i")) { + italic = false; + } + if (qName.equals("u")) { + underline = false; + } + if (qName.equals("li")) { + li = false; + } + } + + private void putText(String txt) { + + result += ""; + result += "" + xmlString(txt) + ""; + result += ""; + result += " -1) { + result += " indent=\"" + twipToPixel(indent) + "\""; + } + if (leftMargin > -1) { + result += " leftMargin=\"" + twipToPixel(leftMargin) + "\""; + } + if (letterSpacing > -1) { + result += " letterSpacing=\"" + letterSpacing + "\""; + } + if (lineSpacing > -1) { + result += " lineSpacing=\"" + twipToPixel(lineSpacing) + "\""; + } + if (rightMargin > -1) { + result += " rightMargin=\"" + twipToPixel(rightMargin) + "\""; + } + if (size > -1) { + result += " size=\"" + size + "\""; + result += " bitmapSize=\"" + (size * 20) + "\""; + } + if (fontFace != null) { + result += " face=\"" + fontFace + "\""; + } + if (color != null) { + result += " fillColor=\"" + color + "\""; + } + if (url != null) { + result += " url=\"" + url + "\""; + } + if (target != null) { + result += " target=\"" + target + "\""; + } + result += "/>"; + result += ""; + result += ""; + } + + @Override + public void characters(char[] ch, int start, int length) + throws SAXException { + putText(new String(ch, start, length)); + + } + + @Override + public void endDocument() { + if (this.result.isEmpty()) { + putText(""); + } + } + } +} diff --git a/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java b/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java index 043b14fa0..4cd488383 100644 --- a/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java +++ b/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java @@ -816,7 +816,7 @@ public class CommandLineArgumentParser { try { tagId = Integer.parseInt(tagIdOrName); } catch (NumberFormatException e) { - tagId = Tag.getKnownClassesByName().get(tagIdOrName).id; + tagId = Tag.getKnownClassesByName().get(tagIdOrName).getId(); } File[] files = new File(folder).listFiles(getSwfFilter());