/*
* 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.SWF;
import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.helpers.Highlighting;
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.PlaceObjectTypeTag;
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.SoundStreamHeadTypeTag;
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.RemoveTag;
import com.jpexs.decompiler.flash.tags.base.ShapeTag;
import com.jpexs.decompiler.flash.tags.base.TextTag;
import com.jpexs.decompiler.flash.types.BUTTONCONDACTION;
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 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.RGB;
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.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 java.awt.Font;
import java.awt.GraphicsEnvironment;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
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.Map;
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.parsers.SAXParserFactory;
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;
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 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(int startX, int startY, MATRIX mat, List records) {
String ret = "";
int x = startX;
int y = startY;
ret += "!" + startX + " " + startY;
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(HashMap characters, LINESTYLE2 ls, int shapeNum) {
String ret = "";
String params = "";
if (ls.pixelHintingFlag) {
params += " pixelHinting=\"true\"";
}
if (ls.width == 1) {
params += " solidStyle=\"hairline\"";
}
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.endCapStyle) { //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 += "";
ret += "";
if (!ls.hasFillFlag) {
ret += "";
} else {
ret += convertFillStyle(null/* FIXME */, characters, ls.fillType, shapeNum);
}
ret += "";
ret += "";
return ret;
}
private static float toFloat(int i) {
return ((float) i) / (1 << 16);
}
public static String convertFillStyle(MATRIX mat, HashMap characters, FILLSTYLE fs, int shapeNum) {
if (mat == null) {
mat = new MATRIX();
}
String ret = "";
//ret += "";
switch (fs.fillStyleType) {
case FILLSTYLE.SOLID:
ret += "= 3) {
ret += fs.colorA.toHexRGB();
} else {
ret += fs.color.toHexRGB();
}
ret += "\"";
if (shapeNum >= 3) {
ret += " alpha=\"" + fs.colorA.getAlphaFloat() + "\"";
}
ret += " />";
break;
case FILLSTYLE.REPEATING_BITMAP:
case FILLSTYLE.CLIPPED_BITMAP:
case FILLSTYLE.NON_SMOOTHED_REPEATING_BITMAP:
case FILLSTYLE.NON_SMOOTHED_CLIPPED_BITMAP:
ret += "";
ret += "" + convertMatrix(fs.bitmapMatrix) + "";
ret += "";
break;
case FILLSTYLE.LINEAR_GRADIENT:
case FILLSTYLE.RADIAL_GRADIENT:
case FILLSTYLE.FOCAL_RADIAL_GRADIENT:
if (fs.fillStyleType == FILLSTYLE.LINEAR_GRADIENT) {
ret += "";
ret += "" + convertMatrix(fs.gradientMatrix) + "";
GRADRECORD records[];
if (fs.fillStyleType == FILLSTYLE.FOCAL_RADIAL_GRADIENT) {
records = fs.focalGradient.gradientRecords;
} else {
records = fs.gradient.gradientRecords;
}
for (GRADRECORD rec : records) {
ret += "= 3 ? rec.colorA.toHexRGB() : rec.color.toHexRGB()) + "\"";
if (shapeNum >= 3) {
ret += " alpha=\"" + rec.colorA.getAlphaFloat() + "\"";
}
ret += " ratio=\"" + rec.getRatioFloat() + "\"";
ret += " />";
}
if (fs.fillStyleType == FILLSTYLE.LINEAR_GRADIENT) {
ret += "";
} else {
ret += "";
}
break;
}
//ret += "";
return ret;
}
public static String convertMatrix(MATRIX m) {
String ret = "";
if (m == null) {
m = new MATRIX();
}
ret += "";
return ret;
}
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) {
return convertShape(characters, mat, shapeNum, shape.shapeRecords, shape.fillStyles, shape.lineStyles, false);
}
public static String convertShape(HashMap characters, MATRIX mat, ShapeTag shape) {
return convertShape(characters, mat, shape.getShapeNum(), shape.getShapes());
}
public static String convertShape(HashMap characters, MATRIX mat, int shapeNum, List shapeRecords) {
return convertShape(characters, mat, shapeNum, shapeRecords, null, null, false);
}
public static String convertShape(HashMap characters, MATRIX mat, int shapeNum, List shapeRecords, FILLSTYLEARRAY fillStyles, LINESTYLEARRAY lineStyles, boolean morphshape) {
String ret = "";
if (mat == null) {
mat = new MATRIX();
}
List edges = new ArrayList<>();
//int fillStyleCount = 0;
int lineStyleCount = 0;
int fillStyle0 = -1;
int fillStyle1 = -1;
int strokeStyle = -1;
//String edgesStr = "";
String fillsStr = "";
String strokesStr = "";
fillsStr += "";
strokesStr += "";
//edgesStr += "";
List layers = new ArrayList<>();
String currentLayer = "";
int fillStyleCount = 0;
//List fillStylesStr = new ArrayList<>();
if (fillStyles != null) {
for (FILLSTYLE fs : fillStyles.fillStyles) {
fillsStr += "";
fillsStr += convertFillStyle(mat, characters, fs, shapeNum);
fillsStr += "";
fillStyleCount++;
}
}
if (lineStyles != null) {
if (lineStyles.lineStyles2 != null) { //(shapeNum == 4) {
for (int l = 0; l < lineStyles.lineStyles2.length; l++) {
strokesStr += "";
strokesStr += convertLineStyle(characters, 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++;
}
}
}
fillsStr += "";
strokesStr += "";
int layer = 1;
if ((fillStyleCount > 0) || (lineStyleCount > 0)) {
currentLayer += ""; //color=\"#4FFF4F\"
currentLayer += "";
currentLayer += "";
currentLayer += "";
currentLayer += "";
currentLayer += fillsStr;
currentLayer += strokesStr;
currentLayer += "";
}
//edgesStr += "";
/*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++) {
fillStylesStr.add(convertFillStyle(mat, characters, scr.fillStyles.fillStyles[f], shapeNum));
}
}
}
}
boolean usedFillStyles[] = new boolean[fillStylesStr.size()];
int fillStyleCount = 0;
lastFillStyleCount = 0;
if (fillStyles != null) {
lastFillStyleCount = fillStyles.fillStyles.length;
fillStyleCount += lastFillStyleCount;
}
for (SHAPERECORD edge : shapeRecords) {
if (edge instanceof StyleChangeRecord) {
StyleChangeRecord scr = (StyleChangeRecord) edge;
if (scr.stateNewStyles) {
lastFillStyleCount = scr.fillStyles.fillStyles.length;
fillStyleCount += lastFillStyleCount;
}
if (scr.stateFillStyle0 && scr.fillStyle0 > 0) {
usedFillStyles[fillStyleCount - lastFillStyleCount + scr.fillStyle0 - 1] = true;
}
if (scr.stateFillStyle1 && scr.fillStyle1 > 0) {
usedFillStyles[fillStyleCount - lastFillStyleCount + scr.fillStyle1 - 1] = true;
}
}
}
*/
/*int mapPos = 0;
HashMap fillStylesMap = new HashMap<>();
for (int f = 0; f < fillStyleCount; f++) {
if (usedFillStyles[f]) {
fillStylesMap.put(f, mapPos);
mapPos++;
fillsStr += "";
fillsStr += fillStylesStr.get(f);
fillsStr += "";
}
}*/
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 (!actualLinestyles.lineStyles2[strokeStyleOrig].hasFillFlag) {
if (actualLinestyles.lineStyles2[strokeStyleOrig].color.alpha == 0) {
if (actualLinestyles.lineStyles2[strokeStyleOrig].color.red == 0) {
if (actualLinestyles.lineStyles2[strokeStyleOrig].color.green == 0) {
if (actualLinestyles.lineStyles2[strokeStyleOrig].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 += "";
currentLayer += "";
currentLayer += "";
currentLayer += "";
currentLayer += "";
layers.add(currentLayer);
currentLayer = "";
}
currentLayer += ""; //color=\"#4FFF4F\"
currentLayer += "";
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++;
}
if (shapeNum == 4) {
for (int l = 0; l < scr.lineStyles.lineStyles2.length; l++) {
strokesStr += "";
strokesStr += convertLineStyle(characters, 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++;
}
}
fillsStr += "";
strokesStr += "";
currentLayer += fillsStr;
currentLayer += strokesStr;
currentLayer += "";
//lastFillStyleCount = scr.fillStyles.fillStyles.length;
//fillStyleCount += lastFillStyleCount;
//lastLineStyleCount = (shapeNum == 4) ? scr.lineStyles.lineStyles2.length : scr.lineStyles.lineStyles.length;
actualLinestyles = scr.lineStyles;
}
if (scr.stateFillStyle0) {
/*edgeStyle += " fillStyle0=\"";
edgeStyle += fillStyleCount - lastFillStyleCount + scr.fillStyle0;
edgeStyle += "\"";*/
int fillStyle0_new = scr.fillStyle0;// == 0 ? 0 : fillStylesMap.get(fillStyleCount - lastFillStyleCount + scr.fillStyle0 - 1) + 1;
//fillStyle0 = fillStyle0_new;
if (morphshape) { //???
fillStyle1 = fillStyle0_new;
} else {
fillStyle0 = fillStyle0_new;
}
styleChange = true;
}
if (scr.stateFillStyle1) {
/*edgeStyle += " fillStyle1=\"";
edgeStyle += fillStyleCount - lastFillStyleCount + scr.fillStyle1;
edgeStyle += "\"";*/
int fillStyle1_new = scr.fillStyle1;// == 0 ? 0 : fillStylesMap.get(fillStyleCount - lastFillStyleCount + scr.fillStyle1 - 1) + 1;
if (morphshape) {
fillStyle0 = fillStyle1_new;
} else {
fillStyle1 = fillStyle1_new;
}
//fillStyle1 = fillStyle1_new;
styleChange = true;
}
if (scr.stateLineStyle) {
/*edgeStyle += " strokeStyle=\"";
edgeStyle += lineStyleCount - lastLineStyleCount + scr.lineStyle;
edgeStyle += "\"";*/
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)) {
//if(true){
boolean empty = false;
if ((fillStyle0 <= 0) && (fillStyle1 <= 0) && (strokeStyle > 0) && morphshape) {
if (shapeNum == 4) {
if (strokeStyleOrig > 0) {
if (!actualLinestyles.lineStyles2[strokeStyleOrig].hasFillFlag) {
if (actualLinestyles.lineStyles2[strokeStyleOrig].color.alpha == 0) {
if (actualLinestyles.lineStyles2[strokeStyleOrig].color.red == 0) {
if (actualLinestyles.lineStyles2[strokeStyleOrig].color.green == 0) {
if (actualLinestyles.lineStyles2[strokeStyleOrig].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;
//strokeStyle = -1;
//fillStyle0 = -1;
//fillStyle1 = -1;
}
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 (!actualLinestyles.lineStyles2[strokeStyleOrig].hasFillFlag) {
if (actualLinestyles.lineStyles2[strokeStyleOrig].color.alpha == 0) {
if (actualLinestyles.lineStyles2[strokeStyleOrig].color.red == 0) {
if (actualLinestyles.lineStyles2[strokeStyleOrig].color.green == 0) {
if (actualLinestyles.lineStyles2[strokeStyleOrig].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 += "";
currentLayer += "";
currentLayer += "";
currentLayer += "";
currentLayer += "";
currentLayer += "";
currentLayer += "";
layers.add(currentLayer);
for (int l = layers.size() - 1; l >= 0; l--) {
ret += layers.get(l);
}
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) {
if (true) { //the feature was removed due to multiple layers in some shapes
return new ArrayList<>();
}
HashMap usages = 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.getInstanceName() != null) {
usageCount++;
}
if (po.getColorTransform() != null) {
usageCount++;
}
if (po.getColorTransformWithAlpha() != null) {
usageCount++;
}
if (po.cacheAsBitmap()) {
usageCount++;
}
MATRIX mat = po.getMatrix();
if (mat != null) {
if (!mat.isEmpty()) {
usageCount++;
}
}
usages.put(ch, usageCount + 1);
}
}
}
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<>();
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) {
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 += "";
} else if (filter instanceof BLURFILTER) {
BLURFILTER bf = (BLURFILTER) filter;
ret += "";
} else if (filter instanceof GLOWFILTER) {
GLOWFILTER gf = (GLOWFILTER) filter;
ret += "";
} else if (filter instanceof BEVELFILTER) {
BEVELFILTER bf = (BEVELFILTER) filter;
ret += "";
} else if (filter instanceof GRADIENTGLOWFILTER) {
GRADIENTGLOWFILTER ggf = (GRADIENTGLOWFILTER) filter;
ret += "";
for (int g = 0; g < ggf.gradientColors.length; g++) {
RGBA gc = ggf.gradientColors[g];
ret += "";
}
ret += "";
} else if (filter instanceof GRADIENTBEVELFILTER) {
GRADIENTBEVELFILTER gbf = (GRADIENTBEVELFILTER) filter;
ret += "";
for (int g = 0; g < gbf.gradientColors.length; g++) {
RGBA gc = gbf.gradientColors[g];
ret += "";
}
ret += "";
} else if (filter instanceof COLORMATRIXFILTER) {
COLORMATRIXFILTER cmf = (COLORMATRIXFILTER) filter;
ret += convertAdjustColorFilter(cmf);
}
return ret;
}
public static String convertSymbolInstance(String name, MATRIX matrix, CXFORM colorTransform, CXFORMWITHALPHA colorTransformAlpha, boolean cacheAsBitmap, int blendMode, List filters, boolean isVisible, RGBA backgroundColor, CharacterTag tag, HashMap characters, List tags) {
String ret = "";
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 += "";
ret += "";
ret += convertMatrix(matrix);
ret += "";
ret += "";
if (backgroundColor != null) {
ret += "";
}
if (colorTransform != null) {
ret += "";
} else if (colorTransformAlpha != null) {
ret += "";
}
if (filters != null) {
ret += "";
for (FILTER f : filters) {
ret += convertFilter(f);
}
ret += "";
}
if (tag instanceof DefineButtonTag) {
ret += "";
}
if (tag instanceof DefineButton2Tag) {
DefineButton2Tag db2 = (DefineButton2Tag) tag;
if (!db2.actions.isEmpty()) {
ret += "";
}
}
ret += "";
return ret;
}
private static String convertActionScript(ASMSource as) {
String decompiledASHilighted = com.jpexs.decompiler.flash.action.Action.actionsToSource(as.getActions(SWF.DEFAULT_VERSION), SWF.DEFAULT_VERSION);
return Highlighting.stripHilights(decompiledASHilighted);
}
private static long getTimestamp() {
return new Date().getTime() / 1000;
}
public static String convertLibrary(SWF swf, Map characterVariables, Map characterClasses, List oneInstanceShapes, String backgroundColor, List tags, HashMap characters, HashMap files) {
//TODO: Imported assets
//linkageImportForRS="true" linkageIdentifier="xxx" linkageURL="yyy.swf"
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 += "";
String itemIcon = null;
if (symbol instanceof ButtonTag) {
itemIcon = "0";
symbolStr += "";
symbolStr += "";
ButtonTag button = (ButtonTag) symbol;
List records = button.getRecords();
String frames[] = {"", "", "", ""};
int maxDepth = 0;
for (BUTTONRECORD rec : records) {
if (rec.placeDepth > maxDepth) {
maxDepth = rec.placeDepth;
}
}
for (int i = maxDepth; i >= 1; i--) {
symbolStr += ""; //color=\"#4FFF4F\"
symbolStr += "";
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(tags, (TextTag) character, matrix, filters);
} else if (character instanceof DefineVideoStreamTag) {
recCharStr = convertVideoInstance(matrix, (DefineVideoStreamTag) character);
} else {
recCharStr = convertSymbolInstance(null, matrix, null, colorTransformAlpha, false, blendMode, filters, true, null, characters.get(rec.characterId), characters, tags);
}
int duration = frame - lastFrame;
lastFrame = frame;
if (duration > 0) {
if (duration > 1) {
symbolStr += "";
symbolStr += "";
symbolStr += "";
symbolStr += "";
}
symbolStr += "";
symbolStr += "";
symbolStr += recCharStr;
symbolStr += "";
symbolStr += "";
}
}
}
}
symbolStr += "";
symbolStr += "";
}
symbolStr += "";
symbolStr += "";
} else if (symbol instanceof DefineSpriteTag) {
DefineSpriteTag sprite = (DefineSpriteTag) symbol;
if (sprite.subTags.isEmpty()) { //probably AS2 class
continue;
}
symbolStr += convertTimeline(sprite.spriteId, oneInstanceShapes, backgroundColor, tags, sprite.getSubTags(), characters, "Symbol " + symbol.getCharacterID());
} else if (symbol instanceof ShapeTag) {
itemIcon = "1";
ShapeTag shape = (ShapeTag) symbol;
symbolStr += "";
symbolStr += "";
symbolStr += convertShape(characters, null, shape);
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";
media.add(mediaLinkStr);
} else if ((symbol instanceof SoundStreamHeadTypeTag) || (symbol instanceof DefineSoundTag)) {
int soundFormat = 0;
int soundRate = 0;
int soundType = 0;
int soundSize = 0;
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.getSoundFormat();
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.getData(SWF.DEFAULT_VERSION);
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;
soundSize = sound.soundSize;
soundSampleCount = sound.soundSampleCount;
}
int format = 0;
int bits = 0;
if ((soundFormat == DefineSoundTag.FORMAT_ADPCM)
|| (soundFormat == DefineSoundTag.FORMAT_UNCOMPRESSED_LITTLE_ENDIAN)
|| (soundFormat == DefineSoundTag.FORMAT_UNCOMPRESSED_NATIVE_ENDIAN)) {
if (soundType == 1) { //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 == DefineSoundTag.FORMAT_SPEEX) {
bits = 18;
}
if (soundFormat == DefineSoundTag.FORMAT_ADPCM) {
SWFInputStream sis = new SWFInputStream(new ByteArrayInputStream(soundData), SWF.DEFAULT_VERSION);
exportFormat = "wav";
try {
int adpcmCodeSize = (int) sis.readUB(2);
bits = 2 + adpcmCodeSize;
} catch (IOException ex) {
Logger.getLogger(XFLConverter.class.getName()).log(Level.SEVERE, null, ex);
}
}
if (soundFormat == DefineSoundTag.FORMAT_MP3) {
exportFormat = "mp3";
if (soundType == 0) { //mono
format += 1;
}
format += 4; //quality best
SWFInputStream sis = new SWFInputStream(new ByteArrayInputStream(soundData), SWF.DEFAULT_VERSION);
try {
sis.readSI16();
MP3FRAME frame = new MP3FRAME(sis);
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);
}
}
byte data[] = new byte[0];
try {
data = swf.exportSound(symbol);
} catch (IOException ex) {
Logger.getLogger(XFLConverter.class.getName()).log(Level.SEVERE, null, ex);
}
if (!exportFormat.equals("flv")) { //FLV import format unsupported
String symbolFile = "sound" + symbol.getCharacterID() + "." + exportFormat;
files.put(symbolFile, data);
String mediaLinkStr = "\n";
media.add(mediaLinkStr);
}
} else if (symbol instanceof DefineVideoStreamTag) {
DefineVideoStreamTag video = (DefineVideoStreamTag) symbol;
String videoType = "no media";
switch (video.codecID) {
case 2:
videoType = "h263 media";
break;
case 3:
videoType = "screen share media";
break;
case 4:
videoType = "vp6 media";
break;
case 5:
videoType = "vp6 alpha media";
break;
}
byte data[] = new byte[0];
try {
data = swf.exportMovie(video);
} catch (IOException ex) {
Logger.getLogger(XFLConverter.class.getName()).log(Level.SEVERE, null, ex);
}
String symbolFile = "movie" + symbol.getCharacterID() + "." + "flv";
files.put(symbolFile, data);
String mediaLinkStr = "\n";
media.add(mediaLinkStr);
}
}
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) {
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, String frameName, boolean isAnchor, int duration, String actionScript, String elements) {
String ret = "";
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 += " 1) {
ret += " duration=\"" + duration + "\"";
}
if (frameName != null) {
ret += " name=\"" + frameName + "\"";
if (isAnchor) {
ret += " labelType=\"anchor\" bookmark=\"true\"";
} else {
ret += " labelType=\"name\"";
}
isAnchor = false;
frameName = null;
}
if (shapeTween) {
ret += " tweenType=\"shape\" keyMode=\"" + KEY_MODE_SHAPE_TWEEN + "\"";
} else {
ret += " keyMode=\"" + KEY_MODE_NORMAL + "\"";
}
String soundEnvelopeStr = "";
if (soundStreamHead != null) {
ret += " soundName=\"sound" + soundStreamHead.getCharacterID() + "." + soundStreamHead.getExportFormat() + "\"";
ret += " soundSync=\"stream\"";
soundEnvelopeStr += "";
soundEnvelopeStr += "";
soundEnvelopeStr += "";
}
if (startSound != null && sound != null) {
ret += " soundName=\"sound" + sound.soundId + "." + sound.getExportFormat() + "\"";
if (startSound.soundInfo.hasInPoint) {
ret += " inPoint44=\"" + startSound.soundInfo.inPoint + "\"";
}
if (startSound.soundInfo.hasOutPoint) {
ret += " outPoint44=\"" + startSound.soundInfo.outPoint + "\"";
}
if (startSound.soundInfo.hasLoops) {
if (startSound.soundInfo.loopCount == 32767) {
ret += " soundLoopMode=\"loop\"";
}
ret += " soundLoop=\"" + startSound.soundInfo.loopCount + "\"";
}
if (startSound.soundInfo.syncStop) {
ret += " soundSync=\"stop\"";
} else if (startSound.soundInfo.syncNoMultiple) {
ret += " soundSync=\"start\"";
};
soundEnvelopeStr += "";
if (startSound.soundInfo.hasEnvelope) {
for (SOUNDENVELOPE env : startSound.soundInfo.envelopeRecords) {
soundEnvelopeStr += "";
}
if (startSound.soundInfo.envelopeRecords.length == 1
&& startSound.soundInfo.envelopeRecords[0].leftLevel == 32768
&& startSound.soundInfo.envelopeRecords[0].pos44 == 0
&& startSound.soundInfo.envelopeRecords[0].rightLevel == 0) {
ret += " soundEffect=\"left channel\"";
} else if (startSound.soundInfo.envelopeRecords.length == 1
&& startSound.soundInfo.envelopeRecords[0].leftLevel == 0
&& startSound.soundInfo.envelopeRecords[0].pos44 == 0
&& startSound.soundInfo.envelopeRecords[0].rightLevel == 32768) {
ret += " soundEffect=\"right channel\"";
} else if (startSound.soundInfo.envelopeRecords.length == 2
&& startSound.soundInfo.envelopeRecords[0].leftLevel == 32768
&& startSound.soundInfo.envelopeRecords[0].pos44 == 0
&& startSound.soundInfo.envelopeRecords[0].rightLevel == 0
&& startSound.soundInfo.envelopeRecords[1].leftLevel == 0
&& startSound.soundInfo.envelopeRecords[1].pos44 == sound.soundSampleCount
&& startSound.soundInfo.envelopeRecords[1].rightLevel == 32768) {
ret += " soundEffect=\"fade left to right\"";
} else if (startSound.soundInfo.envelopeRecords.length == 2
&& startSound.soundInfo.envelopeRecords[0].leftLevel == 0
&& startSound.soundInfo.envelopeRecords[0].pos44 == 0
&& startSound.soundInfo.envelopeRecords[0].rightLevel == 32768
&& startSound.soundInfo.envelopeRecords[1].leftLevel == 32768
&& startSound.soundInfo.envelopeRecords[1].pos44 == sound.soundSampleCount
&& startSound.soundInfo.envelopeRecords[1].rightLevel == 0) {
ret += " soundEffect=\"fade right to left\"";
} else {
ret += " soundEffect=\"custom\"";
}
//TODO: fade in, fade out
} else {
soundEnvelopeStr += "";
}
soundEnvelopeStr += "";
}
ret += ">";
ret += soundEnvelopeStr;
if (!actionScript.equals("")) {
ret += "";
}
ret += "";
ret += elements;
ret += "";
ret += "";
return ret;
}
private static String convertVideoInstance(MATRIX matrix, DefineVideoStreamTag video) {
String ret = "";
ret += "";
ret += convertMatrix(matrix);
ret += "";
ret += "";
ret += "";
ret += "";
ret += "";
return ret;
}
private static String convertFrames(String prevStr, String afterStr, List oneInstanceShapes, List tags, List timelineTags, HashMap characters, int depth) {
String ret = "";
prevStr += "";
int frame = -1;
String elements = "";
String lastElements = "";
int duration = 1;
String frameName = null;
boolean isAnchor = false;
CharacterTag character = null;
MATRIX matrix = null;
String instanceName = null;
CXFORM colorTransForm = null;
CXFORMWITHALPHA colorTransFormAlpha = null;
boolean cacheAsBitmap = false;
int blendMode = 0;
List filters = new ArrayList<>();
boolean isVisible = true;
RGBA backGroundColor = null;
int characterId = -1;
int ratio = -1;
boolean shapeTween = false;
boolean lastShapeTween = false;
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;
}
CXFORM colorTransForm2 = po.getColorTransform();
if (colorTransForm2 != null) {
colorTransForm = colorTransForm2;
}
CXFORMWITHALPHA colorTransFormAlpha2 = po.getColorTransformWithAlpha();
if (colorTransFormAlpha2 != null) {
colorTransFormAlpha = colorTransFormAlpha2;
}
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();
colorTransFormAlpha = po.getColorTransformWithAlpha();
cacheAsBitmap = po.cacheAsBitmap();
blendMode = po.getBlendMode();
filters = po.getFilters();
ratio = po.getRatio();
}
}
}
}
if (t instanceof RemoveTag) {
RemoveTag rt = (RemoveTag) t;
if (rt.getDepth() == depth) {
character = null;
matrix = null;
instanceName = null;
colorTransForm = null;
colorTransFormAlpha = null;
cacheAsBitmap = false;
blendMode = 0;
filters = new ArrayList<>();
isVisible = true;
backGroundColor = null;
characterId = -1;
}
}
if (t instanceof FrameLabelTag) {
FrameLabelTag flt = (FrameLabelTag) t;
frameName = flt.getLabelName();
isAnchor = flt.isNamedAnchor();
}
if (t instanceof ShowFrameTag) {
elements = "";
if ((character instanceof ShapeTag) && oneInstanceShapes.contains(characterId)) {
elements += convertShape(characters, matrix, (ShapeTag) character);
shapeTween = false;
} else if (character != null) {
if (character instanceof MorphShapeTag) {
MorphShapeTag m = (MorphShapeTag) character;
if (ratio == 65535) {
elements += convertShape(characters, matrix, 3, m.getEndEdges().shapeRecords, m.getFillStyles().getEndFillStyles(), m.getLineStyles().getEndLineStyles(m.getShapeNum()), true);
shapeTween = false;
} else {
elements += convertShape(characters, matrix, 3, m.getStartEdges().shapeRecords, m.getFillStyles().getStartFillStyles(), m.getLineStyles().getStartLineStyles(m.getShapeNum()), true);
shapeTween = true;
}
} else {
shapeTween = false;
if (character instanceof TextTag) {
elements += convertText(tags, (TextTag) character, matrix, filters);
} else if (character instanceof DefineVideoStreamTag) {
elements += convertVideoInstance(matrix, (DefineVideoStreamTag) character);
} else {
elements += convertSymbolInstance(instanceName, matrix, colorTransForm, colorTransFormAlpha, cacheAsBitmap, blendMode, filters, isVisible, backGroundColor, character, characters, tags);
}
}
}
frame++;
if (!elements.equals(lastElements) && frame > 0) {
ret += convertFrame(lastShapeTween, characters, tags, null, null, frame - duration, frameName, isAnchor, duration, "", lastElements);
duration = 1;
} else if (frame == 0) {
duration = 1;
} else {
duration++;
}
lastShapeTween = shapeTween;
lastElements = elements;
frameName = null;
isAnchor = false;
}
}
if (!lastElements.equals("")) {
ret += convertFrame(lastShapeTween, characters, tags, null, null, (frame < 0 ? 0 : frame) - duration, frameName, isAnchor, duration, "", lastElements);
}
afterStr = "" + afterStr;
if (!ret.equals("")) {
ret = prevStr + ret + afterStr;
}
return ret;
}
public static String convertActionScriptLayer(int layerIndex, int spriteId, List tags, List timeLineTags, String backgroundColor) {
String ret = "";
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.equals("")) {
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.equals("")) {
duration++;
} else {
if (duration > 0) {
ret += " 1) {
ret += " duration=\"" + duration + "\"";
}
ret += " keyMode=\"" + KEY_MODE_NORMAL + "\">";
ret += "";
ret += "";
ret += "";
}
ret += "";
ret += "";
ret += "";
ret += "";
ret += "";
script = "";
duration = 0;
}
frame++;
}
}
if (!ret.equals("")) {
ret = ""
+ ""
+ ret
+ ""
+ "";
}
return ret;
}
public static String convertSoundLayer(int layerIndex, String backgroundColor, HashMap characters, List tags, List timeLineTags) {
String ret = "";
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;
}
if (t instanceof SoundStreamHeadTypeTag) {
soundStreamHead = (SoundStreamHeadTypeTag) t;
}
if (t instanceof ShowFrameTag) {
if (soundStreamHead != null || startSound != null) {
if (lastSoundStreamHead != null || lastStartSound != null) {
ret += convertFrame(false, characters, tags, lastSoundStreamHead, lastStartSound, frame, null, false, duration, "", "");
}
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 += convertFrame(false, characters, tags, lastSoundStreamHead, lastStartSound, frame, null, false, duration, "", "");
}
if (!ret.equals("")) {
ret = ""
+ "" + ret + ""
+ "";
}
return ret;
}
public static String convertTimeline(int spriteId, List oneInstanceShapes, String backgroundColor, List tags, List timelineTags, HashMap characters, String name) {
String ret = "";
ret += "";
ret += "";
int layerCount = getLayerCount(timelineTags);
Stack parentLayers = new Stack<>();
int index = 0;
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 += "";
ret += convertFrames("", "", oneInstanceShapes, tags, timelineTags, characters, po.getDepth());
ret += "";
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 += "";
String layerAfter = "";
String cf = convertFrames(layerPrev, layerAfter, oneInstanceShapes, tags, timelineTags, characters, d);
if (cf.equals("")) {
index--;
}
ret += cf;
}
int soundLayerIndex = layerCount;
layerCount++;
ret += convertSoundLayer(soundLayerIndex, backgroundColor, characters, tags, timelineTags);
int actionScriptLayerIndex = layerCount;
layerCount++;
ret += convertActionScriptLayer(actionScriptLayerIndex, spriteId, tags, timelineTags, backgroundColor);
ret += "";
ret += "";
return ret;
}
private static void writeFile(byte data[], String file) {
try (FileOutputStream fos = new FileOutputStream(file)) {
fos.write(data);
} catch (IOException iex) {
Logger.getLogger(XFLConverter.class.getName()).log(Level.SEVERE, "Error during file write", iex);
}
}
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.tagIDs.length; i++) {
if (!ret.containsKey(sc.tagIDs[i]) && !ret.containsValue(sc.classNames[i])) {
ret.put(sc.tagIDs[i], sc.classNames[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(List tags, TextTag tag, MATRIX matrix, List filters) {
String ret = "";
if (matrix == null) {
matrix = new MATRIX();
}
CSMTextSettingsTag csmts = null;
String filterStr = "";
if (filters != null) {
filterStr += "";
for (FILTER f : filters) {
filterStr += convertFilter(f);
}
filterStr += "";
}
for (Tag t : 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 += "";
RECT bounds = tag.getBounds();
matrix.translateX += bounds.Xmin + 40/*??*/;
matrix.translateY += bounds.Ymin + 40/*??*/;
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;
}
looprec:
for (TEXTRECORD rec : textRecords) {
if (rec.styleFlagsHasFont) {
for (Tag t : tags) {
if (t instanceof FontTag) {
FontTag ft = (FontTag) t;
if (ft.getFontId() == rec.fontId) {
if (ft.isSmall()) {
fontRenderingMode = "bitmap";
break looprec;
}
}
}
}
}
}
ret += "";
ret += matStr;
ret += "";
int fontId = -1;
FontTag font = null;
String fontName = null;
String psFontName = null;
String availableFonts[] = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
int textHeight = -1;
RGB textColor = null;
RGBA textColorA = null;
for (TEXTRECORD rec : textRecords) {
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 = null;
for (Tag t : tags) {
if (t instanceof FontTag) {
if (((FontTag) t).getFontId() == fontId) {
font = (FontTag) t;
}
}
if (t instanceof DefineFontNameTag) {
if (((DefineFontNameTag) t).fontId == fontId) {
fontName = ((DefineFontNameTag) t).fontName;
}
}
}
if ((fontName == null) && (font != null)) {
fontName = font.getFontName(tags);
}
psFontName = fontName;
if (fontName != null) {
for (String avFont : availableFonts) {
if (avFont.equals(fontName)) {
Font f = new Font(fontName, 0, 10);
psFontName = f.getPSName();
}
}
}
}
if (font != null) {
ret += "";
ret += "" + xmlString(rec.getText(tags, font)) + "";
ret += "";
ret += "";
ret += "";
ret += "";
}
}
ret += "";
ret += filterStr;
ret += "";
} else if (tag instanceof DefineEditTextTag) {
DefineEditTextTag det = (DefineEditTextTag) tag;
String tagName;
for (Tag t : tags) {
if (t instanceof FontTag) {
FontTag ft = (FontTag) t;
if (ft.getFontId() == det.fontId) {
if (ft.isSmall()) {
fontRenderingMode = "bitmap";
break;
}
}
}
}
if (!det.useOutlines) {
fontRenderingMode = "device";
}
if (det.wasStatic) {
tagName = "DOMStaticText";
} else if (det.readOnly) {
tagName = "DOMDynamicText";
} else {
tagName = "DOMInputText";
}
ret += "<" + tagName;
if (fontRenderingMode != null) {
ret += " fontRenderingMode=\"" + fontRenderingMode + "\"";
}
ret += 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 += " width=\"" + width + "\"";
ret += " height=\"" + height + "\"";
if (det.border) {
ret += " border=\"true\"";
}
if (det.html) {
ret += " renderAsHTML=\"true\"";
}
if (det.noSelect) {
ret += " isSelectable=\"false\"";
}
if (det.multiline && det.wordWrap) {
ret += " lineType=\"multiline\"";
} else if (det.multiline && (!det.wordWrap)) {
ret += " lineType=\"multiline no wrap\"";
} else if (det.password) {
ret += " lineType=\"password\"";
}
if (det.hasMaxLength) {
ret += " maxCharacters=\"" + det.maxLength + "\"";
}
if (!det.variableName.equals("")) {
ret += " variableName=\"" + det.variableName + "\"";
}
ret += ">";
ret += matStr;
ret += "";
if (det.hasText) {
if (det.html) {
ret += convertHTMLText(tags, det, det.initialText);
} else {
ret += "";
ret += "" + xmlString(det.initialText) + "";
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;
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.getFontName(tags);
}
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"};
alignment = alignNames[det.align];
}
ret += "";
ret += " -1) {
ret += " indent=\"" + twipToPixel(indent) + "\"";
}
if (leftMargin > -1) {
ret += " leftMargin=\"" + twipToPixel(leftMargin) + "\"";
}
if (lineSpacing > -1) {
ret += " lineSpacing=\"" + twipToPixel(lineSpacing) + "\"";
}
if (rightMargin > -1) {
ret += " rightMargin=\"" + twipToPixel(rightMargin) + "\"";
}
if (size > -1) {
ret += " size=\"" + size + "\"";
ret += " bitmapSize=\"" + (size * 20) + "\"";
}
if (fontFace != null) {
ret += " face=\"" + fontFace + "\"";
}
ret += "/>";
ret += "";
ret += "";
}
}
ret += "";
ret += filterStr;
ret += "" + tagName + ">";
}
return ret;
}
public static void convertSWF(SWF swf, String swfFileName, String outfile, boolean compressed, String generator, String generatorVerName, String generatorVersion, boolean paralel) {
File file = new File(outfile);
File outDir = file.getParentFile();
String domDocument = "";
String baseName = swfFileName;
File f = new File(baseName);
baseName = f.getName();
if (baseName.contains(".")) {
baseName = baseName.substring(0, baseName.lastIndexOf("."));
}
HashMap files = new HashMap<>();
HashMap characters = getCharacters(swf.tags);
List oneInstaceShapes = getOneInstanceShapes(swf.tags, characters);
Map characterClasses = getCharacterClasses(swf.tags);
Map characterVariables = getCharacterVariables(swf.tags);
FileAttributesTag fa = null;
for (Tag t : swf.tags) {
if (t instanceof FileAttributesTag) {
fa = (FileAttributesTag) t;
}
}
boolean useAS3 = false;
boolean useNetwork = false;
if (fa != null) {
useAS3 = fa.actionScript3;
useNetwork = fa.useNetwork;
}
String backgroundColor = "#ffffff";
for (Tag t : swf.tags) {
if (t instanceof SetBackgroundColorTag) {
SetBackgroundColorTag sbc = (SetBackgroundColorTag) t;
backgroundColor = sbc.backgroundColor.toHexRGB();
}
}
domDocument += "";
domDocument += convertLibrary(swf, characterVariables, characterClasses, oneInstaceShapes, backgroundColor, swf.tags, characters, files);
domDocument += "";
domDocument += convertTimeline(0, oneInstaceShapes, backgroundColor, swf.tags, swf.tags, characters, "Scene 1");
domDocument += "";
domDocument += "";
domDocument = prettyFormatXML(domDocument);
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 expPath = dia.getExportName();
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);
if (!cdir.exists()) {
cdir.mkdirs();
}
try {
writeFile(data.getBytes("UTF-8"), outDir.getAbsolutePath() + File.separator + expPath + ".as");
} catch (UnsupportedEncodingException ex) {
Logger.getLogger(XFLConverter.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
}
}
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"
+ " " + twipToPixel(swf.displayRect.getWidth()) + "\n"
+ " " + twipToPixel(swf.displayRect.getHeight()) + "\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"
+ " " + (useAS3 ? "3" : "2") + "\n"
+ " 1\n"
+ " \n"
+ " .\n"
+ " CONFIG::FLASH_AUTHORING="true";\n"
+ " 0\n"
+ " \n"
+ " " + (swf.compressed ? "1" : "0") + "\n"
+ " " + (swf.lzma ? "1" : "0") + "\n"
+ " 1\n"
+ " 0\n"
+ " 0\n"
+ " 0\n"
+ " " + (useNetwork ? 1 : 0) + "\n"
+ " " + xmlString(characterClasses.containsKey(0) ? characterClasses.get(0) : "") + "\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"
+ " " + twipToPixel(swf.displayRect.getWidth()) + "\n"
+ " " + twipToPixel(swf.displayRect.getHeight()) + "\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"
+ " " + twipToPixel(swf.displayRect.getWidth()) + "\n"
+ " " + twipToPixel(swf.displayRect.getHeight()) + "\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"
+ " " + twipToPixel(swf.displayRect.getWidth()) + "\n"
+ " " + twipToPixel(swf.displayRect.getHeight()) + "\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"
+ " " + twipToPixel(swf.displayRect.getWidth()) + "\n"
+ " " + twipToPixel(swf.displayRect.getHeight()) + "\n"
+ " 1\n"
+ " 0\n"
+ " \n"
+ " \n"
+ " 00000000\n"
+ " 0\n"
+ " 0\n"
+ " 0\n"
+ " 0\n"
+ " 1\n"
+ " \n"
+ "\n"
+ "";
if (compressed) {
try (ZipOutputStream 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);
}
} else {
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);
}
try {
writeFile("PROXY-CS5".getBytes("utf-8"), outfile);
} catch (UnsupportedEncodingException ex) {
Logger.getLogger(XFLConverter.class.getName()).log(Level.SEVERE, null, ex);
}
}
if (useAS3) {
try {
swf.exportActionScript(outDir.getAbsolutePath(), false, paralel);
} 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();
//factory.setValidating(false);
parser = XMLReaderFactory.createXMLReader();
parser.setContentHandler(tparser);
parser.setErrorHandler(tparser);
//parser.setFeature("http://xml.org/sax/features/validation", false);
html = "\n"
+ " \n"
+ "]>" + html + "";
try {
parser.parse(new InputSource(new InputStreamReader(new ByteArrayInputStream(html.getBytes("UTF-8")), "UTF-8")));
} catch (SAXParseException spe) {
System.out.println(html);
System.err.println(tparser.result);
}
//XMLReader reader = parser.getXMLReader();
/*reader.setContentHandler(tparser);
reader.setErrorHandler(tparser);
reader.setEntityResolver(tparser);
html = "" + html + "";
reader.parse(new InputSource(new InputStreamReader(new ByteArrayInputStream(html.getBytes("UTF-8")), "UTF-8")));*/
} catch (Exception 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 / 20.0;
}
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 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.getFontName(tags);
}
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"};
alignment = alignNames[det.align];
}
this.tags = tags;
}
@Override
public void startDocument() throws SAXException {
}
@Override
public void startElement(String uri, String localName,
String qName, Attributes attributes) throws SAXException {
if (qName.equals("a")) {
String href = attributes.getValue("href");
if (href != null) {
url = href;
}
String t = attributes.getValue("target");
if (t != null) {
target = t;
}
} else if (qName.equals("b")) {
bold = true;
} else if (qName.equals("i")) {
italic = true;
} else if (qName.equals("u")) {
underline = true;
} else if (qName.equals("li")) {
li = true;
} else if (qName.equals("p")) {
String a = attributes.getValue("align");
if (a != null) {
alignment = a;
}
if (!result.equals("")) {
putText("\r\n");
}
} else if (qName.equals("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 t : tags) {
if (t instanceof FontTag) {
FontTag ft = (FontTag) t;
String fontName = "";
if (f.equals(ft.getFontName(tags))) {
for (Tag u : tags) {
if (u instanceof DefineFontNameTag) {
if (((DefineFontNameTag) u).fontId == ft.getFontId()) {
fontName = ((DefineFontNameTag) u).fontName;
}
}
}
if (fontName == null) {
fontName = ft.getFontName(tags);
}
fontFace = new Font(fontName, (italic ? Font.ITALIC : 0) | (bold ? Font.BOLD : 0) | (!italic && !bold ? Font.PLAIN : 0), size < 0 ? 10 : size).getPSName();
break;
}
}
}
}
}
//textformat,tab,br
}
@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() {
}
}
}