Files
jpexs-decompiler/trunk/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java
2013-06-29 19:54:07 +02:00

3177 lines
148 KiB
Java

/*
* 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 <http://www.gnu.org/licenses/>.
*/
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<SHAPERECORD> 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 "<SolidStroke weight=\"" + (((float) ls.width) / 20.0) + "\">"
+ "<fill>"
+ "<SolidColor color=\"" + (shapeNum == 3 ? ls.colorA.toHexRGB() : ls.color.toHexRGB()) + "\""
+ (shapeNum == 3 ? " alpha=\"" + ls.colorA.getAlphaFloat() + "\"" : "")
+ " />"
+ "</fill>"
+ "</SolidStroke>";
}
public static String convertLineStyle(HashMap<Integer, CharacterTag> 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 += "<SolidStroke weight=\"" + (((float) ls.width) / 20.0) + "\"";
ret += params;
ret += ">";
ret += "<fill>";
if (!ls.hasFillFlag) {
ret += "<SolidColor color=\"" + ls.color.toHexRGB() + "\""
+ (ls.color.getAlphaFloat() != 1 ? " alpha=\"" + ls.color.getAlphaFloat() + "\"" : "")
+ " />";
} else {
ret += convertFillStyle(null/* FIXME */, characters, ls.fillType, shapeNum);
}
ret += "</fill>";
ret += "</SolidStroke>";
return ret;
}
private static float toFloat(int i) {
return ((float) i) / (1 << 16);
}
public static String convertFillStyle(MATRIX mat, HashMap<Integer, CharacterTag> characters, FILLSTYLE fs, int shapeNum) {
if (mat == null) {
mat = new MATRIX();
}
String ret = "";
//ret += "<FillStyle index=\"" + index + "\">";
switch (fs.fillStyleType) {
case FILLSTYLE.SOLID:
ret += "<SolidColor color=\"";
if (shapeNum >= 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 += "<BitmapFill";
ret += " bitmapPath=\"";
CharacterTag bitmapCh = characters.get(fs.bitmapId);
if (bitmapCh instanceof ImageTag) {
ImageTag it = (ImageTag) bitmapCh;
ret += "bitmap" + bitmapCh.getCharacterID() + "." + it.getImageFormat();
}
ret += "\"";
if ((fs.fillStyleType == FILLSTYLE.CLIPPED_BITMAP) || (fs.fillStyleType == FILLSTYLE.NON_SMOOTHED_CLIPPED_BITMAP)) {
ret += " bitmapIsClipped=\"true\"";
}
ret += ">";
ret += "<matrix>" + convertMatrix(fs.bitmapMatrix) + "</matrix>";
ret += "</BitmapFill>";
break;
case FILLSTYLE.LINEAR_GRADIENT:
case FILLSTYLE.RADIAL_GRADIENT:
case FILLSTYLE.FOCAL_RADIAL_GRADIENT:
if (fs.fillStyleType == FILLSTYLE.LINEAR_GRADIENT) {
ret += "<LinearGradient";
} else {
ret += "<RadialGradient";
ret += " focalPointRatio=\"";
if (fs.fillStyleType == FILLSTYLE.FOCAL_RADIAL_GRADIENT) {
ret += fs.focalGradient.focalPoint;
} else {
ret += "0";
}
ret += "\"";
}
int interpolationMode;
if (fs.fillStyleType == FILLSTYLE.FOCAL_RADIAL_GRADIENT) {
interpolationMode = fs.focalGradient.interPolationMode;
} else {
interpolationMode = fs.gradient.interPolationMode;
}
int spreadMode;
if (fs.fillStyleType == FILLSTYLE.FOCAL_RADIAL_GRADIENT) {
spreadMode = fs.focalGradient.spreadMode;
} else {
spreadMode = fs.gradient.spreadMode;
}
if (interpolationMode == GRADIENT.INTERPOLATION_LINEAR_RGB_MODE) {
ret += " interpolationMethod=\"linearRGB\"";
}
switch (spreadMode) {
case GRADIENT.SPREAD_PAD_MODE:
break;
case GRADIENT.SPREAD_REFLECT_MODE:
ret += " spreadMethod=\"reflect\"";
break;
case GRADIENT.SPREAD_REPEAT_MODE:
ret += " spreadMethod=\"repeat\"";
break;
}
ret += ">";
ret += "<matrix>" + convertMatrix(fs.gradientMatrix) + "</matrix>";
GRADRECORD records[];
if (fs.fillStyleType == FILLSTYLE.FOCAL_RADIAL_GRADIENT) {
records = fs.focalGradient.gradientRecords;
} else {
records = fs.gradient.gradientRecords;
}
for (GRADRECORD rec : records) {
ret += "<GradientEntry";
ret += " color=\"" + (shapeNum >= 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 += "</LinearGradient>";
} else {
ret += "</RadialGradient>";
}
break;
}
//ret += "</FillStyle>";
return ret;
}
public static String convertMatrix(MATRIX m) {
String ret = "";
if (m == null) {
m = new MATRIX();
}
ret += "<Matrix ";
ret += "tx=\"" + (((float) m.translateX) / 20.0) + "\" ";
ret += "ty=\"" + (((float) m.translateY) / 20.0) + "\" ";
if (m.hasScale) {
ret += "a=\"" + m.toFloat(m.scaleX) + "\" ";
ret += "d=\"" + m.toFloat(m.scaleY) + "\" ";
}
if (m.hasRotate) {
ret += "b=\"" + m.toFloat(m.rotateSkew0) + "\" ";
ret += "c=\"" + m.toFloat(m.rotateSkew1) + "\" ";
}
ret += "/>";
return ret;
}
public static String convertShape(HashMap<Integer, CharacterTag> characters, MATRIX mat, int shapeNum, SHAPE shape) {
return convertShape(characters, mat, shapeNum, shape.shapeRecords);
}
public static String convertShape(HashMap<Integer, CharacterTag> characters, MATRIX mat, int shapeNum, SHAPEWITHSTYLE shape) {
return convertShape(characters, mat, shapeNum, shape.shapeRecords, shape.fillStyles, shape.lineStyles, false);
}
public static String convertShape(HashMap<Integer, CharacterTag> characters, MATRIX mat, ShapeTag shape) {
return convertShape(characters, mat, shape.getShapeNum(), shape.getShapes());
}
public static String convertShape(HashMap<Integer, CharacterTag> characters, MATRIX mat, int shapeNum, List<SHAPERECORD> shapeRecords) {
return convertShape(characters, mat, shapeNum, shapeRecords, null, null, false);
}
public static String convertShape(HashMap<Integer, CharacterTag> characters, MATRIX mat, int shapeNum, List<SHAPERECORD> shapeRecords, FILLSTYLEARRAY fillStyles, LINESTYLEARRAY lineStyles, boolean morphshape) {
String ret = "";
if (mat == null) {
mat = new MATRIX();
}
List<SHAPERECORD> 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 += "<fills>";
strokesStr += "<strokes>";
//edgesStr += "<edges>";
List<String> layers = new ArrayList<>();
String currentLayer = "";
int fillStyleCount = 0;
//List<String> fillStylesStr = new ArrayList<>();
if (fillStyles != null) {
for (FILLSTYLE fs : fillStyles.fillStyles) {
fillsStr += "<FillStyle index=\"" + (fillStyleCount + 1) + "\">";
fillsStr += convertFillStyle(mat, characters, fs, shapeNum);
fillsStr += "</FillStyle>";
fillStyleCount++;
}
}
if (lineStyles != null) {
if (lineStyles.lineStyles2 != null) { //(shapeNum == 4) {
for (int l = 0; l < lineStyles.lineStyles2.length; l++) {
strokesStr += "<StrokeStyle index=\"" + (lineStyleCount + 1) + "\">";
strokesStr += convertLineStyle(characters, lineStyles.lineStyles2[l], shapeNum);
strokesStr += "</StrokeStyle>";
lineStyleCount++;
}
} else {
for (int l = 0; l < lineStyles.lineStyles.length; l++) {
strokesStr += "<StrokeStyle index=\"" + (lineStyleCount + 1) + "\">";
strokesStr += convertLineStyle(lineStyles.lineStyles[l], shapeNum);
strokesStr += "</StrokeStyle>";
lineStyleCount++;
}
}
}
fillsStr += "</fills>";
strokesStr += "</strokes>";
int layer = 1;
if ((fillStyleCount > 0) || (lineStyleCount > 0)) {
currentLayer += "<DOMLayer name=\"Layer " + (layer++) + "\">"; //color=\"#4FFF4F\"
currentLayer += "<frames>";
currentLayer += "<DOMFrame index=\"0\" motionTweenScale=\"false\" keyMode=\"" + KEY_MODE_SHAPE_LAYERS + "\">";
currentLayer += "<elements>";
currentLayer += "<DOMShape isFloating=\"true\">";
currentLayer += fillsStr;
currentLayer += strokesStr;
currentLayer += "<edges>";
}
//edgesStr += "</edges>";
/*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<Integer, Integer> fillStylesMap = new HashMap<>();
for (int f = 0; f < fillStyleCount; f++) {
if (usedFillStyles[f]) {
fillStylesMap.put(f, mapPos);
mapPos++;
fillsStr += "<FillStyle index=\"" + mapPos + "\">";
fillsStr += fillStylesStr.get(f);
fillsStr += "</FillStyle>";
}
}*/
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 = "<fills>";
strokesStr = "<strokes>";
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 += "<Edge";
if (fillStyle0 > -1) {
currentLayer += " fillStyle0=\"" + fillStyle0 + "\"";
}
if (fillStyle1 > -1) {
currentLayer += " fillStyle1=\"" + fillStyle1 + "\"";
}
if (strokeStyle > -1) {
currentLayer += " strokeStyle=\"" + strokeStyle + "\"";
}
currentLayer += " edges=\"" + convertShapeEdges(startEdgeX, startEdgeY, mat, edges) + "\" />";
}
}
currentLayer += "</edges>";
currentLayer += "</DOMShape>";
currentLayer += "</elements>";
currentLayer += "</DOMFrame>";
currentLayer += "</frames>";
currentLayer += "</DOMLayer>";
layers.add(currentLayer);
currentLayer = "";
}
currentLayer += "<DOMLayer name=\"Layer " + (layer++) + "\">"; //color=\"#4FFF4F\"
currentLayer += "<frames>";
currentLayer += "<DOMFrame index=\"0\" motionTweenScale=\"false\" keyMode=\"" + KEY_MODE_SHAPE_LAYERS + "\">";
currentLayer += "<elements>";
currentLayer += "<DOMShape isFloating=\"true\">";
//ret += convertShape(characters, null, shape);
for (int f = 0; f < scr.fillStyles.fillStyles.length; f++) {
fillsStr += "<FillStyle index=\"" + (f + 1) + "\">";
fillsStr += convertFillStyle(mat, characters, scr.fillStyles.fillStyles[f], shapeNum);
fillsStr += "</FillStyle>";
fillStyleCount++;
}
if (shapeNum == 4) {
for (int l = 0; l < scr.lineStyles.lineStyles2.length; l++) {
strokesStr += "<StrokeStyle index=\"" + (lineStyleCount + 1) + "\">";
strokesStr += convertLineStyle(characters, scr.lineStyles.lineStyles2[l], shapeNum);
strokesStr += "</StrokeStyle>";
lineStyleCount++;
}
} else {
for (int l = 0; l < scr.lineStyles.lineStyles.length; l++) {
strokesStr += "<StrokeStyle index=\"" + (lineStyleCount + 1) + "\">";
strokesStr += convertLineStyle(scr.lineStyles.lineStyles[l], shapeNum);
strokesStr += "</StrokeStyle>";
lineStyleCount++;
}
}
fillsStr += "</fills>";
strokesStr += "</strokes>";
currentLayer += fillsStr;
currentLayer += strokesStr;
currentLayer += "<edges>";
//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 += "<Edge";
if (fillStyle0 > -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 += "<Edge";
if (fillStyle0 > -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 += "</fills>";
strokesStr += "</strokes>";
currentLayer += "</edges>";
currentLayer += "</DOMShape>";
currentLayer += "</elements>";
currentLayer += "</DOMFrame>";
currentLayer += "</frames>";
currentLayer += "</DOMLayer>";
layers.add(currentLayer);
for (int l = layers.size() - 1; l >= 0; l--) {
ret += layers.get(l);
}
return ret;
}
private static int getLayerCount(List<Tag> 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<Integer> getOneInstanceShapes(List<Tag> tags, HashMap<Integer, CharacterTag> characters) {
if (true) { //the feature was removed due to multiple layers in some shapes
return new ArrayList<>();
}
HashMap<Integer, Integer> 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<Integer> ret = new ArrayList<>();
for (int ch : usages.keySet()) {
if (usages.get(ch) < 2) {
ret.add(ch);
}
}
return ret;
}
private static HashMap<Integer, CharacterTag> getCharacters(List<Tag> tags) {
HashMap<Integer, CharacterTag> 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 += "<DropShadowFilter";
if (dsf.dropShadowColor.alpha != 255) {
ret += " alpha=\"" + doubleToString(dsf.dropShadowColor.getAlphaFloat()) + "\"";
}
ret += " angle=\"" + doubleToString(radToDeg(dsf.angle)) + "\"";
ret += " blurX=\"" + doubleToString(dsf.blurX) + "\"";
ret += " blurY=\"" + doubleToString(dsf.blurY) + "\"";
ret += " color=\"" + dsf.dropShadowColor.toHexRGB() + "\"";
ret += " distance=\"" + doubleToString(dsf.distance) + "\"";
if (!dsf.compositeSource) {
ret += " hideObject=\"true\"";
}
if (dsf.innerShadow) {
ret += " inner=\"true\"";
}
if (dsf.knockout) {
ret += " knockout=\"true\"";
}
ret += " quality=\"" + dsf.passes + "\"";
ret += " strength=\"" + doubleToString(dsf.strength) + "\"";
ret += " />";
} else if (filter instanceof BLURFILTER) {
BLURFILTER bf = (BLURFILTER) filter;
ret += "<BlurFilter";
ret += " blurX=\"" + doubleToString(bf.blurX) + "\"";
ret += " blurY=\"" + doubleToString(bf.blurY) + "\"";
ret += " quality=\"" + bf.passes + "\"";
ret += " />";
} else if (filter instanceof GLOWFILTER) {
GLOWFILTER gf = (GLOWFILTER) filter;
ret += "<GlowFilter";
if (gf.glowColor.alpha != 255) {
ret += " alpha=\"" + gf.glowColor.getAlphaFloat() + "\"";
}
ret += " blurX=\"" + doubleToString(gf.blurX) + "\"";
ret += " blurY=\"" + doubleToString(gf.blurY) + "\"";
ret += " color=\"" + gf.glowColor.toHexRGB() + "\"";
if (gf.innerGlow) {
ret += " inner=\"true\"";
}
if (gf.knockout) {
ret += " knockout=\"true\"";
}
ret += " quality=\"" + gf.passes + "\"";
ret += " strength=\"" + doubleToString(gf.strength) + "\"";
ret += " />";
} else if (filter instanceof BEVELFILTER) {
BEVELFILTER bf = (BEVELFILTER) filter;
ret += "<BevelFilter";
ret += " blurX=\"" + doubleToString(bf.blurX) + "\"";
ret += " blurY=\"" + doubleToString(bf.blurY) + "\"";
ret += " quality=\"" + bf.passes + "\"";
ret += " angle=\"" + doubleToString(radToDeg(bf.angle)) + "\"";
ret += " distance=\"" + bf.distance + "\"";
if (bf.highlightColor.alpha != 255) {
ret += " highlightAlpha=\"" + bf.highlightColor.getAlphaFloat() + "\"";
}
ret += " highlightColor=\"" + bf.highlightColor.toHexRGB() + "\"";
if (bf.knockout) {
ret += " knockout=\"true\"";
}
if (bf.shadowColor.alpha != 255) {
ret += " shadowAlpha=\"" + bf.shadowColor.getAlphaFloat() + "\"";
}
ret += " shadowColor=\"" + bf.shadowColor.toHexRGB() + "\"";
ret += " strength=\"" + doubleToString(bf.strength) + "\"";
if (bf.onTop && !bf.innerShadow) {
ret += " type=\"full\"";
} else if (!bf.innerShadow) {
ret += " type=\"outer\"";
}
ret += " />";
} else if (filter instanceof GRADIENTGLOWFILTER) {
GRADIENTGLOWFILTER ggf = (GRADIENTGLOWFILTER) filter;
ret += "<GradientGlowFilter";
ret += " angle=\"" + doubleToString(radToDeg(ggf.angle)) + "\"";
ret += " blurX=\"" + doubleToString(ggf.blurX) + "\"";
ret += " blurY=\"" + doubleToString(ggf.blurY) + "\"";
ret += " quality=\"" + ggf.passes + "\"";
ret += " distance=\"" + doubleToString(ggf.distance) + "\"";
if (ggf.knockout) {
ret += " knockout=\"true\"";
}
ret += " strength=\"" + doubleToString(ggf.strength) + "\"";
if (ggf.onTop && !ggf.innerShadow) {
ret += " type=\"full\"";
} else if (!ggf.innerShadow) {
ret += " type=\"outer\"";
}
ret += ">";
for (int g = 0; g < ggf.gradientColors.length; g++) {
RGBA gc = ggf.gradientColors[g];
ret += "<GradientEntry color=\"" + gc.toHexRGB() + "\"";
if (gc.alpha != 255) {
ret += " alpha=\"" + gc.getAlphaFloat() + "\"";
}
ret += " ratio=\"" + doubleToString(((float) ggf.gradientRatio[g]) / 255.0) + "\"";
ret += "/>";
}
ret += "</GradientGlowFilter>";
} else if (filter instanceof GRADIENTBEVELFILTER) {
GRADIENTBEVELFILTER gbf = (GRADIENTBEVELFILTER) filter;
ret += "<GradientBevelFilter";
ret += " angle=\"" + doubleToString(radToDeg(gbf.angle)) + "\"";
ret += " blurX=\"" + doubleToString(gbf.blurX) + "\"";
ret += " blurY=\"" + doubleToString(gbf.blurY) + "\"";
ret += " quality=\"" + gbf.passes + "\"";
ret += " distance=\"" + doubleToString(gbf.distance) + "\"";
if (gbf.knockout) {
ret += " knockout=\"true\"";
}
ret += " strength=\"" + doubleToString(gbf.strength) + "\"";
if (gbf.onTop && !gbf.innerShadow) {
ret += " type=\"full\"";
} else if (!gbf.innerShadow) {
ret += " type=\"outer\"";
}
ret += ">";
for (int g = 0; g < gbf.gradientColors.length; g++) {
RGBA gc = gbf.gradientColors[g];
ret += "<GradientEntry color=\"" + gc.toHexRGB() + "\"";
if (gc.alpha != 255) {
ret += " alpha=\"" + gc.getAlphaFloat() + "\"";
}
ret += " ratio=\"" + doubleToString(((float) gbf.gradientRatio[g]) / 255.0) + "\"";
ret += "/>";
}
ret += "</GradientBevelFilter>";
} 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<FILTER> filters, boolean isVisible, RGBA backgroundColor, CharacterTag tag, HashMap<Integer, CharacterTag> characters, List<Tag> 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 += "<DOMSymbolInstance libraryItemName=\"" + "Symbol " + tag.getCharacterID() + "\"";
if (name != null) {
ret += " name=\"" + xmlString(name) + "\"";
}
String blendModeStr = null;
if (blendMode < BLENDMODES.length) {
blendModeStr = BLENDMODES[blendMode];
}
if (blendModeStr != null) {
ret += " blendMode=\"" + blendModeStr + "\"";
}
if (tag instanceof ShapeTag) {
ret += " symbolType=\"graphic\" loop=\"loop\"";
} else if (tag instanceof DefineSpriteTag) {
DefineSpriteTag sprite = (DefineSpriteTag) tag;
RECT spriteRect = sprite.getRect(characters);
double centerPoint3DX = twipToPixel(matrix.translateX + spriteRect.getWidth() / 2);
double centerPoint3DY = twipToPixel(matrix.translateY + spriteRect.getHeight() / 2);
ret += " centerPoint3DX=\"" + centerPoint3DX + "\" centerPoint3DY=\"" + centerPoint3DY + "\"";
} else if (tag instanceof ButtonTag) {
ret += " symbolType=\"button\"";
}
if (cacheAsBitmap) {
ret += " cacheAsBitmap=\"true\"";
}
if (!isVisible) {
ret += " isVisible=\"false\"";
}
ret += ">";
ret += "<matrix>";
ret += convertMatrix(matrix);
ret += "</matrix>";
ret += "<transformationPoint><Point/></transformationPoint>";
if (backgroundColor != null) {
ret += "<MatteColor color=\"" + backgroundColor.toHexRGB() + "\"";
if (backgroundColor.alpha != 255) {
ret += " alpha=\"" + doubleToString(backgroundColor.getAlphaFloat()) + "\"";
}
ret += "/>";
}
if (colorTransform != null) {
ret += "<color><Color";
if (colorTransform.hasMultTerms) {
ret += " redMultiplier=\"" + (((float) colorTransform.redMultTerm) / 256.0f) + "\"";
ret += " greenMultiplier=\"" + (((float) colorTransform.greenMultTerm) / 256.0f) + "\"";
ret += " blueMultiplier=\"" + (((float) colorTransform.blueMultTerm) / 256.0f) + "\"";
}
if (colorTransform.hasAddTerms) {
ret += " redOffset=\"" + colorTransform.redAddTerm + "\"";
ret += " greenOffset=\"" + colorTransform.greenAddTerm + "\"";
ret += " blueOffset=\"" + colorTransform.blueAddTerm + "\"";
}
ret += "/></color>";
} else if (colorTransformAlpha != null) {
ret += "<color><Color";
if (colorTransformAlpha.hasMultTerms) {
ret += " alphaMultiplier=\"" + (((float) colorTransformAlpha.alphaMultTerm) / 256.0f) + "\"";
ret += " redMultiplier=\"" + (((float) colorTransformAlpha.redMultTerm) / 256.0f) + "\"";
ret += " greenMultiplier=\"" + (((float) colorTransformAlpha.greenMultTerm) / 256.0f) + "\"";
ret += " blueMultiplier=\"" + (((float) colorTransformAlpha.blueMultTerm) / 256.0f) + "\"";
}
if (colorTransformAlpha.hasAddTerms) {
ret += " alphaOffset=\"" + colorTransformAlpha.alphaAddTerm + "\"";
ret += " redOffset=\"" + colorTransformAlpha.redAddTerm + "\"";
ret += " greenOffset=\"" + colorTransformAlpha.greenAddTerm + "\"";
ret += " blueOffset=\"" + colorTransformAlpha.blueAddTerm + "\"";
}
ret += "/></color>";
}
if (filters != null) {
ret += "<filters>";
for (FILTER f : filters) {
ret += convertFilter(f);
}
ret += "</filters>";
}
if (tag instanceof DefineButtonTag) {
ret += "<Actionscript><script><![CDATA[";
ret += "on(press){\r\n";
ret += convertActionScript(((DefineButtonTag) tag));
ret += "}";
ret += "]]></script></Actionscript>";
}
if (tag instanceof DefineButton2Tag) {
DefineButton2Tag db2 = (DefineButton2Tag) tag;
if (!db2.actions.isEmpty()) {
ret += "<Actionscript><script><![CDATA[";
for (BUTTONCONDACTION bca : db2.actions) {
List<String> events = new ArrayList<>();
if (bca.condOverUpToOverDown) {
events.add("press");
}
if (bca.condOverDownToOverUp) {
events.add("release");
}
if (bca.condOutDownToIdle) {
events.add("releaseOutside");
}
if (bca.condIdleToOverUp) {
events.add("rollOver");
}
if (bca.condOverUpToIddle) {
events.add("rollOut");
}
if (bca.condOverDownToOutDown) {
events.add("dragOut");
}
if (bca.condOutDownToOverDown) {
events.add("dragOver");
}
if (bca.condKeyPress > 0) {
String keyNames[] = {
null,
"<Left>",
"<Right>",
"<Home>",
"<End>",
"<Insert>",
"<Delete>",
null,
"<Backspace>",
null,
null,
null,
null,
"<Enter>",
"<Up>",
"<Down>",
"<PageUp>",
"<PageDown>",
"<Tab>",
"<Escape>",
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
"<Space>"
};
if ((bca.condKeyPress < keyNames.length) && (bca.condKeyPress > 0) && (keyNames[bca.condKeyPress] != null)) {
events.add("keyPress \"" + keyNames[bca.condKeyPress] + "\"");
} else {
events.add("keyPress \"" + (char) bca.condKeyPress + "\"");
}
}
String onStr = "";
for (int i = 0; i < events.size(); i++) {
if (i > 0) {
onStr += ", ";
}
onStr += events.get(i);
}
ret += "on(" + onStr + "){\r\n";
ret += convertActionScript(bca);
ret += "}";
}
ret += "]]></script></Actionscript>";
}
}
ret += "</DOMSymbolInstance>";
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<Integer, String> characterVariables, Map<Integer, String> characterClasses, List<Integer> oneInstanceShapes, String backgroundColor, List<Tag> tags, HashMap<Integer, CharacterTag> characters, HashMap<String, byte[]> files) {
//TODO: Imported assets
//linkageImportForRS="true" linkageIdentifier="xxx" linkageURL="yyy.swf"
String ret = "";
List<String> media = new ArrayList<>();
List<String> 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 += "<DOMSymbolItem xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://ns.adobe.com/xfl/2008/\" name=\"Symbol " + symbol.getCharacterID() + "\" lastModified=\"" + getTimestamp() + "\""; //TODO:itemID
if (symbol instanceof ShapeTag) {
symbolStr += " symbolType=\"graphic\"";
} else if (symbol instanceof ButtonTag) {
symbolStr += " symbolType=\"button\"";
if (((ButtonTag) symbol).trackAsMenu()) {
symbolStr += " trackAsMenu=\"true\"";
}
}
boolean linkageExportForAS = false;
if (characterClasses.containsKey(symbol.getCharacterID())) {
linkageExportForAS = true;
symbolStr += " linkageClassName=\"" + xmlString(characterClasses.get(symbol.getCharacterID())) + "\"";
}
if (characterVariables.containsKey(symbol.getCharacterID())) {
linkageExportForAS = true;
symbolStr += " linkageIdentifier=\"" + xmlString(characterVariables.get(symbol.getCharacterID())) + "\"";
}
if (linkageExportForAS) {
symbolStr += " linkageExportForAS=\"true\"";
}
symbolStr += ">";
symbolStr += "<timeline>";
String itemIcon = null;
if (symbol instanceof ButtonTag) {
itemIcon = "0";
symbolStr += "<DOMTimeline name=\"Symbol " + symbol.getCharacterID() + "\" currentFrame=\"0\">";
symbolStr += "<layers>";
ButtonTag button = (ButtonTag) symbol;
List<BUTTONRECORD> 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 += "<DOMLayer name=\"Layer " + (maxDepth - i + 1) + "\"";
if (i == 1) {
symbolStr += " current=\"true\" isSelected=\"true\"";
}
symbolStr += ">"; //color=\"#4FFF4F\"
symbolStr += "<frames>";
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<FILTER> 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 += "<DOMFrame index=\"";
symbolStr += (frame - duration);
symbolStr += "\"";
symbolStr += " duration=\"" + (duration - 1) + "\"";
symbolStr += " keyMode=\"" + KEY_MODE_NORMAL + "\">";
symbolStr += "<elements>";
symbolStr += "</elements>";
symbolStr += "</DOMFrame>";
}
symbolStr += "<DOMFrame index=\"";
symbolStr += (frame - 1);
symbolStr += "\"";
symbolStr += " keyMode=\"" + KEY_MODE_NORMAL + "\">";
symbolStr += "<elements>";
symbolStr += recCharStr;
symbolStr += "</elements>";
symbolStr += "</DOMFrame>";
}
}
}
}
symbolStr += "</frames>";
symbolStr += "</DOMLayer>";
}
symbolStr += "</layers>";
symbolStr += "</DOMTimeline>";
} 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 += "<DOMTimeline name=\"Symbol " + symbol.getCharacterID() + "\" currentFrame=\"0\">";
symbolStr += "<layers>";
symbolStr += convertShape(characters, null, shape);
symbolStr += "</layers>";
symbolStr += "</DOMTimeline>";
}
symbolStr += "</timeline>";
symbolStr += "</DOMSymbolItem>";
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 += "<Include href=\"" + symbolFile + "\"";
if (itemIcon != null) {
symbLinkStr += " itemIcon=\"" + itemIcon + "\"";
}
symbLinkStr += " loadImmediate=\"false\" lastModified=\"" + getTimestamp() + "\"/>"; //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 = "<DOMBitmapItem name=\"" + symbolFile + "\" sourceLastImported=\"" + getTimestamp() + "\" externalFileSize=\"" + baos.toByteArray().length + "\"";
if (format.equals("png") || format.equals("gif")) {
mediaLinkStr += " useImportedJPEGData=\"false\" compressionType=\"lossless\" originalCompressionType=\"lossless\"";
} else if (format.equals("jpg")) {
mediaLinkStr += " isJPEG=\"true\"";
}
if (characterClasses.containsKey(symbol.getCharacterID())) {
mediaLinkStr += " linkageExportForAS=\"true\" linkageClassName=\"" + characterClasses.get(symbol.getCharacterID()) + "\"";
}
mediaLinkStr += " quality=\"50\" href=\"" + symbolFile + "\" bitmapDataHRef=\"M " + (media.size() + 1) + " " + getTimestamp() + ".dat\" frameRight=\"" + image.getWidth() + "\" frameBottom=\"" + image.getHeight() + "\"/>\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 = "<DOMSoundItem name=\"" + symbolFile + "\" sourceLastImported=\"" + getTimestamp() + "\" externalFileSize=\"" + data.length + "\"";
mediaLinkStr += " href=\"" + symbolFile + "\"";
mediaLinkStr += " format=\"";
mediaLinkStr += rateMap[soundRate] + "kHz";
mediaLinkStr += " " + (soundSize == 1 ? "16bit" : "8bit");
mediaLinkStr += " " + (soundType == 1 ? "Stereo" : "Mono");
mediaLinkStr += "\"";
mediaLinkStr += " exportFormat=\"" + format + "\" exportBits=\"" + bits + "\" sampleCount=\"" + soundSampleCount + "\"";
if (characterClasses.containsKey(symbol.getCharacterID())) {
mediaLinkStr += " linkageExportForAS=\"true\" linkageClassName=\"" + characterClasses.get(symbol.getCharacterID()) + "\"";
}
if (characterVariables.containsKey(symbol.getCharacterID())) {
mediaLinkStr += " linkageExportForAS=\"true\" linkageIdentifier=\"" + xmlString(characterVariables.get(symbol.getCharacterID())) + "\"";
}
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 = "<DOMVideoItem name=\"" + symbolFile + "\" sourceLastImported=\"" + getTimestamp() + "\" externalFileSize=\"" + data.length + "\"";
mediaLinkStr += " href=\"" + symbolFile + "\"";
mediaLinkStr += " videoType=\"" + videoType + "\"";
mediaLinkStr += " fps=\"" + swf.frameRate + "\"";
mediaLinkStr += " width=\"" + video.width + "\"";
mediaLinkStr += " height=\"" + video.height + "\"";
double len = ((double) video.numFrames) / ((double) swf.frameRate);
mediaLinkStr += " length=\"" + len + "\"";
if (characterClasses.containsKey(symbol.getCharacterID())) {
mediaLinkStr += " linkageExportForAS=\"true\" linkageClassName=\"" + characterClasses.get(symbol.getCharacterID()) + "\"";
}
if (characterVariables.containsKey(symbol.getCharacterID())) {
mediaLinkStr += " linkageExportForAS=\"true\" linkageIdentifier=\"" + xmlString(characterVariables.get(symbol.getCharacterID())) + "\"";
}
mediaLinkStr += "/>\n";
media.add(mediaLinkStr);
}
}
if (!media.isEmpty()) {
ret += "<media>";
for (String m : media) {
ret += m;
}
ret += "</media>";
}
if (!symbols.isEmpty()) {
ret += "<symbols>";
for (String s : symbols) {
ret += s;
}
ret += "</symbols>";
}
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<Integer, CharacterTag> characters, List<Tag> 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 += "<DOMFrame index=\"" + (frame) + "\"";
if (duration > 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 += "<SoundEnvelope>";
soundEnvelopeStr += "<SoundEnvelopePoint level0=\"32768\" level1=\"32768\"/>";
soundEnvelopeStr += "</SoundEnvelope>";
}
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 += "<SoundEnvelope>";
if (startSound.soundInfo.hasEnvelope) {
for (SOUNDENVELOPE env : startSound.soundInfo.envelopeRecords) {
soundEnvelopeStr += "<SoundEnvelopePoint mark44=\"" + env.pos44 + "\" level0=\"" + env.leftLevel + "\" level1=\"" + env.rightLevel + "\"/>";
}
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 += "<SoundEnvelopePoint level0=\"32768\" level1=\"32768\"/>";
}
soundEnvelopeStr += "</SoundEnvelope>";
}
ret += ">";
ret += soundEnvelopeStr;
if (!actionScript.equals("")) {
ret += "<Actionscript><script><![CDATA[";
ret += actionScript;
ret += "]]></script></Actionscript>";
}
ret += "<elements>";
ret += elements;
ret += "</elements>";
ret += "</DOMFrame>";
return ret;
}
private static String convertVideoInstance(MATRIX matrix, DefineVideoStreamTag video) {
String ret = "<DOMVideoInstance libraryItemName=\"movie" + video.characterID + ".flv\" frameRight=\"" + (20 * video.width) + "\" frameBottom=\"" + (20 * video.height) + "\">";
ret += "<matrix>";
ret += convertMatrix(matrix);
ret += "</matrix>";
ret += "<transformationPoint>";
ret += "<Point />";
ret += "</transformationPoint>";
ret += "</DOMVideoInstance>";
return ret;
}
private static String convertFrames(String prevStr, String afterStr, List<Integer> oneInstanceShapes, List<Tag> tags, List<Tag> timelineTags, HashMap<Integer, CharacterTag> characters, int depth) {
String ret = "";
prevStr += "<frames>";
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<FILTER> 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<FILTER> 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 = "</frames>" + afterStr;
if (!ret.equals("")) {
ret = prevStr + ret + afterStr;
}
return ret;
}
public static String convertActionScriptLayer(int layerIndex, int spriteId, List<Tag> tags, List<Tag> 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 += "<DOMFrame index=\"" + (frame - duration) + "\"";
if (duration > 1) {
ret += " duration=\"" + duration + "\"";
}
ret += " keyMode=\"" + KEY_MODE_NORMAL + "\">";
ret += "<elements>";
ret += "</elements>";
ret += "</DOMFrame>";
}
ret += "<DOMFrame index=\"" + frame + "\"";
ret += " keyMode=\"" + KEY_MODE_NORMAL + "\">";
ret += "<Actionscript><script><![CDATA[";
ret += script;
ret += "]]></script></Actionscript>";
ret += "<elements>";
ret += "</elements>";
ret += "</DOMFrame>";
script = "";
duration = 0;
}
frame++;
}
}
if (!ret.equals("")) {
ret = "<DOMLayer name=\"Layer " + (layerIndex + 1) + "\" color=\"" + backgroundColor + "\">"
+ "<frames>"
+ ret
+ "</frames>"
+ "</DOMLayer>";
}
return ret;
}
public static String convertSoundLayer(int layerIndex, String backgroundColor, HashMap<Integer, CharacterTag> characters, List<Tag> tags, List<Tag> 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 = "<DOMLayer name=\"Layer " + layerIndex + "\" color=\"" + backgroundColor + "\">"
+ "<frames>" + ret + "</frames>"
+ "</DOMLayer>";
}
return ret;
}
public static String convertTimeline(int spriteId, List<Integer> oneInstanceShapes, String backgroundColor, List<Tag> tags, List<Tag> timelineTags, HashMap<Integer, CharacterTag> characters, String name) {
String ret = "";
ret += "<DOMTimeline name=\"" + name + "\">";
ret += "<layers>";
int layerCount = getLayerCount(timelineTags);
Stack<Integer> 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 += "<DOMLayer name=\"Layer " + (index + 1) + "\" color=\"" + backgroundColor + "\" ";
ret += " layerType=\"mask\" locked=\"true\"";
ret += ">";
ret += convertFrames("", "", oneInstanceShapes, tags, timelineTags, characters, po.getDepth());
ret += "</DOMLayer>";
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 += "<DOMLayer name=\"Layer " + (index + 1) + "\" color=\"" + backgroundColor + "\" ";
if (d == 1) {
layerPrev += " current=\"true\" isSelected=\"true\"";
}
if (parentLayer != -1) {
if (parentLayer != d) {
layerPrev += " parentLayerIndex=\"" + (parentLayer) + "\" locked=\"true\"";
}
}
layerPrev += ">";
String layerAfter = "</DOMLayer>";
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 += "</layers>";
ret += "</DOMTimeline>";
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<Integer, String> getCharacterClasses(List<Tag> tags) {
Map<Integer, String> 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<Integer, String> getCharacterVariables(List<Tag> tags) {
Map<Integer, String> 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<Tag> tags, TextTag tag, MATRIX matrix, List<FILTER> filters) {
String ret = "";
if (matrix == null) {
matrix = new MATRIX();
}
CSMTextSettingsTag csmts = null;
String filterStr = "";
if (filters != null) {
filterStr += "<filters>";
for (FILTER f : filters) {
filterStr += convertFilter(f);
}
filterStr += "</filters>";
}
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 += "<matrix>";
RECT bounds = tag.getBounds();
matrix.translateX += bounds.Xmin;
matrix.translateY += bounds.Ymin;
matStr += convertMatrix(matrix);
matStr += "</matrix>";
if ((tag instanceof DefineTextTag) || (tag instanceof DefineText2Tag)) {
List<TEXTRECORD> 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 += "<DOMStaticText";
if (fontRenderingMode != null) {
ret += " fontRenderingMode=\"" + fontRenderingMode + "\"";
}
ret += antiAlias;
ret += " width=\"" + tag.getBounds().getWidth() / 2 + "\" height=\"" + tag.getBounds().getHeight() + "\" autoExpand=\"true\" isSelectable=\"false\">";
ret += matStr;
ret += "<textRuns>";
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 += "<DOMTextRun>";
ret += "<characters>" + xmlString(rec.getText(tags, font)) + "</characters>";
ret += "<textAttrs>";
ret += "<DOMTextAttrs aliasText=\"false\" rotation=\"true\" size=\"" + twipToPixel(textHeight) + "\" bitmapSize=\"1040\"";
//indent=\"5\" leftMargin=\"2\" letterSpacing=\"1\" lineSpacing=\"6\" rightMargin=\"3\"
if (textColor != null) {
ret += " fillColor=\"" + textColor.toHexRGB() + "\"";
} else if (textColorA != null) {
ret += " fillColor=\"" + textColorA.toHexRGB() + "\" alpha=\"" + textColorA.getAlphaFloat() + "\"";
}
ret += " face=\"" + psFontName + "\"";
ret += "/>";
ret += "</textAttrs>";
ret += "</DOMTextRun>";
}
}
ret += "</textRuns>";
ret += filterStr;
ret += "</DOMStaticText>";
} 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(det.getBounds().getWidth());
double height = twipToPixel(det.getBounds().getHeight());
if (det.hasLayout) {
width -= twipToPixel(det.rightMargin);
width -= twipToPixel(det.leftMargin);
//height-=det.
}
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 += "<textRuns>";
if (det.hasText) {
if (det.html) {
ret += convertHTMLText(tags, det, det.initialText);
} else {
ret += "<DOMTextRun>";
ret += "<characters>" + xmlString(det.initialText) + "</characters>";
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 += "<textAttrs>";
ret += "<DOMTextAttrs";
if (alignment != null) {
ret += " alignment=\"" + alignment + "\"";
}
ret += " rotation=\"true\""; //?
if (indent > -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 += "</textAttrs>";
ret += "</DOMTextRun>";
}
}
ret += "</textRuns>";
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<String, byte[]> files = new HashMap<>();
HashMap<Integer, CharacterTag> characters = getCharacters(swf.tags);
List<Integer> oneInstaceShapes = getOneInstanceShapes(swf.tags, characters);
Map<Integer, String> characterClasses = getCharacterClasses(swf.tags);
Map<Integer, String> 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 xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://ns.adobe.com/xfl/2008/\" currentTimeline=\"1\" xflVersion=\"2.2\" creatorInfo=\"" + generator + "\" platform=\"Windows\" versionInfo=\"Saved by " + generatorVerName + "\" majorVersion=\"" + generatorVersion + "\" buildNumber=\"\" nextSceneIdentifier=\"2\" playOptionsPlayLoop=\"false\" playOptionsPlayPages=\"false\" playOptionsPlayFrameActions=\"false\" autoSaveHasPrompted=\"true\"";
domDocument += " backgroundColor=\"" + backgroundColor + "\"";
domDocument += " frameRate=\"" + swf.frameRate + "\"";
domDocument += ">";
domDocument += convertLibrary(swf, characterVariables, characterClasses, oneInstaceShapes, backgroundColor, swf.tags, characters, files);
domDocument += "<timelines>";
domDocument += convertTimeline(0, oneInstaceShapes, backgroundColor, swf.tags, swf.tags, characters, "Scene 1");
domDocument += "</timelines>";
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 = "<flash_profiles>\n"
+ "<flash_profile version=\"1.0\" name=\"Default\" current=\"true\">\n"
+ " <PublishFormatProperties enabled=\"true\">\n"
+ " <defaultNames>1</defaultNames>\n"
+ " <flash>1</flash>\n"
+ " <projectorWin>0</projectorWin>\n"
+ " <projectorMac>0</projectorMac>\n"
+ " <html>1</html>\n"
+ " <gif>0</gif>\n"
+ " <jpeg>0</jpeg>\n"
+ " <png>0</png>\n"
+ " <qt>0</qt>\n"
+ " <rnwk>0</rnwk>\n"
+ " <swc>0</swc>\n"
+ " <flashDefaultName>1</flashDefaultName>\n"
+ " <projectorWinDefaultName>1</projectorWinDefaultName>\n"
+ " <projectorMacDefaultName>1</projectorMacDefaultName>\n"
+ " <htmlDefaultName>1</htmlDefaultName>\n"
+ " <gifDefaultName>1</gifDefaultName>\n"
+ " <jpegDefaultName>1</jpegDefaultName>\n"
+ " <pngDefaultName>1</pngDefaultName>\n"
+ " <qtDefaultName>1</qtDefaultName>\n"
+ " <rnwkDefaultName>1</rnwkDefaultName>\n"
+ " <swcDefaultName>1</swcDefaultName>\n"
+ " <flashFileName>" + baseName + ".swf</flashFileName>\n"
+ " <projectorWinFileName>" + baseName + ".exe</projectorWinFileName>\n"
+ " <projectorMacFileName>" + baseName + ".app</projectorMacFileName>\n"
+ " <htmlFileName>" + baseName + ".html</htmlFileName>\n"
+ " <gifFileName>" + baseName + ".gif</gifFileName>\n"
+ " <jpegFileName>" + baseName + ".jpg</jpegFileName>\n"
+ " <pngFileName>" + baseName + ".png</pngFileName>\n"
+ " <qtFileName>" + baseName + ".mov</qtFileName>\n"
+ " <rnwkFileName>" + baseName + ".smil</rnwkFileName>\n"
+ " <swcFileName>Untitled-4.swc</swcFileName>\n"
+ " </PublishFormatProperties>\n"
+ " <PublishHtmlProperties enabled=\"true\">\n"
+ " <VersionDetectionIfAvailable>0</VersionDetectionIfAvailable>\n"
+ " <VersionInfo>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;</VersionInfo>\n"
+ " <UsingDefaultContentFilename>1</UsingDefaultContentFilename>\n"
+ " <UsingDefaultAlternateFilename>1</UsingDefaultAlternateFilename>\n"
+ " <ContentFilename>" + baseName + "_content.html</ContentFilename>\n"
+ " <AlternateFilename>" + baseName + "_alternate.html</AlternateFilename>\n"
+ " <UsingOwnAlternateFile>0</UsingOwnAlternateFile>\n"
+ " <OwnAlternateFilename></OwnAlternateFilename>\n"
+ " <Width>" + twipToPixel(swf.displayRect.getWidth()) + "</Width>\n"
+ " <Height>" + twipToPixel(swf.displayRect.getHeight()) + "</Height>\n"
+ " <Align>0</Align>\n"
+ " <Units>0</Units>\n"
+ " <Loop>1</Loop>\n"
+ " <StartPaused>0</StartPaused>\n"
+ " <Scale>0</Scale>\n"
+ " <HorizontalAlignment>1</HorizontalAlignment>\n"
+ " <VerticalAlignment>1</VerticalAlignment>\n"
+ " <Quality>4</Quality>\n"
+ " <DeblockingFilter>0</DeblockingFilter>\n"
+ " <WindowMode>0</WindowMode>\n"
+ " <DisplayMenu>1</DisplayMenu>\n"
+ " <DeviceFont>0</DeviceFont>\n"
+ " <TemplateFileName></TemplateFileName>\n"
+ " <showTagWarnMsg>1</showTagWarnMsg>\n"
+ " </PublishHtmlProperties>\n"
+ " <PublishFlashProperties enabled=\"true\">\n"
+ " <TopDown></TopDown>\n"
+ " <FireFox></FireFox>\n"
+ " <Report>0</Report>\n"
+ " <Protect>0</Protect>\n"
+ " <OmitTraceActions>0</OmitTraceActions>\n"
+ " <Quality>80</Quality>\n"
+ " <DeblockingFilter>0</DeblockingFilter>\n"
+ " <StreamFormat>0</StreamFormat>\n"
+ " <StreamCompress>7</StreamCompress>\n"
+ " <EventFormat>0</EventFormat>\n"
+ " <EventCompress>7</EventCompress>\n"
+ " <OverrideSounds>0</OverrideSounds>\n"
+ " <Version>15</Version>\n"
+ " <ExternalPlayer>FlashPlayer11.2</ExternalPlayer>\n"
+ " <ActionScriptVersion>" + (useAS3 ? "3" : "2") + "</ActionScriptVersion>\n"
+ " <PackageExportFrame>1</PackageExportFrame>\n"
+ " <PackagePaths></PackagePaths>\n"
+ " <AS3PackagePaths>.</AS3PackagePaths>\n"
+ " <AS3ConfigConst>CONFIG::FLASH_AUTHORING=&quot;true&quot;;</AS3ConfigConst>\n"
+ " <DebuggingPermitted>0</DebuggingPermitted>\n"
+ " <DebuggingPassword></DebuggingPassword>\n"
+ " <CompressMovie>" + (swf.compressed ? "1" : "0") + "</CompressMovie>\n"
+ " <CompressionType>" + (swf.lzma ? "1" : "0") + "</CompressionType>\n"
+ " <InvisibleLayer>1</InvisibleLayer>\n"
+ " <DeviceSound>0</DeviceSound>\n"
+ " <StreamUse8kSampleRate>0</StreamUse8kSampleRate>\n"
+ " <EventUse8kSampleRate>0</EventUse8kSampleRate>\n"
+ " <UseNetwork>" + (useNetwork ? 1 : 0) + "</UseNetwork>\n"
+ " <DocumentClass>" + xmlString(characterClasses.containsKey(0) ? characterClasses.get(0) : "") + "</DocumentClass>\n"
+ " <AS3Strict>2</AS3Strict>\n"
+ " <AS3Coach>4</AS3Coach>\n"
+ " <AS3AutoDeclare>4096</AS3AutoDeclare>\n"
+ " <AS3Dialect>AS3</AS3Dialect>\n"
+ " <AS3ExportFrame>1</AS3ExportFrame>\n"
+ " <AS3Optimize>1</AS3Optimize>\n"
+ " <ExportSwc>0</ExportSwc>\n"
+ " <ScriptStuckDelay>15</ScriptStuckDelay>\n"
+ " <IncludeXMP>1</IncludeXMP>\n"
+ " <HardwareAcceleration>0</HardwareAcceleration>\n"
+ " <AS3Flags>4102</AS3Flags>\n"
+ " <DefaultLibraryLinkage>rsl</DefaultLibraryLinkage>\n"
+ " <RSLPreloaderMethod>wrap</RSLPreloaderMethod>\n"
+ " <RSLPreloaderSWF>$(AppConfig)/ActionScript 3.0/rsls/loader_animation.swf</RSLPreloaderSWF>\n"
+ " <LibraryPath>\n"
+ " <library-path-entry>\n"
+ " <swc-path>$(AppConfig)/ActionScript 3.0/libs</swc-path>\n"
+ " <linkage>merge</linkage>\n"
+ " </library-path-entry>\n"
+ " <library-path-entry>\n"
+ " <swc-path>$(AppConfig)/ActionScript 3.0/libs/11.0/textLayout.swc</swc-path>\n"
+ " <linkage usesDefault=\"true\">rsl</linkage>\n"
+ " <rsl-url>http://fpdownload.adobe.com/pub/swz/tlf/2.0.0.232/textLayout_2.0.0.232.swz</rsl-url>\n"
+ " <policy-file-url>http://fpdownload.adobe.com/pub/swz/crossdomain.xml</policy-file-url>\n"
+ " <rsl-url>textLayout_2.0.0.232.swz</rsl-url>\n"
+ " </library-path-entry>\n"
+ " </LibraryPath>\n"
+ " <LibraryVersions>\n"
+ " <library-version>\n"
+ " <swc-path>$(AppConfig)/ActionScript 3.0/libs/11.0/textLayout.swc</swc-path>\n"
+ " <feature name=\"tlfText\" majorVersion=\"2\" minorVersion=\"0\" build=\"232\"/>\n"
+ " <rsl-url>http://fpdownload.adobe.com/pub/swz/tlf/2.0.0.232/textLayout_2.0.0.232.swz</rsl-url>\n"
+ " <policy-file-url>http://fpdownload.adobe.com/pub/swz/crossdomain.xml</policy-file-url>\n"
+ " <rsl-url>textLayout_2.0.0.232.swz</rsl-url>\n"
+ " </library-version>\n"
+ " </LibraryVersions>\n"
+ " </PublishFlashProperties>\n"
+ " <PublishJpegProperties enabled=\"true\">\n"
+ " <Width>" + twipToPixel(swf.displayRect.getWidth()) + "</Width>\n"
+ " <Height>" + twipToPixel(swf.displayRect.getHeight()) + "</Height>\n"
+ " <Progressive>0</Progressive>\n"
+ " <DPI>4718592</DPI>\n"
+ " <Size>0</Size>\n"
+ " <Quality>80</Quality>\n"
+ " <MatchMovieDim>1</MatchMovieDim>\n"
+ " </PublishJpegProperties>\n"
+ " <PublishRNWKProperties enabled=\"true\">\n"
+ " <exportFlash>1</exportFlash>\n"
+ " <flashBitRate>0</flashBitRate>\n"
+ " <exportAudio>1</exportAudio>\n"
+ " <audioFormat>0</audioFormat>\n"
+ " <singleRateAudio>0</singleRateAudio>\n"
+ " <realVideoRate>100000</realVideoRate>\n"
+ " <speed28K>1</speed28K>\n"
+ " <speed56K>1</speed56K>\n"
+ " <speedSingleISDN>0</speedSingleISDN>\n"
+ " <speedDualISDN>0</speedDualISDN>\n"
+ " <speedCorporateLAN>0</speedCorporateLAN>\n"
+ " <speed256K>0</speed256K>\n"
+ " <speed384K>0</speed384K>\n"
+ " <speed512K>0</speed512K>\n"
+ " <exportSMIL>1</exportSMIL>\n"
+ " </PublishRNWKProperties>\n"
+ " <PublishGifProperties enabled=\"true\">\n"
+ " <Width>" + twipToPixel(swf.displayRect.getWidth()) + "</Width>\n"
+ " <Height>" + twipToPixel(swf.displayRect.getHeight()) + "</Height>\n"
+ " <Animated>0</Animated>\n"
+ " <MatchMovieDim>1</MatchMovieDim>\n"
+ " <Loop>1</Loop>\n"
+ " <LoopCount></LoopCount>\n"
+ " <OptimizeColors>1</OptimizeColors>\n"
+ " <Interlace>0</Interlace>\n"
+ " <Smooth>1</Smooth>\n"
+ " <DitherSolids>0</DitherSolids>\n"
+ " <RemoveGradients>0</RemoveGradients>\n"
+ " <TransparentOption></TransparentOption>\n"
+ " <TransparentAlpha>128</TransparentAlpha>\n"
+ " <DitherOption></DitherOption>\n"
+ " <PaletteOption></PaletteOption>\n"
+ " <MaxColors>255</MaxColors>\n"
+ " <PaletteName></PaletteName>\n"
+ " </PublishGifProperties>\n"
+ " <PublishPNGProperties enabled=\"true\">\n"
+ " <Width>" + twipToPixel(swf.displayRect.getWidth()) + "</Width>\n"
+ " <Height>" + twipToPixel(swf.displayRect.getHeight()) + "</Height>\n"
+ " <OptimizeColors>1</OptimizeColors>\n"
+ " <Interlace>0</Interlace>\n"
+ " <Transparent>0</Transparent>\n"
+ " <Smooth>1</Smooth>\n"
+ " <DitherSolids>0</DitherSolids>\n"
+ " <RemoveGradients>0</RemoveGradients>\n"
+ " <MatchMovieDim>1</MatchMovieDim>\n"
+ " <DitherOption></DitherOption>\n"
+ " <FilterOption></FilterOption>\n"
+ " <PaletteOption></PaletteOption>\n"
+ " <BitDepth>24-bit with Alpha</BitDepth>\n"
+ " <MaxColors>255</MaxColors>\n"
+ " <PaletteName></PaletteName>\n"
+ " </PublishPNGProperties>\n"
+ " <PublishQTProperties enabled=\"true\">\n"
+ " <Width>" + twipToPixel(swf.displayRect.getWidth()) + "</Width>\n"
+ " <Height>" + twipToPixel(swf.displayRect.getHeight()) + "</Height>\n"
+ " <MatchMovieDim>1</MatchMovieDim>\n"
+ " <UseQTSoundCompression>0</UseQTSoundCompression>\n"
+ " <AlphaOption></AlphaOption>\n"
+ " <LayerOption></LayerOption>\n"
+ " <QTSndSettings>00000000</QTSndSettings>\n"
+ " <ControllerOption>0</ControllerOption>\n"
+ " <Looping>0</Looping>\n"
+ " <PausedAtStart>0</PausedAtStart>\n"
+ " <PlayEveryFrame>0</PlayEveryFrame>\n"
+ " <Flatten>1</Flatten>\n"
+ " </PublishQTProperties>\n"
+ "</flash_profile>\n"
+ "</flash_profiles>";
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 "<AdjustColorFilter brightness=\"" + normBrightness(b) + "\" contrast=\"" + normContrast(c) + "\" saturation=\"" + normSaturation(s) + "\" hue=\"" + normHue(h) + "\"/>";
}
private static String convertHTMLText(List<Tag> 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 = "<?xml version=\"1.0\"?>\n"
+ "<!DOCTYPE some_name [ \n"
+ "<!ENTITY nbsp \"&#160;\"> \n"
+ "]><html>" + html + "</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>" + 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("<", "&lt;").replace(">", "&gt;").replace("\"", "&quot;").replace("&", "&amp;").replace("\r\n", "&#xD;").replace("\r", "&#xD;").replace("\n", "&#xD;");
}
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<Tag> 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<Tag> 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 += "<DOMTextRun>";
result += "<characters>" + xmlString(txt) + "</characters>";
result += "<textAttrs>";
result += "<DOMTextAttrs";
if (alignment != null) {
result += " alignment=\"" + alignment + "\"";
}
result += " rotation=\"true\""; //?
if (indent > -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 += "</textAttrs>";
result += "</DOMTextRun>";
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
putText(new String(ch, start, length));
}
@Override
public void endDocument() {
}
}
}