diff --git a/trunk/src/com/jpexs/decompiler/flash/Main.java b/trunk/src/com/jpexs/decompiler/flash/Main.java index f436a5ffa..435753e5c 100644 --- a/trunk/src/com/jpexs/decompiler/flash/Main.java +++ b/trunk/src/com/jpexs/decompiler/flash/Main.java @@ -514,8 +514,13 @@ public class Main { if (!exportFormat.toLowerCase().equals("text")) { if (!exportFormat.toLowerCase().equals("textplain")) { if (!exportFormat.toLowerCase().equals("all")) { - System.err.println("Invalid export format:" + exportFormat); - badArguments(); + if (!exportFormat.toLowerCase().equals("fla")) { + if (!exportFormat.toLowerCase().equals("xfl")) { + System.err.println("Invalid export format:" + exportFormat); + badArguments(); + } + } + } } @@ -593,6 +598,12 @@ public class Main { } else if (exportFormat.equals("textplain")) { exfile.exportTexts(outDir.getAbsolutePath(), false); exportOK = true; + } else if (exportFormat.equals("fla")) { + exfile.exportFla(outDir.getAbsolutePath(), inFile.getName()); + exportOK = true; + } else if (exportFormat.equals("xfl")) { + exfile.exportXfl(outDir.getAbsolutePath(), inFile.getName()); + exportOK = true; } else { exportOK = false; } diff --git a/trunk/src/com/jpexs/decompiler/flash/SWF.java b/trunk/src/com/jpexs/decompiler/flash/SWF.java index 01f5d048e..2ab0aeb6d 100644 --- a/trunk/src/com/jpexs/decompiler/flash/SWF.java +++ b/trunk/src/com/jpexs/decompiler/flash/SWF.java @@ -19,7 +19,6 @@ package com.jpexs.decompiler.flash; import SevenZip.Compression.LZMA.Encoder; import com.jpexs.decompiler.flash.abc.ABC; import com.jpexs.decompiler.flash.abc.ScriptPack; -import com.jpexs.decompiler.flash.abc.types.traits.Trait; import com.jpexs.decompiler.flash.action.Action; import com.jpexs.decompiler.flash.action.ActionGraphSource; import com.jpexs.decompiler.flash.action.swf4.ActionEquals; @@ -75,6 +74,7 @@ import com.jpexs.decompiler.flash.tags.base.ImageTag; import com.jpexs.decompiler.flash.tags.base.ShapeTag; import com.jpexs.decompiler.flash.tags.base.TextTag; import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.decompiler.flash.xfl.XFLConverter; import java.io.*; import java.util.ArrayList; import java.util.Arrays; @@ -1147,4 +1147,12 @@ public class SWF { } return ret; } + + public void exportFla(String outfile, String swfName) { + XFLConverter.convertSWF(this, swfName, outfile, true); + } + + public void exportXfl(String outfile, String swfName) { + XFLConverter.convertSWF(this, swfName, outfile, false); + } } diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/ScriptPack.java b/trunk/src/com/jpexs/decompiler/flash/abc/ScriptPack.java index e412af511..e5334b664 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/ScriptPack.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/ScriptPack.java @@ -16,7 +16,6 @@ */ package com.jpexs.decompiler.flash.abc; -import com.jpexs.decompiler.flash.abc.ABC; import com.jpexs.decompiler.flash.abc.types.Multiname; import com.jpexs.decompiler.flash.abc.types.Namespace; import com.jpexs.decompiler.flash.tags.ABCContainerTag; diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/gui/ClassesListTree.java b/trunk/src/com/jpexs/decompiler/flash/abc/gui/ClassesListTree.java index 6825354c7..3879f5fd6 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/gui/ClassesListTree.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/gui/ClassesListTree.java @@ -16,11 +16,9 @@ */ package com.jpexs.decompiler.flash.abc.gui; -import com.jpexs.decompiler.flash.abc.ScriptPack; import com.jpexs.decompiler.flash.Main; import com.jpexs.decompiler.flash.abc.ABC; -import com.jpexs.decompiler.flash.abc.types.Multiname; -import com.jpexs.decompiler.flash.abc.types.Namespace; +import com.jpexs.decompiler.flash.abc.ScriptPack; import com.jpexs.decompiler.flash.abc.types.ScriptInfo; import com.jpexs.decompiler.flash.abc.types.traits.Trait; import com.jpexs.decompiler.flash.abc.types.traits.TraitClass; diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/gui/DecompiledEditorPane.java b/trunk/src/com/jpexs/decompiler/flash/abc/gui/DecompiledEditorPane.java index d82851e54..e116691b0 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/gui/DecompiledEditorPane.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/gui/DecompiledEditorPane.java @@ -16,8 +16,8 @@ */ package com.jpexs.decompiler.flash.abc.gui; -import com.jpexs.decompiler.flash.abc.ScriptPack; import com.jpexs.decompiler.flash.abc.ABC; +import com.jpexs.decompiler.flash.abc.ScriptPack; import com.jpexs.decompiler.flash.abc.types.ScriptInfo; import com.jpexs.decompiler.flash.abc.types.traits.Trait; import com.jpexs.decompiler.flash.abc.types.traits.TraitSlotConst; diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java b/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java index f18ee43d4..8d8b043a4 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java @@ -20,12 +20,12 @@ import com.jpexs.decompiler.flash.Configuration; import com.jpexs.decompiler.flash.Main; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.abc.ScriptPack; import com.jpexs.decompiler.flash.abc.gui.ABCPanel; import com.jpexs.decompiler.flash.abc.gui.ClassesListTreeModel; import com.jpexs.decompiler.flash.abc.gui.DeobfuscationDialog; import com.jpexs.decompiler.flash.abc.gui.LineMarkedEditorPane; import com.jpexs.decompiler.flash.abc.gui.TreeElement; -import com.jpexs.decompiler.flash.abc.ScriptPack; import com.jpexs.decompiler.flash.abc.types.traits.Trait; import com.jpexs.decompiler.flash.abc.types.traits.TraitClass; import com.jpexs.decompiler.flash.action.gui.ActionPanel; diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/NewVersionDialog.java b/trunk/src/com/jpexs/decompiler/flash/gui/NewVersionDialog.java index 2e47351d3..5bc2d292b 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/NewVersionDialog.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/NewVersionDialog.java @@ -43,8 +43,8 @@ import javax.swing.UIManager; */ public class NewVersionDialog extends JDialog implements ActionListener { - Version latestVersion; - + Version latestVersion; + public NewVersionDialog(List versions) { setSize(new Dimension(500, 300)); Container cnt = getContentPane(); @@ -104,9 +104,9 @@ public class NewVersionDialog extends JDialog implements ActionListener { this.getRootPane().setDefaultButton(buttonOk); View.centerScreen(this); setModalityType(ModalityType.APPLICATION_MODAL); - changesText.setCaretPosition(0); + changesText.setCaretPosition(0); } - + @Override public void actionPerformed(ActionEvent e) { if (e.getActionCommand().equals("OK")) { diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java index b334d3e04..6860652d5 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java @@ -21,6 +21,7 @@ import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; import com.jpexs.decompiler.flash.abc.CopyOutputStream; import com.jpexs.decompiler.flash.tags.base.BoundedTag; +import com.jpexs.decompiler.flash.tags.base.ButtonTag; import com.jpexs.decompiler.flash.tags.base.CharacterTag; import com.jpexs.decompiler.flash.tags.base.Container; import com.jpexs.decompiler.flash.types.BUTTONCONDACTION; @@ -44,7 +45,7 @@ import java.util.logging.Logger; * * @author JPEXS */ -public class DefineButton2Tag extends CharacterTag implements Container, BoundedTag { +public class DefineButton2Tag extends CharacterTag implements Container, BoundedTag, ButtonTag { /** * ID for this character @@ -68,6 +69,11 @@ public class DefineButton2Tag extends CharacterTag implements Container, Bounded return buttonId; } + @Override + public List getRecords() { + return characters; + } + /** * Constructor * diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java index 231569fa6..86a714dcf 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java @@ -26,6 +26,7 @@ import com.jpexs.decompiler.flash.abc.CopyOutputStream; import com.jpexs.decompiler.flash.action.Action; import com.jpexs.decompiler.flash.tags.base.ASMSource; import com.jpexs.decompiler.flash.tags.base.BoundedTag; +import com.jpexs.decompiler.flash.tags.base.ButtonTag; import com.jpexs.decompiler.flash.tags.base.CharacterTag; import com.jpexs.decompiler.flash.types.BUTTONRECORD; import com.jpexs.decompiler.flash.types.RECT; @@ -46,7 +47,7 @@ import java.util.logging.Logger; * * @author JPEXS */ -public class DefineButtonTag extends CharacterTag implements ASMSource, BoundedTag { +public class DefineButtonTag extends CharacterTag implements ASMSource, BoundedTag, ButtonTag { /** * ID for this character @@ -68,6 +69,11 @@ public class DefineButtonTag extends CharacterTag implements ASMSource, BoundedT } private long hdrSize; + @Override + public List getRecords() { + return characters; + } + /** * Constructor * diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape2Tag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape2Tag.java index d8e448978..c80ff571e 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape2Tag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape2Tag.java @@ -33,6 +33,16 @@ public class DefineShape2Tag extends CharacterTag implements BoundedTag, ShapeTa public RECT shapeBounds; public SHAPEWITHSTYLE shapes; + @Override + public int getShapeNum() { + return 2; + } + + @Override + public SHAPEWITHSTYLE getShapes() { + return shapes; + } + @Override public Set getNeededCharacters() { return shapes.getNeededCharacters(); diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape3Tag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape3Tag.java index 83879ccf8..84cee3cca 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape3Tag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape3Tag.java @@ -33,6 +33,16 @@ public class DefineShape3Tag extends CharacterTag implements BoundedTag, ShapeTa public RECT shapeBounds; public SHAPEWITHSTYLE shapes; + @Override + public int getShapeNum() { + return 3; + } + + @Override + public SHAPEWITHSTYLE getShapes() { + return shapes; + } + @Override public Set getNeededCharacters() { return shapes.getNeededCharacters(); diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape4Tag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape4Tag.java index 02c04013a..feaa26cd0 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape4Tag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape4Tag.java @@ -37,6 +37,16 @@ public class DefineShape4Tag extends CharacterTag implements BoundedTag, ShapeTa public boolean usesScalingStrokes; public SHAPEWITHSTYLE shapes; + @Override + public int getShapeNum() { + return 4; + } + + @Override + public SHAPEWITHSTYLE getShapes() { + return shapes; + } + @Override public Set getNeededCharacters() { return shapes.getNeededCharacters(); diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineShapeTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineShapeTag.java index 0926649c7..c0a6e2493 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineShapeTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineShapeTag.java @@ -33,6 +33,16 @@ public class DefineShapeTag extends CharacterTag implements BoundedTag, ShapeTag public RECT shapeBounds; public SHAPEWITHSTYLE shapes; + @Override + public int getShapeNum() { + return 1; + } + + @Override + public SHAPEWITHSTYLE getShapes() { + return shapes; + } + @Override public Set getNeededCharacters() { return shapes.getNeededCharacters(); diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/PlaceObject2Tag.java b/trunk/src/com/jpexs/decompiler/flash/tags/PlaceObject2Tag.java index dae37dbaa..10c785115 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/PlaceObject2Tag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/PlaceObject2Tag.java @@ -22,8 +22,10 @@ import com.jpexs.decompiler.flash.SWFOutputStream; import com.jpexs.decompiler.flash.abc.CopyOutputStream; import com.jpexs.decompiler.flash.tags.base.Container; import com.jpexs.decompiler.flash.types.CLIPACTIONS; +import com.jpexs.decompiler.flash.types.CXFORM; import com.jpexs.decompiler.flash.types.CXFORMWITHALPHA; import com.jpexs.decompiler.flash.types.MATRIX; +import com.jpexs.decompiler.flash.types.filters.FILTER; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -105,6 +107,19 @@ public class PlaceObject2Tag extends Tag implements Container, PlaceObjectTypeTa */ public CLIPACTIONS clipActions; + @Override + public int getClipDepth() { + if (placeFlagHasClipDepth) { + return clipDepth; + } + return -1; + } + + @Override + public List getFilters() { + return new ArrayList(); + } + /** * Gets data bytes * @@ -279,4 +294,31 @@ public class PlaceObject2Tag extends Tag implements Container, PlaceObjectTypeTa return null; } } + + @Override + public String getName() { + if (placeFlagHasName) { + return name; + } + return null; + } + + @Override + public CXFORM getColorTransform() { + return null; + } + + @Override + public CXFORMWITHALPHA getColorTransformWithAlpha() { + if (placeFlagHasColorTransform) { + return colorTransform; + } else { + return null; + } + } + + @Override + public int getBlendMode() { + return 0; + } } diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/PlaceObject3Tag.java b/trunk/src/com/jpexs/decompiler/flash/tags/PlaceObject3Tag.java index 218255083..a26ffc902 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/PlaceObject3Tag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/PlaceObject3Tag.java @@ -22,6 +22,7 @@ import com.jpexs.decompiler.flash.SWFOutputStream; import com.jpexs.decompiler.flash.abc.CopyOutputStream; import com.jpexs.decompiler.flash.tags.base.Container; import com.jpexs.decompiler.flash.types.CLIPACTIONS; +import com.jpexs.decompiler.flash.types.CXFORM; import com.jpexs.decompiler.flash.types.CXFORMWITHALPHA; import com.jpexs.decompiler.flash.types.MATRIX; import com.jpexs.decompiler.flash.types.filters.FILTER; @@ -148,6 +149,23 @@ public class PlaceObject3Tag extends Tag implements Container, PlaceObjectTypeTa // FIXME bug found in ecoDrive.swf, private boolean bitmapCacheBug; + @Override + public List getFilters() { + if (placeFlagHasFilterList) { + return surfaceFilterList; + } else { + return new ArrayList(); + } + } + + @Override + public int getClipDepth() { + if (placeFlagHasClipDepth) { + return clipDepth; + } + return -1; + } + /** * Gets data bytes * @@ -181,7 +199,7 @@ public class PlaceObject3Tag extends Tag implements Container, PlaceObjectTypeTa sos.writeUB(1, placeFlagHasBlendMode ? 1 : 0); sos.writeUB(1, placeFlagHasFilterList ? 1 : 0); sos.writeUI16(depth); - if (placeFlagHasClassName || (placeFlagHasImage && placeFlagHasCharacter)) { + if (placeFlagHasClassName) { sos.writeString(className); } if (placeFlagHasCharacter) { @@ -248,7 +266,7 @@ public class PlaceObject3Tag extends Tag implements Container, PlaceObjectTypeTa placeFlagHasFilterList = sis.readUB(1) == 1; depth = sis.readUI16(); - if (placeFlagHasClassName || (placeFlagHasImage && placeFlagHasCharacter)) { + if (placeFlagHasClassName) { className = sis.readString(); } if (placeFlagHasCharacter) { @@ -347,4 +365,31 @@ public class PlaceObject3Tag extends Tag implements Container, PlaceObjectTypeTa return null; } } + + @Override + public String getName() { + if (placeFlagHasName) { + return name; + } + return null; + } + + @Override + public CXFORM getColorTransform() { + return null; + } + + @Override + public CXFORMWITHALPHA getColorTransformWithAlpha() { + if (placeFlagHasColorTransform) { + return colorTransform; + } else { + return null; + } + } + + @Override + public int getBlendMode() { + return blendMode; + } } diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/PlaceObjectTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/PlaceObjectTag.java index b10a7b62e..9cb3ec0a8 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/PlaceObjectTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/PlaceObjectTag.java @@ -19,12 +19,16 @@ package com.jpexs.decompiler.flash.tags; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; import com.jpexs.decompiler.flash.types.CXFORM; +import com.jpexs.decompiler.flash.types.CXFORMWITHALPHA; import com.jpexs.decompiler.flash.types.MATRIX; +import com.jpexs.decompiler.flash.types.filters.FILTER; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; +import java.util.ArrayList; import java.util.HashSet; +import java.util.List; import java.util.Set; /** @@ -51,6 +55,16 @@ public class PlaceObjectTag extends Tag implements PlaceObjectTypeTag { */ public CXFORM colorTransform; + @Override + public List getFilters() { + return new ArrayList(); + } + + @Override + public int getClipDepth() { + return -1; + } + /** * Gets data bytes * @@ -121,4 +135,24 @@ public class PlaceObjectTag extends Tag implements PlaceObjectTypeTag { public MATRIX getMatrix() { return matrix; } + + @Override + public String getName() { + return null; + } + + @Override + public CXFORM getColorTransform() { + return colorTransform; + } + + @Override + public CXFORMWITHALPHA getColorTransformWithAlpha() { + return null; + } + + @Override + public int getBlendMode() { + return 0; + } } diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/PlaceObjectTypeTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/PlaceObjectTypeTag.java index 44925327e..92235d1eb 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/PlaceObjectTypeTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/PlaceObjectTypeTag.java @@ -1,6 +1,10 @@ package com.jpexs.decompiler.flash.tags; +import com.jpexs.decompiler.flash.types.CXFORM; +import com.jpexs.decompiler.flash.types.CXFORMWITHALPHA; import com.jpexs.decompiler.flash.types.MATRIX; +import com.jpexs.decompiler.flash.types.filters.FILTER; +import java.util.List; /** * @@ -13,4 +17,16 @@ public interface PlaceObjectTypeTag { public int getDepth(); public MATRIX getMatrix(); + + public String getName(); + + public CXFORM getColorTransform(); + + public CXFORMWITHALPHA getColorTransformWithAlpha(); + + public int getBlendMode(); + + public List getFilters(); + + public int getClipDepth(); } diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/base/ButtonTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/base/ButtonTag.java new file mode 100644 index 000000000..5f929bda8 --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/tags/base/ButtonTag.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2013 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.jpexs.decompiler.flash.tags.base; + +import com.jpexs.decompiler.flash.types.BUTTONRECORD; +import java.util.List; + +/** + * + * @author JPEXS + */ +public interface ButtonTag { + + public List getRecords(); +} diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/base/ShapeTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/base/ShapeTag.java index 3cf67af6b..08e15eb05 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/base/ShapeTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/base/ShapeTag.java @@ -16,11 +16,17 @@ */ package com.jpexs.decompiler.flash.tags.base; +import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE; + /** * * @author JPEXS */ public interface ShapeTag { + public SHAPEWITHSTYLE getShapes(); + public String toSVG(); + + public int getShapeNum(); } diff --git a/trunk/src/com/jpexs/decompiler/flash/types/GRADIENT.java b/trunk/src/com/jpexs/decompiler/flash/types/GRADIENT.java index e257e7fef..db87fa22f 100644 --- a/trunk/src/com/jpexs/decompiler/flash/types/GRADIENT.java +++ b/trunk/src/com/jpexs/decompiler/flash/types/GRADIENT.java @@ -25,7 +25,7 @@ public class GRADIENT { public int spreadMode; public static final int SPREAD_PAD_MODE = 0; public static final int SPREAD_REFLECT_MODE = 1; - public static final int SPREAD_REPAT_MODE = 2; + public static final int SPREAD_REPEAT_MODE = 2; public static final int SPREAD_RESERVED = 3; public int interPolationMode; public static final int INTERPOLATION_RGB_MODE = 0; diff --git a/trunk/src/com/jpexs/decompiler/flash/types/GRADRECORD.java b/trunk/src/com/jpexs/decompiler/flash/types/GRADRECORD.java index 28e9eaeff..4e0b58d3e 100644 --- a/trunk/src/com/jpexs/decompiler/flash/types/GRADRECORD.java +++ b/trunk/src/com/jpexs/decompiler/flash/types/GRADRECORD.java @@ -26,4 +26,8 @@ public class GRADRECORD { public boolean inShape3; public RGB color; public RGBA colorA; + + public float getRatioFloat() { + return ((float) ratio) / 255.0f; + } } diff --git a/trunk/src/com/jpexs/decompiler/flash/types/MATRIX.java b/trunk/src/com/jpexs/decompiler/flash/types/MATRIX.java index 23fe42896..f7356b372 100644 --- a/trunk/src/com/jpexs/decompiler/flash/types/MATRIX.java +++ b/trunk/src/com/jpexs/decompiler/flash/types/MATRIX.java @@ -68,7 +68,7 @@ public class MATRIX implements Serializable { return "[MATRIX scale:" + scaleX + "," + scaleY + ", rotate:" + rotateSkew0 + "," + rotateSkew1 + ", translate:" + translateX + "," + translateY + "]"; } - private float toFloat(int i) { + public float toFloat(int i) { return ((float) i) / (1 << 16); } diff --git a/trunk/src/com/jpexs/decompiler/flash/types/RGBA.java b/trunk/src/com/jpexs/decompiler/flash/types/RGBA.java index 4aad985f0..e22f6d2a6 100644 --- a/trunk/src/com/jpexs/decompiler/flash/types/RGBA.java +++ b/trunk/src/com/jpexs/decompiler/flash/types/RGBA.java @@ -40,6 +40,10 @@ public class RGBA { */ public int alpha; + public float getAlphaFloat() { + return ((float) alpha) / 255.0f; + } + public String toHexRGB() { String rh = Integer.toHexString(red); if (rh.length() < 2) { diff --git a/trunk/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java b/trunk/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java new file mode 100644 index 000000000..bfadbe6aa --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java @@ -0,0 +1,1547 @@ +/* + * Copyright (C) 2013 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.jpexs.decompiler.flash.xfl; + +import com.jpexs.decompiler.flash.Main; +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.tags.ABCContainerTag; +import com.jpexs.decompiler.flash.tags.DefineButton2Tag; +import com.jpexs.decompiler.flash.tags.DefineSpriteTag; +import com.jpexs.decompiler.flash.tags.PlaceObjectTypeTag; +import com.jpexs.decompiler.flash.tags.SetBackgroundColorTag; +import com.jpexs.decompiler.flash.tags.ShowFrameTag; +import com.jpexs.decompiler.flash.tags.Tag; +import com.jpexs.decompiler.flash.tags.base.ButtonTag; +import com.jpexs.decompiler.flash.tags.base.CharacterTag; +import com.jpexs.decompiler.flash.tags.base.ImageTag; +import com.jpexs.decompiler.flash.tags.base.ShapeTag; +import com.jpexs.decompiler.flash.types.BUTTONRECORD; +import com.jpexs.decompiler.flash.types.CXFORM; +import com.jpexs.decompiler.flash.types.CXFORMWITHALPHA; +import com.jpexs.decompiler.flash.types.FILLSTYLE; +import static com.jpexs.decompiler.flash.types.FILLSTYLE.*; +import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY; +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.RGBA; +import com.jpexs.decompiler.flash.types.SHAPE; +import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE; +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 java.awt.Point; +import java.awt.image.BufferedImage; +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.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +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.imageio.ImageIO; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; + +/** + * + * @author JPEXS + */ +public class XFLConverter { + + private XFLConverter(){ + + } + + public static String convertShapeEdge(MATRIX mat, SHAPERECORD record, int x, int y) { + String ret = ""; + 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 ret; + } + + public static String convertShapeEdges(MATRIX mat, List records) { + String ret = ""; + int x = 0; + int y = 0; + for (SHAPERECORD rec : records) { + ret += convertShapeEdge(mat, rec, x, y); + x = rec.changeX(x); + y = rec.changeY(y); + } + return ret; + } + + public static String convertLineStyle(LINESTYLE ls, int shapeNum) { + return "" + + "" + + "" + + "" + + ""; + } + + public static String convertLineStyle(LINESTYLE2 ls, int shapeNum) { + String ret = ""; + String params = ""; + if (ls.pixelHintingFlag) { + params += " pixelHinting=\"true\""; + } + if ((!ls.noHScaleFlag) && (!ls.noVScaleFlag)) { + params += " scaleMode=\"normal\""; + } else if ((!ls.noHScaleFlag) && ls.noVScaleFlag) { + params += " scaleMode=\"horizontal\""; + } else if (ls.noHScaleFlag && (!ls.noVScaleFlag)) { + params += " scaleMode=\"vertical\""; + } + + switch (ls.startCapStyle) { //What about endCapStyle? + case LINESTYLE2.NO_CAP: + params += " caps=\"none\""; + break; + case LINESTYLE2.SQUARE_CAP: + params += " caps=\"square\""; + break; + } + switch (ls.joinStyle) { + case LINESTYLE2.BEVEL_JOIN: + params += " joints=\"bevel\""; + break; + case LINESTYLE2.MITER_JOIN: + params += " joints=\"miter\""; + float miterLimitFactor = toFloat(ls.miterLimitFactor); + if (miterLimitFactor != 3.0f) { + params += " miterLimit=\"" + miterLimitFactor + "\""; + } + break; + } + + ret += ""; + } else { + ret += convertFillStyle(ls.fillType, shapeNum); + } + ret += ""; + ret += ""; + return ret; + } + + private static float toFloat(int i) { + return ((float) i) / (1 << 16); + } + + public static String convertFillStyle(FILLSTYLE fs, int shapeNum) { + String ret = ""; + //ret += ""; + switch (fs.fillStyleType) { + case SOLID: + ret += "= 3) { + ret += fs.colorA.toHexRGB(); + } else { + ret += fs.color.toHexRGB(); + } + ret += "\""; + if (shapeNum >= 3) { + ret += " alpha=\"" + fs.colorA.getAlphaFloat() + "\""; + } + ret += " />"; + break; + case REPEATING_BITMAP: + case CLIPPED_BITMAP: + case NON_SMOOTHED_REPEATING_BITMAP: + case NON_SMOOTHED_CLIPPED_BITMAP: + ret += ""; + ret += ""; + break; + case LINEAR_GRADIENT: + case RADIAL_GRADIENT: + case FOCAL_RADIAL_GRADIENT: + + if (fs.fillStyleType == LINEAR_GRADIENT) { + ret += ""; + GRADRECORD records[]; + if (fs.fillStyleType == FOCAL_RADIAL_GRADIENT) { + records = fs.focalGradient.gradientRecords; + } else { + records = fs.gradient.gradientRecords; + } + for (GRADRECORD rec : records) { + ret += " shapeRecords) { + return convertShape(mat, shapeNum, shapeRecords, null, null); + } + + public static String convertShape(MATRIX mat, int shapeNum, List shapeRecords, FILLSTYLEARRAY fillStyles, LINESTYLEARRAY lineStyles) { + String ret = ""; + if (mat == null) { + mat = new MATRIX(); + } + List edges = new ArrayList(); + int fillStyleCount = 0; + int lineStyleCount = 0; + int lastFillStyleCount = 0; + int lastLineStyleCount = 0; + String edgeStyle = ""; + int fillStyle0 = -1; + int fillStyle1 = -1; + int strokeStyle = -1; + String edgesStr = ""; + String fillsStr = ""; + String strokesStr = ""; + fillsStr += ""; + strokesStr += ""; + edgesStr += ""; + + if (fillStyles != null) { + for (FILLSTYLE fs : fillStyles.fillStyles) { + fillsStr += ""; + fillsStr += convertFillStyle(fs, shapeNum); + fillsStr += ""; + fillStyleCount++; + } + lastFillStyleCount = fillStyleCount; + } + if (lineStyles != null) { + if (shapeNum == 4) { + for (int l = 0; l < lineStyles.lineStyles2.length; l++) { + strokesStr += ""; + strokesStr += convertLineStyle(lineStyles.lineStyles2[l], shapeNum); + strokesStr += ""; + lineStyleCount++; + } + } else { + for (int l = 0; l < lineStyles.lineStyles.length; l++) { + strokesStr += ""; + strokesStr += convertLineStyle(lineStyles.lineStyles[l], shapeNum); + strokesStr += ""; + lineStyleCount++; + } + } + lastLineStyleCount = lineStyleCount; + } + for (SHAPERECORD edge : shapeRecords) { + if (edge instanceof StyleChangeRecord) { + StyleChangeRecord scr = (StyleChangeRecord) edge; + if (scr.stateNewStyles) { + for (int f = 0; f < scr.fillStyles.fillStyles.length; f++) { + fillsStr += ""; + fillsStr += convertFillStyle(scr.fillStyles.fillStyles[f], shapeNum); + fillsStr += ""; + fillStyleCount++; + } + if (shapeNum == 4) { + for (int l = 0; l < scr.lineStyles.lineStyles2.length; l++) { + strokesStr += ""; + strokesStr += convertLineStyle(scr.lineStyles.lineStyles2[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++; + } + } + lastFillStyleCount = scr.fillStyles.fillStyles.length; + lastLineStyleCount = (shapeNum == 4) ? scr.lineStyles.lineStyles2.length : scr.lineStyles.lineStyles.length; + } + if (scr.stateFillStyle0) { + /*edgeStyle += " fillStyle0=\""; + edgeStyle += fillStyleCount - lastFillStyleCount + scr.fillStyle0; + edgeStyle += "\"";*/ + fillStyle0 = fillStyleCount - lastFillStyleCount + scr.fillStyle0; + } + if (scr.stateFillStyle1) { + /*edgeStyle += " fillStyle1=\""; + edgeStyle += fillStyleCount - lastFillStyleCount + scr.fillStyle1; + edgeStyle += "\"";*/ + fillStyle1 = fillStyleCount - lastFillStyleCount + scr.fillStyle1; + } + if (scr.stateLineStyle) { + /*edgeStyle += " strokeStyle=\""; + edgeStyle += lineStyleCount - lastLineStyleCount + scr.lineStyle; + edgeStyle += "\"";*/ + strokeStyle = lineStyleCount - lastLineStyleCount + scr.lineStyle; + } + if (!edges.isEmpty()) { + edgesStr += " -1) { + edgesStr += " fillStyle0=\"" + fillStyle0 + "\""; + } + if (fillStyle1 > -1) { + edgesStr += " fillStyle1=\"" + fillStyle1 + "\""; + } + if (strokeStyle > -1) { + edgesStr += " strokeStyle=\"" + strokeStyle + "\""; + } + edgesStr += " edges=\"" + convertShapeEdges(mat, edges) + "\" />"; + edgeStyle = ""; + strokeStyle = -1; + fillStyle0 = -1; + fillStyle1 = -1; + } + edges.clear(); + } + edges.add(edge); + } + if (!edges.isEmpty()) { + edgesStr += " -1) { + edgesStr += " fillStyle0=\"" + fillStyle0 + "\""; + } + if (fillStyle1 > -1) { + edgesStr += " fillStyle1=\"" + fillStyle1 + "\""; + } + if (strokeStyle > -1) { + edgesStr += " strokeStyle=\"" + strokeStyle + "\""; + } + edgesStr += " edges=\"" + convertShapeEdges(mat, edges) + "\" />"; + edgeStyle = ""; + } + edges.clear(); + fillsStr += ""; + strokesStr += ""; + edgesStr += ""; + + ret += ""; + ret += fillsStr; + ret += strokesStr; + ret += edgesStr; + ret += ""; + return ret; + } + + 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 List getOneInstanceShapes(List tags, HashMap characters) { + HashMap usages = new HashMap(); + //HashMap stage=new HashMap(); + for (Tag t : tags) { + 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.getName() != null) { + usageCount++; + } + if (po.getColorTransform() != null) { + usageCount++; + } + if (po.getColorTransformWithAlpha() != null) { + usageCount++; + } + usages.put(ch, usageCount + 1); + //stage.put(po.getDepth(), ch); + } + } + } + List ret = new ArrayList(); + for (int ch : usages.keySet()) { + if (usages.get(ch) < 2) { + ret.add(ch); + } + } + return ret; + } + + private static HashMap getCharacters(List tags) { + HashMap ret = new HashMap(); + for (Tag t : tags) { + 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) { + String ds = "" + d; + if (ds.endsWith(".0")) { + ds = ds.substring(0, ds.length() - 2); + } + return ds; + } + + public static String convertFilter(FILTER filter) { + String ret = ""; + if (filter instanceof DROPSHADOWFILTER) { + DROPSHADOWFILTER dsf = (DROPSHADOWFILTER) filter; + ret += " filters, CharacterTag tag, HashMap characters) { + String ret = ""; + if (matrix == null) { + matrix = new MATRIX(); + } + + ret += " oneInstanceShapes, String backgroundColor, List tags, HashMap characters, HashMap files) { + String ret = ""; + List media = new ArrayList(); + List symbols = new ArrayList(); + for (int ch : characters.keySet()) { + CharacterTag symbol = characters.get(ch); + if ((symbol instanceof ShapeTag) && oneInstanceShapes.contains(symbol.getCharacterID())) { + continue; //shapes with 1 ocurrence are not added to library + } + if ((symbol instanceof ShapeTag) || (symbol instanceof DefineSpriteTag) || (symbol instanceof ButtonTag)) { + String symbolStr = ""; + + symbolStr += ""; + symbolStr += ""; + symbolStr += ""; //color=\"#4FFF4F\" + symbolStr += ""; + ButtonTag button = (ButtonTag) symbol; + List records = button.getRecords(); + String frames[] = {"", "", "", ""}; + int lastFrame = 0; + int frame = 0; + for (BUTTONRECORD rec : records) { + 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; + } + } + String recCharStr = convertSymbolInstance(null, null, null, colorTransformAlpha, blendMode, filters, characters.get(rec.characterId), characters); + if (rec.buttonStateUp) { + frame = 1; + } + if (rec.buttonStateOver) { + frame = 2; + } + if (rec.buttonStateDown) { + frame = 3; + } + if (rec.buttonStateHitTest) { + frame = 4; + } + int duration = frame - lastFrame; + lastFrame = frame; + if (duration > 0) { + symbolStr += " 1) { + symbolStr += " duration=\"" + duration + "\""; + } + symbolStr += " keyMode=\"9728\">"; + symbolStr += ""; + symbolStr += recCharStr; + symbolStr += ""; + symbolStr += ""; + } + } + + symbolStr += ""; + symbolStr += ""; + symbolStr += ""; + symbolStr += ""; + } else if (symbol instanceof DefineSpriteTag) { + DefineSpriteTag sprite = (DefineSpriteTag) symbol; + symbolStr += convertTimeline(oneInstanceShapes, backgroundColor, sprite.getSubTags(), characters, "Symbol " + symbol.getCharacterID()); + } else if (symbol instanceof ShapeTag) { + itemIcon = "1"; + ShapeTag shape = (ShapeTag) symbol; + symbolStr += ""; + symbolStr += ""; + symbolStr += ""; //color=\"#4FFF4F\" + symbolStr += ""; + symbolStr += ""; + symbolStr += ""; + symbolStr += convertShape(null, shape); + symbolStr += ""; + symbolStr += ""; + symbolStr += ""; + symbolStr += ""; + symbolStr += ""; + symbolStr += ""; + } + symbolStr += ""; + symbolStr += ""; + symbolStr = prettyFormatXML(symbolStr); + String symbolFile = "Symbol " + symbol.getCharacterID() + ".xml"; + try { + files.put(symbolFile, symbolStr.getBytes("UTF-8")); + } catch (UnsupportedEncodingException ex) { + Logger.getLogger(XFLConverter.class.getName()).log(Level.SEVERE, null, ex); + } + String symbLinkStr = ""; + symbLinkStr += ""; //TODO: itemID=\"518de416-00000341\" + symbols.add(symbLinkStr); + } else { + if (symbol instanceof ImageTag) { + ImageTag imageTag = (ImageTag) symbol; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + BufferedImage image = imageTag.getImage(tags); + String format = imageTag.getImageFormat(); + try { + ImageIO.write(image, format.toUpperCase(), baos); + } catch (IOException ex) { + Logger.getLogger(XFLConverter.class.getName()).log(Level.SEVERE, null, ex); + } + String symbolFile = "bitmap" + symbol.getCharacterID() + "." + imageTag.getImageFormat(); + files.put(symbolFile, baos.toByteArray()); + String mediaLinkStr = "\n"; + //sourceExternalFilepath=\"../xfl/LIBRARY/Page-White-Code-32.png\" + //itemID=\"518d55d6-00000304\" + media.add(mediaLinkStr); + } + //bitmap,sound... + } + } + if (!media.isEmpty()) { + ret += ""; + for (String m : media) { + ret += m; + } + ret += ""; + } + if (!symbols.isEmpty()) { + ret += ""; + for (String s : symbols) { + ret += s; + } + ret += ""; + } + return ret; + } + + 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 (Exception e) { + throw new RuntimeException(e); // simple exception handling, please review it + } + } + + private static String convertFrames(String prevStr, String afterStr, List oneInstanceShapes, List tags, HashMap characters, int depth) { + String ret = ""; + prevStr += ""; + int frame = -1; + String elements = ""; + String lastElements = ""; + int characterId = -1; + int duration = 1; + for (Tag t : tags) { + 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)) { + CharacterTag ch = characters.get(characterId); + if ((ch instanceof ShapeTag) && oneInstanceShapes.contains(characterId)) { + elements += convertShape(po.getMatrix(), (ShapeTag) ch); + } else { + elements += convertSymbolInstance(po.getName(), po.getMatrix(), po.getColorTransform(), po.getColorTransformWithAlpha(), po.getBlendMode(), po.getFilters(), characters.get(characterId), characters); + } + } + } + } + if (t instanceof ShowFrameTag) { + if (!elements.equals("")) { + if (!lastElements.equals("")) { + ret += " 1) { + ret += " duration=\"" + duration + "\""; + } + ret += " keyMode=\"9728\">"; + ret += ""; + ret += lastElements; + ret += ""; + ret += ""; + } + frame += duration; + duration = 1; + lastElements = elements; + elements = ""; + } else { + duration++; + } + } + } + if (!lastElements.equals("")) { + ret += " 1) { + ret += " duration=\"" + duration + "\""; + } + ret += " keyMode=\"9728\">"; + ret += ""; + ret += lastElements; + ret += ""; + ret += ""; + frame += duration; + duration = 1; + elements = ""; + } + + afterStr = "" + afterStr; + if (!ret.equals("")) { + ret = prevStr + ret + afterStr; + } + return ret; + } + + public static String convertTimeline(List oneInstanceShapes, String backgroundColor, List tags, HashMap characters, String name) { + String ret = ""; + ret += ""; + ret += ""; + int layerCount = getLayerCount(tags); + Stack parentLayers = new Stack(); + //Set maskLayers=new HashSet(); + int index = 0; + for (int d = layerCount; d >= 1; d--, index++) { + for (Tag t : tags) { + + 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 += ""; + HashMap files = new HashMap(); + HashMap characters = getCharacters(swf.tags); + List oneInstaceShapes = getOneInstanceShapes(swf.tags, characters); + String backgroundColor = "#ffffff"; + for (Tag t : swf.tags) { + if (t instanceof SetBackgroundColorTag) { + SetBackgroundColorTag sbc = (SetBackgroundColorTag) t; + backgroundColor = sbc.backgroundColor.toHexRGB(); + } + } + domDocument += convertLibrary(oneInstaceShapes, backgroundColor, swf.tags, characters, files); + domDocument += ""; + domDocument += convertTimeline(oneInstaceShapes, backgroundColor, swf.tags, characters, "Scene 1"); + domDocument += ""; + domDocument += ""; + domDocument = prettyFormatXML(domDocument); + + boolean asV3Found = false; + for (Tag t : swf.tags) { + if (t instanceof ABCContainerTag) { + asV3Found = true; + } + } + + String publishSettings = "\n" + + "\n" + + " \n" + + " 1\n" + + " 1\n" + + " 0\n" + + " 0\n" + + " 1\n" + + " 0\n" + + " 0\n" + + " 0\n" + + " 0\n" + + " 0\n" + + " 0\n" + + " 1\n" + + " 1\n" + + " 1\n" + + " 1\n" + + " 1\n" + + " 1\n" + + " 1\n" + + " 1\n" + + " 1\n" + + " 1\n" + + " " + baseName + ".swf\n" + + " " + baseName + ".exe\n" + + " " + baseName + ".app\n" + + " " + baseName + ".html\n" + + " " + baseName + ".gif\n" + + " " + baseName + ".jpg\n" + + " " + baseName + ".png\n" + + " " + baseName + ".mov\n" + + " " + baseName + ".smil\n" + + " Untitled-4.swc\n" + + " \n" + + " \n" + + " 0\n" + + " 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" + + " 1\n" + + " 1\n" + + " " + baseName + "_content.html\n" + + " " + baseName + "_alternate.html\n" + + " 0\n" + + " \n" + + " " + (swf.displayRect.getWidth() / 20) + "\n" + + " " + (swf.displayRect.getHeight() / 20) + "\n" + + " 0\n" + + " 0\n" + + " 1\n" + + " 0\n" + + " 0\n" + + " 1\n" + + " 1\n" + + " 4\n" + + " 0\n" + + " 0\n" + + " 1\n" + + " 0\n" + + " \n" + + " 1\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 0\n" + + " 0\n" + + " 0\n" + + " 80\n" + + " 0\n" + + " 0\n" + + " 7\n" + + " 0\n" + + " 7\n" + + " 0\n" + + " 15\n" + + " FlashPlayer11.2\n" + + " " + (asV3Found ? "3" : "2") + "\n" + + " 1\n" + + " \n" + + " .\n" + + " CONFIG::FLASH_AUTHORING="true";\n" + + " 0\n" + + " \n" + + " 1\n" + + " 0\n" + + " 1\n" + + " 0\n" + + " 0\n" + + " 0\n" + + " 0\n" + + " \n" + + " 2\n" + + " 4\n" + + " 4096\n" + + " AS3\n" + + " 1\n" + + " 1\n" + + " 0\n" + + " 15\n" + + " 1\n" + + " 0\n" + + " 4102\n" + + " rsl\n" + + " wrap\n" + + " $(AppConfig)/ActionScript 3.0/rsls/loader_animation.swf\n" + + " \n" + + " \n" + + " $(AppConfig)/ActionScript 3.0/libs\n" + + " merge\n" + + " \n" + + " \n" + + " $(AppConfig)/ActionScript 3.0/libs/11.0/textLayout.swc\n" + + " rsl\n" + + " http://fpdownload.adobe.com/pub/swz/tlf/2.0.0.232/textLayout_2.0.0.232.swz\n" + + " http://fpdownload.adobe.com/pub/swz/crossdomain.xml\n" + + " textLayout_2.0.0.232.swz\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " $(AppConfig)/ActionScript 3.0/libs/11.0/textLayout.swc\n" + + " \n" + + " http://fpdownload.adobe.com/pub/swz/tlf/2.0.0.232/textLayout_2.0.0.232.swz\n" + + " http://fpdownload.adobe.com/pub/swz/crossdomain.xml\n" + + " textLayout_2.0.0.232.swz\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " " + (swf.displayRect.getWidth() / 20) + "\n" + + " " + (swf.displayRect.getHeight() / 20) + "\n" + + " 0\n" + + " 4718592\n" + + " 0\n" + + " 80\n" + + " 1\n" + + " \n" + + " \n" + + " 1\n" + + " 0\n" + + " 1\n" + + " 0\n" + + " 0\n" + + " 100000\n" + + " 1\n" + + " 1\n" + + " 0\n" + + " 0\n" + + " 0\n" + + " 0\n" + + " 0\n" + + " 0\n" + + " 1\n" + + " \n" + + " \n" + + " 550\n" + + " 400\n" + + " 0\n" + + " 1\n" + + " 1\n" + + " \n" + + " 1\n" + + " 0\n" + + " 1\n" + + " 0\n" + + " 0\n" + + " \n" + + " 128\n" + + " \n" + + " \n" + + " 255\n" + + " \n" + + " \n" + + " \n" + + " 550\n" + + " 400\n" + + " 1\n" + + " 0\n" + + " 0\n" + + " 1\n" + + " 0\n" + + " 0\n" + + " 1\n" + + " \n" + + " \n" + + " \n" + + " 24-bit with Alpha\n" + + " 255\n" + + " \n" + + " \n" + + " \n" + + " 550\n" + + " 400\n" + + " 1\n" + + " 0\n" + + " \n" + + " \n" + + " 00000000\n" + + " 0\n" + + " 0\n" + + " 0\n" + + " 0\n" + + " 1\n" + + " \n" + + "\n" + + ""; + + if (compressed) { + ZipOutputStream out = null; + try { + out = new ZipOutputStream(new FileOutputStream(outfile)); + out.putNextEntry(new ZipEntry("DOMDocument.xml")); + out.write(domDocument.getBytes("UTF-8")); + out.putNextEntry(new ZipEntry("PublishSettings.xml")); + out.write(publishSettings.getBytes("UTF-8")); + for (String fileName : files.keySet()) { + out.putNextEntry(new ZipEntry("LIBRARY/" + fileName)); + out.write(files.get(fileName)); + } + } catch (IOException ex) { + Logger.getLogger(XFLConverter.class.getName()).log(Level.SEVERE, null, ex); + } finally { + if (out != null) { + try { + out.close(); + } catch (IOException ex) { + //ignore + } + } + } + + } else { + File xfl = new File(outfile); + File outDir = xfl.getParentFile(); + outDir.mkdirs(); + try { + writeFile(domDocument.getBytes("UTF-8"), outDir.getAbsolutePath() + File.separator + "DOMDocument.xml"); + } catch (UnsupportedEncodingException ex) { + Logger.getLogger(XFLConverter.class.getName()).log(Level.SEVERE, null, ex); + } + try { + writeFile(publishSettings.getBytes("UTF-8"), outDir.getAbsolutePath() + File.separator + "PublishSettings.xml"); + } catch (UnsupportedEncodingException ex) { + Logger.getLogger(XFLConverter.class.getName()).log(Level.SEVERE, null, ex); + } + File libraryDir = new File(outDir.getAbsolutePath() + File.separator + "LIBRARY"); + libraryDir.mkdir(); + for (String fileName : files.keySet()) { + writeFile(files.get(fileName), libraryDir.getAbsolutePath() + File.separator + fileName); + } + + writeFile("PROXY-CS5".getBytes(), outfile); + } + } + + 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 ""; + } +}