diff --git a/CHANGELOG.md b/CHANGELOG.md index 32c74146a..b7f10d030 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ All notable changes to this project will be documented in this file. - Generic tag editor - Default values for filters - AS1/2 P-code actions inline documentation - AS1/2 P-code hilight currently selected action argument in action documentation +- [#2098] Shape points editation - Protection against saving too large edges ### Fixed - Close action on SWF inside DefineBinaryData @@ -3170,6 +3171,7 @@ Major version of SWF to XML export changed to 2. [#2079]: https://www.free-decompiler.com/flash/issues/2079 [#116]: https://www.free-decompiler.com/flash/issues/116 [#2097]: https://www.free-decompiler.com/flash/issues/2097 +[#2098]: https://www.free-decompiler.com/flash/issues/2098 [#2093]: https://www.free-decompiler.com/flash/issues/2093 [#1678]: https://www.free-decompiler.com/flash/issues/1678 [#2094]: https://www.free-decompiler.com/flash/issues/2094 diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFOutputStream.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFOutputStream.java index 46f8dd3ab..2fc006c7f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFOutputStream.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFOutputStream.java @@ -409,6 +409,25 @@ public class SWFOutputStream extends OutputStream { * @throws IOException */ public void writeUB(int nBits, long value) throws IOException { + if (!fitsInUB(nBits, value)) { + throw new ValueTooLargeException("UB[" + nBits + "]", value); + } + writeNBInternal(nBits, value, "UB"); + } + + public static boolean fitsInSB(int nBits, long value) { + long min = -1L << (nBits - 1); + long max = (1L << (nBits - 1)) - 1; + return value >= min && value <= max; + } + + public static boolean fitsInUB(int nBits, long value) { + long min = 0; + long max = (1L << nBits) - 1; + return value >= min && value <= max; + } + + private void writeNBInternal(int nBits, long value, String type) throws IOException { for (int bit = 0; bit < nBits; bit++) { int nb = (int) ((value >> (nBits - 1 - bit)) & 1); tempByte += nb * (1 << (7 - bitPos)); @@ -428,8 +447,11 @@ public class SWFOutputStream extends OutputStream { * @param value Signed value to write * @throws IOException */ - public void writeSB(int nBits, long value) throws IOException { - writeUB(nBits, value); + public void writeSB(int nBits, long value) throws IOException { + if (!fitsInSB(nBits, value)) { + throw new ValueTooLargeException("SB[" + nBits + "]", value); + } + writeNBInternal(nBits, value, "SB"); } /** @@ -1371,9 +1393,6 @@ public class SWFOutputStream extends OutputStream { for (SHAPERECORD r : value.shapeRecords) { if (r instanceof StyleChangeRecord) { StyleChangeRecord scr = (StyleChangeRecord) r; - if (scr.stateNewStyles) { - break; - } if (scr.stateFillStyle0) { numFillBits = Math.max(numFillBits, getNeededBitsU(scr.fillStyle0)); } @@ -1383,6 +1402,9 @@ public class SWFOutputStream extends OutputStream { if (scr.stateLineStyle) { numLineBits = Math.max(numLineBits, getNeededBitsU(scr.lineStyle)); } + if (scr.stateNewStyles) { + break; + } } } if (Configuration._debugCopy.get()) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/shaperecords/CurvedEdgeRecord.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/shaperecords/CurvedEdgeRecord.java index c9a8ecbdc..e56889ae2 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/shaperecords/CurvedEdgeRecord.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/shaperecords/CurvedEdgeRecord.java @@ -86,4 +86,10 @@ public class CurvedEdgeRecord extends SHAPERECORD { numBits = 0; } } + + @Override + public boolean isTooLarge() { + calculateBits(); + return !SWFOutputStream.fitsInUB(4, numBits); + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/shaperecords/EndShapeRecord.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/shaperecords/EndShapeRecord.java index 8afd66046..cf15ca4e7 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/shaperecords/EndShapeRecord.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/shaperecords/EndShapeRecord.java @@ -57,4 +57,9 @@ public class EndShapeRecord extends SHAPERECORD { @Override public void calculateBits() { } + + @Override + public boolean isTooLarge() { + return false; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/shaperecords/SHAPERECORD.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/shaperecords/SHAPERECORD.java index df9102e7e..e6cce3f58 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/shaperecords/SHAPERECORD.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/shaperecords/SHAPERECORD.java @@ -535,4 +535,6 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters, Seriali throw new RuntimeException(); } } + + public abstract boolean isTooLarge(); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/shaperecords/StraightEdgeRecord.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/shaperecords/StraightEdgeRecord.java index 608ac61f7..d257897bc 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/shaperecords/StraightEdgeRecord.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/shaperecords/StraightEdgeRecord.java @@ -118,4 +118,10 @@ public class StraightEdgeRecord extends SHAPERECORD { } } } + + @Override + public boolean isTooLarge() { + calculateBits(); + return !SWFOutputStream.fitsInUB(4, numBits); + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/shaperecords/StyleChangeRecord.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/shaperecords/StyleChangeRecord.java index 4bede6428..0f50b87fa 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/shaperecords/StyleChangeRecord.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/shaperecords/StyleChangeRecord.java @@ -148,4 +148,13 @@ public final class StyleChangeRecord extends SHAPERECORD implements Cloneable { public void calculateBits() { moveBits = SWFOutputStream.getNeededBitsS(moveDeltaX, moveDeltaY); } + + @Override + public boolean isTooLarge() { + if (!stateMoveTo) { + return false; + } + calculateBits(); + return !SWFOutputStream.fitsInUB(5, moveBits); + } } diff --git a/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java b/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java index 4e3927f68..09a4d7817 100644 --- a/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java @@ -114,6 +114,7 @@ import javax.swing.Box; import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JLabel; +import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JSplitPane; import javax.swing.JToggleButton; @@ -2154,6 +2155,28 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel displayEditGenericPanel.setVisible(true); } if (displayEditMode == EDIT_POINTS) { + List shapeRecords = null; + if (displayEditTag instanceof ShapeTag) { + ShapeTag shape = (ShapeTag) displayEditTag; + shapeRecords = shape.shapes.shapeRecords; + } + if (displayEditTag instanceof MorphShapeTag) { + MorphShapeTag morphShape = (MorphShapeTag) displayEditTag; + if (morphDisplayMode == MORPH_START) { + shapeRecords = morphShape.getStartEdges().shapeRecords; + } + if (morphDisplayMode == MORPH_END) { + shapeRecords = morphShape.getEndEdges().shapeRecords; + } + } + if (shapeRecords != null) { + for (SHAPERECORD rec : shapeRecords) { + if (rec.isTooLarge()) { + ViewMessages.showMessageDialog(this, AppStrings.translate("error.shapeTooLarge"), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE); + return; + } + } + } displayEditImagePanel.setHilightedPoints(null); displayEditTag.setModified(true); if (displayEditTag instanceof ShapeTag) { diff --git a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties index bcb3e8b37..16ce7f87d 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties @@ -1170,4 +1170,6 @@ message.info.importSprites = During importing sprites, you need to select a FOLD import.sprite.result = %count% sprites imported. -menu.file.import.sprite = Import sprites from GIF \ No newline at end of file +menu.file.import.sprite = Import sprites from GIF + +error.shapeTooLarge = One or more edge lengths of the shape is too large to save.\r\nPlease move points closer, resize shape or insert a point in the middle of long edges before proceeding. diff --git a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties index 7c907ff48..8cc0e021e 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties @@ -1148,3 +1148,5 @@ button.abcexploretrait = Zobrazit vlastnost v pr\u016fzkumn\u00edku ABC binarydata.swfInside.packer = Vypad\u00e1 to, \u017ee uvnit\u0159 v tomto BinaryData tagu se nach\u00e1z\u00ed SWF soubor zabalen\u00fd pomoc\u00ed %packer%. Klikn\u011bte zde pro jeho rozbalen\u00ed a na\u010dten\u00ed jako podstrom. button.replaceWithGif = Nahradit GIFem... + +error.shapeTooLarge = Jedna \u010di v\u00edce hran v tvaru je moc dlouh\u00e1 pro ulo\u017een\u00ed.\r\nPros\u00edm p\u0159ed pokra\u010dov\u00e1n\u00edm p\u0159esu\u0148te body bl\u00ed\u017ee, zmen\u0161ete tvar nebo vlo\u017ete bod doprost\u0159ed dlouh\u00e9 hrany.