/* * Copyright (C) 2013 JPEXS * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package com.jpexs.decompiler.flash.xfl; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.helpers.Highlighting; import com.jpexs.decompiler.flash.tags.CSMTextSettingsTag; import com.jpexs.decompiler.flash.tags.DefineButton2Tag; import com.jpexs.decompiler.flash.tags.DefineButtonCxformTag; import com.jpexs.decompiler.flash.tags.DefineButtonTag; import com.jpexs.decompiler.flash.tags.DefineEditTextTag; import com.jpexs.decompiler.flash.tags.DefineFontNameTag; import com.jpexs.decompiler.flash.tags.DefineSoundTag; import com.jpexs.decompiler.flash.tags.DefineSpriteTag; import com.jpexs.decompiler.flash.tags.DefineText2Tag; import com.jpexs.decompiler.flash.tags.DefineTextTag; import com.jpexs.decompiler.flash.tags.DefineVideoStreamTag; import com.jpexs.decompiler.flash.tags.DoActionTag; import com.jpexs.decompiler.flash.tags.DoInitActionTag; import com.jpexs.decompiler.flash.tags.ExportAssetsTag; import com.jpexs.decompiler.flash.tags.FileAttributesTag; import com.jpexs.decompiler.flash.tags.FrameLabelTag; import com.jpexs.decompiler.flash.tags.PlaceObjectTypeTag; import com.jpexs.decompiler.flash.tags.SetBackgroundColorTag; import com.jpexs.decompiler.flash.tags.ShowFrameTag; import com.jpexs.decompiler.flash.tags.SoundStreamBlockTag; import com.jpexs.decompiler.flash.tags.SoundStreamHeadTypeTag; import com.jpexs.decompiler.flash.tags.StartSoundTag; import com.jpexs.decompiler.flash.tags.SymbolClassTag; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.base.ASMSource; import com.jpexs.decompiler.flash.tags.base.ButtonTag; import com.jpexs.decompiler.flash.tags.base.CharacterTag; import com.jpexs.decompiler.flash.tags.base.FontTag; import com.jpexs.decompiler.flash.tags.base.ImageTag; import com.jpexs.decompiler.flash.tags.base.MorphShapeTag; import com.jpexs.decompiler.flash.tags.base.RemoveTag; import com.jpexs.decompiler.flash.tags.base.ShapeTag; import com.jpexs.decompiler.flash.tags.base.TextTag; import com.jpexs.decompiler.flash.types.BUTTONCONDACTION; import com.jpexs.decompiler.flash.types.BUTTONRECORD; import com.jpexs.decompiler.flash.types.CXFORM; import com.jpexs.decompiler.flash.types.CXFORMWITHALPHA; import com.jpexs.decompiler.flash.types.FILLSTYLE; import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY; import com.jpexs.decompiler.flash.types.GRADIENT; import com.jpexs.decompiler.flash.types.GRADRECORD; import com.jpexs.decompiler.flash.types.LINESTYLE; import com.jpexs.decompiler.flash.types.LINESTYLE2; import com.jpexs.decompiler.flash.types.LINESTYLEARRAY; import com.jpexs.decompiler.flash.types.MATRIX; import com.jpexs.decompiler.flash.types.RECT; import com.jpexs.decompiler.flash.types.RGB; import com.jpexs.decompiler.flash.types.RGBA; import com.jpexs.decompiler.flash.types.SHAPE; import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE; import com.jpexs.decompiler.flash.types.SOUNDENVELOPE; import com.jpexs.decompiler.flash.types.TEXTRECORD; import com.jpexs.decompiler.flash.types.filters.BEVELFILTER; import com.jpexs.decompiler.flash.types.filters.BLURFILTER; import com.jpexs.decompiler.flash.types.filters.COLORMATRIXFILTER; import com.jpexs.decompiler.flash.types.filters.DROPSHADOWFILTER; import com.jpexs.decompiler.flash.types.filters.FILTER; import com.jpexs.decompiler.flash.types.filters.GLOWFILTER; import com.jpexs.decompiler.flash.types.filters.GRADIENTBEVELFILTER; import com.jpexs.decompiler.flash.types.filters.GRADIENTGLOWFILTER; import com.jpexs.decompiler.flash.types.shaperecords.CurvedEdgeRecord; import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD; import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord; import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord; import com.jpexs.decompiler.flash.types.sound.MP3FRAME; import java.awt.Font; import java.awt.GraphicsEnvironment; import java.awt.Point; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.StringReader; import java.io.StringWriter; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Stack; import java.util.logging.Level; import java.util.logging.Logger; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import javax.imageio.ImageIO; import javax.xml.parsers.SAXParserFactory; import javax.xml.transform.OutputKeys; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.helpers.XMLReaderFactory; /** * * @author JPEXS */ public class XFLConverter { public static final int KEY_MODE_NORMAL = 9728; public static final int KEY_MODE_CLASSIC_TWEEN = 22017; public static final int KEY_MODE_SHAPE_TWEEN = 17922; public static final int KEY_MODE_MOTION_TWEEN = 8195; public static final int KEY_MODE_SHAPE_LAYERS = 8192; private XFLConverter() { } public static String convertShapeEdge(MATRIX mat, SHAPERECORD record, int x, int y) { String ret = ""; if (record instanceof StyleChangeRecord) { StyleChangeRecord scr = (StyleChangeRecord) record; Point p = new Point(scr.moveDeltaX, scr.moveDeltaY); //p = mat.apply(p); if (scr.stateMoveTo) { return "! " + p.x + " " + p.y; } return ""; } if (record instanceof StraightEdgeRecord) { StraightEdgeRecord ser = (StraightEdgeRecord) record; if (ser.generalLineFlag || ser.vertLineFlag) { y += ser.deltaY; } if (ser.generalLineFlag || (!ser.vertLineFlag)) { x += ser.deltaX; } Point p = new Point(x, y); //p = mat.apply(p); return "| " + p.x + " " + p.y; } if (record instanceof CurvedEdgeRecord) { CurvedEdgeRecord cer = (CurvedEdgeRecord) record; int controlX = cer.controlDeltaX + x; int controlY = cer.controlDeltaY + y; int anchorX = cer.anchorDeltaX + controlX; int anchorY = cer.anchorDeltaY + controlY; Point control = new Point(controlX, controlY); //control = mat.apply(control); Point anchor = new Point(anchorX, anchorY); //anchor = mat.apply(anchor); return "[ " + control.x + " " + control.y + " " + anchor.x + " " + anchor.y; } return ret; } public static String convertShapeEdges(int startX, int startY, MATRIX mat, List records) { String ret = ""; int x = startX; int y = startY; ret += "!" + startX + " " + startY; for (SHAPERECORD rec : records) { ret += convertShapeEdge(mat, rec, x, y); x = rec.changeX(x); y = rec.changeY(y); } return ret; } public static String convertLineStyle(LINESTYLE ls, int shapeNum) { return "" + "" + "" + "" + ""; } public static String convertLineStyle(HashMap characters, LINESTYLE2 ls, int shapeNum) { String ret = ""; String params = ""; if (ls.pixelHintingFlag) { params += " pixelHinting=\"true\""; } if (ls.width == 1) { params += " solidStyle=\"hairline\""; } if ((!ls.noHScaleFlag) && (!ls.noVScaleFlag)) { params += " scaleMode=\"normal\""; } else if ((!ls.noHScaleFlag) && ls.noVScaleFlag) { params += " scaleMode=\"horizontal\""; } else if (ls.noHScaleFlag && (!ls.noVScaleFlag)) { params += " scaleMode=\"vertical\""; } switch (ls.endCapStyle) { //What about endCapStyle? case LINESTYLE2.NO_CAP: params += " caps=\"none\""; break; case LINESTYLE2.SQUARE_CAP: params += " caps=\"square\""; break; } switch (ls.joinStyle) { case LINESTYLE2.BEVEL_JOIN: params += " joints=\"bevel\""; break; case LINESTYLE2.MITER_JOIN: params += " joints=\"miter\""; float miterLimitFactor = toFloat(ls.miterLimitFactor); if (miterLimitFactor != 3.0f) { params += " miterLimit=\"" + miterLimitFactor + "\""; } break; } ret += ""; } else { ret += convertFillStyle(null/* FIXME */, characters, ls.fillType, shapeNum); } ret += ""; ret += ""; return ret; } private static float toFloat(int i) { return ((float) i) / (1 << 16); } public static String convertFillStyle(MATRIX mat, HashMap characters, FILLSTYLE fs, int shapeNum) { if (mat == null) { mat = new MATRIX(); } String ret = ""; //ret += ""; switch (fs.fillStyleType) { case FILLSTYLE.SOLID: ret += "= 3) { ret += fs.colorA.toHexRGB(); } else { ret += fs.color.toHexRGB(); } ret += "\""; if (shapeNum >= 3) { ret += " alpha=\"" + fs.colorA.getAlphaFloat() + "\""; } ret += " />"; break; case FILLSTYLE.REPEATING_BITMAP: case FILLSTYLE.CLIPPED_BITMAP: case FILLSTYLE.NON_SMOOTHED_REPEATING_BITMAP: case FILLSTYLE.NON_SMOOTHED_CLIPPED_BITMAP: ret += ""; ret += ""; break; case FILLSTYLE.LINEAR_GRADIENT: case FILLSTYLE.RADIAL_GRADIENT: case FILLSTYLE.FOCAL_RADIAL_GRADIENT: if (fs.fillStyleType == FILLSTYLE.LINEAR_GRADIENT) { ret += ""; GRADRECORD records[]; if (fs.fillStyleType == FILLSTYLE.FOCAL_RADIAL_GRADIENT) { records = fs.focalGradient.gradientRecords; } else { records = fs.gradient.gradientRecords; } for (GRADRECORD rec : records) { ret += "= 3 ? rec.colorA.toHexRGB() : rec.color.toHexRGB()) + "\""; if (shapeNum >= 3) { ret += " alpha=\"" + rec.colorA.getAlphaFloat() + "\""; } ret += " ratio=\"" + rec.getRatioFloat() + "\""; ret += " />"; } if (fs.fillStyleType == FILLSTYLE.LINEAR_GRADIENT) { ret += ""; } else { ret += ""; } break; } //ret += ""; return ret; } public static String convertMatrix(MATRIX m) { String ret = ""; if (m == null) { m = new MATRIX(); } ret += " characters, MATRIX mat, int shapeNum, SHAPE shape) { return convertShape(characters, mat, shapeNum, shape.shapeRecords); } public static String convertShape(HashMap characters, MATRIX mat, int shapeNum, SHAPEWITHSTYLE shape) { return convertShape(characters, mat, shapeNum, shape.shapeRecords, shape.fillStyles, shape.lineStyles, false); } public static String convertShape(HashMap characters, MATRIX mat, ShapeTag shape) { return convertShape(characters, mat, shape.getShapeNum(), shape.getShapes()); } public static String convertShape(HashMap characters, MATRIX mat, int shapeNum, List shapeRecords) { return convertShape(characters, mat, shapeNum, shapeRecords, null, null, false); } public static String convertShape(HashMap characters, MATRIX mat, int shapeNum, List shapeRecords, FILLSTYLEARRAY fillStyles, LINESTYLEARRAY lineStyles, boolean morphshape) { String ret = ""; if (mat == null) { mat = new MATRIX(); } List edges = new ArrayList<>(); //int fillStyleCount = 0; int lineStyleCount = 0; int fillStyle0 = -1; int fillStyle1 = -1; int strokeStyle = -1; //String edgesStr = ""; String fillsStr = ""; String strokesStr = ""; fillsStr += ""; strokesStr += ""; //edgesStr += ""; List layers = new ArrayList<>(); String currentLayer = ""; int fillStyleCount = 0; //List fillStylesStr = new ArrayList<>(); if (fillStyles != null) { for (FILLSTYLE fs : fillStyles.fillStyles) { fillsStr += ""; fillsStr += convertFillStyle(mat, characters, fs, shapeNum); fillsStr += ""; fillStyleCount++; } } if (lineStyles != null) { if (lineStyles.lineStyles2 != null) { //(shapeNum == 4) { for (int l = 0; l < lineStyles.lineStyles2.length; l++) { strokesStr += ""; strokesStr += convertLineStyle(characters, lineStyles.lineStyles2[l], shapeNum); strokesStr += ""; lineStyleCount++; } } else { for (int l = 0; l < lineStyles.lineStyles.length; l++) { strokesStr += ""; strokesStr += convertLineStyle(lineStyles.lineStyles[l], shapeNum); strokesStr += ""; lineStyleCount++; } } } fillsStr += ""; strokesStr += ""; int layer = 1; if ((fillStyleCount > 0) || (lineStyleCount > 0)) { currentLayer += ""; //color=\"#4FFF4F\" currentLayer += ""; currentLayer += ""; currentLayer += ""; currentLayer += ""; currentLayer += fillsStr; currentLayer += strokesStr; currentLayer += ""; } //edgesStr += ""; /*for (SHAPERECORD edge : shapeRecords) { if (edge instanceof StyleChangeRecord) { StyleChangeRecord scr = (StyleChangeRecord) edge; if (scr.stateNewStyles) { for (int f = 0; f < scr.fillStyles.fillStyles.length; f++) { fillStylesStr.add(convertFillStyle(mat, characters, scr.fillStyles.fillStyles[f], shapeNum)); } } } } boolean usedFillStyles[] = new boolean[fillStylesStr.size()]; int fillStyleCount = 0; lastFillStyleCount = 0; if (fillStyles != null) { lastFillStyleCount = fillStyles.fillStyles.length; fillStyleCount += lastFillStyleCount; } for (SHAPERECORD edge : shapeRecords) { if (edge instanceof StyleChangeRecord) { StyleChangeRecord scr = (StyleChangeRecord) edge; if (scr.stateNewStyles) { lastFillStyleCount = scr.fillStyles.fillStyles.length; fillStyleCount += lastFillStyleCount; } if (scr.stateFillStyle0 && scr.fillStyle0 > 0) { usedFillStyles[fillStyleCount - lastFillStyleCount + scr.fillStyle0 - 1] = true; } if (scr.stateFillStyle1 && scr.fillStyle1 > 0) { usedFillStyles[fillStyleCount - lastFillStyleCount + scr.fillStyle1 - 1] = true; } } } */ /*int mapPos = 0; HashMap fillStylesMap = new HashMap<>(); for (int f = 0; f < fillStyleCount; f++) { if (usedFillStyles[f]) { fillStylesMap.put(f, mapPos); mapPos++; fillsStr += ""; fillsStr += fillStylesStr.get(f); fillsStr += ""; } }*/ int x = 0; int y = 0; int startEdgeX = 0; int startEdgeY = 0; LINESTYLEARRAY actualLinestyles = lineStyles; int strokeStyleOrig = 0; fillStyleCount = fillStyles.fillStyles.length; for (SHAPERECORD edge : shapeRecords) { if (edge instanceof StyleChangeRecord) { StyleChangeRecord scr = (StyleChangeRecord) edge; boolean styleChange = false; int lastFillStyle1 = fillStyle1; int lastFillStyle0 = fillStyle0; int lastStrokeStyle = strokeStyle; if (scr.stateNewStyles) { fillsStr = ""; strokesStr = ""; if (fillStyleCount > 0 || lineStyleCount > 0) { if ((fillStyle0 > 0) || (fillStyle1 > 0) || (strokeStyle > 0)) { boolean empty = false; if ((fillStyle0 <= 0) && (fillStyle1 <= 0) && (strokeStyle > 0) && morphshape) { if (shapeNum == 4) { if (strokeStyleOrig > 0) { if (!actualLinestyles.lineStyles2[strokeStyleOrig].hasFillFlag) { if (actualLinestyles.lineStyles2[strokeStyleOrig].color.alpha == 0) { if (actualLinestyles.lineStyles2[strokeStyleOrig].color.red == 0) { if (actualLinestyles.lineStyles2[strokeStyleOrig].color.green == 0) { if (actualLinestyles.lineStyles2[strokeStyleOrig].color.blue == 0) { empty = true; } } } } } } } } if (!empty) { currentLayer += " -1) { currentLayer += " fillStyle0=\"" + fillStyle0 + "\""; } if (fillStyle1 > -1) { currentLayer += " fillStyle1=\"" + fillStyle1 + "\""; } if (strokeStyle > -1) { currentLayer += " strokeStyle=\"" + strokeStyle + "\""; } currentLayer += " edges=\"" + convertShapeEdges(startEdgeX, startEdgeY, mat, edges) + "\" />"; } } currentLayer += ""; currentLayer += ""; currentLayer += ""; currentLayer += ""; currentLayer += ""; currentLayer += ""; layers.add(currentLayer); currentLayer = ""; } currentLayer += ""; //color=\"#4FFF4F\" currentLayer += ""; currentLayer += ""; currentLayer += ""; currentLayer += ""; //ret += convertShape(characters, null, shape); for (int f = 0; f < scr.fillStyles.fillStyles.length; f++) { fillsStr += ""; fillsStr += convertFillStyle(mat, characters, scr.fillStyles.fillStyles[f], shapeNum); fillsStr += ""; fillStyleCount++; } if (shapeNum == 4) { for (int l = 0; l < scr.lineStyles.lineStyles2.length; l++) { strokesStr += ""; strokesStr += convertLineStyle(characters, scr.lineStyles.lineStyles2[l], shapeNum); strokesStr += ""; lineStyleCount++; } } else { for (int l = 0; l < scr.lineStyles.lineStyles.length; l++) { strokesStr += ""; strokesStr += convertLineStyle(scr.lineStyles.lineStyles[l], shapeNum); strokesStr += ""; lineStyleCount++; } } fillsStr += ""; strokesStr += ""; currentLayer += fillsStr; currentLayer += strokesStr; currentLayer += ""; //lastFillStyleCount = scr.fillStyles.fillStyles.length; //fillStyleCount += lastFillStyleCount; //lastLineStyleCount = (shapeNum == 4) ? scr.lineStyles.lineStyles2.length : scr.lineStyles.lineStyles.length; actualLinestyles = scr.lineStyles; } if (scr.stateFillStyle0) { /*edgeStyle += " fillStyle0=\""; edgeStyle += fillStyleCount - lastFillStyleCount + scr.fillStyle0; edgeStyle += "\"";*/ int fillStyle0_new = scr.fillStyle0;// == 0 ? 0 : fillStylesMap.get(fillStyleCount - lastFillStyleCount + scr.fillStyle0 - 1) + 1; //fillStyle0 = fillStyle0_new; if (morphshape) { //??? fillStyle1 = fillStyle0_new; } else { fillStyle0 = fillStyle0_new; } styleChange = true; } if (scr.stateFillStyle1) { /*edgeStyle += " fillStyle1=\""; edgeStyle += fillStyleCount - lastFillStyleCount + scr.fillStyle1; edgeStyle += "\"";*/ int fillStyle1_new = scr.fillStyle1;// == 0 ? 0 : fillStylesMap.get(fillStyleCount - lastFillStyleCount + scr.fillStyle1 - 1) + 1; if (morphshape) { fillStyle0 = fillStyle1_new; } else { fillStyle1 = fillStyle1_new; } //fillStyle1 = fillStyle1_new; styleChange = true; } if (scr.stateLineStyle) { /*edgeStyle += " strokeStyle=\""; edgeStyle += lineStyleCount - lastLineStyleCount + scr.lineStyle; edgeStyle += "\"";*/ strokeStyle = scr.lineStyle;// == 0 ? 0 : lineStyleCount - lastLineStyleCount + scr.lineStyle; strokeStyleOrig = scr.lineStyle - 1; styleChange = true; } if (!edges.isEmpty()) { if ((fillStyle0 > 0) || (fillStyle1 > 0) || (strokeStyle > 0)) { //if(true){ boolean empty = false; if ((fillStyle0 <= 0) && (fillStyle1 <= 0) && (strokeStyle > 0) && morphshape) { if (shapeNum == 4) { if (strokeStyleOrig > 0) { if (!actualLinestyles.lineStyles2[strokeStyleOrig].hasFillFlag) { if (actualLinestyles.lineStyles2[strokeStyleOrig].color.alpha == 0) { if (actualLinestyles.lineStyles2[strokeStyleOrig].color.red == 0) { if (actualLinestyles.lineStyles2[strokeStyleOrig].color.green == 0) { if (actualLinestyles.lineStyles2[strokeStyleOrig].color.blue == 0) { empty = true; } } } } } } } } if (!empty) { currentLayer += " -1) { currentLayer += " fillStyle0=\"" + lastFillStyle0 + "\""; } if (fillStyle1 > -1) { currentLayer += " fillStyle1=\"" + lastFillStyle1 + "\""; } if (strokeStyle > -1) { currentLayer += " strokeStyle=\"" + lastStrokeStyle + "\""; } currentLayer += " edges=\"" + convertShapeEdges(startEdgeX, startEdgeY, mat, edges) + "\" />"; } startEdgeX = x; startEdgeY = y; //strokeStyle = -1; //fillStyle0 = -1; //fillStyle1 = -1; } edges.clear(); } } edges.add(edge); x = edge.changeX(x); y = edge.changeY(y); } if (!edges.isEmpty()) { if ((fillStyle0 > 0) || (fillStyle1 > 0) || (strokeStyle > 0)) { boolean empty = false; if ((fillStyle0 <= 0) && (fillStyle1 <= 0) && (strokeStyle > 0) && morphshape) { if (shapeNum == 4) { if (strokeStyleOrig > 0) { if (!actualLinestyles.lineStyles2[strokeStyleOrig].hasFillFlag) { if (actualLinestyles.lineStyles2[strokeStyleOrig].color.alpha == 0) { if (actualLinestyles.lineStyles2[strokeStyleOrig].color.red == 0) { if (actualLinestyles.lineStyles2[strokeStyleOrig].color.green == 0) { if (actualLinestyles.lineStyles2[strokeStyleOrig].color.blue == 0) { empty = true; } } } } } } } } if (!empty) { currentLayer += " -1) { currentLayer += " fillStyle0=\"" + fillStyle0 + "\""; } if (fillStyle1 > -1) { currentLayer += " fillStyle1=\"" + fillStyle1 + "\""; } if (strokeStyle > -1) { currentLayer += " strokeStyle=\"" + strokeStyle + "\""; } currentLayer += " edges=\"" + convertShapeEdges(startEdgeX, startEdgeY, mat, edges) + "\" />"; } } } edges.clear(); fillsStr += ""; strokesStr += ""; currentLayer += ""; currentLayer += ""; currentLayer += ""; currentLayer += ""; currentLayer += ""; currentLayer += ""; layers.add(currentLayer); for (int l = layers.size() - 1; l >= 0; l--) { ret += layers.get(l); } return ret; } private static int getLayerCount(List tags) { int maxDepth = 0; for (Tag t : tags) { if (t instanceof PlaceObjectTypeTag) { int d = ((PlaceObjectTypeTag) t).getDepth(); if (d > maxDepth) { maxDepth = d; } int cd = ((PlaceObjectTypeTag) t).getClipDepth(); if (cd > maxDepth) { maxDepth = cd; } } } return maxDepth; } private static List getOneInstanceShapes(List tags, HashMap characters) { if (true) { //the feature was removed due to multiple layers in some shapes return new ArrayList<>(); } HashMap usages = new HashMap<>(); for (Tag t : tags) { if (t instanceof PlaceObjectTypeTag) { PlaceObjectTypeTag po = (PlaceObjectTypeTag) t; int ch = po.getCharacterId(); if (ch > -1) { if (!usages.containsKey(ch)) { usages.put(ch, 0); } int usageCount = usages.get(ch); if (po.getInstanceName() != null) { usageCount++; } if (po.getColorTransform() != null) { usageCount++; } if (po.getColorTransformWithAlpha() != null) { usageCount++; } if (po.cacheAsBitmap()) { usageCount++; } MATRIX mat = po.getMatrix(); if (mat != null) { if (!mat.isEmpty()) { usageCount++; } } usages.put(ch, usageCount + 1); } } } List ret = new ArrayList<>(); for (int ch : usages.keySet()) { if (usages.get(ch) < 2) { ret.add(ch); } } return ret; } private static HashMap getCharacters(List tags) { HashMap ret = new HashMap<>(); int maxId = 0; for (Tag t : tags) { if (t instanceof CharacterTag) { CharacterTag ct = (CharacterTag) t; if (ct.getCharacterID() > maxId) { maxId = ct.getCharacterID(); } } } for (Tag t : tags) { if (t instanceof SoundStreamHeadTypeTag) { SoundStreamHeadTypeTag ssh = (SoundStreamHeadTypeTag) t; ssh.setVirtualCharacterId(++maxId); } if (t instanceof CharacterTag) { CharacterTag ct = (CharacterTag) t; ret.put(ct.getCharacterID(), ct); } } return ret; } private static final String[] BLENDMODES = { null, null, "layer", "multiply", "screen", "lighten", "darken", "difference", "add", "subtract", "invert", "alpha", "erase", "overlay", "hardligh" }; private static double radToDeg(double rad) { return rad * 180 / Math.PI; } private static String doubleToString(double d) { String ds = "" + d; if (ds.endsWith(".0")) { ds = ds.substring(0, ds.length() - 2); } return ds; } public static String convertFilter(FILTER filter) { String ret = ""; if (filter instanceof DROPSHADOWFILTER) { DROPSHADOWFILTER dsf = (DROPSHADOWFILTER) filter; ret += " filters, boolean isVisible, RGBA backgroundColor, CharacterTag tag, HashMap characters, List tags) { String ret = ""; if (matrix == null) { matrix = new MATRIX(); } if (tag instanceof DefineButtonTag) { DefineButtonTag bt = (DefineButtonTag) tag; for (Tag t : tags) { if (t instanceof DefineButtonCxformTag) { DefineButtonCxformTag bcx = (DefineButtonCxformTag) t; if (bcx.buttonId == bt.buttonId) { colorTransform = bcx.buttonColorTransform; } } } } ret += " 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, "", "", "", "", "", "", null, "", null, null, null, null, "", "", "", "", "", "", "", null, null, null, null, null, null, null, null, null, null, null, null, "" }; 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 += "]]>"; } } ret += ""; return ret; } private static String convertActionScript(ASMSource as) { String decompiledASHilighted = com.jpexs.decompiler.flash.action.Action.actionsToSource(as.getActions(SWF.DEFAULT_VERSION), SWF.DEFAULT_VERSION); return Highlighting.stripHilights(decompiledASHilighted); } private static long getTimestamp() { return new Date().getTime() / 1000; } public static String convertLibrary(SWF swf, Map characterVariables, Map characterClasses, List oneInstanceShapes, String backgroundColor, List tags, HashMap characters, HashMap files) { //TODO: Imported assets //linkageImportForRS="true" linkageIdentifier="xxx" linkageURL="yyy.swf" String ret = ""; List media = new ArrayList<>(); List symbols = new ArrayList<>(); for (int ch : characters.keySet()) { CharacterTag symbol = characters.get(ch); if ((symbol instanceof ShapeTag) && oneInstanceShapes.contains(symbol.getCharacterID())) { continue; //shapes with 1 ocurrence are not added to library } if ((symbol instanceof ShapeTag) || (symbol instanceof DefineSpriteTag) || (symbol instanceof ButtonTag)) { String symbolStr = ""; symbolStr += ""; symbolStr += ""; ButtonTag button = (ButtonTag) symbol; List records = button.getRecords(); String frames[] = {"", "", "", ""}; int maxDepth = 0; for (BUTTONRECORD rec : records) { if (rec.placeDepth > maxDepth) { maxDepth = rec.placeDepth; } } for (int i = maxDepth; i >= 1; i--) { symbolStr += " filters = new ArrayList<>(); if (button instanceof DefineButton2Tag) { colorTransformAlpha = rec.colorTransform; if (rec.buttonHasBlendMode) { blendMode = rec.blendMode; } if (rec.buttonHasFilterList) { filters = rec.filterList; } } CharacterTag character = characters.get(rec.characterId); MATRIX matrix = rec.placeMatrix; String recCharStr = ""; if (character instanceof TextTag) { recCharStr = convertText(tags, (TextTag) character, matrix, filters); } else if (character instanceof DefineVideoStreamTag) { recCharStr = convertVideoInstance(matrix, (DefineVideoStreamTag) character); } else { recCharStr = convertSymbolInstance(null, matrix, null, colorTransformAlpha, false, blendMode, filters, true, null, characters.get(rec.characterId), characters, tags); } int duration = frame - lastFrame; lastFrame = frame; if (duration > 0) { if (duration > 1) { symbolStr += ""; symbolStr += ""; symbolStr += ""; symbolStr += ""; } symbolStr += ""; symbolStr += ""; symbolStr += recCharStr; symbolStr += ""; symbolStr += ""; } } } } symbolStr += ""; symbolStr += ""; } symbolStr += ""; symbolStr += ""; } else if (symbol instanceof DefineSpriteTag) { DefineSpriteTag sprite = (DefineSpriteTag) symbol; if (sprite.subTags.isEmpty()) { //probably AS2 class continue; } symbolStr += convertTimeline(sprite.spriteId, oneInstanceShapes, backgroundColor, tags, sprite.getSubTags(), characters, "Symbol " + symbol.getCharacterID()); } else if (symbol instanceof ShapeTag) { itemIcon = "1"; ShapeTag shape = (ShapeTag) symbol; symbolStr += ""; symbolStr += ""; symbolStr += convertShape(characters, null, shape); symbolStr += ""; symbolStr += ""; } symbolStr += ""; symbolStr += ""; symbolStr = prettyFormatXML(symbolStr); String symbolFile = "Symbol " + symbol.getCharacterID() + ".xml"; try { files.put(symbolFile, symbolStr.getBytes("UTF-8")); } catch (UnsupportedEncodingException ex) { Logger.getLogger(XFLConverter.class.getName()).log(Level.SEVERE, null, ex); } String symbLinkStr = ""; symbLinkStr += ""; //TODO: itemID=\"518de416-00000341\" symbols.add(symbLinkStr); } else if (symbol instanceof ImageTag) { ImageTag imageTag = (ImageTag) symbol; ByteArrayOutputStream baos = new ByteArrayOutputStream(); BufferedImage image = imageTag.getImage(tags); String format = imageTag.getImageFormat(); try { ImageIO.write(image, format.toUpperCase(), baos); } catch (IOException ex) { Logger.getLogger(XFLConverter.class.getName()).log(Level.SEVERE, null, ex); } String symbolFile = "bitmap" + symbol.getCharacterID() + "." + imageTag.getImageFormat(); files.put(symbolFile, baos.toByteArray()); String mediaLinkStr = "\n"; media.add(mediaLinkStr); } else if ((symbol instanceof SoundStreamHeadTypeTag) || (symbol instanceof DefineSoundTag)) { int soundFormat = 0; int soundRate = 0; int soundType = 0; int soundSize = 0; long soundSampleCount = 0; byte soundData[] = new byte[0]; int rateMap[] = {5, 11, 22, 44}; String exportFormat = "flv"; if (symbol instanceof SoundStreamHeadTypeTag) { SoundStreamHeadTypeTag sstream = (SoundStreamHeadTypeTag) symbol; soundFormat = sstream.getSoundFormat(); soundRate = sstream.getSoundRate(); soundType = sstream.getSoundType(); soundSize = sstream.getSoundSize(); soundSampleCount = sstream.getSoundSampleCount(); boolean found = false; for (Tag t : tags) { if (found && (t instanceof SoundStreamBlockTag)) { SoundStreamBlockTag bl = (SoundStreamBlockTag) t; soundData = bl.getData(SWF.DEFAULT_VERSION); break; } if (t == symbol) { found = true; } } } else if (symbol instanceof DefineSoundTag) { DefineSoundTag sound = (DefineSoundTag) symbol; soundFormat = sound.soundFormat; soundRate = sound.soundRate; soundType = sound.soundType; soundData = sound.soundData; soundSize = sound.soundSize; soundSampleCount = sound.soundSampleCount; } int format = 0; int bits = 0; if ((soundFormat == DefineSoundTag.FORMAT_ADPCM) || (soundFormat == DefineSoundTag.FORMAT_UNCOMPRESSED_LITTLE_ENDIAN) || (soundFormat == DefineSoundTag.FORMAT_UNCOMPRESSED_NATIVE_ENDIAN)) { if (soundType == 1) { //stereo format += 1; } switch (soundRate) { case 0: format += 2; break; case 1: format += 6; break; case 2: format += 10; break; case 3: format += 14; break; } } if (soundFormat == DefineSoundTag.FORMAT_SPEEX) { bits = 18; } if (soundFormat == DefineSoundTag.FORMAT_ADPCM) { SWFInputStream sis = new SWFInputStream(new ByteArrayInputStream(soundData), SWF.DEFAULT_VERSION); exportFormat = "wav"; try { int adpcmCodeSize = (int) sis.readUB(2); bits = 2 + adpcmCodeSize; } catch (IOException ex) { Logger.getLogger(XFLConverter.class.getName()).log(Level.SEVERE, null, ex); } } if (soundFormat == DefineSoundTag.FORMAT_MP3) { exportFormat = "mp3"; if (soundType == 0) { //mono format += 1; } format += 4; //quality best SWFInputStream sis = new SWFInputStream(new ByteArrayInputStream(soundData), SWF.DEFAULT_VERSION); try { sis.readSI16(); MP3FRAME frame = new MP3FRAME(sis); int bitRate = frame.getBitrate(); switch (bitRate) { case 8: bits = 6; break; case 16: bits = 7; break; case 20: bits = 8; break; case 24: bits = 9; break; case 32: bits = 10; break; case 48: bits = 11; break; case 56: bits = 12; break; case 64: bits = 13; break; case 80: bits = 14; break; case 112: bits = 15; break; case 128: bits = 16; break; case 160: bits = 17; break; } } catch (IOException ex) { Logger.getLogger(XFLConverter.class.getName()).log(Level.SEVERE, null, ex); } } byte data[] = new byte[0]; try { data = swf.exportSound(symbol); } catch (IOException ex) { Logger.getLogger(XFLConverter.class.getName()).log(Level.SEVERE, null, ex); } if (!exportFormat.equals("flv")) { //FLV import format unsupported String symbolFile = "sound" + symbol.getCharacterID() + "." + exportFormat; files.put(symbolFile, data); String mediaLinkStr = " characters, List tags, SoundStreamHeadTypeTag soundStreamHead, StartSoundTag startSound, int frame, String frameName, boolean isAnchor, int duration, String actionScript, String elements) { String ret = ""; DefineSoundTag sound = null; if (startSound != null) { for (Tag t : tags) { if (t instanceof DefineSoundTag) { DefineSoundTag s = (DefineSoundTag) t; if (s.soundId == startSound.soundId) { sound = s; break; } } } } ret += " 1) { ret += " duration=\"" + duration + "\""; } if (frameName != null) { ret += " name=\"" + frameName + "\""; if (isAnchor) { ret += " labelType=\"anchor\" bookmark=\"true\""; } else { ret += " labelType=\"name\""; } isAnchor = false; frameName = null; } if (shapeTween) { ret += " tweenType=\"shape\" keyMode=\"" + KEY_MODE_SHAPE_TWEEN + "\""; } else { ret += " keyMode=\"" + KEY_MODE_NORMAL + "\""; } String soundEnvelopeStr = ""; if (soundStreamHead != null) { ret += " soundName=\"sound" + soundStreamHead.getCharacterID() + "." + soundStreamHead.getExportFormat() + "\""; ret += " soundSync=\"stream\""; soundEnvelopeStr += ""; soundEnvelopeStr += ""; soundEnvelopeStr += ""; } if (startSound != null && sound != null) { ret += " soundName=\"sound" + sound.soundId + "." + sound.getExportFormat() + "\""; if (startSound.soundInfo.hasInPoint) { ret += " inPoint44=\"" + startSound.soundInfo.inPoint + "\""; } if (startSound.soundInfo.hasOutPoint) { ret += " outPoint44=\"" + startSound.soundInfo.outPoint + "\""; } if (startSound.soundInfo.hasLoops) { if (startSound.soundInfo.loopCount == 32767) { ret += " soundLoopMode=\"loop\""; } ret += " soundLoop=\"" + startSound.soundInfo.loopCount + "\""; } if (startSound.soundInfo.syncStop) { ret += " soundSync=\"stop\""; } else if (startSound.soundInfo.syncNoMultiple) { ret += " soundSync=\"start\""; }; soundEnvelopeStr += ""; if (startSound.soundInfo.hasEnvelope) { for (SOUNDENVELOPE env : startSound.soundInfo.envelopeRecords) { soundEnvelopeStr += ""; } if (startSound.soundInfo.envelopeRecords.length == 1 && startSound.soundInfo.envelopeRecords[0].leftLevel == 32768 && startSound.soundInfo.envelopeRecords[0].pos44 == 0 && startSound.soundInfo.envelopeRecords[0].rightLevel == 0) { ret += " soundEffect=\"left channel\""; } else if (startSound.soundInfo.envelopeRecords.length == 1 && startSound.soundInfo.envelopeRecords[0].leftLevel == 0 && startSound.soundInfo.envelopeRecords[0].pos44 == 0 && startSound.soundInfo.envelopeRecords[0].rightLevel == 32768) { ret += " soundEffect=\"right channel\""; } else if (startSound.soundInfo.envelopeRecords.length == 2 && startSound.soundInfo.envelopeRecords[0].leftLevel == 32768 && startSound.soundInfo.envelopeRecords[0].pos44 == 0 && startSound.soundInfo.envelopeRecords[0].rightLevel == 0 && startSound.soundInfo.envelopeRecords[1].leftLevel == 0 && startSound.soundInfo.envelopeRecords[1].pos44 == sound.soundSampleCount && startSound.soundInfo.envelopeRecords[1].rightLevel == 32768) { ret += " soundEffect=\"fade left to right\""; } else if (startSound.soundInfo.envelopeRecords.length == 2 && startSound.soundInfo.envelopeRecords[0].leftLevel == 0 && startSound.soundInfo.envelopeRecords[0].pos44 == 0 && startSound.soundInfo.envelopeRecords[0].rightLevel == 32768 && startSound.soundInfo.envelopeRecords[1].leftLevel == 32768 && startSound.soundInfo.envelopeRecords[1].pos44 == sound.soundSampleCount && startSound.soundInfo.envelopeRecords[1].rightLevel == 0) { ret += " soundEffect=\"fade right to left\""; } else { ret += " soundEffect=\"custom\""; } //TODO: fade in, fade out } else { soundEnvelopeStr += ""; } soundEnvelopeStr += ""; } ret += ">"; ret += soundEnvelopeStr; if (!actionScript.equals("")) { ret += ""; } ret += ""; ret += elements; ret += ""; ret += ""; return ret; } private static String convertVideoInstance(MATRIX matrix, DefineVideoStreamTag video) { String ret = ""; ret += ""; ret += convertMatrix(matrix); ret += ""; ret += ""; ret += ""; ret += ""; ret += ""; return ret; } private static String convertFrames(String prevStr, String afterStr, List oneInstanceShapes, List tags, List timelineTags, HashMap characters, int depth) { String ret = ""; prevStr += ""; int frame = -1; String elements = ""; String lastElements = ""; int duration = 1; String frameName = null; boolean isAnchor = false; CharacterTag character = null; MATRIX matrix = null; String instanceName = null; CXFORM colorTransForm = null; CXFORMWITHALPHA colorTransFormAlpha = null; boolean cacheAsBitmap = false; int blendMode = 0; List filters = new ArrayList<>(); boolean isVisible = true; RGBA backGroundColor = null; int characterId = -1; int ratio = -1; boolean shapeTween = false; boolean lastShapeTween = false; for (Tag t : timelineTags) { if (t instanceof PlaceObjectTypeTag) { PlaceObjectTypeTag po = (PlaceObjectTypeTag) t; if (po.getDepth() == depth) { int newCharId = po.getCharacterId(); if (newCharId == -1) { newCharId = characterId; } characterId = newCharId; if (characters.containsKey(characterId)) { character = characters.get(characterId); if (po.flagMove()) { MATRIX matrix2 = po.getMatrix(); if (matrix2 != null) { matrix = matrix2; } String instanceName2 = po.getInstanceName(); if (instanceName2 != null) { instanceName = instanceName2; } CXFORM colorTransForm2 = po.getColorTransform(); if (colorTransForm2 != null) { colorTransForm = colorTransForm2; } CXFORMWITHALPHA colorTransFormAlpha2 = po.getColorTransformWithAlpha(); if (colorTransFormAlpha2 != null) { colorTransFormAlpha = colorTransFormAlpha2; } if (po.cacheAsBitmap()) { cacheAsBitmap = true; } int blendMode2 = po.getBlendMode(); if (blendMode2 > 0) { blendMode = blendMode2; } List filters2 = po.getFilters(); if (filters2 != null) { filters = filters2; } int ratio2 = po.getRatio(); if (ratio2 > -1) { ratio = ratio2; } } else { matrix = po.getMatrix(); instanceName = po.getInstanceName(); colorTransForm = po.getColorTransform(); colorTransFormAlpha = po.getColorTransformWithAlpha(); cacheAsBitmap = po.cacheAsBitmap(); blendMode = po.getBlendMode(); filters = po.getFilters(); ratio = po.getRatio(); } } } } if (t instanceof RemoveTag) { RemoveTag rt = (RemoveTag) t; if (rt.getDepth() == depth) { character = null; matrix = null; instanceName = null; colorTransForm = null; colorTransFormAlpha = null; cacheAsBitmap = false; blendMode = 0; filters = new ArrayList<>(); isVisible = true; backGroundColor = null; characterId = -1; } } if (t instanceof FrameLabelTag) { FrameLabelTag flt = (FrameLabelTag) t; frameName = flt.getLabelName(); isAnchor = flt.isNamedAnchor(); } if (t instanceof ShowFrameTag) { elements = ""; if ((character instanceof ShapeTag) && oneInstanceShapes.contains(characterId)) { elements += convertShape(characters, matrix, (ShapeTag) character); shapeTween = false; } else if (character != null) { if (character instanceof MorphShapeTag) { MorphShapeTag m = (MorphShapeTag) character; if (ratio == 65535) { elements += convertShape(characters, matrix, 3, m.getEndEdges().shapeRecords, m.getFillStyles().getEndFillStyles(), m.getLineStyles().getEndLineStyles(m.getShapeNum()), true); shapeTween = false; } else { elements += convertShape(characters, matrix, 3, m.getStartEdges().shapeRecords, m.getFillStyles().getStartFillStyles(), m.getLineStyles().getStartLineStyles(m.getShapeNum()), true); shapeTween = true; } } else { shapeTween = false; if (character instanceof TextTag) { elements += convertText(tags, (TextTag) character, matrix, filters); } else if (character instanceof DefineVideoStreamTag) { elements += convertVideoInstance(matrix, (DefineVideoStreamTag) character); } else { elements += convertSymbolInstance(instanceName, matrix, colorTransForm, colorTransFormAlpha, cacheAsBitmap, blendMode, filters, isVisible, backGroundColor, character, characters, tags); } } } frame++; if (!elements.equals(lastElements) && frame > 0) { ret += convertFrame(lastShapeTween, characters, tags, null, null, frame - duration, frameName, isAnchor, duration, "", lastElements); duration = 1; } else if (frame == 0) { duration = 1; } else { duration++; } lastShapeTween = shapeTween; lastElements = elements; frameName = null; isAnchor = false; } } if (!lastElements.equals("")) { ret += convertFrame(lastShapeTween, characters, tags, null, null, (frame < 0 ? 0 : frame) - duration, frameName, isAnchor, duration, "", lastElements); } afterStr = "" + afterStr; if (!ret.equals("")) { ret = prevStr + ret + afterStr; } return ret; } public static String convertActionScriptLayer(int layerIndex, int spriteId, List tags, List timeLineTags, String backgroundColor) { String ret = ""; String script = ""; int duration = 0; int frame = 0; for (Tag t : tags) { if (t instanceof DoInitActionTag) { DoInitActionTag dia = (DoInitActionTag) t; if (dia.spriteId == spriteId) { script += convertActionScript(dia); } } } if (!script.equals("")) { script = "#initclip\r\n" + script + "#endinitclip\r\n"; } for (Tag t : timeLineTags) { if (t instanceof DoActionTag) { DoActionTag da = (DoActionTag) t; script += convertActionScript(da); } if (t instanceof ShowFrameTag) { if (script.equals("")) { duration++; } else { if (duration > 0) { ret += " 1) { ret += " duration=\"" + duration + "\""; } ret += " keyMode=\"" + KEY_MODE_NORMAL + "\">"; ret += ""; ret += ""; ret += ""; } ret += ""; ret += ""; ret += ""; ret += ""; ret += ""; script = ""; duration = 0; } frame++; } } if (!ret.equals("")) { ret = "" + "" + ret + "" + ""; } return ret; } public static String convertSoundLayer(int layerIndex, String backgroundColor, HashMap characters, List tags, List timeLineTags) { String ret = ""; StartSoundTag lastStartSound = null; SoundStreamHeadTypeTag lastSoundStreamHead = null; StartSoundTag startSound = null; SoundStreamHeadTypeTag soundStreamHead = null; int duration = 1; int frame = 0; for (Tag t : timeLineTags) { if (t instanceof StartSoundTag) { startSound = (StartSoundTag) t; } if (t instanceof SoundStreamHeadTypeTag) { soundStreamHead = (SoundStreamHeadTypeTag) t; } if (t instanceof ShowFrameTag) { if (soundStreamHead != null || startSound != null) { if (lastSoundStreamHead != null || lastStartSound != null) { ret += convertFrame(false, characters, tags, lastSoundStreamHead, lastStartSound, frame, null, false, duration, "", ""); } frame += duration; duration = 1; lastSoundStreamHead = soundStreamHead; lastStartSound = startSound; soundStreamHead = null; startSound = null; } else { duration++; } } } if (lastSoundStreamHead != null || lastStartSound != null) { if (frame < 0) { frame = 0; duration = 1; } ret += convertFrame(false, characters, tags, lastSoundStreamHead, lastStartSound, frame, null, false, duration, "", ""); } if (!ret.equals("")) { ret = "" + "" + ret + "" + ""; } return ret; } public static String convertTimeline(int spriteId, List oneInstanceShapes, String backgroundColor, List tags, List timelineTags, HashMap characters, String name) { String ret = ""; ret += ""; ret += ""; int layerCount = getLayerCount(timelineTags); Stack parentLayers = new Stack<>(); int index = 0; for (int d = layerCount; d >= 1; d--, index++) { for (Tag t : timelineTags) { if (t instanceof PlaceObjectTypeTag) { PlaceObjectTypeTag po = (PlaceObjectTypeTag) t; if (po.getClipDepth() == d) { for (int m = po.getDepth(); m < po.getClipDepth(); m++) { parentLayers.push(index); } ret += " getCharacterClasses(List tags) { Map ret = new HashMap<>(); for (Tag t : tags) { if (t instanceof SymbolClassTag) { SymbolClassTag sc = (SymbolClassTag) t; for (int i = 0; i < sc.tagIDs.length; i++) { if (!ret.containsKey(sc.tagIDs[i]) && !ret.containsValue(sc.classNames[i])) { ret.put(sc.tagIDs[i], sc.classNames[i]); } } } } return ret; } private static Map getCharacterVariables(List tags) { Map ret = new HashMap<>(); for (Tag t : tags) { if (t instanceof ExportAssetsTag) { ExportAssetsTag ea = (ExportAssetsTag) t; for (int i = 0; i < ea.tags.size(); i++) { if (!ret.containsKey(ea.tags.get(i))) { ret.put(ea.tags.get(i), ea.names.get(i)); } } } } return ret; } public static String convertText(List tags, TextTag tag, MATRIX matrix, List filters) { String ret = ""; if (matrix == null) { matrix = new MATRIX(); } CSMTextSettingsTag csmts = null; String filterStr = ""; if (filters != null) { filterStr += ""; for (FILTER f : filters) { filterStr += convertFilter(f); } filterStr += ""; } for (Tag t : tags) { if (t instanceof CSMTextSettingsTag) { CSMTextSettingsTag c = (CSMTextSettingsTag) t; if (c.textID == tag.getCharacterID()) { csmts = c; break; } } } String fontRenderingMode = "standard"; String antiAlias = ""; if (csmts != null) { if (csmts.thickness == 0 & csmts.sharpness == 0) { fontRenderingMode = null; } else { fontRenderingMode = "customThicknessSharpness"; } antiAlias = " antiAliasSharpness=\"" + doubleToString(csmts.sharpness) + "\" antiAliasThickness=\"" + doubleToString(csmts.thickness) + "\""; } String matStr = ""; matStr += ""; RECT bounds = tag.getBounds(); matrix.translateX += bounds.Xmin + 40/*??*/; matrix.translateY += bounds.Ymin + 40/*??*/; matStr += convertMatrix(matrix); matStr += ""; if ((tag instanceof DefineTextTag) || (tag instanceof DefineText2Tag)) { List textRecords = new ArrayList<>(); if (tag instanceof DefineTextTag) { textRecords = ((DefineTextTag) tag).textRecords; } else if (tag instanceof DefineText2Tag) { textRecords = ((DefineText2Tag) tag).textRecords; } looprec: for (TEXTRECORD rec : textRecords) { if (rec.styleFlagsHasFont) { for (Tag t : tags) { if (t instanceof FontTag) { FontTag ft = (FontTag) t; if (ft.getFontId() == rec.fontId) { if (ft.isSmall()) { fontRenderingMode = "bitmap"; break looprec; } } } } } } ret += ""; ret += matStr; ret += ""; int fontId = -1; FontTag font = null; String fontName = null; String psFontName = null; String availableFonts[] = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames(); int textHeight = -1; RGB textColor = null; RGBA textColorA = null; for (TEXTRECORD rec : textRecords) { if (rec.styleFlagsHasColor) { if (tag instanceof DefineTextTag) { textColor = rec.textColor; } else { textColorA = rec.textColorA; } } if (rec.styleFlagsHasFont) { fontId = rec.fontId; fontName = null; textHeight = rec.textHeight; font = null; for (Tag t : tags) { if (t instanceof FontTag) { if (((FontTag) t).getFontId() == fontId) { font = (FontTag) t; } } if (t instanceof DefineFontNameTag) { if (((DefineFontNameTag) t).fontId == fontId) { fontName = ((DefineFontNameTag) t).fontName; } } } if ((fontName == null) && (font != null)) { fontName = font.getFontName(tags); } psFontName = fontName; if (fontName != null) { for (String avFont : availableFonts) { if (avFont.equals(fontName)) { Font f = new Font(fontName, 0, 10); psFontName = f.getPSName(); } } } } if (font != null) { ret += ""; ret += "" + xmlString(rec.getText(tags, font)) + ""; ret += ""; ret += ""; int leftMargin = -1; int rightMargin = -1; int indent = -1; int lineSpacing = -1; String alignment = null; boolean italic = false; boolean bold = false; String fontFace = null; int size = -1; if (det.hasFont) { String fontName = null; FontTag ft = null; for (Tag u : tags) { if (u instanceof DefineFontNameTag) { if (((DefineFontNameTag) u).fontId == det.fontId) { fontName = ((DefineFontNameTag) u).fontName; } } if (u instanceof FontTag) { if (((FontTag) u).getFontId() == det.fontId) { ft = (FontTag) u; } } if (fontName != null && ft != null) { break; } } if (ft != null) { if (fontName == null) { fontName = ft.getFontName(tags); } italic = ft.isItalic(); bold = ft.isBold(); size = det.fontHeight; fontFace = new Font(fontName, (italic ? Font.ITALIC : 0) | (bold ? Font.BOLD : 0) | (!italic && !bold ? Font.PLAIN : 0), size < 0 ? 10 : size).getPSName(); } } if (det.hasLayout) { leftMargin = det.leftMargin; rightMargin = det.rightMargin; indent = det.indent; lineSpacing = det.leading; String alignNames[] = {"left", "right", "center", "justify"}; alignment = alignNames[det.align]; } ret += ""; ret += " -1) { ret += " indent=\"" + twipToPixel(indent) + "\""; } if (leftMargin > -1) { ret += " leftMargin=\"" + twipToPixel(leftMargin) + "\""; } if (lineSpacing > -1) { ret += " lineSpacing=\"" + twipToPixel(lineSpacing) + "\""; } if (rightMargin > -1) { ret += " rightMargin=\"" + twipToPixel(rightMargin) + "\""; } if (size > -1) { ret += " size=\"" + size + "\""; ret += " bitmapSize=\"" + (size * 20) + "\""; } if (fontFace != null) { ret += " face=\"" + fontFace + "\""; } ret += "/>"; ret += ""; ret += ""; } } ret += ""; ret += filterStr; ret += ""; } return ret; } public static void convertSWF(SWF swf, String swfFileName, String outfile, boolean compressed, String generator, String generatorVerName, String generatorVersion, boolean paralel) { File file = new File(outfile); File outDir = file.getParentFile(); String domDocument = ""; String baseName = swfFileName; File f = new File(baseName); baseName = f.getName(); if (baseName.contains(".")) { baseName = baseName.substring(0, baseName.lastIndexOf(".")); } HashMap files = new HashMap<>(); HashMap characters = getCharacters(swf.tags); List oneInstaceShapes = getOneInstanceShapes(swf.tags, characters); Map characterClasses = getCharacterClasses(swf.tags); Map characterVariables = getCharacterVariables(swf.tags); FileAttributesTag fa = null; for (Tag t : swf.tags) { if (t instanceof FileAttributesTag) { fa = (FileAttributesTag) t; } } boolean useAS3 = false; boolean useNetwork = false; if (fa != null) { useAS3 = fa.actionScript3; useNetwork = fa.useNetwork; } String backgroundColor = "#ffffff"; for (Tag t : swf.tags) { if (t instanceof SetBackgroundColorTag) { SetBackgroundColorTag sbc = (SetBackgroundColorTag) t; backgroundColor = sbc.backgroundColor.toHexRGB(); } } domDocument += "\n" + " \n" + " 1\n" + " 1\n" + " 0\n" + " 0\n" + " 1\n" + " 0\n" + " 0\n" + " 0\n" + " 0\n" + " 0\n" + " 0\n" + " 1\n" + " 1\n" + " 1\n" + " 1\n" + " 1\n" + " 1\n" + " 1\n" + " 1\n" + " 1\n" + " 1\n" + " " + baseName + ".swf\n" + " " + baseName + ".exe\n" + " " + baseName + ".app\n" + " " + baseName + ".html\n" + " " + baseName + ".gif\n" + " " + baseName + ".jpg\n" + " " + baseName + ".png\n" + " " + baseName + ".mov\n" + " " + baseName + ".smil\n" + " Untitled-4.swc\n" + " \n" + " \n" + " 0\n" + " 12,0,0,0;11,2,0,0;11,1,0,0;10,3,0,0;10,2,153,0;10,1,52,0;9,0,124,0;8,0,24,0;7,0,14,0;6,0,79,0;5,0,58,0;4,0,32,0;3,0,8,0;2,0,1,12;1,0,0,1;\n" + " 1\n" + " 1\n" + " " + baseName + "_content.html\n" + " " + baseName + "_alternate.html\n" + " 0\n" + " \n" + " " + twipToPixel(swf.displayRect.getWidth()) + "\n" + " " + twipToPixel(swf.displayRect.getHeight()) + "\n" + " 0\n" + " 0\n" + " 1\n" + " 0\n" + " 0\n" + " 1\n" + " 1\n" + " 4\n" + " 0\n" + " 0\n" + " 1\n" + " 0\n" + " \n" + " 1\n" + " \n" + " \n" + " \n" + " \n" + " 0\n" + " 0\n" + " 0\n" + " 80\n" + " 0\n" + " 0\n" + " 7\n" + " 0\n" + " 7\n" + " 0\n" + " 15\n" + " FlashPlayer11.2\n" + " " + (useAS3 ? "3" : "2") + "\n" + " 1\n" + " \n" + " .\n" + " CONFIG::FLASH_AUTHORING="true";\n" + " 0\n" + " \n" + " " + (swf.compressed ? "1" : "0") + "\n" + " " + (swf.lzma ? "1" : "0") + "\n" + " 1\n" + " 0\n" + " 0\n" + " 0\n" + " " + (useNetwork ? 1 : 0) + "\n" + " " + xmlString(characterClasses.containsKey(0) ? characterClasses.get(0) : "") + "\n" + " 2\n" + " 4\n" + " 4096\n" + " AS3\n" + " 1\n" + " 1\n" + " 0\n" + " 15\n" + " 1\n" + " 0\n" + " 4102\n" + " rsl\n" + " wrap\n" + " $(AppConfig)/ActionScript 3.0/rsls/loader_animation.swf\n" + " \n" + " \n" + " $(AppConfig)/ActionScript 3.0/libs\n" + " merge\n" + " \n" + " \n" + " $(AppConfig)/ActionScript 3.0/libs/11.0/textLayout.swc\n" + " rsl\n" + " http://fpdownload.adobe.com/pub/swz/tlf/2.0.0.232/textLayout_2.0.0.232.swz\n" + " http://fpdownload.adobe.com/pub/swz/crossdomain.xml\n" + " textLayout_2.0.0.232.swz\n" + " \n" + " \n" + " \n" + " \n" + " $(AppConfig)/ActionScript 3.0/libs/11.0/textLayout.swc\n" + " \n" + " http://fpdownload.adobe.com/pub/swz/tlf/2.0.0.232/textLayout_2.0.0.232.swz\n" + " http://fpdownload.adobe.com/pub/swz/crossdomain.xml\n" + " textLayout_2.0.0.232.swz\n" + " \n" + " \n" + " \n" + " \n" + " " + twipToPixel(swf.displayRect.getWidth()) + "\n" + " " + twipToPixel(swf.displayRect.getHeight()) + "\n" + " 0\n" + " 4718592\n" + " 0\n" + " 80\n" + " 1\n" + " \n" + " \n" + " 1\n" + " 0\n" + " 1\n" + " 0\n" + " 0\n" + " 100000\n" + " 1\n" + " 1\n" + " 0\n" + " 0\n" + " 0\n" + " 0\n" + " 0\n" + " 0\n" + " 1\n" + " \n" + " \n" + " " + twipToPixel(swf.displayRect.getWidth()) + "\n" + " " + twipToPixel(swf.displayRect.getHeight()) + "\n" + " 0\n" + " 1\n" + " 1\n" + " \n" + " 1\n" + " 0\n" + " 1\n" + " 0\n" + " 0\n" + " \n" + " 128\n" + " \n" + " \n" + " 255\n" + " \n" + " \n" + " \n" + " " + twipToPixel(swf.displayRect.getWidth()) + "\n" + " " + twipToPixel(swf.displayRect.getHeight()) + "\n" + " 1\n" + " 0\n" + " 0\n" + " 1\n" + " 0\n" + " 0\n" + " 1\n" + " \n" + " \n" + " \n" + " 24-bit with Alpha\n" + " 255\n" + " \n" + " \n" + " \n" + " " + twipToPixel(swf.displayRect.getWidth()) + "\n" + " " + twipToPixel(swf.displayRect.getHeight()) + "\n" + " 1\n" + " 0\n" + " \n" + " \n" + " 00000000\n" + " 0\n" + " 0\n" + " 0\n" + " 0\n" + " 1\n" + " \n" + "\n" + ""; if (compressed) { try (ZipOutputStream out = new ZipOutputStream(new FileOutputStream(outfile))) { out.putNextEntry(new ZipEntry("DOMDocument.xml")); out.write(domDocument.getBytes("UTF-8")); out.putNextEntry(new ZipEntry("PublishSettings.xml")); out.write(publishSettings.getBytes("UTF-8")); for (String fileName : files.keySet()) { out.putNextEntry(new ZipEntry("LIBRARY/" + fileName)); out.write(files.get(fileName)); } } catch (IOException ex) { Logger.getLogger(XFLConverter.class.getName()).log(Level.SEVERE, null, ex); } } else { outDir.mkdirs(); try { writeFile(domDocument.getBytes("UTF-8"), outDir.getAbsolutePath() + File.separator + "DOMDocument.xml"); } catch (UnsupportedEncodingException ex) { Logger.getLogger(XFLConverter.class.getName()).log(Level.SEVERE, null, ex); } try { writeFile(publishSettings.getBytes("UTF-8"), outDir.getAbsolutePath() + File.separator + "PublishSettings.xml"); } catch (UnsupportedEncodingException ex) { Logger.getLogger(XFLConverter.class.getName()).log(Level.SEVERE, null, ex); } File libraryDir = new File(outDir.getAbsolutePath() + File.separator + "LIBRARY"); libraryDir.mkdir(); for (String fileName : files.keySet()) { writeFile(files.get(fileName), libraryDir.getAbsolutePath() + File.separator + fileName); } try { writeFile("PROXY-CS5".getBytes("utf-8"), outfile); } catch (UnsupportedEncodingException ex) { Logger.getLogger(XFLConverter.class.getName()).log(Level.SEVERE, null, ex); } } if (useAS3) { try { swf.exportActionScript(outDir.getAbsolutePath(), false, paralel); } catch (Exception ex) { Logger.getLogger(XFLConverter.class.getName()).log(Level.SEVERE, "Error during ActionScript3 export", ex); } } } private static int normHue(double h) { if (Double.isNaN(h)) { h = -Math.PI; } int ret = (int) Math.round(h * 180 / Math.PI); while (ret > 180) { ret -= 360; } while (ret < -180) { ret += 360; } return ret; } private static int normBrightness(double b) { if (Double.isNaN(b)) { b = -100; } return (int) Math.round(b); } private static int normSaturation(double s) { if (Double.isNaN(s)) { return -100; } else if (s == 1) { return 0; } else if (s - 1 < 0) { return (int) Math.round((s - 1) * 100); } else { return (int) Math.round(((s - 1) * 100) / 3); } } private static int normContrast(double c) { double ctrMap[] = { // 0 1 2 3 4 5 6 7 8 9 /*0*/0, 0.01, 0.02, 0.04, 0.05, 0.06, 0.07, 0.08, 0.1, 0.11, /*1*/ 0.12, 0.14, 0.15, 0.16, 0.17, 0.18, 0.20, 0.21, 0.22, 0.24, /*2*/ 0.25, 0.27, 0.28, 0.30, 0.32, 0.34, 0.36, 0.38, 0.40, 0.42, /*3*/ 0.44, 0.46, 0.48, 0.5, 0.53, 0.56, 0.59, 0.62, 0.65, 0.68, /*4*/ 0.71, 0.74, 0.77, 0.80, 0.83, 0.86, 0.89, 0.92, 0.95, 0.98, /*5*/ 1.0, 1.06, 1.12, 1.18, 1.24, 1.30, 1.36, 1.42, 1.48, 1.54, /*6*/ 1.60, 1.66, 1.72, 1.78, 1.84, 1.90, 1.96, 2.0, 2.12, 2.25, /*7*/ 2.37, 2.50, 2.62, 2.75, 2.87, 3.0, 3.2, 3.4, 3.6, 3.8, /*8*/ 4.0, 4.3, 4.7, 4.9, 5.0, 5.5, 6.0, 6.5, 6.8, 7.0, /*9*/ 7.3, 7.5, 7.8, 8.0, 8.4, 8.7, 9.0, 9.4, 9.6, 9.8, /*10*/ 10.0}; if (c == 127) { return 0; } else if (c - 127 < 0) { return (int) Math.round((c - 127) * 100.0 / 127.0); } else { c = (c - 127) / 127; for (int i = 0; i < ctrMap.length; i++) { if (ctrMap[i] >= c) { return i; } } } return ctrMap.length - 1; } private static boolean sameDouble(double a, double b) { final double EPSILON = 0.00001; return a == b ? true : Math.abs(a - b) < EPSILON; } public static String convertAdjustColorFilter(COLORMATRIXFILTER filter) { float matrix[][] = new float[5][5]; int index = 0; for (int i = 0; i < 4; i++) { for (int j = 0; j < 5; j++) { matrix[j][i] = filter.matrix[index]; index++; } } double a11 = matrix[0][0], a12 = matrix[0][1], a13 = matrix[0][2], a21 = matrix[1][0], a22 = matrix[1][1], a23 = matrix[1][2], a31 = matrix[2][0], a32 = matrix[2][1], a33 = matrix[2][2], a41 = matrix[4][0]; double b, c, h, s; b = (24872168661075.0 * a11 * a11 - 151430415740925.0 * a12 + 341095051289483.0 * a12 * a12 - 15302094789450.0 * a13 + 82428663495404.0 * a12 * a13 - 4592294873812.0 * a13 * a13 + 43556251470.0 * Math.sqrt(216225 * a11 * a11 + 332369 * a12 * a12 - 397828 * a12 * a13 + 281684 * a13 * a13 - 930 * a11 * (287 * a12 + 178 * a13)) + 2384730956550.0 * a12 * a41 + 240977870700.0 * a13 * a41 - 685925220 * Math.sqrt(216225 * a11 * a11 + 332369 * a12 * a12 - 397828 * a12 * a13 + 281684 * a13 * a13 - 930 * a11 * (287 * a12 + 178 * a13)) * a41 + 465 * a11 * (466201717582.0 * a12 + 55756962908.0 * a13 + 764132175 * (-127 + 2 * a41))) / (391687695450.0 * a11 * a11 + 5371575610858.0 * a12 * a12 + 1298089188904.0 * a12 * a13 - 72319604312.0 * a13 * a13 + 1860 * a11 * (1835439833 * a12 + 219515602 * a13)); c = (127 * (495225 * a11 + 1661845 * a12 + 167930 * a13 + 478 * Math.sqrt(216225 * a11 * a11 + 332369 * a12 * a12 - 397828 * a12 * a13 + 281684 * a13 * a13 - 930 * a11 * (287 * a12 + 178 * a13)))) / 717495; h = 2 * (Math.atan((-465 * a11 + 287 * a12 + 178 * a13 + Math.sqrt(216225 * a11 * a11 + 332369 * a12 * a12 - 397828 * a12 * a13 + 281684 * a13 * a13 - 930 * a11 * (287 * a12 + 178 * a13))) / (500. * (a12 - a13))) + Math.PI/*+ Pi*C(1)*/); s = (1543 * (-103355550 * a11 * a11 - 158872382 * a12 * a12 + 190161784 * a12 * a13 - 134644952 * a13 * a13 + 1661845 * a12 * Math.sqrt(216225 * a11 * a11 + 332369 * a12 * a12 - 397828 * a12 * a13 + 281684 * a13 * a13 - 930 * a11 * (287 * a12 + 178 * a13)) + 167930 * a13 * Math.sqrt(216225 * a11 * a11 + 332369 * a12 * a12 - 397828 * a12 * a13 + 281684 * a13 * a13 - 930 * a11 * (287 * a12 + 178 * a13)) + 465 * a11 * (274372 * a12 + 170168 * a13 + 1065 * Math.sqrt(216225 * a11 * a11 + 332369 * a12 * a12 - 397828 * a12 * a13 + 281684 * a13 * a13 - 930 * a11 * (287 * a12 + 178 * a13))))) / (195843847725.0 * a11 * a11 + 2685787805429.0 * a12 * a12 + 649044594452.0 * a12 * a13 - 36159802156.0 * a13 * a13 + 930 * a11 * (1835439833 * a12 + 219515602 * a13)); if (sameDouble(410 * a12, 1543 * a31) && sameDouble(410 * a12, 1543 * a32) && sameDouble(3047 * a12, 1543 * a21) && sameDouble(3047 * a12, 1543 * a23) && sameDouble(a22, a11 + (1504 * a12) / 1543.) && sameDouble((1133 * a12) / 1543. + a33, a11) /*&& (b == (195961 * a11 + 439039 * a12 + 1543 * (-127 + 2 * a41)) / (3086 * a11 + 6914 * a12)) && (c == 127 * a11 + (439039 * a12) / 1543.) && (s == (1543 * (a11 - a12)) / (1543 * a11 + 3457 * a12)) */ && !sameDouble(a11, a12) && !sameDouble(1543 * a11 + 3457 * a12, 0)) { h = 0; } return ""; } private static String convertHTMLText(List tags, DefineEditTextTag det, String html) { HTMLTextParser tparser = new HTMLTextParser(tags, det); XMLReader parser; try { SAXParserFactory factory = SAXParserFactory.newInstance(); //factory.setValidating(false); parser = XMLReaderFactory.createXMLReader(); parser.setContentHandler(tparser); parser.setErrorHandler(tparser); //parser.setFeature("http://xml.org/sax/features/validation", false); html = "\n" + " \n" + "]>" + html + ""; try { parser.parse(new InputSource(new InputStreamReader(new ByteArrayInputStream(html.getBytes("UTF-8")), "UTF-8"))); } catch (SAXParseException spe) { System.out.println(html); System.err.println(tparser.result); } //XMLReader reader = parser.getXMLReader(); /*reader.setContentHandler(tparser); reader.setErrorHandler(tparser); reader.setEntityResolver(tparser); html = "" + html + ""; reader.parse(new InputSource(new InputStreamReader(new ByteArrayInputStream(html.getBytes("UTF-8")), "UTF-8")));*/ } catch (Exception e) { Logger.getLogger(XFLConverter.class.getName()).log(Level.SEVERE, "Error while converting HTML", e); } return tparser.result; } private static String xmlString(String s) { return s.replace("<", "<").replace(">", ">").replace("\"", """).replace("&", "&").replace("\r\n", " ").replace("\r", " ").replace("\n", " "); } private static double twipToPixel(double tw) { return tw / 20.0; } private static class HTMLTextParser extends DefaultHandler { public String result = ""; private String fontFace = ""; private String color = ""; private int size = -1; private int indent = -1; private int leftMargin = -1; private int rightMargin = -1; private int lineSpacing = -1; private double letterSpacing = -1; private String alignment = null; private List tags; private boolean bold = false; private boolean italic = false; private boolean underline = false; private boolean li = false; private String url = null; private String target = null; @Override public void error(SAXParseException e) throws SAXException { } @Override public void fatalError(SAXParseException e) throws SAXException { } @Override public void warning(SAXParseException e) throws SAXException { } public HTMLTextParser(List tags, DefineEditTextTag det) { if (det.hasFont) { String fontName = null; FontTag ft = null; for (Tag u : tags) { if (u instanceof DefineFontNameTag) { if (((DefineFontNameTag) u).fontId == det.fontId) { fontName = ((DefineFontNameTag) u).fontName; } } if (u instanceof FontTag) { if (((FontTag) u).getFontId() == det.fontId) { ft = (FontTag) u; } } if (fontName != null && ft != null) { break; } } if (ft != null) { if (fontName == null) { fontName = ft.getFontName(tags); } italic = ft.isItalic(); bold = ft.isBold(); size = det.fontHeight; fontFace = new Font(fontName, (italic ? Font.ITALIC : 0) | (bold ? Font.BOLD : 0) | (!italic && !bold ? Font.PLAIN : 0), size < 0 ? 10 : size).getPSName(); } } if (det.hasLayout) { leftMargin = det.leftMargin; rightMargin = det.rightMargin; indent = det.indent; lineSpacing = det.leading; String alignNames[] = {"left", "right", "center", "justify"}; alignment = alignNames[det.align]; } this.tags = tags; } @Override public void startDocument() throws SAXException { } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if (qName.equals("a")) { String href = attributes.getValue("href"); if (href != null) { url = href; } String t = attributes.getValue("target"); if (t != null) { target = t; } } else if (qName.equals("b")) { bold = true; } else if (qName.equals("i")) { italic = true; } else if (qName.equals("u")) { underline = true; } else if (qName.equals("li")) { li = true; } else if (qName.equals("p")) { String a = attributes.getValue("align"); if (a != null) { alignment = a; } if (!result.equals("")) { putText("\r\n"); } } else if (qName.equals("font")) { //kerning ? String ls = attributes.getValue("letterSpacing"); if (ls != null) { letterSpacing = Double.parseDouble(ls); } String s = attributes.getValue("size"); if (s != null) { size = Integer.parseInt(s); } String c = attributes.getValue("color"); if (c != null) { color = c; } String f = attributes.getValue("face"); if (f != null) { for (Tag t : tags) { if (t instanceof FontTag) { FontTag ft = (FontTag) t; String fontName = ""; if (f.equals(ft.getFontName(tags))) { for (Tag u : tags) { if (u instanceof DefineFontNameTag) { if (((DefineFontNameTag) u).fontId == ft.getFontId()) { fontName = ((DefineFontNameTag) u).fontName; } } } if (fontName == null) { fontName = ft.getFontName(tags); } fontFace = new Font(fontName, (italic ? Font.ITALIC : 0) | (bold ? Font.BOLD : 0) | (!italic && !bold ? Font.PLAIN : 0), size < 0 ? 10 : size).getPSName(); break; } } } } } //textformat,tab,br } @Override public void endElement(String uri, String localName, String qName) throws SAXException { if (qName.equals("a")) { url = null; target = null; } if (qName.equals("b")) { bold = false; } if (qName.equals("i")) { italic = false; } if (qName.equals("u")) { underline = false; } if (qName.equals("li")) { li = false; } } private void putText(String txt) { result += ""; result += "" + xmlString(txt) + ""; result += ""; result += " -1) { result += " indent=\"" + twipToPixel(indent) + "\""; } if (leftMargin > -1) { result += " leftMargin=\"" + twipToPixel(leftMargin) + "\""; } if (letterSpacing > -1) { result += " letterSpacing=\"" + letterSpacing + "\""; } if (lineSpacing > -1) { result += " lineSpacing=\"" + twipToPixel(lineSpacing) + "\""; } if (rightMargin > -1) { result += " rightMargin=\"" + twipToPixel(rightMargin) + "\""; } if (size > -1) { result += " size=\"" + size + "\""; result += " bitmapSize=\"" + (size * 20) + "\""; } if (fontFace != null) { result += " face=\"" + fontFace + "\""; } if (color != null) { result += " fillColor=\"" + color + "\""; } if (url != null) { result += " url=\"" + url + "\""; } if (target != null) { result += " target=\"" + target + "\""; } result += "/>"; result += ""; result += ""; } @Override public void characters(char[] ch, int start, int length) throws SAXException { putText(new String(ch, start, length)); } @Override public void endDocument() { } } }