diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d37b0a7f..fa318b2cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ All notable changes to this project will be documented in this file. - [#2100] Copy/paste frames (same SWF only) - Updated portugese-brasil translation - AS3 Debugging - export/import ByteArray variable data +- [#2123] FLA export - show some progress info (which symbols are exported) ### Fixed - [#2021], [#2000] Caret position in editors when using tabs and / or unicode @@ -19,7 +20,10 @@ All notable changes to this project will be documented in this file. - AS3 direct editation - namespaces were initialized in class initializers - Debugging - do not invoke getter when there is none - avoid freezing - Debugging - properly getting variable value through getter +- [#2123] FLA export - IndexOutOfBounds in shape fixer +### Removed +- [#2123] FLA export - Using shape fixer for morphshapes (needs something better) ## [20.0.0] - 2023-11-05 ### Added @@ -3268,6 +3272,7 @@ Major version of SWF to XML export changed to 2. [alpha 8]: https://github.com/jindrapetrik/jpexs-decompiler/compare/alpha7...alpha8 [alpha 7]: https://github.com/jindrapetrik/jpexs-decompiler/releases/tag/alpha7 [#2100]: https://www.free-decompiler.com/flash/issues/2100 +[#2123]: https://www.free-decompiler.com/flash/issues/2123 [#2021]: https://www.free-decompiler.com/flash/issues/2021 [#2000]: https://www.free-decompiler.com/flash/issues/2000 [#2116]: https://www.free-decompiler.com/flash/issues/2116 diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java index 649ea0893..1dc302227 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java @@ -3152,20 +3152,20 @@ public final class SWF implements SWFContainerItem, Timelined, Openable { return deobfuscation; } - public void exportFla(AbortRetryIgnoreHandler handler, String outfile, String swfName, String generator, String generatorVerName, String generatorVersion, boolean parallel, FLAVersion version) throws IOException, InterruptedException { + public void exportFla(AbortRetryIgnoreHandler handler, String outfile, String swfName, String generator, String generatorVerName, String generatorVersion, boolean parallel, FLAVersion version, ProgressListener progressListener) throws IOException, InterruptedException { XFLExportSettings settings = new XFLExportSettings(); settings.compressed = true; - exportXfl(handler, outfile, swfName, generator, generatorVerName, generatorVersion, parallel, version, settings); + exportXfl(handler, outfile, swfName, generator, generatorVerName, generatorVersion, parallel, version, settings, progressListener); } - public void exportXfl(AbortRetryIgnoreHandler handler, String outfile, String swfName, String generator, String generatorVerName, String generatorVersion, boolean parallel, FLAVersion version) throws IOException, InterruptedException { + public void exportXfl(AbortRetryIgnoreHandler handler, String outfile, String swfName, String generator, String generatorVerName, String generatorVersion, boolean parallel, FLAVersion version, ProgressListener progressListener) throws IOException, InterruptedException { XFLExportSettings settings = new XFLExportSettings(); settings.compressed = false; - exportXfl(handler, outfile, swfName, generator, generatorVerName, generatorVersion, parallel, version, settings); + exportXfl(handler, outfile, swfName, generator, generatorVerName, generatorVersion, parallel, version, settings, progressListener); } - public void exportXfl(AbortRetryIgnoreHandler handler, String outfile, String swfName, String generator, String generatorVerName, String generatorVersion, boolean parallel, FLAVersion version, XFLExportSettings settings) throws IOException, InterruptedException { - new XFLConverter().convertSWF(handler, this, swfName, outfile, settings, generator, generatorVerName, generatorVersion, parallel, version); + public void exportXfl(AbortRetryIgnoreHandler handler, String outfile, String swfName, String generator, String generatorVerName, String generatorVersion, boolean parallel, FLAVersion version, XFLExportSettings settings, ProgressListener progressListener) throws IOException, InterruptedException { + new XFLConverter().convertSWF(handler, this, swfName, outfile, settings, generator, generatorVerName, generatorVersion, parallel, version, progressListener); clearAllCache(); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/math/BezierEdge.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/math/BezierEdge.java index 1469480eb..85d2acc21 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/math/BezierEdge.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/math/BezierEdge.java @@ -481,14 +481,16 @@ public class BezierEdge implements Serializable { //Error Y values of bounds must be of opposite sign BezierEdge qi = new BezierEdge(6369.0, 13040.0, 6380.0, 13030.0, 6427.0, 13018.0); BezierEdge qj = new BezierEdge(6338.0, 13099.0, 6358.0, 13050.0, 6369.0, 13040.0); - - + //Error Y values of bounds must be of opposite sign BezierEdge qk = new BezierEdge(45334.0, 2421.0, 45348.0, 2373.0, 45348.0, 2330.0); BezierEdge ql = new BezierEdge(45348.0, 2330.0, 45348.0, 2263.0, 45314.0, 2223.0); - + + BezierEdge qm = new BezierEdge(-1957, 2676, -1957, 2676.5, -1957.5, 2676.5); + BezierEdge qn = new BezierEdge(-1957, 2675.5, -1957, 2676, -1957, 2676); + List ps = new ArrayList<>(); - qk.intersects(ql, t1, t2, ps); + qm.intersects(qn, t1, t2, ps); System.err.println("t1 is " + t1); System.err.println("t2 is " + t2); System.err.println("intersections is " + ps); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/math/Intersections.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/math/Intersections.java index 79fc89aa8..3d7055138 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/math/Intersections.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/math/Intersections.java @@ -247,7 +247,10 @@ public class Intersections { if (0 <= xRoot && xRoot <= 1) { for (int k = 0; k < yRoots.size(); k++) { if (Math.abs(xRoot - yRoots.get(k)) < TOLERANCE) { - result.add(add(multiply(c22, s * s), (add(multiply(c21, s), c20)))); + Point2D res = add(multiply(c22, s * s), (add(multiply(c21, s), c20))); + if (!result.contains(res)) { + result.add(res); + } break checkRoots; } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java index 28a072f5a..89c51fbfd 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java @@ -150,6 +150,7 @@ import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.ScopeStack; import com.jpexs.helpers.Helper; import com.jpexs.helpers.Path; +import com.jpexs.helpers.ProgressListener; import com.jpexs.helpers.Reference; import com.jpexs.helpers.SerializableImage; import com.jpexs.helpers.XmlPrettyFormat; @@ -173,6 +174,7 @@ import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Objects; import java.util.Random; import java.util.Set; import java.util.Stack; @@ -582,8 +584,8 @@ public class XFLConverter { return false; } - private static void convertShape(SWF swf, HashMap characters, MATRIX mat, int shapeNum, List shapeRecords, FILLSTYLEARRAY fillStyles, LINESTYLEARRAY lineStyles, boolean morphshape, boolean useLayers, XFLXmlWriter writer) throws XMLStreamException { - List layers = getShapeLayers(swf, characters, mat, shapeNum, shapeRecords, fillStyles, lineStyles, morphshape); + private static void convertShape(SWF swf, HashMap characters, MATRIX mat, int shapeNum, List shapeRecords, FILLSTYLEARRAY fillStyles, LINESTYLEARRAY lineStyles, boolean morphshape, boolean useLayers, XFLXmlWriter writer, boolean useFixer) throws XMLStreamException { + List layers = getShapeLayers(swf, characters, mat, shapeNum, shapeRecords, fillStyles, lineStyles, morphshape, useFixer); if (!useLayers) { for (int l = layers.size() - 1; l >= 0; l--) { writer.writeCharactersRaw(layers.get(l)); @@ -775,15 +777,13 @@ public class XFLConverter { return ret; } - private static List getShapeLayers(SWF swf, HashMap characters, MATRIX mat, int shapeNum, List shapeRecords, FILLSTYLEARRAY fillStyles, LINESTYLEARRAY lineStyles, boolean morphshape) throws XMLStreamException { + private static List getShapeLayers(SWF swf, HashMap characters, MATRIX mat, int shapeNum, List shapeRecords, FILLSTYLEARRAY fillStyles, LINESTYLEARRAY lineStyles, boolean morphshape, boolean useFixer) throws XMLStreamException { if (mat == null) { mat = new MATRIX(); } - - boolean doFix = true; - + List shapeRecordsAdvanced; - if (doFix) { + if (useFixer) { ShapeFixer fixer = new ShapeFixer(); shapeRecordsAdvanced = fixer.fix(shapeRecords); } else { @@ -1631,21 +1631,24 @@ public class XFLConverter { return date.getTime() / 1000; } - private void convertLibrary(SWF swf, Map characterVariables, Map characterClasses, Map characterScriptPacks, List nonLibraryShapes, String backgroundColor, ReadOnlyTagList tags, HashMap characters, HashMap files, HashMap datfiles, FLAVersion flaVersion, XFLXmlWriter writer, Map placeToMaskedSymbol, List multiUsageMorphShapes) throws XMLStreamException { + private void convertLibrary(SWF swf, Map characterVariables, Map characterClasses, Map characterScriptPacks, List nonLibraryShapes, String backgroundColor, ReadOnlyTagList tags, HashMap characters, HashMap files, HashMap datfiles, FLAVersion flaVersion, XFLXmlWriter writer, Map placeToMaskedSymbol, List multiUsageMorphShapes, ProgressListener progressListener) throws XMLStreamException { //TODO: Imported assets //linkageImportForRS="true" linkageIdentifier="xxx" linkageURL="yyy.swf" - convertMedia(swf, characterVariables, characterClasses, nonLibraryShapes, backgroundColor, tags, characters, files, datfiles, flaVersion, writer); - convertSymbols(swf, characterVariables, characterClasses, characterScriptPacks, nonLibraryShapes, backgroundColor, tags, characters, files, datfiles, flaVersion, writer, placeToMaskedSymbol, multiUsageMorphShapes); + convertMedia(swf, characterVariables, characterClasses, nonLibraryShapes, backgroundColor, tags, characters, files, datfiles, flaVersion, writer, progressListener); + convertSymbols(swf, characterVariables, characterClasses, characterScriptPacks, nonLibraryShapes, backgroundColor, tags, characters, files, datfiles, flaVersion, writer, placeToMaskedSymbol, multiUsageMorphShapes, progressListener); } - private void convertSymbols(SWF swf, Map characterVariables, Map characterClasses, Map characterScriptPacks, List nonLibraryShapes, String backgroundColor, ReadOnlyTagList tags, HashMap characters, HashMap files, HashMap datfiles, FLAVersion flaVersion, XFLXmlWriter writer, Map placeToMaskedSymbol, List multiUsageMorphShapes) throws XMLStreamException { - boolean hasSymbol = false; + private void convertSymbols(SWF swf, Map characterVariables, Map characterClasses, Map characterScriptPacks, List nonLibraryShapes, String backgroundColor, ReadOnlyTagList tags, HashMap characters, HashMap files, HashMap datfiles, FLAVersion flaVersion, XFLXmlWriter writer, Map placeToMaskedSymbol, List multiUsageMorphShapes, ProgressListener progressListener) throws XMLStreamException { + //boolean hasSymbol = false; Reference nextClipId = new Reference<>(-1); writer.writeStartElement("symbols"); for (int ch : characters.keySet()) { - //System.err.println("converting " + ch); CharacterTag symbol = characters.get(ch); + if (progressListener != null && symbol != null) { + progressListener.status(symbol.toString()); + } + if ((symbol instanceof ShapeTag) && nonLibraryShapes.contains(symbol.getCharacterId())) { continue; //shapes with 1 ocurrence and single layer are not added to library } @@ -1800,7 +1803,7 @@ public class XFLConverter { int characterId = character.getCharacterId(); if ((character instanceof ShapeTag) && (nonLibraryShapes.contains(characterId))) { ShapeTag shape = (ShapeTag) character; - convertShape(swf, characters, matrix, shape.getShapeNum(), shape.getShapes().shapeRecords, shape.getShapes().fillStyles, shape.getShapes().lineStyles, false, false, recCharWriter); + convertShape(swf, characters, matrix, shape.getShapeNum(), shape.getShapes().shapeRecords, shape.getShapes().fillStyles, shape.getShapes().lineStyles, false, false, recCharWriter, true); } else if (character instanceof TextTag) { convertText(null, (TextTag) character, matrix, filters, null, recCharWriter); } else if (character instanceof DefineVideoStreamTag) { @@ -1861,7 +1864,7 @@ public class XFLConverter { symbolStr.writeStartElement("layers"); SHAPEWITHSTYLE shapeWithStyle = shape.getShapes(); if (shapeWithStyle != null) { - convertShape(swf, characters, null, shape.getShapeNum(), shapeWithStyle.shapeRecords, shapeWithStyle.fillStyles, shapeWithStyle.lineStyles, false, true, symbolStr); + convertShape(swf, characters, null, shape.getShapeNum(), shapeWithStyle.shapeRecords, shapeWithStyle.fillStyles, shapeWithStyle.lineStyles, false, true, symbolStr, true); } symbolStr.writeEndElement(); // layers @@ -1885,7 +1888,7 @@ public class XFLConverter { //TODO: itemID="518de416-00000341" } writer.writeEndElement(); - hasSymbol = true; + //hasSymbol = true; } } @@ -1897,7 +1900,7 @@ public class XFLConverter { writer.writeEndElement(); } - private void convertMedia(SWF swf, Map characterVariables, Map characterClasses, List nonLibraryShapes, String backgroundColor, ReadOnlyTagList tags, HashMap characters, HashMap files, HashMap datfiles, FLAVersion flaVersion, XFLXmlWriter writer) throws XMLStreamException { + private void convertMedia(SWF swf, Map characterVariables, Map characterClasses, List nonLibraryShapes, String backgroundColor, ReadOnlyTagList tags, HashMap characters, HashMap files, HashMap datfiles, FLAVersion flaVersion, XFLXmlWriter writer, ProgressListener progressListener) throws XMLStreamException { boolean hasMedia = false; for (int ch : characters.keySet()) { CharacterTag symbol = characters.get(ch); @@ -1919,6 +1922,11 @@ public class XFLConverter { for (int ch : characters.keySet()) { CharacterTag symbol = characters.get(ch); if (symbol instanceof ImageTag) { + + if (progressListener != null) { + progressListener.status(symbol.toString()); + } + ImageTag imageTag = (ImageTag) symbol; boolean allowSmoothing = false; @@ -2367,7 +2375,7 @@ public class XFLConverter { SWF swf = startSound.getSwf(); sound = swf.getSound(startSound.soundId); } - + //System.err.println("-- writing frame " + frame); writer.writeStartElement("DOMFrame"); writer.writeAttribute("index", frame); if (duration > 1) { @@ -2444,6 +2452,8 @@ public class XFLConverter { prevStr += ""; int frame = -1; String lastElements = ""; + CharacterTag lastCharacter = null; + MATRIX lastMatrix = null; int duration = 1; @@ -2606,11 +2616,13 @@ public class XFLConverter { MorphShapeTag m = shapeTweener; XFLXmlWriter addLastWriter = new XFLXmlWriter(); SHAPEWITHSTYLE endShape = m.getShapeAtRatio(65535); //lastTweenRatio); - convertShape(swf, characters, matrix, m.getShapeNum() == 1 ? 3 : 4, endShape.shapeRecords, m.getFillStyles().getFillStylesAt(lastTweenRatio), m.getLineStyles().getLineStylesAt(m.getShapeNum(), lastTweenRatio), true, false, addLastWriter); + convertShape(swf, characters, matrix, m.getShapeNum() == 1 ? 3 : 4, endShape.shapeRecords, m.getFillStyles().getFillStylesAt(lastTweenRatio), m.getLineStyles().getLineStylesAt(m.getShapeNum(), lastTweenRatio), true, false, addLastWriter, false); //duration--; convertFrame(true, null, null, frame - duration, duration, "", lastElements, files, writer2); duration = 1; lastElements = addLastWriter.toString(); + lastCharacter = m; + lastMatrix = matrix; shapeTweener = null; shapeTweenNow = true; } @@ -2620,7 +2632,7 @@ public class XFLConverter { standaloneShapeTweener = null; } else if ((character instanceof ShapeTag) && (nonLibraryShapes.contains(characterId))) { // || shapeTweener != null)) { ShapeTag shape = (ShapeTag) character; - convertShape(swf, characters, matrix, shape.getShapeNum(), shape.getShapes().shapeRecords, shape.getShapes().fillStyles, shape.getShapes().lineStyles, false, false, elementsWriter); + convertShape(swf, characters, matrix, shape.getShapeNum(), shape.getShapes().shapeRecords, shape.getShapes().fillStyles, shape.getShapes().lineStyles, false, false, elementsWriter, true); shapeTween = false; shapeTweener = null; @@ -2634,7 +2646,14 @@ public class XFLConverter { standaloneShapeTweenerMatrix = matrix; convertSymbolInstance(instanceName, matrix, colorTransForm, cacheAsBitmap, blendMode, filters, isVisible, backGroundColor, clipActions, metadata, character, characters, tags, flaVersion, elementsWriter); } else { - convertShape(swf, characters, matrix, m.getShapeNum() == 1 ? 3 : 4, m.getStartEdges().shapeRecords, m.getFillStyles().getStartFillStyles(), m.getLineStyles().getStartLineStyles(m.getShapeNum()), true, false, elementsWriter); + if (lastCharacter == m && Objects.equals(matrix, lastMatrix)) { + elementsWriter.writeCharactersRaw(lastElements); + } else { + convertShape(swf, characters, matrix, m.getShapeNum() == 1 ? 3 : 4, m.getStartEdges().shapeRecords, m.getFillStyles().getStartFillStyles(), m.getLineStyles().getStartLineStyles(m.getShapeNum()), true, false, elementsWriter, false); + } + + lastCharacter = m; + lastMatrix = matrix; shapeTween = true; } } else { @@ -2665,10 +2684,14 @@ public class XFLConverter { } lastElements = elements; + lastCharacter = character; + lastMatrix = matrix; if (frame > endFrame) { if (lastIn) { lastElements = ""; lastIn = false; + lastCharacter = null; + lastMatrix = null; } } } @@ -2676,6 +2699,8 @@ public class XFLConverter { if (lastIn) { lastElements = ""; lastIn = false; + lastCharacter = null; + lastMatrix = null; } frame++; if (frame == 0) { @@ -2699,7 +2724,7 @@ public class XFLConverter { } } - private static void convertFonts(Map characterClasses, ReadOnlyTagList tags, XFLXmlWriter writer) throws XMLStreamException { + private static void convertFonts(Map characterClasses, ReadOnlyTagList tags, XFLXmlWriter writer, ProgressListener progressListener) throws XMLStreamException { boolean hasFont = false; for (Tag t : tags) { if (t instanceof FontTag) { @@ -2719,6 +2744,9 @@ public class XFLConverter { for (Tag t : tags) { if (t instanceof FontTag) { + if (progressListener != null) { + progressListener.status(t.toString()); + } SWF swf = t.getSwf(); FontTag font = (FontTag) t; int fontId = font.getFontId(); @@ -3803,7 +3831,7 @@ public class XFLConverter { Map>> frameToDepthToClips = new TreeMap<>(); - for (f = 0; f < frameCount; f++) { + for (f = 0; f < frameCount; f++) { for (int d = 0; d < maxDepth; d++) { for (int p = 0; p < clipPlaces.size() - 1; p++) { PlaceObjectTypeTag po = clipPlaces.get(p); @@ -4033,6 +4061,7 @@ public class XFLConverter { private boolean writeLayer(SWF swf, int index, List onlyFrames, int d, int startFrame, int endFrame, int parentLayer, XFLXmlWriter writer, List nonLibraryShapes, ReadOnlyTagList tags, ReadOnlyTagList timelineTags, HashMap characters, FLAVersion flaVersion, HashMap files, List multiUsageMorphShapes) throws XMLStreamException { XFLXmlWriter layerPrev = new XFLXmlWriter(); + //System.err.println("- writing layer " + (index + 1) + (startFrame == 0 && endFrame == Integer.MAX_VALUE ? ", all frames": ", frame " + startFrame + " to " + endFrame)); layerPrev.writeStartElement("DOMLayer", new String[]{ "name", "Layer " + (index + 1) + (DEBUG_EXPORT_LAYER_DEPTHS ? " (depth " + d + ")" : ""), "color", randomOutlineColor() @@ -4498,7 +4527,7 @@ public class XFLConverter { return false; } - public void convertSWF(AbortRetryIgnoreHandler handler, SWF swf, String swfFileName, String outfile, XFLExportSettings settings, String generator, String generatorVerName, String generatorVersion, boolean parallel, FLAVersion flaVersion) throws IOException, InterruptedException { + public void convertSWF(AbortRetryIgnoreHandler handler, SWF swf, String swfFileName, String outfile, XFLExportSettings settings, String generator, String generatorVerName, String generatorVersion, boolean parallel, FLAVersion flaVersion, ProgressListener progressListener) throws IOException, InterruptedException { FileAttributesTag fa = swf.getFileAttributes(); @@ -4580,11 +4609,14 @@ public class XFLConverter { Map placeToMaskedSymbol = new HashMap<>(); - convertFonts(characterClasses, swf.getTags(), domDocument); - convertLibrary(swf, characterVariables, characterClasses, characterScriptPacks, nonLibraryShapes, backgroundColor, swf.getTags(), characters, files, datfiles, flaVersion, domDocument, placeToMaskedSymbol, multiUsageMorphShapes); + convertFonts(characterClasses, swf.getTags(), domDocument, progressListener); + convertLibrary(swf, characterVariables, characterClasses, characterScriptPacks, nonLibraryShapes, backgroundColor, swf.getTags(), characters, files, datfiles, flaVersion, domDocument, placeToMaskedSymbol, multiUsageMorphShapes, progressListener); //domDocument.writeStartElement("timelines"); ScriptPack documentScriptPack = characterScriptPacks.containsKey(0) ? characterScriptPacks.get(0) : null; + if (progressListener != null) { + progressListener.status("main timeline"); + } convertTimeline(swf, swf.getAbcIndex(), -1, null, nonLibraryShapes, backgroundColor, swf.getTags(), swf.getTags(), characters, "Scene 1", flaVersion, files, domDocument, documentScriptPack, placeToMaskedSymbol, multiUsageMorphShapes); //domDocument.writeEndElement(); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/shapefixer/ShapeFixer.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/shapefixer/ShapeFixer.java index 92a1a5b39..a4f6f2ccb 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/shapefixer/ShapeFixer.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/shapefixer/ShapeFixer.java @@ -37,26 +37,32 @@ import java.util.Objects; */ public class ShapeFixer { - final boolean DEBUG_PRINT = false; + boolean DEBUG_PRINT = false; private class BezierPair { BezierEdge be1; BezierEdge be2; + private Integer hash; public BezierPair(BezierEdge be1, BezierEdge be2) { this.be1 = be1; - this.be2 = be2; + this.be2 = be2; } @Override public int hashCode() { - return Objects.hashCode(this.be1) + Objects.hashCode(this.be2); + if (hash != null) { + return hash; + } + return hash = Objects.hashCode(this.be1) + Objects.hashCode(this.be2); } @Override public boolean equals(Object obj) { - if (this == obj) { + //simplifyed to be fast, not so neccessarily accurate + return hashCode() == obj.hashCode(); + /*if (this == obj) { return true; } if (obj == null) { @@ -70,7 +76,7 @@ public class ShapeFixer { || (Objects.equals(this.be1, other.be2) && Objects.equals(this.be2, other.be1))) { return true; } - return false; + return false;*/ } } @@ -175,16 +181,20 @@ public class ShapeFixer { if (i1 == i2 && j1 == j2) { continue; } - - - + if (be1.isEmpty()) { shapes.get(i1).remove(j1); + if (i1 == i2 && j2 > j1) { + j2--; + } j1--; continue loopj1; } if (be2.isEmpty()) { shapes.get(i2).remove(j2); + if (i1 == i2 && j1 > j2) { + j1--; + } j2--; continue loopj2; } @@ -192,6 +202,9 @@ public class ShapeFixer { //duplicated edge if (be1.equals(be2) || be1.equals(be2.reverse())) { shapes.get(i2).remove(j2); + if (i1 == i2 && j1 > j2) { + j1--; + } j2--; if (DEBUG_PRINT) { System.err.println("removing duplicate " + be1.toSvg() + " and " + be2.toSvg()); diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/xfl/XFLConverterTest.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/xfl/XFLConverterTest.java index fee417604..71fee108d 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/xfl/XFLConverterTest.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/xfl/XFLConverterTest.java @@ -63,7 +63,8 @@ public class XFLConverterTest { }, outputDir + "/" + ( new File(fileName).getName().replace(".swf", ".fla")), new File(fileName).getName(), - ApplicationInfo.APPLICATION_NAME, ApplicationInfo.applicationVerName, ApplicationInfo.version, true, FLAVersion.CS6); + ApplicationInfo.APPLICATION_NAME, ApplicationInfo.applicationVerName, ApplicationInfo.version, true, FLAVersion.CS6, + null); //TODO: Actually do some tests - asserts. Without them it is not much useful - it just tests that no exception is thrown. diff --git a/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java b/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java index cfc81f7f2..d8a0e696a 100644 --- a/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java +++ b/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java @@ -2648,9 +2648,9 @@ public class CommandLineArgumentParser { try { if (Configuration.setFFDecVersionInExportedFont.get()) { - swf.exportXfl(handler, outFile, inFile.getName(), ApplicationInfo.APPLICATION_NAME, ApplicationInfo.applicationVerName, ApplicationInfo.version, Configuration.parallelSpeedUp.get(), flaVersion, settings); + swf.exportXfl(handler, outFile, inFile.getName(), ApplicationInfo.APPLICATION_NAME, ApplicationInfo.applicationVerName, ApplicationInfo.version, Configuration.parallelSpeedUp.get(), flaVersion, settings, null); } else { - swf.exportXfl(handler, outFile, inFile.getName(), ApplicationInfo.APPLICATION_NAME, ApplicationInfo.APPLICATION_NAME, "1.0.0", Configuration.parallelSpeedUp.get(), flaVersion, settings); + swf.exportXfl(handler, outFile, inFile.getName(), ApplicationInfo.APPLICATION_NAME, ApplicationInfo.APPLICATION_NAME, "1.0.0", Configuration.parallelSpeedUp.get(), flaVersion, settings, null); } } catch (Exception ex) { logger.log(Level.SEVERE, "Error during XFL/FLA export", ex); diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index 596992479..49ad60848 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -3350,17 +3350,31 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } path += compressed ? ".fla" : ".xfl"; final FLAVersion selectedVersion = versions.get(compressed ? flaFilters.indexOf(selectedFilter) : xflFilters.indexOf(selectedFilter)); - final File selfile = new File(path); + final File selfile = new File(path); new CancellableWorker() { @Override protected Void doInBackground() throws Exception { Helper.freeMem(); + + CancellableWorker w = this; + + ProgressListener prog = new ProgressListener() { + @Override + public void progress(int p) { + } + + @Override + public void status(String status) { + Main.startWork(translate("work.exporting.fla") + "..." + status, w); + } + }; + try { AbortRetryIgnoreHandler errorHandler = new GuiAbortRetryIgnoreHandler(); if (compressed) { - swf.exportFla(errorHandler, selfile.getAbsolutePath(), fSwfShortName, ApplicationInfo.APPLICATION_NAME, ApplicationInfo.applicationVerName, ApplicationInfo.version, Configuration.parallelSpeedUp.get(), selectedVersion); + swf.exportFla(errorHandler, selfile.getAbsolutePath(), fSwfShortName, ApplicationInfo.APPLICATION_NAME, ApplicationInfo.applicationVerName, ApplicationInfo.version, Configuration.parallelSpeedUp.get(), selectedVersion, prog); } else { - swf.exportXfl(errorHandler, selfile.getAbsolutePath(), fSwfShortName, ApplicationInfo.APPLICATION_NAME, ApplicationInfo.applicationVerName, ApplicationInfo.version, Configuration.parallelSpeedUp.get(), selectedVersion); + swf.exportXfl(errorHandler, selfile.getAbsolutePath(), fSwfShortName, ApplicationInfo.APPLICATION_NAME, ApplicationInfo.applicationVerName, ApplicationInfo.version, Configuration.parallelSpeedUp.get(), selectedVersion, prog); } } catch (Exception ex) { logger.log(Level.SEVERE, "FLA export error", ex);