diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFInputStream.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFInputStream.java index 21f9eae51..cf0b9a471 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFInputStream.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFInputStream.java @@ -2564,7 +2564,7 @@ public class SWFInputStream implements AutoCloseable { FILLSTYLEARRAY ret = new FILLSTYLEARRAY(); newDumpLevel(name, "FILLSTYLEARRAY"); int fillStyleCount = readUI8("fillStyleCount"); - if (((shapeNum == 2) || (shapeNum == 3) || (shapeNum == 4/*?*/)) && (fillStyleCount == 0xff)) { + if (shapeNum > 1 && fillStyleCount == 0xff) { fillStyleCount = readUI16("fillStyleCount"); } ret.fillStyles = new FILLSTYLE[fillStyleCount]; @@ -2645,7 +2645,7 @@ public class SWFInputStream implements AutoCloseable { if (lineStyleCount == 0xff) { lineStyleCount = readUI16("lineStyleCount"); } - if ((shapeNum == 1 || shapeNum == 2 || shapeNum == 3)) { + if (shapeNum <= 3) { ret.lineStyles = new LINESTYLE[lineStyleCount]; for (int i = 0; i < lineStyleCount; i++) { ret.lineStyles[i] = readLINESTYLE(shapeNum, "lineStyle"); 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 e905bb6b7..19ec08358 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFOutputStream.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFOutputStream.java @@ -1186,7 +1186,7 @@ public class SWFOutputStream extends OutputStream { */ public void writeFILLSTYLEARRAY(FILLSTYLEARRAY value, int shapeNum) throws IOException { int fillStyleCount = value.fillStyles.length; - if (shapeNum == 2 || shapeNum == 3) { + if (shapeNum > 1) { if (fillStyleCount >= 0xff) { writeUI8(0xff); writeUI16(fillStyleCount); @@ -1303,7 +1303,7 @@ public class SWFOutputStream extends OutputStream { */ public void writeLINESTYLEARRAY(LINESTYLEARRAY value, int shapeNum) throws IOException { int lineStyleCount; - if (shapeNum == 1 || shapeNum == 2 || shapeNum == 3) { + if (shapeNum <= 3) { lineStyleCount = value.lineStyles.length; if (lineStyleCount >= 0xff) { writeUI8(0xff); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/SwfXmlImporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/SwfXmlImporter.java index 7d2d7c804..1ba208bc3 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/SwfXmlImporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/SwfXmlImporter.java @@ -36,6 +36,7 @@ import com.jpexs.decompiler.flash.abc.types.traits.TraitMethodGetterSetter; import com.jpexs.decompiler.flash.abc.types.traits.TraitSlotConst; import com.jpexs.decompiler.flash.abc.types.traits.Traits; import com.jpexs.decompiler.flash.tags.Tag; +import com.jpexs.decompiler.flash.tags.TagInfo; import com.jpexs.decompiler.flash.types.ALPHABITMAPDATA; import com.jpexs.decompiler.flash.types.ALPHACOLORMAPDATA; import com.jpexs.decompiler.flash.types.ARGB; @@ -240,9 +241,9 @@ public class SwfXmlImporter { private Object createObject(String type, SWF swf, Tag tag) throws NoSuchMethodException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { if (swfTags == null) { Map tags = new HashMap<>(); - Map knownTags = Tag.getKnownClasses(); + Map knownTags = Tag.getKnownClasses(); for (Integer key : knownTags.keySet()) { - Class cls = knownTags.get(key); + Class cls = knownTags.get(key).cls; if (!ReflectionTools.canInstantiate(cls)) { System.err.println("Can't instantiate: " + cls.getName()); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/CSMTextSettingsTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/CSMTextSettingsTag.java index d17240a28..7fb77be19 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/CSMTextSettingsTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/CSMTextSettingsTag.java @@ -1,127 +1,129 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.tags.base.CharacterIdTag; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.annotations.Reserved; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.helpers.ByteArrayRange; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -/** - * - * @author JPEXS - */ -public class CSMTextSettingsTag extends Tag implements CharacterIdTag { - - @SWFType(BasicType.UI16) - public int textID; - - @SWFType(value = BasicType.UB, count = 2) - public int useFlashType; - - @SWFType(value = BasicType.UB, count = 3) - public int gridFit; - - @Reserved - @SWFType(value = BasicType.UB, count = 3) - public int reserved; - - @SWFType(value = BasicType.FLOAT) //F32 = FLOAT - public float thickness; - - @SWFType(value = BasicType.FLOAT) //F32 = FLOAT - public float sharpness; - - @Reserved - @SWFType(BasicType.UI8) - public int reserved2; - - public static final int ID = 74; - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(textID); - sos.writeUB(2, useFlashType); - sos.writeUB(3, gridFit); - sos.writeUB(3, reserved); - sos.writeFLOAT(thickness); //F32 = FLOAT - sos.writeFLOAT(sharpness); //F32 = FLOAT - sos.writeUI8(reserved2); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - - /** - * Constructor - * - * @param swf - */ - public CSMTextSettingsTag(SWF swf) { - super(swf, ID, "CSMTextSettings", null); - } - - /** - * Constructor - * - * @param sis - * @param data - * @throws IOException - */ - public CSMTextSettingsTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "CSMTextSettings", data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - textID = sis.readUI16("textID"); - useFlashType = (int) sis.readUB(2, "useFlashType"); - gridFit = (int) sis.readUB(3, "gridFit"); - reserved = (int) sis.readUB(3, "reserved"); - thickness = sis.readFLOAT("thickness"); //F32 = FLOAT - sharpness = sis.readFLOAT("sharpness"); //F32 = FLOAT - reserved2 = sis.readUI8("reserved2"); //reserved - } - - @Override - public int getCharacterId() { - return textID; - } - - @Override - public void setCharacterId(int characterId) { - this.textID = characterId; - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.tags.base.CharacterIdTag; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.annotations.Reserved; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.helpers.ByteArrayRange; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * + * @author JPEXS + */ +public class CSMTextSettingsTag extends Tag implements CharacterIdTag { + + @SWFType(BasicType.UI16) + public int textID; + + @SWFType(value = BasicType.UB, count = 2) + public int useFlashType; + + @SWFType(value = BasicType.UB, count = 3) + public int gridFit; + + @Reserved + @SWFType(value = BasicType.UB, count = 3) + public int reserved; + + @SWFType(value = BasicType.FLOAT) //F32 = FLOAT + public float thickness; + + @SWFType(value = BasicType.FLOAT) //F32 = FLOAT + public float sharpness; + + @Reserved + @SWFType(BasicType.UI8) + public int reserved2; + + public static final int ID = 74; + + public static final String NAME = "CSMTextSettings"; + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(textID); + sos.writeUB(2, useFlashType); + sos.writeUB(3, gridFit); + sos.writeUB(3, reserved); + sos.writeFLOAT(thickness); //F32 = FLOAT + sos.writeFLOAT(sharpness); //F32 = FLOAT + sos.writeUI8(reserved2); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + /** + * Constructor + * + * @param swf + */ + public CSMTextSettingsTag(SWF swf) { + super(swf, ID, NAME, null); + } + + /** + * Constructor + * + * @param sis + * @param data + * @throws IOException + */ + public CSMTextSettingsTag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + textID = sis.readUI16("textID"); + useFlashType = (int) sis.readUB(2, "useFlashType"); + gridFit = (int) sis.readUB(3, "gridFit"); + reserved = (int) sis.readUB(3, "reserved"); + thickness = sis.readFLOAT("thickness"); //F32 = FLOAT + sharpness = sis.readFLOAT("sharpness"); //F32 = FLOAT + reserved2 = sis.readUI8("reserved2"); //reserved + } + + @Override + public int getCharacterId() { + return textID; + } + + @Override + public void setCharacterId(int characterId) { + this.textID = characterId; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DebugIDTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DebugIDTag.java index 595b41e87..fdaada60c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DebugIDTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DebugIDTag.java @@ -37,6 +37,8 @@ public class DebugIDTag extends Tag { public static final int ID = 63; + public static final String NAME = "DebugID"; + /** * Gets data bytes * @@ -61,7 +63,7 @@ public class DebugIDTag extends Tag { * @param swf */ public DebugIDTag(SWF swf) { - super(swf, ID, "DebugID", null); + super(swf, ID, NAME, null); debugId = new byte[16]; } @@ -73,7 +75,7 @@ public class DebugIDTag extends Tag { * @throws IOException */ public DebugIDTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DebugID", data); + super(sis.getSwf(), ID, NAME, data); readData(sis, data, 0, false, false, false); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBinaryDataTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBinaryDataTag.java index c83a3b708..b528302d2 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBinaryDataTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBinaryDataTag.java @@ -1,151 +1,153 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.decompiler.flash.tags.base.CharacterTag; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.annotations.Internal; -import com.jpexs.decompiler.flash.types.annotations.Reserved; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.helpers.ByteArrayRange; -import com.jpexs.helpers.utf8.Utf8Helper; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.Arrays; - -/** - * - * @author JPEXS - */ -public class DefineBinaryDataTag extends CharacterTag { - - @SWFType(BasicType.UI16) - public int tag; - - public ByteArrayRange binaryData; - - @Reserved - @SWFType(BasicType.UI32) - public long reserved; - - public static final int ID = 87; - - @Internal - public SWF innerSwf; - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(tag); - sos.writeUI32(reserved); - sos.write(binaryData); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - - /** - * Constructor - * - * @param swf - */ - public DefineBinaryDataTag(SWF swf) { - super(swf, ID, "DefineBinaryData", null); - tag = swf.getNextCharacterId(); - binaryData = ByteArrayRange.EMPTY; - } - - public DefineBinaryDataTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DefineBinaryData", data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - tag = sis.readUI16("tag"); - reserved = sis.readUI32("reserved"); - binaryData = sis.readByteRangeEx(sis.available(), "binaryData"); - - if (Configuration.autoLoadEmbeddedSwfs.get()) { - try { - InputStream is = new ByteArrayInputStream(binaryData.getArray(), binaryData.getPos(), binaryData.getLength()); - SWF bswf = new SWF(is, null, "(SWF Data)", Configuration.parallelSpeedUp.get()); - innerSwf = bswf; - bswf.binaryData = this; - } catch (IOException | InterruptedException ex) { - // ignore - } - } - } - - @Override - public int getCharacterId() { - return tag; - } - - @Override - public void setCharacterId(int characterId) { - this.tag = characterId; - } - - public boolean isSwfData() { - try { - if (binaryData.getLength() > 8) { - String signature = new String(binaryData.getRangeData(0, 3), Utf8Helper.charset); - if (Arrays.asList( - "FWS", //Uncompressed Flash - "CWS", //ZLib compressed Flash - "ZWS", //LZMA compressed Flash - "GFX", //Uncompressed ScaleForm GFx - "CFX" //Compressed ScaleForm GFx - ).contains(signature)) { - return true; - } - } - } catch (Exception ex) { - } - - return false; - } - - @Override - public boolean isModified() { - if (super.isModified()) { - return true; - } - if (innerSwf != null) { - return innerSwf.isModified(); - } - return false; - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.tags.base.CharacterTag; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.annotations.Internal; +import com.jpexs.decompiler.flash.types.annotations.Reserved; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.helpers.ByteArrayRange; +import com.jpexs.helpers.utf8.Utf8Helper; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Arrays; + +/** + * + * @author JPEXS + */ +public class DefineBinaryDataTag extends CharacterTag { + + @SWFType(BasicType.UI16) + public int tag; + + public ByteArrayRange binaryData; + + @Reserved + @SWFType(BasicType.UI32) + public long reserved; + + public static final int ID = 87; + + public static final String NAME = "DefineBinaryData"; + + @Internal + public SWF innerSwf; + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(tag); + sos.writeUI32(reserved); + sos.write(binaryData); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + /** + * Constructor + * + * @param swf + */ + public DefineBinaryDataTag(SWF swf) { + super(swf, ID, NAME, null); + tag = swf.getNextCharacterId(); + binaryData = ByteArrayRange.EMPTY; + } + + public DefineBinaryDataTag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + tag = sis.readUI16("tag"); + reserved = sis.readUI32("reserved"); + binaryData = sis.readByteRangeEx(sis.available(), "binaryData"); + + if (Configuration.autoLoadEmbeddedSwfs.get()) { + try { + InputStream is = new ByteArrayInputStream(binaryData.getArray(), binaryData.getPos(), binaryData.getLength()); + SWF bswf = new SWF(is, null, "(SWF Data)", Configuration.parallelSpeedUp.get()); + innerSwf = bswf; + bswf.binaryData = this; + } catch (IOException | InterruptedException ex) { + // ignore + } + } + } + + @Override + public int getCharacterId() { + return tag; + } + + @Override + public void setCharacterId(int characterId) { + this.tag = characterId; + } + + public boolean isSwfData() { + try { + if (binaryData.getLength() > 8) { + String signature = new String(binaryData.getRangeData(0, 3), Utf8Helper.charset); + if (Arrays.asList( + "FWS", //Uncompressed Flash + "CWS", //ZLib compressed Flash + "ZWS", //LZMA compressed Flash + "GFX", //Uncompressed ScaleForm GFx + "CFX" //Compressed ScaleForm GFx + ).contains(signature)) { + return true; + } + } + } catch (Exception ex) { + } + + return false; + } + + @Override + public boolean isModified() { + if (super.isModified()) { + return true; + } + if (innerSwf != null) { + return innerSwf.isModified(); + } + return false; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG2Tag.java index fb9ed5cec..475b2aacc 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG2Tag.java @@ -1,142 +1,144 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.helpers.ImageHelper; -import com.jpexs.decompiler.flash.tags.base.AloneTag; -import com.jpexs.decompiler.flash.tags.base.ImageTag; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.helpers.ByteArrayRange; -import com.jpexs.helpers.SerializableImage; -import java.awt.image.BufferedImage; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - * @author JPEXS - */ -public class DefineBitsJPEG2Tag extends ImageTag implements AloneTag { - - @SWFType(BasicType.UI16) - public int characterID; - - @SWFType(BasicType.UI8) - public ByteArrayRange imageData; - - public static final int ID = 21; - - @Override - public int getCharacterId() { - return characterID; - } - - @Override - public void setCharacterId(int characterId) { - this.characterID = characterId; - } - - @Override - public String getImageFormat() { - return ImageTag.getImageFormat(imageData); - } - - @Override - public InputStream getImageData() { - int errorLength = hasErrorHeader(imageData) ? 4 : 0; - return new ByteArrayInputStream(imageData.getArray(), imageData.getPos() + errorLength, imageData.getLength() - errorLength); - } - - @Override - public SerializableImage getImage() { - if (cachedImage != null) { - return cachedImage; - } - try { - BufferedImage image = ImageHelper.read(getImageData()); - if (image == null) { - Logger.getLogger(DefineBitsJPEG2Tag.class.getName()).log(Level.SEVERE, "Failed to load image"); - return null; - } - - SerializableImage ret = new SerializableImage(image); - cachedImage = ret; - return ret; - } catch (IOException ex) { - Logger.getLogger(DefineBitsJPEG2Tag.class.getName()).log(Level.SEVERE, "Failed to get image", ex); - } - return null; - } - - /** - * Constructor - * - * @param swf - */ - public DefineBitsJPEG2Tag(SWF swf) { - super(swf, ID, "DefineBitsJPEG2", null); - characterID = swf.getNextCharacterId(); - imageData = ByteArrayRange.EMPTY; - } - - public DefineBitsJPEG2Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DefineBitsJPEG2", data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - characterID = sis.readUI16("characterID"); - imageData = sis.readByteRangeEx(sis.available(), "imageData"); - } - - public DefineBitsJPEG2Tag(SWF swf, ByteArrayRange data, int characterID, byte[] imageData) throws IOException { - super(swf, ID, "DefineBitsJPEG2", data); - this.characterID = characterID; - this.imageData = new ByteArrayRange(imageData); - } - - @Override - public void setImage(byte[] data) { - imageData = new ByteArrayRange(data); - clearCache(); - setModified(true); - } - - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(characterID); - sos.write(imageData); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.helpers.ImageHelper; +import com.jpexs.decompiler.flash.tags.base.AloneTag; +import com.jpexs.decompiler.flash.tags.base.ImageTag; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.helpers.ByteArrayRange; +import com.jpexs.helpers.SerializableImage; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author JPEXS + */ +public class DefineBitsJPEG2Tag extends ImageTag implements AloneTag { + + @SWFType(BasicType.UI16) + public int characterID; + + @SWFType(BasicType.UI8) + public ByteArrayRange imageData; + + public static final int ID = 21; + + public static final String NAME = "DefineBitsJPEG2"; + + @Override + public int getCharacterId() { + return characterID; + } + + @Override + public void setCharacterId(int characterId) { + this.characterID = characterId; + } + + @Override + public String getImageFormat() { + return ImageTag.getImageFormat(imageData); + } + + @Override + public InputStream getImageData() { + int errorLength = hasErrorHeader(imageData) ? 4 : 0; + return new ByteArrayInputStream(imageData.getArray(), imageData.getPos() + errorLength, imageData.getLength() - errorLength); + } + + @Override + public SerializableImage getImage() { + if (cachedImage != null) { + return cachedImage; + } + try { + BufferedImage image = ImageHelper.read(getImageData()); + if (image == null) { + Logger.getLogger(DefineBitsJPEG2Tag.class.getName()).log(Level.SEVERE, "Failed to load image"); + return null; + } + + SerializableImage ret = new SerializableImage(image); + cachedImage = ret; + return ret; + } catch (IOException ex) { + Logger.getLogger(DefineBitsJPEG2Tag.class.getName()).log(Level.SEVERE, "Failed to get image", ex); + } + return null; + } + + /** + * Constructor + * + * @param swf + */ + public DefineBitsJPEG2Tag(SWF swf) { + super(swf, ID, NAME, null); + characterID = swf.getNextCharacterId(); + imageData = ByteArrayRange.EMPTY; + } + + public DefineBitsJPEG2Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + characterID = sis.readUI16("characterID"); + imageData = sis.readByteRangeEx(sis.available(), "imageData"); + } + + public DefineBitsJPEG2Tag(SWF swf, ByteArrayRange data, int characterID, byte[] imageData) throws IOException { + super(swf, ID, NAME, data); + this.characterID = characterID; + this.imageData = new ByteArrayRange(imageData); + } + + @Override + public void setImage(byte[] data) { + imageData = new ByteArrayRange(data); + clearCache(); + setModified(true); + } + + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(characterID); + sos.write(imageData); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG3Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG3Tag.java index 477bf3e98..6abc27702 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG3Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG3Tag.java @@ -1,175 +1,177 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.helpers.ImageHelper; -import com.jpexs.decompiler.flash.tags.base.AloneTag; -import com.jpexs.decompiler.flash.tags.base.ImageTag; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.helpers.ByteArrayRange; -import com.jpexs.helpers.SerializableImage; -import java.awt.image.BufferedImage; -import java.awt.image.DataBufferInt; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - * @author JPEXS - */ -public class DefineBitsJPEG3Tag extends ImageTag implements AloneTag { - - @SWFType(BasicType.UI16) - public int characterID; - - @SWFType(BasicType.UI8) - public ByteArrayRange imageData; - - @SWFType(BasicType.UI8) - public byte[] bitmapAlphaData; - - public static final int ID = 35; - - @Override - public int getCharacterId() { - return characterID; - } - - @Override - public void setCharacterId(int characterId) { - this.characterID = characterId; - } - - @Override - public void setImage(byte[] data) throws IOException { - if (ImageTag.getImageFormat(data).equals("jpg")) { - SerializableImage image = new SerializableImage(ImageHelper.read(data)); - byte[] ba = new byte[image.getWidth() * image.getHeight()]; - for (int i = 0; i < ba.length; i++) { - ba[i] = (byte) 255; - } - bitmapAlphaData = ba; - } else { - bitmapAlphaData = new byte[0]; - } - imageData = new ByteArrayRange(data); - clearCache(); - setModified(true); - } - - @Override - public String getImageFormat() { - String fmt = ImageTag.getImageFormat(imageData); - if (fmt.equals("jpg")) { - fmt = "png"; //transparency - } - return fmt; - } - - @Override - public InputStream getImageData() { - int errorLength = hasErrorHeader(imageData) ? 4 : 0; - return new ByteArrayInputStream(imageData.getArray(), imageData.getPos() + errorLength, imageData.getLength() - errorLength); - } - - @Override - public SerializableImage getImage() { - if (cachedImage != null) { - return cachedImage; - } - try { - BufferedImage image = ImageHelper.read(getImageData()); - if (image == null) { - Logger.getLogger(DefineBitsJPEG3Tag.class.getName()).log(Level.SEVERE, "Failed to load image"); - return null; - } - - SerializableImage img = new SerializableImage(image); - if (bitmapAlphaData.length == 0) { - cachedImage = img; - return img; - } - - int[] pixels = ((DataBufferInt) img.getRaster().getDataBuffer()).getData(); - for (int i = 0; i < pixels.length; i++) { - int a = bitmapAlphaData[i] & 0xff; - pixels[i] = multiplyAlpha((pixels[i] & 0xffffff) | (a << 24)); - } - - cachedImage = img; - return img; - } catch (IOException ex) { - Logger.getLogger(DefineBitsJPEG3Tag.class.getName()).log(Level.SEVERE, "Failed to get image", ex); - } - return null; - } - - /** - * Constructor - * - * @param swf - */ - public DefineBitsJPEG3Tag(SWF swf) { - super(swf, ID, "DefineBitsJPEG3", null); - characterID = swf.getNextCharacterId(); - imageData = ByteArrayRange.EMPTY; - bitmapAlphaData = new byte[0]; - } - - public DefineBitsJPEG3Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DefineBitsJPEG3", data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - characterID = sis.readUI16("characterID"); - long alphaDataOffset = sis.readUI32("alphaDataOffset"); - imageData = sis.readByteRangeEx(alphaDataOffset, "imageData"); - bitmapAlphaData = sis.readBytesZlib(sis.available(), "bitmapAlphaData"); - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(characterID); - sos.writeUI32(imageData.getLength()); - sos.write(imageData); - sos.writeBytesZlib(bitmapAlphaData); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.helpers.ImageHelper; +import com.jpexs.decompiler.flash.tags.base.AloneTag; +import com.jpexs.decompiler.flash.tags.base.ImageTag; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.helpers.ByteArrayRange; +import com.jpexs.helpers.SerializableImage; +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferInt; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author JPEXS + */ +public class DefineBitsJPEG3Tag extends ImageTag implements AloneTag { + + @SWFType(BasicType.UI16) + public int characterID; + + @SWFType(BasicType.UI8) + public ByteArrayRange imageData; + + @SWFType(BasicType.UI8) + public byte[] bitmapAlphaData; + + public static final int ID = 35; + + public static final String NAME = "DefineBitsJPEG3"; + + @Override + public int getCharacterId() { + return characterID; + } + + @Override + public void setCharacterId(int characterId) { + this.characterID = characterId; + } + + @Override + public void setImage(byte[] data) throws IOException { + if (ImageTag.getImageFormat(data).equals("jpg")) { + SerializableImage image = new SerializableImage(ImageHelper.read(data)); + byte[] ba = new byte[image.getWidth() * image.getHeight()]; + for (int i = 0; i < ba.length; i++) { + ba[i] = (byte) 255; + } + bitmapAlphaData = ba; + } else { + bitmapAlphaData = new byte[0]; + } + imageData = new ByteArrayRange(data); + clearCache(); + setModified(true); + } + + @Override + public String getImageFormat() { + String fmt = ImageTag.getImageFormat(imageData); + if (fmt.equals("jpg")) { + fmt = "png"; //transparency + } + return fmt; + } + + @Override + public InputStream getImageData() { + int errorLength = hasErrorHeader(imageData) ? 4 : 0; + return new ByteArrayInputStream(imageData.getArray(), imageData.getPos() + errorLength, imageData.getLength() - errorLength); + } + + @Override + public SerializableImage getImage() { + if (cachedImage != null) { + return cachedImage; + } + try { + BufferedImage image = ImageHelper.read(getImageData()); + if (image == null) { + Logger.getLogger(DefineBitsJPEG3Tag.class.getName()).log(Level.SEVERE, "Failed to load image"); + return null; + } + + SerializableImage img = new SerializableImage(image); + if (bitmapAlphaData.length == 0) { + cachedImage = img; + return img; + } + + int[] pixels = ((DataBufferInt) img.getRaster().getDataBuffer()).getData(); + for (int i = 0; i < pixels.length; i++) { + int a = bitmapAlphaData[i] & 0xff; + pixels[i] = multiplyAlpha((pixels[i] & 0xffffff) | (a << 24)); + } + + cachedImage = img; + return img; + } catch (IOException ex) { + Logger.getLogger(DefineBitsJPEG3Tag.class.getName()).log(Level.SEVERE, "Failed to get image", ex); + } + return null; + } + + /** + * Constructor + * + * @param swf + */ + public DefineBitsJPEG3Tag(SWF swf) { + super(swf, ID, NAME, null); + characterID = swf.getNextCharacterId(); + imageData = ByteArrayRange.EMPTY; + bitmapAlphaData = new byte[0]; + } + + public DefineBitsJPEG3Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + characterID = sis.readUI16("characterID"); + long alphaDataOffset = sis.readUI32("alphaDataOffset"); + imageData = sis.readByteRangeEx(alphaDataOffset, "imageData"); + bitmapAlphaData = sis.readBytesZlib(sis.available(), "bitmapAlphaData"); + } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(characterID); + sos.writeUI32(imageData.getLength()); + sos.write(imageData); + sos.writeBytesZlib(bitmapAlphaData); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG4Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG4Tag.java index 8cd03428a..301d091e2 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG4Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG4Tag.java @@ -1,186 +1,188 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.helpers.ImageHelper; -import com.jpexs.decompiler.flash.tags.base.AloneTag; -import com.jpexs.decompiler.flash.tags.base.ImageTag; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.helpers.ByteArrayRange; -import com.jpexs.helpers.SerializableImage; -import java.awt.image.BufferedImage; -import java.awt.image.DataBufferInt; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - * @author JPEXS - */ -public class DefineBitsJPEG4Tag extends ImageTag implements AloneTag { - - @SWFType(BasicType.UI16) - public int characterID; - - @SWFType(BasicType.UI16) - public int deblockParam; - - @SWFType(BasicType.UI8) - public ByteArrayRange imageData; - - @SWFType(BasicType.UI8) - public ByteArrayRange bitmapAlphaData; - - public static final int ID = 90; - - @Override - public int getCharacterId() { - return characterID; - } - - @Override - public void setCharacterId(int characterId) { - this.characterID = characterId; - } - - @Override - public String getImageFormat() { - String fmt = ImageTag.getImageFormat(imageData); - if (fmt.equals("jpg")) { - fmt = "png"; //transparency - } - return fmt; - } - - @Override - public void setImage(byte[] data) { - imageData = new ByteArrayRange(data); - if (ImageTag.getImageFormat(data).equals("jpg")) { - SerializableImage image = getImage(); - byte[] ba = new byte[image.getWidth() * image.getHeight()]; - for (int i = 0; i < ba.length; i++) { - ba[i] = (byte) 255; - } - bitmapAlphaData = new ByteArrayRange(ba); - } else { - bitmapAlphaData = ByteArrayRange.EMPTY; - } - clearCache(); - setModified(true); - } - - @Override - public InputStream getImageData() { - return new ByteArrayInputStream(imageData.getArray(), imageData.getPos(), imageData.getLength()); - } - - @Override - public SerializableImage getImage() { - if (cachedImage != null) { - return cachedImage; - } - try { - BufferedImage image = ImageHelper.read(getImageData()); - if (image == null) { - Logger.getLogger(DefineBitsJPEG4Tag.class.getName()).log(Level.SEVERE, "Failed to load image"); - return null; - } - - SerializableImage img = new SerializableImage(image); - if (bitmapAlphaData.getLength() == 0) { - cachedImage = img; - return img; - } - - int[] pixels = ((DataBufferInt) img.getRaster().getDataBuffer()).getData(); - for (int i = 0; i < pixels.length; i++) { - int a = bitmapAlphaData.get(i) & 0xff; - pixels[i] = multiplyAlpha((pixels[i] & 0xffffff) | (a << 24)); - } - - cachedImage = img; - return img; - } catch (IOException ex) { - Logger.getLogger(DefineBitsJPEG4Tag.class.getName()).log(Level.SEVERE, "Failed to get image", ex); - } - return null; - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(characterID); - sos.writeUI32(imageData.getLength()); - sos.writeUI16(deblockParam); - sos.write(imageData); - sos.write(bitmapAlphaData); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - - /** - * Constructor - * - * @param swf - */ - public DefineBitsJPEG4Tag(SWF swf) { - super(swf, ID, "DefineBitsJPEG4", null); - characterID = swf.getNextCharacterId(); - imageData = ByteArrayRange.EMPTY; - bitmapAlphaData = ByteArrayRange.EMPTY; - } - - /** - * Constructor - * - * @param sis - * @param data - * @throws IOException - */ - public DefineBitsJPEG4Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DefineBitsJPEG4", data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - characterID = sis.readUI16("characterID"); - long alphaDataOffset = sis.readUI32("alphaDataOffset"); - deblockParam = sis.readUI16("deblockParam"); - imageData = sis.readByteRangeEx(alphaDataOffset, "imageData"); - bitmapAlphaData = sis.readByteRangeEx(sis.available(), "bitmapAlphaData"); - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.helpers.ImageHelper; +import com.jpexs.decompiler.flash.tags.base.AloneTag; +import com.jpexs.decompiler.flash.tags.base.ImageTag; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.helpers.ByteArrayRange; +import com.jpexs.helpers.SerializableImage; +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferInt; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author JPEXS + */ +public class DefineBitsJPEG4Tag extends ImageTag implements AloneTag { + + @SWFType(BasicType.UI16) + public int characterID; + + @SWFType(BasicType.UI16) + public int deblockParam; + + @SWFType(BasicType.UI8) + public ByteArrayRange imageData; + + @SWFType(BasicType.UI8) + public ByteArrayRange bitmapAlphaData; + + public static final int ID = 90; + + public static final String NAME = "DefineBitsJPEG4"; + + @Override + public int getCharacterId() { + return characterID; + } + + @Override + public void setCharacterId(int characterId) { + this.characterID = characterId; + } + + @Override + public String getImageFormat() { + String fmt = ImageTag.getImageFormat(imageData); + if (fmt.equals("jpg")) { + fmt = "png"; //transparency + } + return fmt; + } + + @Override + public void setImage(byte[] data) { + imageData = new ByteArrayRange(data); + if (ImageTag.getImageFormat(data).equals("jpg")) { + SerializableImage image = getImage(); + byte[] ba = new byte[image.getWidth() * image.getHeight()]; + for (int i = 0; i < ba.length; i++) { + ba[i] = (byte) 255; + } + bitmapAlphaData = new ByteArrayRange(ba); + } else { + bitmapAlphaData = ByteArrayRange.EMPTY; + } + clearCache(); + setModified(true); + } + + @Override + public InputStream getImageData() { + return new ByteArrayInputStream(imageData.getArray(), imageData.getPos(), imageData.getLength()); + } + + @Override + public SerializableImage getImage() { + if (cachedImage != null) { + return cachedImage; + } + try { + BufferedImage image = ImageHelper.read(getImageData()); + if (image == null) { + Logger.getLogger(DefineBitsJPEG4Tag.class.getName()).log(Level.SEVERE, "Failed to load image"); + return null; + } + + SerializableImage img = new SerializableImage(image); + if (bitmapAlphaData.getLength() == 0) { + cachedImage = img; + return img; + } + + int[] pixels = ((DataBufferInt) img.getRaster().getDataBuffer()).getData(); + for (int i = 0; i < pixels.length; i++) { + int a = bitmapAlphaData.get(i) & 0xff; + pixels[i] = multiplyAlpha((pixels[i] & 0xffffff) | (a << 24)); + } + + cachedImage = img; + return img; + } catch (IOException ex) { + Logger.getLogger(DefineBitsJPEG4Tag.class.getName()).log(Level.SEVERE, "Failed to get image", ex); + } + return null; + } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(characterID); + sos.writeUI32(imageData.getLength()); + sos.writeUI16(deblockParam); + sos.write(imageData); + sos.write(bitmapAlphaData); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + /** + * Constructor + * + * @param swf + */ + public DefineBitsJPEG4Tag(SWF swf) { + super(swf, ID, NAME, null); + characterID = swf.getNextCharacterId(); + imageData = ByteArrayRange.EMPTY; + bitmapAlphaData = ByteArrayRange.EMPTY; + } + + /** + * Constructor + * + * @param sis + * @param data + * @throws IOException + */ + public DefineBitsJPEG4Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + characterID = sis.readUI16("characterID"); + long alphaDataOffset = sis.readUI32("alphaDataOffset"); + deblockParam = sis.readUI16("deblockParam"); + imageData = sis.readByteRangeEx(alphaDataOffset, "imageData"); + bitmapAlphaData = sis.readByteRangeEx(sis.available(), "bitmapAlphaData"); + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsLossless2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsLossless2Tag.java index babc21f76..5b3442def 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsLossless2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsLossless2Tag.java @@ -81,6 +81,8 @@ public class DefineBitsLossless2Tag extends ImageTag implements AloneTag { public static final int ID = 36; + public static final String NAME = "DefineBitsLossless2"; + @Override public int getCharacterId() { return characterID; @@ -152,7 +154,7 @@ public class DefineBitsLossless2Tag extends ImageTag implements AloneTag { * @param swf */ public DefineBitsLossless2Tag(SWF swf) { - super(swf, ID, "DefineBitsLossless2", null); + super(swf, ID, NAME, null); characterID = swf.getNextCharacterId(); bitmapFormat = DefineBitsLossless2Tag.FORMAT_32BIT_ARGB; bitmapWidth = 1; @@ -161,7 +163,7 @@ public class DefineBitsLossless2Tag extends ImageTag implements AloneTag { } public DefineBitsLossless2Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DefineBitsLossless2", data); + super(sis.getSwf(), ID, NAME, data); readData(sis, data, 0, false, false, false); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsLosslessTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsLosslessTag.java index fca53349c..09214081a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsLosslessTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsLosslessTag.java @@ -83,6 +83,8 @@ public class DefineBitsLosslessTag extends ImageTag implements AloneTag { public static final int ID = 20; + public static final String NAME = "DefineBitsLossless"; + private byte[] createEmptyImage() { try { BITMAPDATA bitmapData = new BITMAPDATA(); @@ -230,7 +232,7 @@ public class DefineBitsLosslessTag extends ImageTag implements AloneTag { * @param swf */ public DefineBitsLosslessTag(SWF swf) { - super(swf, ID, "DefineBitsLossless", null); + super(swf, ID, NAME, null); characterID = swf.getNextCharacterId(); bitmapFormat = DefineBitsLosslessTag.FORMAT_24BIT_RGB; bitmapWidth = 1; @@ -239,7 +241,7 @@ public class DefineBitsLosslessTag extends ImageTag implements AloneTag { } public DefineBitsLosslessTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DefineBitsLossless", data); + super(sis.getSwf(), ID, NAME, data); readData(sis, data, 0, false, false, false); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsTag.java index 874d845e9..d04d47b21 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsTag.java @@ -1,158 +1,160 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.helpers.ImageHelper; -import com.jpexs.decompiler.flash.tags.base.ImageTag; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.helpers.ByteArrayRange; -import com.jpexs.helpers.SerializableImage; -import java.awt.image.BufferedImage; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - * @author JPEXS - */ -public class DefineBitsTag extends ImageTag implements TagChangedListener { - - @SWFType(BasicType.UI16) - public int characterID; - - @SWFType(BasicType.UI8) - public ByteArrayRange jpegData; - - public static final int ID = 6; - - @Override - public void setImage(byte[] data) { - throw new UnsupportedOperationException("Set image is not supported for DefineBits"); - } - - @Override - public boolean importSupported() { - // importing a new image will replace the current DefineBitsTag with a new DefineBitsJPEG2Tag - return true; - } - - /** - * Constructor - * - * @param swf - */ - public DefineBitsTag(SWF swf) { - super(swf, ID, "DefineBits", null); - characterID = swf.getNextCharacterId(); - jpegData = ByteArrayRange.EMPTY; - } - - public DefineBitsTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DefineBits", data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - characterID = sis.readUI16("characterID"); - jpegData = sis.readByteRangeEx(sis.available(), "jpegData"); - } - - @Override - public InputStream getImageData() { - return null; - } - - @Override - public SerializableImage getImage() { - if (cachedImage != null) { - return cachedImage; - } - if (swf.getJtt() != null) { - try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { - byte[] jttdata = swf.getJtt().jpegData; - if (jttdata.length != 0) { - int jttErrorLength = hasErrorHeader(jttdata) ? 4 : 0; - baos.write(jttdata, jttErrorLength, jttdata.length - jttErrorLength - 2); - } - - int errorLength = hasErrorHeader(jpegData) ? 4 : 0; - baos.write(jpegData.getArray(), jpegData.getPos() + errorLength, jpegData.getLength() - errorLength); - - BufferedImage image = ImageHelper.read(baos.toByteArray()); - if (image == null) { - Logger.getLogger(DefineBitsTag.class.getName()).log(Level.SEVERE, "Failed to load image"); - return null; - } - - SerializableImage ret = new SerializableImage(image); - cachedImage = ret; - return ret; - } catch (IOException ex) { - Logger.getLogger(DefineBitsTag.class.getName()).log(Level.SEVERE, "Failed to get image", ex); - } - } - return null; - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(characterID); - sos.write(jpegData); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - - @Override - public int getCharacterId() { - return characterID; - } - - @Override - public void setCharacterId(int characterId) { - this.characterID = characterId; - } - - @Override - public String getImageFormat() { - return "jpg"; - } - - @Override - public void handleEvent(Tag tag) { - clearCache(); - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.helpers.ImageHelper; +import com.jpexs.decompiler.flash.tags.base.ImageTag; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.helpers.ByteArrayRange; +import com.jpexs.helpers.SerializableImage; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author JPEXS + */ +public class DefineBitsTag extends ImageTag implements TagChangedListener { + + @SWFType(BasicType.UI16) + public int characterID; + + @SWFType(BasicType.UI8) + public ByteArrayRange jpegData; + + public static final int ID = 6; + + public static final String NAME = "DefineBits"; + + @Override + public void setImage(byte[] data) { + throw new UnsupportedOperationException("Set image is not supported for DefineBits"); + } + + @Override + public boolean importSupported() { + // importing a new image will replace the current DefineBitsTag with a new DefineBitsJPEG2Tag + return true; + } + + /** + * Constructor + * + * @param swf + */ + public DefineBitsTag(SWF swf) { + super(swf, ID, NAME, null); + characterID = swf.getNextCharacterId(); + jpegData = ByteArrayRange.EMPTY; + } + + public DefineBitsTag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + characterID = sis.readUI16("characterID"); + jpegData = sis.readByteRangeEx(sis.available(), "jpegData"); + } + + @Override + public InputStream getImageData() { + return null; + } + + @Override + public SerializableImage getImage() { + if (cachedImage != null) { + return cachedImage; + } + if (swf.getJtt() != null) { + try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { + byte[] jttdata = swf.getJtt().jpegData; + if (jttdata.length != 0) { + int jttErrorLength = hasErrorHeader(jttdata) ? 4 : 0; + baos.write(jttdata, jttErrorLength, jttdata.length - jttErrorLength - 2); + } + + int errorLength = hasErrorHeader(jpegData) ? 4 : 0; + baos.write(jpegData.getArray(), jpegData.getPos() + errorLength, jpegData.getLength() - errorLength); + + BufferedImage image = ImageHelper.read(baos.toByteArray()); + if (image == null) { + Logger.getLogger(DefineBitsTag.class.getName()).log(Level.SEVERE, "Failed to load image"); + return null; + } + + SerializableImage ret = new SerializableImage(image); + cachedImage = ret; + return ret; + } catch (IOException ex) { + Logger.getLogger(DefineBitsTag.class.getName()).log(Level.SEVERE, "Failed to get image", ex); + } + } + return null; + } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(characterID); + sos.write(jpegData); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + @Override + public int getCharacterId() { + return characterID; + } + + @Override + public void setCharacterId(int characterId) { + this.characterID = characterId; + } + + @Override + public String getImageFormat() { + return "jpg"; + } + + @Override + public void handleEvent(Tag tag) { + clearCache(); + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java index b301f2c91..760075f1d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java @@ -1,358 +1,360 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.abc.CopyOutputStream; -import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.decompiler.flash.tags.base.ASMSourceContainer; -import com.jpexs.decompiler.flash.tags.base.BoundedTag; -import com.jpexs.decompiler.flash.tags.base.ButtonTag; -import com.jpexs.decompiler.flash.tags.base.CharacterTag; -import com.jpexs.decompiler.flash.timeline.DepthState; -import com.jpexs.decompiler.flash.timeline.Frame; -import com.jpexs.decompiler.flash.timeline.Timeline; -import com.jpexs.decompiler.flash.types.BUTTONCONDACTION; -import com.jpexs.decompiler.flash.types.BUTTONRECORD; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.MATRIX; -import com.jpexs.decompiler.flash.types.RECT; -import com.jpexs.decompiler.flash.types.annotations.Reserved; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.helpers.ByteArrayRange; -import com.jpexs.helpers.Cache; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -/** - * Extends the capabilities of DefineButton by allowing any state transition to - * trigger actions - * - * @author JPEXS - */ -public class DefineButton2Tag extends ButtonTag implements ASMSourceContainer { - - /** - * ID for this character - */ - @SWFType(BasicType.UI16) - public int buttonId; - - @Reserved - @SWFType(value = BasicType.UB, count = 7) - public int reserved; - - /** - * Track as menu button - */ - public boolean trackAsMenu; - - /** - * Characters that make up the button - */ - public List characters; - - /** - * Actions to execute at particular button events - */ - public List actions = new ArrayList<>(); - - public static final int ID = 34; - - private Timeline timeline; - - private boolean isSingleFrameInitialized; - - private boolean isSingleFrame; - - private static final Cache rectCache = Cache.getInstance(true, true, "rect_button2"); - - @Override - public int getCharacterId() { - return buttonId; - } - - @Override - public void setCharacterId(int characterId) { - this.buttonId = characterId; - } - - @Override - public List getRecords() { - return characters; - } - - /** - * Constructor - * - * @param swf - */ - public DefineButton2Tag(SWF swf) { - super(swf, ID, "DefineButton2", null); - buttonId = swf.getNextCharacterId(); - characters = new ArrayList<>(); - } - - /** - * Constructor - * - * @param sis - * @param data - * @throws IOException - */ - public DefineButton2Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DefineButton2", data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - buttonId = sis.readUI16("buttonId"); - reserved = (int) sis.readUB(7, "reserved"); - trackAsMenu = sis.readUB(1, "trackAsMenu") == 1; - int actionOffset = sis.readUI16("actionOffset"); - characters = sis.readBUTTONRECORDList(true, "characters"); - if (actionOffset > 0) { - actions = sis.readBUTTONCONDACTIONList(swf, this, "actions"); - } - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - if (Configuration.debugCopy.get()) { - ByteArrayInputStream bais = new ByteArrayInputStream(getOriginalData()); - os = new CopyOutputStream(os, bais); - } - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(buttonId); - sos.writeUB(7, reserved); - sos.writeUB(1, trackAsMenu ? 1 : 0); - - ByteArrayOutputStream baos2 = new ByteArrayOutputStream(); - try (SWFOutputStream sos2 = new SWFOutputStream(baos2, getVersion())) { - sos2.writeBUTTONRECORDList(characters, true); - } - byte[] brdata = baos2.toByteArray(); - if ((actions == null) || (actions.isEmpty())) { - sos.writeUI16(0); - } else { - sos.writeUI16(2 + brdata.length); - } - sos.write(brdata); - sos.writeBUTTONCONDACTIONList(actions); - sos.close(); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - - /** - * Returns all sub-items - * - * @return List of sub-items - */ - @Override - public List getSubItems() { - return actions; - } - - @Override - public void getNeededCharacters(Set needed) { - for (BUTTONRECORD r : characters) { - needed.add(r.characterId); - } - } - - @Override - public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { - boolean modified = false; - for (int i = 0; i < characters.size(); i++) { - BUTTONRECORD character = characters.get(i); - if (character.characterId == oldCharacterId) { - character.characterId = newCharacterId; - modified = true; - } - } - if (modified) { - setModified(true); - } - return modified; - } - - @Override - public boolean removeCharacter(int characterId) { - boolean modified = false; - for (int i = 0; i < characters.size(); i++) { - if (characters.get(i).characterId == characterId) { - characters.remove(i); - modified = true; - i--; - } - } - if (modified) { - setModified(true); - } - return modified; - } - - @Override - public RECT getRect(Set added) { - if (rectCache.contains(this)) { - return rectCache.get(this); - } - RECT rect = new RECT(Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE); - for (BUTTONRECORD r : characters) { - CharacterTag ch = swf.getCharacter(r.characterId); - if (ch instanceof BoundedTag) { - BoundedTag bt = (BoundedTag) ch; - if (!added.contains(bt)) { - added.add(bt); - RECT r2 = bt.getRect(added); - added.remove(bt); - MATRIX mat = r.placeMatrix; - if (mat != null) { - r2 = mat.apply(r2); - } - rect.Xmin = Math.min(r2.Xmin, rect.Xmin); - rect.Ymin = Math.min(r2.Ymin, rect.Ymin); - rect.Xmax = Math.max(r2.Xmax, rect.Xmax); - rect.Ymax = Math.max(r2.Ymax, rect.Ymax); - } - } - } - rectCache.put(this, rect); - return rect; - } - - public static void clearCache() { - rectCache.clear(); - } - - @Override - public boolean trackAsMenu() { - return trackAsMenu; - } - - @Override - public int getNumFrames() { - return 1; - } - - @Override - public boolean isSingleFrame() { - if (!isSingleFrameInitialized) { - initialiteIsSingleFrame(); - } - return isSingleFrame; - } - - private synchronized void initialiteIsSingleFrame() { - if (!isSingleFrameInitialized) { - isSingleFrame = getTimeline().isSingleFrame(); - isSingleFrameInitialized = true; - } - } - - @Override - public Timeline getTimeline() { - if (timeline != null) { - return timeline; - } - - timeline = new Timeline(swf, this, new ArrayList(), buttonId, getRect()); - initTimeline(timeline); - return timeline; - } - - @Override - public void resetTimeline() { - if (timeline != null) { - timeline.reset(swf, this, new ArrayList(), buttonId, getRect()); - initTimeline(timeline); - } - } - - private void initTimeline(Timeline timeline) { - int maxDepth = 0; - Frame frameUp = new Frame(timeline, 0); - Frame frameDown = new Frame(timeline, 0); - Frame frameOver = new Frame(timeline, 0); - Frame frameHit = new Frame(timeline, 0); - for (BUTTONRECORD r : this.characters) { - - DepthState layer = new DepthState(swf, null); - layer.colorTransForm = r.colorTransform; - layer.blendMode = r.blendMode; - layer.filters = r.filterList; - layer.matrix = r.placeMatrix; - layer.characterId = r.characterId; - if (r.placeDepth > maxDepth) { - maxDepth = r.placeDepth; - } - - if (r.buttonStateUp) { - frameUp.layers.put(r.placeDepth, new DepthState(layer, frameUp, false)); - } - if (r.buttonStateDown) { - frameDown.layers.put(r.placeDepth, new DepthState(layer, frameDown, false)); - } - if (r.buttonStateOver) { - frameOver.layers.put(r.placeDepth, new DepthState(layer, frameOver, false)); - } - if (r.buttonStateHitTest) { - frameHit.layers.put(r.placeDepth, new DepthState(layer, frameHit, false)); - } - - } - - timeline.addFrame(frameUp); - - if (frameOver.layers.isEmpty()) { - frameOver = frameUp; - } - - timeline.addFrame(frameOver); - - if (frameDown.layers.isEmpty()) { - frameDown = frameOver; - } - - timeline.addFrame(frameDown); - - if (frameHit.layers.isEmpty()) { - frameHit = frameUp; - } - - timeline.addFrame(frameHit); - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.abc.CopyOutputStream; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.tags.base.ASMSourceContainer; +import com.jpexs.decompiler.flash.tags.base.BoundedTag; +import com.jpexs.decompiler.flash.tags.base.ButtonTag; +import com.jpexs.decompiler.flash.tags.base.CharacterTag; +import com.jpexs.decompiler.flash.timeline.DepthState; +import com.jpexs.decompiler.flash.timeline.Frame; +import com.jpexs.decompiler.flash.timeline.Timeline; +import com.jpexs.decompiler.flash.types.BUTTONCONDACTION; +import com.jpexs.decompiler.flash.types.BUTTONRECORD; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.MATRIX; +import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.decompiler.flash.types.annotations.Reserved; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.helpers.ByteArrayRange; +import com.jpexs.helpers.Cache; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** + * Extends the capabilities of DefineButton by allowing any state transition to + * trigger actions + * + * @author JPEXS + */ +public class DefineButton2Tag extends ButtonTag implements ASMSourceContainer { + + /** + * ID for this character + */ + @SWFType(BasicType.UI16) + public int buttonId; + + @Reserved + @SWFType(value = BasicType.UB, count = 7) + public int reserved; + + /** + * Track as menu button + */ + public boolean trackAsMenu; + + /** + * Characters that make up the button + */ + public List characters; + + /** + * Actions to execute at particular button events + */ + public List actions = new ArrayList<>(); + + public static final int ID = 34; + + public static final String NAME = "DefineButton2"; + + private Timeline timeline; + + private boolean isSingleFrameInitialized; + + private boolean isSingleFrame; + + private static final Cache rectCache = Cache.getInstance(true, true, "rect_button2"); + + @Override + public int getCharacterId() { + return buttonId; + } + + @Override + public void setCharacterId(int characterId) { + this.buttonId = characterId; + } + + @Override + public List getRecords() { + return characters; + } + + /** + * Constructor + * + * @param swf + */ + public DefineButton2Tag(SWF swf) { + super(swf, ID, NAME, null); + buttonId = swf.getNextCharacterId(); + characters = new ArrayList<>(); + } + + /** + * Constructor + * + * @param sis + * @param data + * @throws IOException + */ + public DefineButton2Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + buttonId = sis.readUI16("buttonId"); + reserved = (int) sis.readUB(7, "reserved"); + trackAsMenu = sis.readUB(1, "trackAsMenu") == 1; + int actionOffset = sis.readUI16("actionOffset"); + characters = sis.readBUTTONRECORDList(true, "characters"); + if (actionOffset > 0) { + actions = sis.readBUTTONCONDACTIONList(swf, this, "actions"); + } + } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + if (Configuration.debugCopy.get()) { + ByteArrayInputStream bais = new ByteArrayInputStream(getOriginalData()); + os = new CopyOutputStream(os, bais); + } + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(buttonId); + sos.writeUB(7, reserved); + sos.writeUB(1, trackAsMenu ? 1 : 0); + + ByteArrayOutputStream baos2 = new ByteArrayOutputStream(); + try (SWFOutputStream sos2 = new SWFOutputStream(baos2, getVersion())) { + sos2.writeBUTTONRECORDList(characters, true); + } + byte[] brdata = baos2.toByteArray(); + if ((actions == null) || (actions.isEmpty())) { + sos.writeUI16(0); + } else { + sos.writeUI16(2 + brdata.length); + } + sos.write(brdata); + sos.writeBUTTONCONDACTIONList(actions); + sos.close(); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + /** + * Returns all sub-items + * + * @return List of sub-items + */ + @Override + public List getSubItems() { + return actions; + } + + @Override + public void getNeededCharacters(Set needed) { + for (BUTTONRECORD r : characters) { + needed.add(r.characterId); + } + } + + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + boolean modified = false; + for (int i = 0; i < characters.size(); i++) { + BUTTONRECORD character = characters.get(i); + if (character.characterId == oldCharacterId) { + character.characterId = newCharacterId; + modified = true; + } + } + if (modified) { + setModified(true); + } + return modified; + } + + @Override + public boolean removeCharacter(int characterId) { + boolean modified = false; + for (int i = 0; i < characters.size(); i++) { + if (characters.get(i).characterId == characterId) { + characters.remove(i); + modified = true; + i--; + } + } + if (modified) { + setModified(true); + } + return modified; + } + + @Override + public RECT getRect(Set added) { + if (rectCache.contains(this)) { + return rectCache.get(this); + } + RECT rect = new RECT(Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE); + for (BUTTONRECORD r : characters) { + CharacterTag ch = swf.getCharacter(r.characterId); + if (ch instanceof BoundedTag) { + BoundedTag bt = (BoundedTag) ch; + if (!added.contains(bt)) { + added.add(bt); + RECT r2 = bt.getRect(added); + added.remove(bt); + MATRIX mat = r.placeMatrix; + if (mat != null) { + r2 = mat.apply(r2); + } + rect.Xmin = Math.min(r2.Xmin, rect.Xmin); + rect.Ymin = Math.min(r2.Ymin, rect.Ymin); + rect.Xmax = Math.max(r2.Xmax, rect.Xmax); + rect.Ymax = Math.max(r2.Ymax, rect.Ymax); + } + } + } + rectCache.put(this, rect); + return rect; + } + + public static void clearCache() { + rectCache.clear(); + } + + @Override + public boolean trackAsMenu() { + return trackAsMenu; + } + + @Override + public int getNumFrames() { + return 1; + } + + @Override + public boolean isSingleFrame() { + if (!isSingleFrameInitialized) { + initialiteIsSingleFrame(); + } + return isSingleFrame; + } + + private synchronized void initialiteIsSingleFrame() { + if (!isSingleFrameInitialized) { + isSingleFrame = getTimeline().isSingleFrame(); + isSingleFrameInitialized = true; + } + } + + @Override + public Timeline getTimeline() { + if (timeline != null) { + return timeline; + } + + timeline = new Timeline(swf, this, new ArrayList(), buttonId, getRect()); + initTimeline(timeline); + return timeline; + } + + @Override + public void resetTimeline() { + if (timeline != null) { + timeline.reset(swf, this, new ArrayList(), buttonId, getRect()); + initTimeline(timeline); + } + } + + private void initTimeline(Timeline timeline) { + int maxDepth = 0; + Frame frameUp = new Frame(timeline, 0); + Frame frameDown = new Frame(timeline, 0); + Frame frameOver = new Frame(timeline, 0); + Frame frameHit = new Frame(timeline, 0); + for (BUTTONRECORD r : this.characters) { + + DepthState layer = new DepthState(swf, null); + layer.colorTransForm = r.colorTransform; + layer.blendMode = r.blendMode; + layer.filters = r.filterList; + layer.matrix = r.placeMatrix; + layer.characterId = r.characterId; + if (r.placeDepth > maxDepth) { + maxDepth = r.placeDepth; + } + + if (r.buttonStateUp) { + frameUp.layers.put(r.placeDepth, new DepthState(layer, frameUp, false)); + } + if (r.buttonStateDown) { + frameDown.layers.put(r.placeDepth, new DepthState(layer, frameDown, false)); + } + if (r.buttonStateOver) { + frameOver.layers.put(r.placeDepth, new DepthState(layer, frameOver, false)); + } + if (r.buttonStateHitTest) { + frameHit.layers.put(r.placeDepth, new DepthState(layer, frameHit, false)); + } + + } + + timeline.addFrame(frameUp); + + if (frameOver.layers.isEmpty()) { + frameOver = frameUp; + } + + timeline.addFrame(frameOver); + + if (frameDown.layers.isEmpty()) { + frameDown = frameOver; + } + + timeline.addFrame(frameDown); + + if (frameHit.layers.isEmpty()) { + frameHit = frameUp; + } + + timeline.addFrame(frameHit); + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonCxformTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonCxformTag.java index b11767b78..993d55fea 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonCxformTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonCxformTag.java @@ -1,100 +1,102 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.tags.base.CharacterIdTag; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.CXFORM; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.helpers.ByteArrayRange; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -/** - * - * @author JPEXS - */ -public class DefineButtonCxformTag extends Tag implements CharacterIdTag { - - @SWFType(BasicType.UI16) - public int buttonId; - - public CXFORM buttonColorTransform; - - public static final int ID = 23; - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(buttonId); - sos.writeCXFORM(buttonColorTransform); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - - /** - * Constructor - * - * @param swf - */ - public DefineButtonCxformTag(SWF swf) { - super(swf, ID, "DefineButtonCxform", null); - buttonColorTransform = new CXFORM(); - } - - /** - * Constructor - * - * @param sis - * @param data - * @throws IOException - */ - public DefineButtonCxformTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DefineButtonCxform", data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - buttonId = sis.readUI16("buttonId"); - buttonColorTransform = sis.readCXFORM("buttonColorTransform"); - } - - @Override - public int getCharacterId() { - return buttonId; - } - - @Override - public void setCharacterId(int characterId) { - this.buttonId = characterId; - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.tags.base.CharacterIdTag; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.CXFORM; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.helpers.ByteArrayRange; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * + * @author JPEXS + */ +public class DefineButtonCxformTag extends Tag implements CharacterIdTag { + + @SWFType(BasicType.UI16) + public int buttonId; + + public CXFORM buttonColorTransform; + + public static final int ID = 23; + + public static final String NAME = "DefineButtonCxform"; + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(buttonId); + sos.writeCXFORM(buttonColorTransform); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + /** + * Constructor + * + * @param swf + */ + public DefineButtonCxformTag(SWF swf) { + super(swf, ID, NAME, null); + buttonColorTransform = new CXFORM(); + } + + /** + * Constructor + * + * @param sis + * @param data + * @throws IOException + */ + public DefineButtonCxformTag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + buttonId = sis.readUI16("buttonId"); + buttonColorTransform = sis.readCXFORM("buttonColorTransform"); + } + + @Override + public int getCharacterId() { + return buttonId; + } + + @Override + public void setCharacterId(int characterId) { + this.buttonId = characterId; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonSoundTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonSoundTag.java index 01a4a9812..cdbb04eb0 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonSoundTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonSoundTag.java @@ -1,147 +1,149 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.tags.base.CharacterIdTag; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.SOUNDINFO; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.helpers.ByteArrayRange; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -/** - * - * @author JPEXS - */ -public class DefineButtonSoundTag extends Tag implements CharacterIdTag { - - @SWFType(BasicType.UI16) - public int buttonId; - - @SWFType(BasicType.UI16) - public int buttonSoundChar0; - - public SOUNDINFO buttonSoundInfo0; - - @SWFType(BasicType.UI16) - public int buttonSoundChar1; - - public SOUNDINFO buttonSoundInfo1; - - @SWFType(BasicType.UI16) - public int buttonSoundChar2; - - public SOUNDINFO buttonSoundInfo2; - - @SWFType(BasicType.UI16) - public int buttonSoundChar3; - - public SOUNDINFO buttonSoundInfo3; - - public static final int ID = 17; - - @Override - public int getCharacterId() { - return buttonId; - } - - @Override - public void setCharacterId(int characterId) { - this.buttonId = characterId; - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(buttonId); - sos.writeUI16(buttonSoundChar0); - if (buttonSoundChar0 != 0) { - sos.writeSOUNDINFO(buttonSoundInfo0); - } - sos.writeUI16(buttonSoundChar1); - if (buttonSoundChar1 != 0) { - sos.writeSOUNDINFO(buttonSoundInfo1); - } - sos.writeUI16(buttonSoundChar2); - if (buttonSoundChar2 != 0) { - sos.writeSOUNDINFO(buttonSoundInfo2); - } - sos.writeUI16(buttonSoundChar3); - if (buttonSoundChar3 != 0) { - sos.writeSOUNDINFO(buttonSoundInfo3); - } - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - - /** - * Constructor - * - * @param swf - */ - public DefineButtonSoundTag(SWF swf) { - super(swf, ID, "DefineButtonSound", null); - } - - /** - * Constructor - * - * @param sis - * @param data - * @throws IOException - */ - public DefineButtonSoundTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DefineButtonSound", data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - buttonId = sis.readUI16("buttonId"); - buttonSoundChar0 = sis.readUI16("buttonSoundChar0"); - if (buttonSoundChar0 != 0) { - buttonSoundInfo0 = sis.readSOUNDINFO("buttonSoundInfo0"); - } - buttonSoundChar1 = sis.readUI16("buttonSoundChar1"); - if (buttonSoundChar1 != 0) { - buttonSoundInfo1 = sis.readSOUNDINFO("buttonSoundInfo1"); - } - buttonSoundChar2 = sis.readUI16("buttonSoundChar2"); - if (buttonSoundChar2 != 0) { - buttonSoundInfo2 = sis.readSOUNDINFO("buttonSoundInfo2"); - } - buttonSoundChar3 = sis.readUI16("buttonSoundChar3"); - if (buttonSoundChar3 != 0) { - buttonSoundInfo3 = sis.readSOUNDINFO("buttonSoundInfo3"); - } - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.tags.base.CharacterIdTag; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.SOUNDINFO; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.helpers.ByteArrayRange; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * + * @author JPEXS + */ +public class DefineButtonSoundTag extends Tag implements CharacterIdTag { + + @SWFType(BasicType.UI16) + public int buttonId; + + @SWFType(BasicType.UI16) + public int buttonSoundChar0; + + public SOUNDINFO buttonSoundInfo0; + + @SWFType(BasicType.UI16) + public int buttonSoundChar1; + + public SOUNDINFO buttonSoundInfo1; + + @SWFType(BasicType.UI16) + public int buttonSoundChar2; + + public SOUNDINFO buttonSoundInfo2; + + @SWFType(BasicType.UI16) + public int buttonSoundChar3; + + public SOUNDINFO buttonSoundInfo3; + + public static final int ID = 17; + + public static final String NAME = "DefineButtonSound"; + + @Override + public int getCharacterId() { + return buttonId; + } + + @Override + public void setCharacterId(int characterId) { + this.buttonId = characterId; + } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(buttonId); + sos.writeUI16(buttonSoundChar0); + if (buttonSoundChar0 != 0) { + sos.writeSOUNDINFO(buttonSoundInfo0); + } + sos.writeUI16(buttonSoundChar1); + if (buttonSoundChar1 != 0) { + sos.writeSOUNDINFO(buttonSoundInfo1); + } + sos.writeUI16(buttonSoundChar2); + if (buttonSoundChar2 != 0) { + sos.writeSOUNDINFO(buttonSoundInfo2); + } + sos.writeUI16(buttonSoundChar3); + if (buttonSoundChar3 != 0) { + sos.writeSOUNDINFO(buttonSoundInfo3); + } + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + /** + * Constructor + * + * @param swf + */ + public DefineButtonSoundTag(SWF swf) { + super(swf, ID, NAME, null); + } + + /** + * Constructor + * + * @param sis + * @param data + * @throws IOException + */ + public DefineButtonSoundTag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + buttonId = sis.readUI16("buttonId"); + buttonSoundChar0 = sis.readUI16("buttonSoundChar0"); + if (buttonSoundChar0 != 0) { + buttonSoundInfo0 = sis.readSOUNDINFO("buttonSoundInfo0"); + } + buttonSoundChar1 = sis.readUI16("buttonSoundChar1"); + if (buttonSoundChar1 != 0) { + buttonSoundInfo1 = sis.readSOUNDINFO("buttonSoundInfo1"); + } + buttonSoundChar2 = sis.readUI16("buttonSoundChar2"); + if (buttonSoundChar2 != 0) { + buttonSoundInfo2 = sis.readSOUNDINFO("buttonSoundInfo2"); + } + buttonSoundChar3 = sis.readUI16("buttonSoundChar3"); + if (buttonSoundChar3 != 0) { + buttonSoundInfo3 = sis.readSOUNDINFO("buttonSoundInfo3"); + } + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java index b4bc8aa37..138762ec9 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java @@ -1,449 +1,451 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.DisassemblyListener; -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.abc.CopyOutputStream; -import com.jpexs.decompiler.flash.action.Action; -import com.jpexs.decompiler.flash.action.ActionList; -import com.jpexs.decompiler.flash.action.ActionListReader; -import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; -import com.jpexs.decompiler.flash.helpers.GraphTextWriter; -import com.jpexs.decompiler.flash.tags.base.ASMSource; -import com.jpexs.decompiler.flash.tags.base.BoundedTag; -import com.jpexs.decompiler.flash.tags.base.ButtonTag; -import com.jpexs.decompiler.flash.tags.base.CharacterTag; -import com.jpexs.decompiler.flash.timeline.DepthState; -import com.jpexs.decompiler.flash.timeline.Frame; -import com.jpexs.decompiler.flash.timeline.Timeline; -import com.jpexs.decompiler.flash.types.BUTTONRECORD; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.ColorTransform; -import com.jpexs.decompiler.flash.types.MATRIX; -import com.jpexs.decompiler.flash.types.RECT; -import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.helpers.ByteArrayRange; -import com.jpexs.helpers.Cache; -import com.jpexs.helpers.Helper; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Defines a button character - * - * @author JPEXS - */ -public class DefineButtonTag extends ButtonTag implements ASMSource { - - /** - * ID for this character - */ - @SWFType(BasicType.UI16) - public int buttonId; - - /** - * Characters that make up the button - */ - public List characters; - - /** - * Actions to perform - */ - //public List actions; - @HideInRawEdit - public ByteArrayRange actionBytes; - - public static final int ID = 7; - - @Override - public int getCharacterId() { - return buttonId; - } - - @Override - public void setCharacterId(int characterId) { - this.buttonId = characterId; - } - - private Timeline timeline; - - private boolean isSingleFrameInitialized; - - private boolean isSingleFrame; - - private static final Cache rectCache = Cache.getInstance(true, true, "rect_button"); - - @Override - public List getRecords() { - return characters; - } - - /** - * Constructor - * - * @param swf - */ - public DefineButtonTag(SWF swf) { - super(swf, ID, "DefineButton", null); - buttonId = swf.getNextCharacterId(); - characters = new ArrayList<>(); - actionBytes = ByteArrayRange.EMPTY; - } - - /** - * Constructor - * - * @param sis - * @param data - * @throws IOException - */ - public DefineButtonTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DefineButton", data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - buttonId = sis.readUI16("buttonId"); - characters = sis.readBUTTONRECORDList(false, "characters"); - actionBytes = sis.readByteRangeEx(sis.available(), "actionBytes"); - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - if (Configuration.debugCopy.get()) { - os = new CopyOutputStream(os, new ByteArrayInputStream(getOriginalData())); - } - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(buttonId); - sos.writeBUTTONRECORDList(characters, false); - sos.write(getActionBytes()); - //sos.write(Action.actionsToBytes(actions, true, version)); - sos.close(); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - - /** - * Converts actions to ASM source - * - * @param exportMode PCode or hex? - * @param writer - * @param actions - * @return ASM source - * @throws java.lang.InterruptedException - */ - @Override - public GraphTextWriter getASMSource(ScriptExportMode exportMode, GraphTextWriter writer, ActionList actions) throws InterruptedException { - if (actions == null) { - actions = getActions(); - } - return Action.actionsToString(listeners, 0, actions, swf.version, exportMode, writer); - } - - /** - * Whether or not this object contains ASM source - * - * @return True when contains - */ - @Override - public boolean containsSource() { - return true; - } - - /** - * Returns actions associated with this object - * - * @return List of actions - * @throws java.lang.InterruptedException - */ - @Override - public ActionList getActions() throws InterruptedException { - try { - int prevLength = actionBytes.getPos(); - SWFInputStream rri = new SWFInputStream(swf, actionBytes.getArray()); - if (prevLength != 0) { - rri.seek(prevLength); - } - - ActionList list = ActionListReader.readActionListTimeout(listeners, rri, getVersion(), prevLength, prevLength + actionBytes.getLength(), toString()/*FIXME?*/); - return list; - } catch (InterruptedException ex) { - throw ex; - } catch (Exception ex) { - Logger.getLogger(DefineButtonTag.class.getName()).log(Level.SEVERE, null, ex); - return new ActionList(); - } - } - - @Override - public void setActions(List actions) { - byte[] bytes = Action.actionsToBytes(actions, true, swf.version); - actionBytes = new ByteArrayRange(bytes, 0, bytes.length); - } - - @Override - public byte[] getActionBytes() { - return actionBytes.getRangeData(); - } - - @Override - public void setActionBytes(byte[] actionBytes) { - this.actionBytes = new ByteArrayRange(actionBytes); - } - - @Override - public void setModified() { - setModified(true); - } - - @Override - public GraphTextWriter getActionBytesAsHex(GraphTextWriter writer) { - return Helper.byteArrayToHexWithHeader(writer, actionBytes.getRangeData()); - } - - @Override - public void getNeededCharacters(Set needed) { - for (BUTTONRECORD r : characters) { - needed.add(r.characterId); - } - } - - @Override - public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { - boolean modified = false; - for (int i = 0; i < characters.size(); i++) { - BUTTONRECORD character = characters.get(i); - if (character.characterId == oldCharacterId) { - character.characterId = newCharacterId; - modified = true; - } - } - if (modified) { - setModified(true); - } - return modified; - } - - @Override - public boolean removeCharacter(int characterId) { - boolean modified = false; - for (int i = 0; i < characters.size(); i++) { - if (characters.get(i).characterId == characterId) { - characters.remove(i); - modified = true; - i--; - } - } - if (modified) { - setModified(true); - } - return modified; - } - - @Override - public RECT getRect(Set added) { - if (rectCache.contains(this)) { - return rectCache.get(this); - } - RECT rect = new RECT(Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE); - for (BUTTONRECORD r : characters) { - CharacterTag ch = swf.getCharacter(r.characterId); - if (ch instanceof BoundedTag) { - BoundedTag bt = (BoundedTag) ch; - if (!added.contains(bt)) { - added.add(bt); - RECT r2 = bt.getRect(added); - added.remove(bt); - MATRIX mat = r.placeMatrix; - if (mat != null) { - r2 = mat.apply(r2); - } - rect.Xmin = Math.min(r2.Xmin, rect.Xmin); - rect.Ymin = Math.min(r2.Ymin, rect.Ymin); - rect.Xmax = Math.max(r2.Xmax, rect.Xmax); - rect.Ymax = Math.max(r2.Ymax, rect.Ymax); - } - } - } - - rectCache.put(this, rect); - return rect; - } - - public static void clearCache() { - rectCache.clear(); - } - - List listeners = new ArrayList<>(); - - @Override - public void addDisassemblyListener(DisassemblyListener listener) { - listeners.add(listener); - } - - @Override - public void removeDisassemblyListener(DisassemblyListener listener) { - listeners.remove(listener); - } - - @Override - public boolean trackAsMenu() { - return false; - } - - @Override - public int getNumFrames() { - return 1; - } - - @Override - public boolean isSingleFrame() { - if (!isSingleFrameInitialized) { - initialiteIsSingleFrame(); - } - return isSingleFrame; - } - - private synchronized void initialiteIsSingleFrame() { - if (!isSingleFrameInitialized) { - isSingleFrame = getTimeline().isSingleFrame(); - isSingleFrameInitialized = true; - } - } - - @Override - public GraphTextWriter getActionSourcePrefix(GraphTextWriter writer) { - return writer; - } - - @Override - public GraphTextWriter getActionSourceSuffix(GraphTextWriter writer) { - return writer; - } - - @Override - public int getPrefixLineCount() { - return 0; - } - - @Override - public String removePrefixAndSuffix(String source) { - return source; - } - - @Override - public Timeline getTimeline() { - if (timeline != null) { - return timeline; - } - - timeline = new Timeline(swf, this, new ArrayList(), buttonId, getRect()); - initTimeline(timeline); - return timeline; - } - - @Override - public void resetTimeline() { - if (timeline != null) { - timeline.reset(swf, this, new ArrayList(), buttonId, getRect()); - initTimeline(timeline); - } - } - - private void initTimeline(Timeline timeline) { - ColorTransform clrTrans = null; - for (Tag t : swf.tags) { - if (t instanceof DefineButtonCxformTag) { - DefineButtonCxformTag cx = (DefineButtonCxformTag) t; - clrTrans = cx.buttonColorTransform; - } - } - int maxDepth = 0; - Frame frameUp = new Frame(timeline, 0); - Frame frameDown = new Frame(timeline, 0); - Frame frameOver = new Frame(timeline, 0); - Frame frameHit = new Frame(timeline, 0); - for (BUTTONRECORD r : this.characters) { - - DepthState layer = new DepthState(swf, null); - layer.colorTransForm = clrTrans; - layer.blendMode = r.blendMode; - layer.filters = r.filterList; - layer.matrix = r.placeMatrix; - layer.characterId = r.characterId; - if (r.placeDepth > maxDepth) { - maxDepth = r.placeDepth; - } - - if (r.buttonStateUp) { - frameUp.layers.put(r.placeDepth, new DepthState(layer, frameUp, false)); - } - if (r.buttonStateDown) { - frameDown.layers.put(r.placeDepth, new DepthState(layer, frameDown, false)); - } - if (r.buttonStateOver) { - frameOver.layers.put(r.placeDepth, new DepthState(layer, frameOver, false)); - } - if (r.buttonStateHitTest) { - frameHit.layers.put(r.placeDepth, new DepthState(layer, frameHit, false)); - } - - } - - timeline.addFrame(frameUp); - if (frameOver.layers.isEmpty()) { - frameOver = frameUp; - } - timeline.addFrame(frameOver); - if (frameDown.layers.isEmpty()) { - frameDown = frameOver; - } - timeline.addFrame(frameDown); - if (frameHit.layers.isEmpty()) { - frameHit = frameUp; - } - timeline.addFrame(frameHit); - } - - @Override - public Tag getSourceTag() { - return this; - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.DisassemblyListener; +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.abc.CopyOutputStream; +import com.jpexs.decompiler.flash.action.Action; +import com.jpexs.decompiler.flash.action.ActionList; +import com.jpexs.decompiler.flash.action.ActionListReader; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; +import com.jpexs.decompiler.flash.helpers.GraphTextWriter; +import com.jpexs.decompiler.flash.tags.base.ASMSource; +import com.jpexs.decompiler.flash.tags.base.BoundedTag; +import com.jpexs.decompiler.flash.tags.base.ButtonTag; +import com.jpexs.decompiler.flash.tags.base.CharacterTag; +import com.jpexs.decompiler.flash.timeline.DepthState; +import com.jpexs.decompiler.flash.timeline.Frame; +import com.jpexs.decompiler.flash.timeline.Timeline; +import com.jpexs.decompiler.flash.types.BUTTONRECORD; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.ColorTransform; +import com.jpexs.decompiler.flash.types.MATRIX; +import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.helpers.ByteArrayRange; +import com.jpexs.helpers.Cache; +import com.jpexs.helpers.Helper; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Defines a button character + * + * @author JPEXS + */ +public class DefineButtonTag extends ButtonTag implements ASMSource { + + /** + * ID for this character + */ + @SWFType(BasicType.UI16) + public int buttonId; + + /** + * Characters that make up the button + */ + public List characters; + + /** + * Actions to perform + */ + //public List actions; + @HideInRawEdit + public ByteArrayRange actionBytes; + + public static final int ID = 7; + + public static final String NAME = "DefineButton"; + + @Override + public int getCharacterId() { + return buttonId; + } + + @Override + public void setCharacterId(int characterId) { + this.buttonId = characterId; + } + + private Timeline timeline; + + private boolean isSingleFrameInitialized; + + private boolean isSingleFrame; + + private static final Cache rectCache = Cache.getInstance(true, true, "rect_button"); + + @Override + public List getRecords() { + return characters; + } + + /** + * Constructor + * + * @param swf + */ + public DefineButtonTag(SWF swf) { + super(swf, ID, NAME, null); + buttonId = swf.getNextCharacterId(); + characters = new ArrayList<>(); + actionBytes = ByteArrayRange.EMPTY; + } + + /** + * Constructor + * + * @param sis + * @param data + * @throws IOException + */ + public DefineButtonTag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + buttonId = sis.readUI16("buttonId"); + characters = sis.readBUTTONRECORDList(false, "characters"); + actionBytes = sis.readByteRangeEx(sis.available(), "actionBytes"); + } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + if (Configuration.debugCopy.get()) { + os = new CopyOutputStream(os, new ByteArrayInputStream(getOriginalData())); + } + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(buttonId); + sos.writeBUTTONRECORDList(characters, false); + sos.write(getActionBytes()); + //sos.write(Action.actionsToBytes(actions, true, version)); + sos.close(); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + /** + * Converts actions to ASM source + * + * @param exportMode PCode or hex? + * @param writer + * @param actions + * @return ASM source + * @throws java.lang.InterruptedException + */ + @Override + public GraphTextWriter getASMSource(ScriptExportMode exportMode, GraphTextWriter writer, ActionList actions) throws InterruptedException { + if (actions == null) { + actions = getActions(); + } + return Action.actionsToString(listeners, 0, actions, swf.version, exportMode, writer); + } + + /** + * Whether or not this object contains ASM source + * + * @return True when contains + */ + @Override + public boolean containsSource() { + return true; + } + + /** + * Returns actions associated with this object + * + * @return List of actions + * @throws java.lang.InterruptedException + */ + @Override + public ActionList getActions() throws InterruptedException { + try { + int prevLength = actionBytes.getPos(); + SWFInputStream rri = new SWFInputStream(swf, actionBytes.getArray()); + if (prevLength != 0) { + rri.seek(prevLength); + } + + ActionList list = ActionListReader.readActionListTimeout(listeners, rri, getVersion(), prevLength, prevLength + actionBytes.getLength(), toString()/*FIXME?*/); + return list; + } catch (InterruptedException ex) { + throw ex; + } catch (Exception ex) { + Logger.getLogger(DefineButtonTag.class.getName()).log(Level.SEVERE, null, ex); + return new ActionList(); + } + } + + @Override + public void setActions(List actions) { + byte[] bytes = Action.actionsToBytes(actions, true, swf.version); + actionBytes = new ByteArrayRange(bytes, 0, bytes.length); + } + + @Override + public byte[] getActionBytes() { + return actionBytes.getRangeData(); + } + + @Override + public void setActionBytes(byte[] actionBytes) { + this.actionBytes = new ByteArrayRange(actionBytes); + } + + @Override + public void setModified() { + setModified(true); + } + + @Override + public GraphTextWriter getActionBytesAsHex(GraphTextWriter writer) { + return Helper.byteArrayToHexWithHeader(writer, actionBytes.getRangeData()); + } + + @Override + public void getNeededCharacters(Set needed) { + for (BUTTONRECORD r : characters) { + needed.add(r.characterId); + } + } + + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + boolean modified = false; + for (int i = 0; i < characters.size(); i++) { + BUTTONRECORD character = characters.get(i); + if (character.characterId == oldCharacterId) { + character.characterId = newCharacterId; + modified = true; + } + } + if (modified) { + setModified(true); + } + return modified; + } + + @Override + public boolean removeCharacter(int characterId) { + boolean modified = false; + for (int i = 0; i < characters.size(); i++) { + if (characters.get(i).characterId == characterId) { + characters.remove(i); + modified = true; + i--; + } + } + if (modified) { + setModified(true); + } + return modified; + } + + @Override + public RECT getRect(Set added) { + if (rectCache.contains(this)) { + return rectCache.get(this); + } + RECT rect = new RECT(Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE); + for (BUTTONRECORD r : characters) { + CharacterTag ch = swf.getCharacter(r.characterId); + if (ch instanceof BoundedTag) { + BoundedTag bt = (BoundedTag) ch; + if (!added.contains(bt)) { + added.add(bt); + RECT r2 = bt.getRect(added); + added.remove(bt); + MATRIX mat = r.placeMatrix; + if (mat != null) { + r2 = mat.apply(r2); + } + rect.Xmin = Math.min(r2.Xmin, rect.Xmin); + rect.Ymin = Math.min(r2.Ymin, rect.Ymin); + rect.Xmax = Math.max(r2.Xmax, rect.Xmax); + rect.Ymax = Math.max(r2.Ymax, rect.Ymax); + } + } + } + + rectCache.put(this, rect); + return rect; + } + + public static void clearCache() { + rectCache.clear(); + } + + List listeners = new ArrayList<>(); + + @Override + public void addDisassemblyListener(DisassemblyListener listener) { + listeners.add(listener); + } + + @Override + public void removeDisassemblyListener(DisassemblyListener listener) { + listeners.remove(listener); + } + + @Override + public boolean trackAsMenu() { + return false; + } + + @Override + public int getNumFrames() { + return 1; + } + + @Override + public boolean isSingleFrame() { + if (!isSingleFrameInitialized) { + initialiteIsSingleFrame(); + } + return isSingleFrame; + } + + private synchronized void initialiteIsSingleFrame() { + if (!isSingleFrameInitialized) { + isSingleFrame = getTimeline().isSingleFrame(); + isSingleFrameInitialized = true; + } + } + + @Override + public GraphTextWriter getActionSourcePrefix(GraphTextWriter writer) { + return writer; + } + + @Override + public GraphTextWriter getActionSourceSuffix(GraphTextWriter writer) { + return writer; + } + + @Override + public int getPrefixLineCount() { + return 0; + } + + @Override + public String removePrefixAndSuffix(String source) { + return source; + } + + @Override + public Timeline getTimeline() { + if (timeline != null) { + return timeline; + } + + timeline = new Timeline(swf, this, new ArrayList(), buttonId, getRect()); + initTimeline(timeline); + return timeline; + } + + @Override + public void resetTimeline() { + if (timeline != null) { + timeline.reset(swf, this, new ArrayList(), buttonId, getRect()); + initTimeline(timeline); + } + } + + private void initTimeline(Timeline timeline) { + ColorTransform clrTrans = null; + for (Tag t : swf.tags) { + if (t instanceof DefineButtonCxformTag) { + DefineButtonCxformTag cx = (DefineButtonCxformTag) t; + clrTrans = cx.buttonColorTransform; + } + } + int maxDepth = 0; + Frame frameUp = new Frame(timeline, 0); + Frame frameDown = new Frame(timeline, 0); + Frame frameOver = new Frame(timeline, 0); + Frame frameHit = new Frame(timeline, 0); + for (BUTTONRECORD r : this.characters) { + + DepthState layer = new DepthState(swf, null); + layer.colorTransForm = clrTrans; + layer.blendMode = r.blendMode; + layer.filters = r.filterList; + layer.matrix = r.placeMatrix; + layer.characterId = r.characterId; + if (r.placeDepth > maxDepth) { + maxDepth = r.placeDepth; + } + + if (r.buttonStateUp) { + frameUp.layers.put(r.placeDepth, new DepthState(layer, frameUp, false)); + } + if (r.buttonStateDown) { + frameDown.layers.put(r.placeDepth, new DepthState(layer, frameDown, false)); + } + if (r.buttonStateOver) { + frameOver.layers.put(r.placeDepth, new DepthState(layer, frameOver, false)); + } + if (r.buttonStateHitTest) { + frameHit.layers.put(r.placeDepth, new DepthState(layer, frameHit, false)); + } + + } + + timeline.addFrame(frameUp); + if (frameOver.layers.isEmpty()) { + frameOver = frameUp; + } + timeline.addFrame(frameOver); + if (frameDown.layers.isEmpty()) { + frameDown = frameOver; + } + timeline.addFrame(frameDown); + if (frameHit.layers.isEmpty()) { + frameHit = frameUp; + } + timeline.addFrame(frameHit); + } + + @Override + public Tag getSourceTag() { + return this; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java index aa7941be6..782a2d45f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java @@ -1,1134 +1,1136 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.decompiler.flash.exporters.commonshape.ExportRectangle; -import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; -import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; -import com.jpexs.decompiler.flash.helpers.HighlightedText; -import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter; -import com.jpexs.decompiler.flash.helpers.hilight.HighlightSpecialType; -import com.jpexs.decompiler.flash.tags.base.BoundedTag; -import com.jpexs.decompiler.flash.tags.base.FontTag; -import com.jpexs.decompiler.flash.tags.base.MissingCharacterHandler; -import com.jpexs.decompiler.flash.tags.base.RenderContext; -import com.jpexs.decompiler.flash.tags.base.TextTag; -import com.jpexs.decompiler.flash.tags.dynamictext.CharacterWithStyle; -import com.jpexs.decompiler.flash.tags.dynamictext.DynamicTextModel; -import com.jpexs.decompiler.flash.tags.dynamictext.GlyphCharacter; -import com.jpexs.decompiler.flash.tags.dynamictext.Paragraph; -import com.jpexs.decompiler.flash.tags.dynamictext.SameStyleTextRecord; -import com.jpexs.decompiler.flash.tags.dynamictext.TextStyle; -import com.jpexs.decompiler.flash.tags.dynamictext.Word; -import com.jpexs.decompiler.flash.tags.text.ParsedSymbol; -import com.jpexs.decompiler.flash.tags.text.TextAlign; -import com.jpexs.decompiler.flash.tags.text.TextLexer; -import com.jpexs.decompiler.flash.tags.text.TextParseException; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.ColorTransform; -import com.jpexs.decompiler.flash.types.GLYPHENTRY; -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.TEXTRECORD; -import com.jpexs.decompiler.flash.types.annotations.Conditional; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.helpers.ByteArrayRange; -import com.jpexs.helpers.SerializableImage; -import com.jpexs.helpers.utf8.Utf8Helper; -import java.awt.Color; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.io.StringReader; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Set; -import java.util.Stack; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; -import org.xml.sax.Attributes; -import org.xml.sax.SAXException; -import org.xml.sax.helpers.DefaultHandler; - -/** - * - * @author JPEXS - */ -public class DefineEditTextTag extends TextTag { - - @SWFType(BasicType.UI16) - public int characterID; - - public RECT bounds; - - public boolean hasText; - - public boolean wordWrap; - - public boolean multiline; - - public boolean password; - - public boolean readOnly; - - public boolean hasTextColor; - - public boolean hasMaxLength; - - public boolean hasFont; - - public boolean hasFontClass; - - public boolean autoSize; - - public boolean hasLayout; - - public boolean noSelect; - - public boolean border; - - public boolean wasStatic; - - public boolean html; - - public boolean useOutlines; - - @SWFType(BasicType.UI16) - @Conditional("hasFont") - public int fontId; - - @Conditional("hasFontClass") - public String fontClass; - - @SWFType(BasicType.UI16) - @Conditional("hasFont") - public int fontHeight; - - @Conditional("hasTextColor") - public RGBA textColor; - - @SWFType(BasicType.UI16) - @Conditional("hasMaxLength") - public int maxLength; - - @SWFType(BasicType.UI8) - @Conditional("hasLayout") - public int align; - - @SWFType(BasicType.UI16) - @Conditional("hasLayout") - public int leftMargin; - - @SWFType(BasicType.UI16) - @Conditional("hasLayout") - public int rightMargin; - - @SWFType(BasicType.UI16) - @Conditional("hasLayout") - public int indent; - - @SWFType(BasicType.SI16) - @Conditional("hasLayout") - public int leading; - - public String variableName; - - @Conditional("hasText") - public String initialText; - - public static final int ID = 37; - - @Override - public RECT getBounds() { - return bounds; - } - - @Override - public MATRIX getTextMatrix() { - MATRIX matrix = new MATRIX(); - matrix.translateX = bounds.Xmin; - matrix.translateY = bounds.Ymin; - return matrix; - } - - @Override - public void setBounds(RECT r) { - bounds = r; - } - - private String stripTags(String inp) { - boolean intag = false; - String outp = ""; - inp = inp.replaceAll("
", "\r\n"); - for (int i = 0; i < inp.length(); ++i) { - if (!intag && inp.charAt(i) == '<') { - intag = true; - continue; - } - if (intag && inp.charAt(i) == '>') { - intag = false; - continue; - } - if (!intag) { - outp += inp.charAt(i); - } - } - return outp; - } - - private String entitiesReplace(String s) { - s = s.replace("<", "<"); - s = s.replace(">", ">"); - s = s.replace("&", "&"); - s = s.replace(""", "\""); - return s; - } - - @Override - public List getTexts() { - String ret = ""; - if (hasText) { - ret = initialText; - } - if (html) { - ret = stripTags(ret); - ret = entitiesReplace(ret); - } - return Arrays.asList(ret); - } - - private List getTextWithStyle() { - String str = ""; - TextStyle style = new TextStyle(); - style.font = swf.getFont(fontId); - style.fontHeight = fontHeight; - style.fontLeading = leading; - if (hasTextColor) { - style.textColor = textColor; - } - if (hasText) { - str = initialText; - } - final List ret = new ArrayList<>(); - if (html) { - SAXParserFactory factory = SAXParserFactory.newInstance(); - SAXParser saxParser; - final Stack styles = new Stack<>(); - styles.add(style); - try { - saxParser = factory.newSAXParser(); - DefaultHandler handler = new DefaultHandler() { - - @Override - public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { - TextStyle style = styles.peek(); - switch (qName) { - case "p": - // todo: parse the following attribute: - // align - break; - case "b": - style = style.clone(); - style.bold = true; - styles.add(style); - break; - case "i": - style = style.clone(); - style.italic = true; - styles.add(style); - break; - case "u": - style = style.clone(); - style.underlined = true; - styles.add(style); - break; - case "font": - style = style.clone(); - String color = attributes.getValue("color"); - if (color != null) { - if (color.startsWith("#")) { - style.textColor = new RGBA(Color.decode(color)); - } - } - String size = attributes.getValue("size"); - if (size != null && size.length() > 0) { - char firstChar = size.charAt(0); - if (firstChar != '+' && firstChar != '-') { - int fontSize = Integer.parseInt(size); - style.fontHeight = (int) Math.round(fontSize * (style.font == null ? 1 : style.font.getDivider())); - style.fontLeading = leading; - } else { - // todo: parse relative sizes - } - } - // todo: parse the following attributes: - // face, letterSpacing, kerning - styles.add(style); - break; - case "br": - case "sbr": // what's this? - CharacterWithStyle cs = new CharacterWithStyle(); - cs.character = '\n'; - cs.style = style; - ret.add(cs); - break; - } - //ret = entitiesReplace(ret); - } - - @Override - public void endElement(String uri, String localName, String qName) throws SAXException { - switch (qName) { - case "b": - case "i": - case "u": - case "font": - styles.pop(); - break; - case "p": - TextStyle style = styles.peek(); - CharacterWithStyle cs = new CharacterWithStyle(); - cs.character = '\n'; - cs.style = style; - ret.add(cs); - break; - } - } - - @Override - public void characters(char[] ch, int start, int length) throws SAXException { - String txt = new String(ch, start, length); - TextStyle style = styles.peek(); - addCharacters(ret, txt, style); - } - }; - str = " \n" - + "]>" + str + ""; - saxParser.parse(new ByteArrayInputStream(str.getBytes(Utf8Helper.charset)), handler); - } catch (ParserConfigurationException | SAXException | IOException ex) { - Logger.getLogger(DefineEditTextTag.class.getName()).log(Level.SEVERE, null, ex); - } - } else { - addCharacters(ret, str, style); - } - return ret; - } - - private void addCharacters(List list, String str, TextStyle style) { - for (int i = 0; i < str.length(); i++) { - char ch = str.charAt(i); - CharacterWithStyle cs = new CharacterWithStyle(); - cs.character = ch; - cs.style = style; - list.add(cs); - } - } - - @Override - public List getFontIds() { - List ret = new ArrayList<>(); - ret.add(fontId); - return ret; - } - - @Override - public HighlightedText getFormattedText() { - HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), true); - writer.append("["); - String[] alignNames = {"left", "right", "center", "justify"}; - String alignment; - if (align < alignNames.length) { - alignment = alignNames[align]; - } else { - alignment = "unknown"; - } - writer.newLine(); - writer.append("xmin " + bounds.Xmin).newLine(); - writer.append("ymin " + bounds.Ymin).newLine(); - writer.append("xmax " + bounds.Xmax).newLine(); - writer.append("ymax " + bounds.Ymax).newLine(); - if (wordWrap) { - writer.append("wordwrap 1").newLine(); - } - if (multiline) { - writer.append("multiline 1").newLine(); - } - if (password) { - writer.append("password 1").newLine(); - } - if (readOnly) { - writer.append("readonly 1").newLine(); - } - if (autoSize) { - writer.append("autosize 1").newLine(); - } - if (noSelect) { - writer.append("noselect 1").newLine(); - } - if (border) { - writer.append("border 1").newLine(); - } - if (wasStatic) { - writer.append("wasstatic 1").newLine(); - } - if (html) { - writer.append("html 1").newLine(); - } - if (useOutlines) { - writer.append("useoutlines 1").newLine(); - } - if (hasFont) { - writer.append("font " + fontId).newLine(); - writer.append("height " + fontHeight).newLine(); - } - if (hasTextColor) { - writer.append("color " + textColor.toHexARGB()).newLine(); - } - if (hasFontClass) { - writer.append("fontclass " + fontClass).newLine(); - } - if (hasMaxLength) { - writer.append("maxlength " + maxLength).newLine(); - } - writer.append("align " + alignment).newLine(); - if (hasLayout) { - writer.append("leftmargin " + leftMargin).newLine(); - writer.append("rightmargin " + rightMargin).newLine(); - writer.append("indent " + indent).newLine(); - writer.append("leading " + leading).newLine(); - } - if (!variableName.isEmpty()) { - writer.append("variablename " + variableName).newLine(); - } - writer.append("]"); - if (hasText) { - String text = initialText.replace("\\", "\\\\").replace("[", "\\[").replace("]", "\\]"); - writer.hilightSpecial(text, HighlightSpecialType.TEXT); - } - return new HighlightedText(writer); - } - - @Override - public boolean setFormattedText(MissingCharacterHandler missingCharHandler, String formattedText, String[] texts) throws TextParseException { - try { - TextLexer lexer = new TextLexer(new StringReader(formattedText)); - ParsedSymbol s = null; - formattedText = ""; - RECT bounds = new RECT(this.bounds); - boolean wordWrap = false; - boolean multiline = false; - boolean password = false; - boolean readOnly = false; - boolean autoSize = false; - boolean noSelect = false; - boolean border = false; - boolean wasStatic = false; - boolean html = false; - boolean useOutlines = false; - int fontId = -1; - int fontHeight = -1; - String fontClass = null; - RGBA textColor = null; - int maxLength = -1; - int align = -1; - int leftMargin = -1; - int rightMargin = -1; - int indent = -1; - int leading = -1; - String variableName = null; - - int textIdx = 0; - while ((s = lexer.yylex()) != null) { - switch (s.type) { - case PARAMETER: - String paramName = (String) s.values[0]; - String paramValue = (String) s.values[1]; - switch (paramName) { - case "xmin": - try { - bounds.Xmin = Integer.parseInt(paramValue); - } catch (NumberFormatException nfe) { - throw new TextParseException("Invalid xmin value. Number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "ymin": - try { - bounds.Ymin = Integer.parseInt(paramValue); - } catch (NumberFormatException nfe) { - throw new TextParseException("Invalid ymin value. Number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "xmax": - try { - bounds.Xmax = Integer.parseInt(paramValue); - } catch (NumberFormatException nfe) { - throw new TextParseException("Invalid xmax value. Number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "ymax": - try { - bounds.Ymax = Integer.parseInt(paramValue); - } catch (NumberFormatException nfe) { - throw new TextParseException("Invalid ymax value. Number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "wordwrap": - if (paramValue.equals("1")) { - wordWrap = true; - } - break; - case "multiline": - if (paramValue.equals("1")) { - multiline = true; - } - break; - case "password": - if (paramValue.equals("1")) { - password = true; - } - break; - case "readonly": - if (paramValue.equals("1")) { - readOnly = true; - } - break; - case "autosize": - if (paramValue.equals("1")) { - autoSize = true; - } - break; - case "noselect": - if (paramValue.equals("1")) { - noSelect = true; - } - break; - case "border": - if (paramValue.equals("1")) { - border = true; - } - break; - case "wasstatic": - if (paramValue.equals("1")) { - wasStatic = true; - } - break; - case "html": - if (paramValue.equals("1")) { - html = true; - } - break; - case "useoutlines": - if (paramValue.equals("1")) { - useOutlines = true; - } - break; - case "font": - try { - fontId = Integer.parseInt(paramValue); - - FontTag ft = swf.getFont(fontId); - if (ft == null) { - throw new TextParseException("Font not found.", lexer.yyline()); - } - } catch (NumberFormatException ne) { - throw new TextParseException("Invalid font value. Number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "fontclass": - fontClass = paramValue; - break; - case "height": - try { - fontHeight = Integer.parseInt(paramValue); - } catch (NumberFormatException ne) { - throw new TextParseException("Invalid height value. Number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "color": - Matcher m = Pattern.compile("#([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])").matcher(paramValue); - if (m.matches()) { - textColor = new RGBA(Integer.parseInt(m.group(2), 16), Integer.parseInt(m.group(3), 16), Integer.parseInt(m.group(4), 16), Integer.parseInt(m.group(1), 16)); - } else { - throw new TextParseException("Invalid color. Valid format is #aarrggbb. Found: " + paramValue, lexer.yyline()); - } - break; - case "maxlength": - try { - maxLength = Integer.parseInt(paramValue); - } catch (NumberFormatException ne) { - throw new TextParseException("Invalid maxLength value. Number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "align": - switch (paramValue) { - case "left": - align = 0; - break; - case "right": - align = 1; - break; - case "center": - align = 2; - break; - case "justify": - align = 3; - break; - default: - throw new TextParseException("Invalid align value. Expected one of: left,right,center or justify. Found: " + paramValue, lexer.yyline()); - } - break; - case "leftmargin": - try { - leftMargin = Integer.parseInt(paramValue); - } catch (NumberFormatException ne) { - throw new TextParseException("Invalid leftmargin value. Number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "rightmargin": - try { - rightMargin = Integer.parseInt(paramValue); - } catch (NumberFormatException ne) { - throw new TextParseException("Invalid rightmargin value. Number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "indent": - try { - indent = Integer.parseInt(paramValue); - } catch (NumberFormatException ne) { - throw new TextParseException("Invalid indent value. Number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "leading": - try { - leading = Integer.parseInt(paramValue); - } catch (NumberFormatException ne) { - throw new TextParseException("Invalid leading value. Number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "variablename": - variableName = paramValue; - break; - default: - throw new TextParseException("Unrecognized parameter name: " + paramName, lexer.yyline()); - } - break; - case TEXT: - String s2 = (String) s.values[0]; - if (s2 == null) { - s2 = ""; - } - - formattedText += (texts == null || textIdx >= texts.length) ? s2 : texts[textIdx++]; - formattedText = formattedText.replace("\r\n", "\r"); - break; - } - } - - setModified(true); - this.bounds = bounds; - if (formattedText.length() > 0) { - initialText = formattedText; - this.hasText = true; - } else { - this.hasText = false; - } - this.wordWrap = wordWrap; - this.multiline = multiline; - this.password = password; - this.readOnly = readOnly; - this.noSelect = noSelect; - this.border = border; - this.wasStatic = wasStatic; - this.html = html; - this.useOutlines = useOutlines; - if (textColor != null) { - hasTextColor = true; - this.textColor = textColor; - } - if (maxLength > -1) { - this.maxLength = maxLength; - hasMaxLength = true; - } - if (fontId > -1) { - this.fontId = fontId; - } - if (fontHeight > -1) { - this.fontHeight = fontHeight; - } - if (fontClass != null) { - this.fontClass = fontClass; - hasFontClass = true; - } - this.autoSize = autoSize; - this.align = align; - if ((leftMargin > -1) - || (rightMargin > -1) - || (indent > -1) - || (leading > -1)) { - this.leftMargin = leftMargin; - this.rightMargin = rightMargin; - this.indent = indent; - this.leading = leading; - hasLayout = true; - } - if (variableName == null) { - variableName = ""; - } - this.variableName = variableName; - - } catch (IOException ex) { - Logger.getLogger(DefineEditTextTag.class.getName()).log(Level.SEVERE, null, ex); - return false; - } - - return true; - } - - @Override - public void updateTextBounds() { - } - - @Override - public boolean alignText(TextAlign textAlign) { - return true; - } - - @Override - public boolean translateText(int diff) { - return true; - } - - @Override - public RECT getRect(Set added) { - return bounds; - } - - @Override - public int getCharacterId() { - return characterID; - } - - @Override - public void setCharacterId(int characterId) { - this.characterID = characterId; - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(characterID); - sos.writeRECT(bounds); - sos.writeUB(1, hasText ? 1 : 0); - sos.writeUB(1, wordWrap ? 1 : 0); - sos.writeUB(1, multiline ? 1 : 0); - sos.writeUB(1, password ? 1 : 0); - sos.writeUB(1, readOnly ? 1 : 0); - sos.writeUB(1, hasTextColor ? 1 : 0); - sos.writeUB(1, hasMaxLength ? 1 : 0); - sos.writeUB(1, hasFont ? 1 : 0); - sos.writeUB(1, hasFontClass ? 1 : 0); - sos.writeUB(1, autoSize ? 1 : 0); - sos.writeUB(1, hasLayout ? 1 : 0); - sos.writeUB(1, noSelect ? 1 : 0); - sos.writeUB(1, border ? 1 : 0); - sos.writeUB(1, wasStatic ? 1 : 0); - sos.writeUB(1, html ? 1 : 0); - sos.writeUB(1, useOutlines ? 1 : 0); - if (hasFont) { - sos.writeUI16(fontId); - } - if (hasFontClass) { - sos.writeString(fontClass); - } - if (hasFont) { - sos.writeUI16(fontHeight); - } - if (hasTextColor) { - sos.writeRGBA(textColor); - } - if (hasMaxLength) { - sos.writeUI16(maxLength); - } - if (hasLayout) { - sos.writeUI8(align); - sos.writeUI16(leftMargin); - sos.writeUI16(rightMargin); - sos.writeUI16(indent); - sos.writeSI16(leading); - } - sos.writeString(variableName); - if (hasText) { - sos.writeString(initialText); - } - - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - - /** - * Constructor - * - * @param swf - */ - public DefineEditTextTag(SWF swf) { - super(swf, ID, "DefineEditText", null); - characterID = swf.getNextCharacterId(); - bounds = new RECT(); - variableName = ""; - } - - /** - * Constructor - * - * @param sis - * @param data - * @throws IOException - */ - public DefineEditTextTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DefineEditText", data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - characterID = sis.readUI16("characterID"); - bounds = sis.readRECT("bounds"); - hasText = sis.readUB(1, "hasText") == 1; - wordWrap = sis.readUB(1, "wordWrap") == 1; - multiline = sis.readUB(1, "multiline") == 1; - password = sis.readUB(1, "password") == 1; - readOnly = sis.readUB(1, "readOnly") == 1; - hasTextColor = sis.readUB(1, "hasTextColor") == 1; - hasMaxLength = sis.readUB(1, "hasMaxLength") == 1; - hasFont = sis.readUB(1, "hasFont") == 1; - hasFontClass = sis.readUB(1, "hasFontClass") == 1; - autoSize = sis.readUB(1, "autoSize") == 1; - hasLayout = sis.readUB(1, "hasLayout") == 1; - noSelect = sis.readUB(1, "noSelect") == 1; - border = sis.readUB(1, "border") == 1; - wasStatic = sis.readUB(1, "wasStatic") == 1; - html = sis.readUB(1, "html") == 1; - useOutlines = sis.readUB(1, "useOutlines") == 1; - if (hasFont) { - fontId = sis.readUI16("fontId"); - } - if (hasFontClass) { - fontClass = sis.readString("fontClass"); - } - if (hasFont) { - fontHeight = sis.readUI16("fontHeight"); - } - if (hasTextColor) { - textColor = sis.readRGBA("textColor"); - } - if (hasMaxLength) { - maxLength = sis.readUI16("maxLength"); - } - if (hasLayout) { - align = sis.readUI8("align"); //0 left, 1 right, 2 center, 3 justify - leftMargin = sis.readUI16("leftMargin"); - rightMargin = sis.readUI16("rightMargin"); - indent = sis.readUI16("indent"); - leading = sis.readSI16("leading"); - } - variableName = sis.readString("variableName"); - if (hasText) { - initialText = sis.readString("initialText"); - } - - } - - @Override - public void getNeededCharacters(Set needed) { - if (hasFont) { - needed.add(fontId); - } - } - - @Override - public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { - if (fontId == oldCharacterId) { - fontId = newCharacterId; - setModified(true); - return true; - } - return false; - } - - @Override - public boolean removeCharacter(int characterId) { - if (fontId == characterId) { - hasFont = false; - fontId = 0; - setModified(true); - return true; - } - return false; - } - - @Override - public int getUsedParameters() { - return 0; - } - - @Override - public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, Matrix transformation, ColorTransform colorTransform) { - render(false, image, transformation, colorTransform); - } - - @Override - public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, double zoom) { - // todo: implement - } - - @Override - public String toHtmlCanvas(double unitDivisor) { - return render(true, null, new Matrix(), new ColorTransform()); - } - - private String render(boolean canvas, SerializableImage image, Matrix transformation, ColorTransform colorTransform) { - if (border) { - // border is always black, fill color is always white? - RGB borderColor = new RGBA(Color.black); - RGB fillColor = new RGBA(Color.white); - if (!canvas) { - drawBorder(swf, image, borderColor, fillColor, getRect(), getTextMatrix(), transformation, colorTransform); - } else { - // TODO: draw border - } - } - if (hasText) { - DynamicTextModel textModel = new DynamicTextModel(); - List txt = getTextWithStyle(); - TextStyle lastStyle = null; - char prevChar = 0; - boolean lastWasWhiteSpace = false; - for (int i = 0; i < txt.size(); i++) { - CharacterWithStyle cs = txt.get(i); - char c = cs.character; - if (c != '\r' && c != '\n') { - // create new SameStyleTextRecord for all words and all diffrent style text parts - if (lastWasWhiteSpace && !Character.isWhitespace(c)) { - textModel.newWord(); - lastWasWhiteSpace = false; - } - if (cs.style != lastStyle) { - lastStyle = cs.style; - textModel.style = lastStyle; - textModel.newRecord(); - } - Character nextChar = null; - if (i + 1 < txt.size()) { - nextChar = txt.get(i + 1).character; - } - int advance; - FontTag font = lastStyle.font; - GLYPHENTRY ge = new GLYPHENTRY(); - ge.glyphIndex = font == null ? -1 : font.charToGlyph(c); - if (font != null && font.hasLayout()) { - int kerningAdjustment = 0; - if (nextChar != null) { - kerningAdjustment = font.getCharKerningAdjustment(c, nextChar); - kerningAdjustment /= font.getDivider(); - } - advance = (int) Math.round(Math.round((double) lastStyle.fontHeight * (font.getGlyphAdvance(ge.glyphIndex) + kerningAdjustment) / (font.getDivider() * 1024.0))); - } else { - String fontName = FontTag.defaultFontName; - int fontStyle = font == null ? 0 : font.getFontStyle(); - advance = (int) Math.round(SWF.unitDivisor * FontTag.getSystemFontAdvance(fontName, fontStyle, (int) (lastStyle.fontHeight / SWF.unitDivisor), c, nextChar)); - } - ge.glyphAdvance = advance; - textModel.addGlyph(c, ge); - if (Character.isWhitespace(c)) { - lastWasWhiteSpace = true; - } - } else { - if (multiline) { - textModel.newParagraph(); - } - } - prevChar = c; - } - - textModel.calculateTextWidths(); - List> lines; - if (multiline && wordWrap) { - lines = new ArrayList<>(); - for (Paragraph paragraph : textModel.paragraphs) { - List line = new ArrayList<>(); - int lineLength = 0; - for (Word word : paragraph.words) { - if (lineLength + word.width <= bounds.getWidth()) { - line.addAll(word.records); - lineLength += word.width; - } else { - lines.add(line); - line = new ArrayList<>(); - line.addAll(word.records); - lineLength = 0; - } - } - if (!line.isEmpty()) { - lines.add(line); - } - } - } else { - lines = new ArrayList<>(); - for (Paragraph paragraph : textModel.paragraphs) { - List line = new ArrayList<>(); - for (Word word : paragraph.words) { - for (SameStyleTextRecord tr : word.records) { - line.add(tr); - } - } - lines.add(line); - } - } - - // remove spaces after last word - for (List line : lines) { - boolean removed = true; - while (removed) { - removed = false; - while (line.size() > 0 && line.get(line.size() - 1).glyphEntries.isEmpty()) { - line.remove(line.size() - 1); - removed = true; - } - if (line.size() > 0) { - SameStyleTextRecord lastRecord = line.get(line.size() - 1); - while (lastRecord.glyphEntries.size() > 0 - && Character.isWhitespace(lastRecord.glyphEntries.get(lastRecord.glyphEntries.size() - 1).character)) { - lastRecord.glyphEntries.remove(lastRecord.glyphEntries.size() - 1); - removed = true; - } - } - } - } - - textModel.calculateTextWidths(); - - List allTextRecords = new ArrayList<>(); - int lastHeight = 0; - int yOffset = 0; - for (List line : lines) { - int width = 0; - int currentOffset = 0; - if (line.isEmpty()) { - currentOffset = lastHeight; - } else { - for (SameStyleTextRecord tr : line) { - width += tr.width; - int lineHeight = tr.style.fontHeight + tr.style.fontLeading; - lastHeight = lineHeight; - if (lineHeight > currentOffset) { - currentOffset = lineHeight; - } - } - } - yOffset += currentOffset; - int alignOffset = 0; - switch (align) { - case 0: // left - alignOffset = 0; - break; - case 1: // right - alignOffset = bounds.getWidth() - width; - break; - case 2: // center - alignOffset = (bounds.getWidth() - width) / 2; - break; - case 3: // justify - // todo; - break; - } - for (SameStyleTextRecord tr : line) { - tr.xOffset = alignOffset; - alignOffset += tr.width; - } - for (SameStyleTextRecord tr : line) { - TEXTRECORD tr2 = new TEXTRECORD(); - tr2.styleFlagsHasFont = fontId != 0; - tr2.fontId = fontId; - tr2.textHeight = tr.style.fontHeight; - if (tr.style.textColor != null) { - tr2.styleFlagsHasColor = true; - tr2.textColorA = tr.style.textColor; - } - // always add xOffset, because no xOffset and 0 xOffset is diffrent in text rendering - tr2.styleFlagsHasXOffset = true; - tr2.xOffset = tr.xOffset; - if (yOffset != 0) { - tr2.styleFlagsHasYOffset = true; - tr2.yOffset = yOffset; - } - tr2.glyphEntries = new ArrayList<>(tr.glyphEntries.size()); - for (GlyphCharacter ge : tr.glyphEntries) { - tr2.glyphEntries.add(ge.glyphEntry); - } - allTextRecords.add(tr2); - } - } - - if (canvas) { - return staticTextToHtmlCanvas(1, swf, allTextRecords, 2, getBounds(), getTextMatrix(), colorTransform); - } else { - staticTextToImage(swf, allTextRecords, 2, image, getTextMatrix(), transformation, colorTransform); - } - } - - return ""; - } - - @Override - public ExportRectangle calculateTextBounds() { - return null; - } - - @Override - public int getNumFrames() { - return 1; - } - - @Override - public boolean isSingleFrame() { - return true; - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.exporters.commonshape.ExportRectangle; +import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; +import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; +import com.jpexs.decompiler.flash.helpers.HighlightedText; +import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter; +import com.jpexs.decompiler.flash.helpers.hilight.HighlightSpecialType; +import com.jpexs.decompiler.flash.tags.base.BoundedTag; +import com.jpexs.decompiler.flash.tags.base.FontTag; +import com.jpexs.decompiler.flash.tags.base.MissingCharacterHandler; +import com.jpexs.decompiler.flash.tags.base.RenderContext; +import com.jpexs.decompiler.flash.tags.base.TextTag; +import com.jpexs.decompiler.flash.tags.dynamictext.CharacterWithStyle; +import com.jpexs.decompiler.flash.tags.dynamictext.DynamicTextModel; +import com.jpexs.decompiler.flash.tags.dynamictext.GlyphCharacter; +import com.jpexs.decompiler.flash.tags.dynamictext.Paragraph; +import com.jpexs.decompiler.flash.tags.dynamictext.SameStyleTextRecord; +import com.jpexs.decompiler.flash.tags.dynamictext.TextStyle; +import com.jpexs.decompiler.flash.tags.dynamictext.Word; +import com.jpexs.decompiler.flash.tags.text.ParsedSymbol; +import com.jpexs.decompiler.flash.tags.text.TextAlign; +import com.jpexs.decompiler.flash.tags.text.TextLexer; +import com.jpexs.decompiler.flash.tags.text.TextParseException; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.ColorTransform; +import com.jpexs.decompiler.flash.types.GLYPHENTRY; +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.TEXTRECORD; +import com.jpexs.decompiler.flash.types.annotations.Conditional; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.helpers.ByteArrayRange; +import com.jpexs.helpers.SerializableImage; +import com.jpexs.helpers.utf8.Utf8Helper; +import java.awt.Color; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import java.util.Stack; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +/** + * + * @author JPEXS + */ +public class DefineEditTextTag extends TextTag { + + @SWFType(BasicType.UI16) + public int characterID; + + public RECT bounds; + + public boolean hasText; + + public boolean wordWrap; + + public boolean multiline; + + public boolean password; + + public boolean readOnly; + + public boolean hasTextColor; + + public boolean hasMaxLength; + + public boolean hasFont; + + public boolean hasFontClass; + + public boolean autoSize; + + public boolean hasLayout; + + public boolean noSelect; + + public boolean border; + + public boolean wasStatic; + + public boolean html; + + public boolean useOutlines; + + @SWFType(BasicType.UI16) + @Conditional("hasFont") + public int fontId; + + @Conditional("hasFontClass") + public String fontClass; + + @SWFType(BasicType.UI16) + @Conditional("hasFont") + public int fontHeight; + + @Conditional("hasTextColor") + public RGBA textColor; + + @SWFType(BasicType.UI16) + @Conditional("hasMaxLength") + public int maxLength; + + @SWFType(BasicType.UI8) + @Conditional("hasLayout") + public int align; + + @SWFType(BasicType.UI16) + @Conditional("hasLayout") + public int leftMargin; + + @SWFType(BasicType.UI16) + @Conditional("hasLayout") + public int rightMargin; + + @SWFType(BasicType.UI16) + @Conditional("hasLayout") + public int indent; + + @SWFType(BasicType.SI16) + @Conditional("hasLayout") + public int leading; + + public String variableName; + + @Conditional("hasText") + public String initialText; + + public static final int ID = 37; + + public static final String NAME = "DefineEditText"; + + @Override + public RECT getBounds() { + return bounds; + } + + @Override + public MATRIX getTextMatrix() { + MATRIX matrix = new MATRIX(); + matrix.translateX = bounds.Xmin; + matrix.translateY = bounds.Ymin; + return matrix; + } + + @Override + public void setBounds(RECT r) { + bounds = r; + } + + private String stripTags(String inp) { + boolean intag = false; + String outp = ""; + inp = inp.replaceAll("
", "\r\n"); + for (int i = 0; i < inp.length(); ++i) { + if (!intag && inp.charAt(i) == '<') { + intag = true; + continue; + } + if (intag && inp.charAt(i) == '>') { + intag = false; + continue; + } + if (!intag) { + outp += inp.charAt(i); + } + } + return outp; + } + + private String entitiesReplace(String s) { + s = s.replace("<", "<"); + s = s.replace(">", ">"); + s = s.replace("&", "&"); + s = s.replace(""", "\""); + return s; + } + + @Override + public List getTexts() { + String ret = ""; + if (hasText) { + ret = initialText; + } + if (html) { + ret = stripTags(ret); + ret = entitiesReplace(ret); + } + return Arrays.asList(ret); + } + + private List getTextWithStyle() { + String str = ""; + TextStyle style = new TextStyle(); + style.font = swf.getFont(fontId); + style.fontHeight = fontHeight; + style.fontLeading = leading; + if (hasTextColor) { + style.textColor = textColor; + } + if (hasText) { + str = initialText; + } + final List ret = new ArrayList<>(); + if (html) { + SAXParserFactory factory = SAXParserFactory.newInstance(); + SAXParser saxParser; + final Stack styles = new Stack<>(); + styles.add(style); + try { + saxParser = factory.newSAXParser(); + DefaultHandler handler = new DefaultHandler() { + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { + TextStyle style = styles.peek(); + switch (qName) { + case "p": + // todo: parse the following attribute: + // align + break; + case "b": + style = style.clone(); + style.bold = true; + styles.add(style); + break; + case "i": + style = style.clone(); + style.italic = true; + styles.add(style); + break; + case "u": + style = style.clone(); + style.underlined = true; + styles.add(style); + break; + case "font": + style = style.clone(); + String color = attributes.getValue("color"); + if (color != null) { + if (color.startsWith("#")) { + style.textColor = new RGBA(Color.decode(color)); + } + } + String size = attributes.getValue("size"); + if (size != null && size.length() > 0) { + char firstChar = size.charAt(0); + if (firstChar != '+' && firstChar != '-') { + int fontSize = Integer.parseInt(size); + style.fontHeight = (int) Math.round(fontSize * (style.font == null ? 1 : style.font.getDivider())); + style.fontLeading = leading; + } else { + // todo: parse relative sizes + } + } + // todo: parse the following attributes: + // face, letterSpacing, kerning + styles.add(style); + break; + case "br": + case "sbr": // what's this? + CharacterWithStyle cs = new CharacterWithStyle(); + cs.character = '\n'; + cs.style = style; + ret.add(cs); + break; + } + //ret = entitiesReplace(ret); + } + + @Override + public void endElement(String uri, String localName, String qName) throws SAXException { + switch (qName) { + case "b": + case "i": + case "u": + case "font": + styles.pop(); + break; + case "p": + TextStyle style = styles.peek(); + CharacterWithStyle cs = new CharacterWithStyle(); + cs.character = '\n'; + cs.style = style; + ret.add(cs); + break; + } + } + + @Override + public void characters(char[] ch, int start, int length) throws SAXException { + String txt = new String(ch, start, length); + TextStyle style = styles.peek(); + addCharacters(ret, txt, style); + } + }; + str = " \n" + + "]>" + str + ""; + saxParser.parse(new ByteArrayInputStream(str.getBytes(Utf8Helper.charset)), handler); + } catch (ParserConfigurationException | SAXException | IOException ex) { + Logger.getLogger(DefineEditTextTag.class.getName()).log(Level.SEVERE, null, ex); + } + } else { + addCharacters(ret, str, style); + } + return ret; + } + + private void addCharacters(List list, String str, TextStyle style) { + for (int i = 0; i < str.length(); i++) { + char ch = str.charAt(i); + CharacterWithStyle cs = new CharacterWithStyle(); + cs.character = ch; + cs.style = style; + list.add(cs); + } + } + + @Override + public List getFontIds() { + List ret = new ArrayList<>(); + ret.add(fontId); + return ret; + } + + @Override + public HighlightedText getFormattedText() { + HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), true); + writer.append("["); + String[] alignNames = {"left", "right", "center", "justify"}; + String alignment; + if (align < alignNames.length) { + alignment = alignNames[align]; + } else { + alignment = "unknown"; + } + writer.newLine(); + writer.append("xmin " + bounds.Xmin).newLine(); + writer.append("ymin " + bounds.Ymin).newLine(); + writer.append("xmax " + bounds.Xmax).newLine(); + writer.append("ymax " + bounds.Ymax).newLine(); + if (wordWrap) { + writer.append("wordwrap 1").newLine(); + } + if (multiline) { + writer.append("multiline 1").newLine(); + } + if (password) { + writer.append("password 1").newLine(); + } + if (readOnly) { + writer.append("readonly 1").newLine(); + } + if (autoSize) { + writer.append("autosize 1").newLine(); + } + if (noSelect) { + writer.append("noselect 1").newLine(); + } + if (border) { + writer.append("border 1").newLine(); + } + if (wasStatic) { + writer.append("wasstatic 1").newLine(); + } + if (html) { + writer.append("html 1").newLine(); + } + if (useOutlines) { + writer.append("useoutlines 1").newLine(); + } + if (hasFont) { + writer.append("font " + fontId).newLine(); + writer.append("height " + fontHeight).newLine(); + } + if (hasTextColor) { + writer.append("color " + textColor.toHexARGB()).newLine(); + } + if (hasFontClass) { + writer.append("fontclass " + fontClass).newLine(); + } + if (hasMaxLength) { + writer.append("maxlength " + maxLength).newLine(); + } + writer.append("align " + alignment).newLine(); + if (hasLayout) { + writer.append("leftmargin " + leftMargin).newLine(); + writer.append("rightmargin " + rightMargin).newLine(); + writer.append("indent " + indent).newLine(); + writer.append("leading " + leading).newLine(); + } + if (!variableName.isEmpty()) { + writer.append("variablename " + variableName).newLine(); + } + writer.append("]"); + if (hasText) { + String text = initialText.replace("\\", "\\\\").replace("[", "\\[").replace("]", "\\]"); + writer.hilightSpecial(text, HighlightSpecialType.TEXT); + } + return new HighlightedText(writer); + } + + @Override + public boolean setFormattedText(MissingCharacterHandler missingCharHandler, String formattedText, String[] texts) throws TextParseException { + try { + TextLexer lexer = new TextLexer(new StringReader(formattedText)); + ParsedSymbol s = null; + formattedText = ""; + RECT bounds = new RECT(this.bounds); + boolean wordWrap = false; + boolean multiline = false; + boolean password = false; + boolean readOnly = false; + boolean autoSize = false; + boolean noSelect = false; + boolean border = false; + boolean wasStatic = false; + boolean html = false; + boolean useOutlines = false; + int fontId = -1; + int fontHeight = -1; + String fontClass = null; + RGBA textColor = null; + int maxLength = -1; + int align = -1; + int leftMargin = -1; + int rightMargin = -1; + int indent = -1; + int leading = -1; + String variableName = null; + + int textIdx = 0; + while ((s = lexer.yylex()) != null) { + switch (s.type) { + case PARAMETER: + String paramName = (String) s.values[0]; + String paramValue = (String) s.values[1]; + switch (paramName) { + case "xmin": + try { + bounds.Xmin = Integer.parseInt(paramValue); + } catch (NumberFormatException nfe) { + throw new TextParseException("Invalid xmin value. Number expected. Found: " + paramValue, lexer.yyline()); + } + break; + case "ymin": + try { + bounds.Ymin = Integer.parseInt(paramValue); + } catch (NumberFormatException nfe) { + throw new TextParseException("Invalid ymin value. Number expected. Found: " + paramValue, lexer.yyline()); + } + break; + case "xmax": + try { + bounds.Xmax = Integer.parseInt(paramValue); + } catch (NumberFormatException nfe) { + throw new TextParseException("Invalid xmax value. Number expected. Found: " + paramValue, lexer.yyline()); + } + break; + case "ymax": + try { + bounds.Ymax = Integer.parseInt(paramValue); + } catch (NumberFormatException nfe) { + throw new TextParseException("Invalid ymax value. Number expected. Found: " + paramValue, lexer.yyline()); + } + break; + case "wordwrap": + if (paramValue.equals("1")) { + wordWrap = true; + } + break; + case "multiline": + if (paramValue.equals("1")) { + multiline = true; + } + break; + case "password": + if (paramValue.equals("1")) { + password = true; + } + break; + case "readonly": + if (paramValue.equals("1")) { + readOnly = true; + } + break; + case "autosize": + if (paramValue.equals("1")) { + autoSize = true; + } + break; + case "noselect": + if (paramValue.equals("1")) { + noSelect = true; + } + break; + case "border": + if (paramValue.equals("1")) { + border = true; + } + break; + case "wasstatic": + if (paramValue.equals("1")) { + wasStatic = true; + } + break; + case "html": + if (paramValue.equals("1")) { + html = true; + } + break; + case "useoutlines": + if (paramValue.equals("1")) { + useOutlines = true; + } + break; + case "font": + try { + fontId = Integer.parseInt(paramValue); + + FontTag ft = swf.getFont(fontId); + if (ft == null) { + throw new TextParseException("Font not found.", lexer.yyline()); + } + } catch (NumberFormatException ne) { + throw new TextParseException("Invalid font value. Number expected. Found: " + paramValue, lexer.yyline()); + } + break; + case "fontclass": + fontClass = paramValue; + break; + case "height": + try { + fontHeight = Integer.parseInt(paramValue); + } catch (NumberFormatException ne) { + throw new TextParseException("Invalid height value. Number expected. Found: " + paramValue, lexer.yyline()); + } + break; + case "color": + Matcher m = Pattern.compile("#([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])").matcher(paramValue); + if (m.matches()) { + textColor = new RGBA(Integer.parseInt(m.group(2), 16), Integer.parseInt(m.group(3), 16), Integer.parseInt(m.group(4), 16), Integer.parseInt(m.group(1), 16)); + } else { + throw new TextParseException("Invalid color. Valid format is #aarrggbb. Found: " + paramValue, lexer.yyline()); + } + break; + case "maxlength": + try { + maxLength = Integer.parseInt(paramValue); + } catch (NumberFormatException ne) { + throw new TextParseException("Invalid maxLength value. Number expected. Found: " + paramValue, lexer.yyline()); + } + break; + case "align": + switch (paramValue) { + case "left": + align = 0; + break; + case "right": + align = 1; + break; + case "center": + align = 2; + break; + case "justify": + align = 3; + break; + default: + throw new TextParseException("Invalid align value. Expected one of: left,right,center or justify. Found: " + paramValue, lexer.yyline()); + } + break; + case "leftmargin": + try { + leftMargin = Integer.parseInt(paramValue); + } catch (NumberFormatException ne) { + throw new TextParseException("Invalid leftmargin value. Number expected. Found: " + paramValue, lexer.yyline()); + } + break; + case "rightmargin": + try { + rightMargin = Integer.parseInt(paramValue); + } catch (NumberFormatException ne) { + throw new TextParseException("Invalid rightmargin value. Number expected. Found: " + paramValue, lexer.yyline()); + } + break; + case "indent": + try { + indent = Integer.parseInt(paramValue); + } catch (NumberFormatException ne) { + throw new TextParseException("Invalid indent value. Number expected. Found: " + paramValue, lexer.yyline()); + } + break; + case "leading": + try { + leading = Integer.parseInt(paramValue); + } catch (NumberFormatException ne) { + throw new TextParseException("Invalid leading value. Number expected. Found: " + paramValue, lexer.yyline()); + } + break; + case "variablename": + variableName = paramValue; + break; + default: + throw new TextParseException("Unrecognized parameter name: " + paramName, lexer.yyline()); + } + break; + case TEXT: + String s2 = (String) s.values[0]; + if (s2 == null) { + s2 = ""; + } + + formattedText += (texts == null || textIdx >= texts.length) ? s2 : texts[textIdx++]; + formattedText = formattedText.replace("\r\n", "\r"); + break; + } + } + + setModified(true); + this.bounds = bounds; + if (formattedText.length() > 0) { + initialText = formattedText; + this.hasText = true; + } else { + this.hasText = false; + } + this.wordWrap = wordWrap; + this.multiline = multiline; + this.password = password; + this.readOnly = readOnly; + this.noSelect = noSelect; + this.border = border; + this.wasStatic = wasStatic; + this.html = html; + this.useOutlines = useOutlines; + if (textColor != null) { + hasTextColor = true; + this.textColor = textColor; + } + if (maxLength > -1) { + this.maxLength = maxLength; + hasMaxLength = true; + } + if (fontId > -1) { + this.fontId = fontId; + } + if (fontHeight > -1) { + this.fontHeight = fontHeight; + } + if (fontClass != null) { + this.fontClass = fontClass; + hasFontClass = true; + } + this.autoSize = autoSize; + this.align = align; + if ((leftMargin > -1) + || (rightMargin > -1) + || (indent > -1) + || (leading > -1)) { + this.leftMargin = leftMargin; + this.rightMargin = rightMargin; + this.indent = indent; + this.leading = leading; + hasLayout = true; + } + if (variableName == null) { + variableName = ""; + } + this.variableName = variableName; + + } catch (IOException ex) { + Logger.getLogger(DefineEditTextTag.class.getName()).log(Level.SEVERE, null, ex); + return false; + } + + return true; + } + + @Override + public void updateTextBounds() { + } + + @Override + public boolean alignText(TextAlign textAlign) { + return true; + } + + @Override + public boolean translateText(int diff) { + return true; + } + + @Override + public RECT getRect(Set added) { + return bounds; + } + + @Override + public int getCharacterId() { + return characterID; + } + + @Override + public void setCharacterId(int characterId) { + this.characterID = characterId; + } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(characterID); + sos.writeRECT(bounds); + sos.writeUB(1, hasText ? 1 : 0); + sos.writeUB(1, wordWrap ? 1 : 0); + sos.writeUB(1, multiline ? 1 : 0); + sos.writeUB(1, password ? 1 : 0); + sos.writeUB(1, readOnly ? 1 : 0); + sos.writeUB(1, hasTextColor ? 1 : 0); + sos.writeUB(1, hasMaxLength ? 1 : 0); + sos.writeUB(1, hasFont ? 1 : 0); + sos.writeUB(1, hasFontClass ? 1 : 0); + sos.writeUB(1, autoSize ? 1 : 0); + sos.writeUB(1, hasLayout ? 1 : 0); + sos.writeUB(1, noSelect ? 1 : 0); + sos.writeUB(1, border ? 1 : 0); + sos.writeUB(1, wasStatic ? 1 : 0); + sos.writeUB(1, html ? 1 : 0); + sos.writeUB(1, useOutlines ? 1 : 0); + if (hasFont) { + sos.writeUI16(fontId); + } + if (hasFontClass) { + sos.writeString(fontClass); + } + if (hasFont) { + sos.writeUI16(fontHeight); + } + if (hasTextColor) { + sos.writeRGBA(textColor); + } + if (hasMaxLength) { + sos.writeUI16(maxLength); + } + if (hasLayout) { + sos.writeUI8(align); + sos.writeUI16(leftMargin); + sos.writeUI16(rightMargin); + sos.writeUI16(indent); + sos.writeSI16(leading); + } + sos.writeString(variableName); + if (hasText) { + sos.writeString(initialText); + } + + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + /** + * Constructor + * + * @param swf + */ + public DefineEditTextTag(SWF swf) { + super(swf, ID, NAME, null); + characterID = swf.getNextCharacterId(); + bounds = new RECT(); + variableName = ""; + } + + /** + * Constructor + * + * @param sis + * @param data + * @throws IOException + */ + public DefineEditTextTag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + characterID = sis.readUI16("characterID"); + bounds = sis.readRECT("bounds"); + hasText = sis.readUB(1, "hasText") == 1; + wordWrap = sis.readUB(1, "wordWrap") == 1; + multiline = sis.readUB(1, "multiline") == 1; + password = sis.readUB(1, "password") == 1; + readOnly = sis.readUB(1, "readOnly") == 1; + hasTextColor = sis.readUB(1, "hasTextColor") == 1; + hasMaxLength = sis.readUB(1, "hasMaxLength") == 1; + hasFont = sis.readUB(1, "hasFont") == 1; + hasFontClass = sis.readUB(1, "hasFontClass") == 1; + autoSize = sis.readUB(1, "autoSize") == 1; + hasLayout = sis.readUB(1, "hasLayout") == 1; + noSelect = sis.readUB(1, "noSelect") == 1; + border = sis.readUB(1, "border") == 1; + wasStatic = sis.readUB(1, "wasStatic") == 1; + html = sis.readUB(1, "html") == 1; + useOutlines = sis.readUB(1, "useOutlines") == 1; + if (hasFont) { + fontId = sis.readUI16("fontId"); + } + if (hasFontClass) { + fontClass = sis.readString("fontClass"); + } + if (hasFont) { + fontHeight = sis.readUI16("fontHeight"); + } + if (hasTextColor) { + textColor = sis.readRGBA("textColor"); + } + if (hasMaxLength) { + maxLength = sis.readUI16("maxLength"); + } + if (hasLayout) { + align = sis.readUI8("align"); //0 left, 1 right, 2 center, 3 justify + leftMargin = sis.readUI16("leftMargin"); + rightMargin = sis.readUI16("rightMargin"); + indent = sis.readUI16("indent"); + leading = sis.readSI16("leading"); + } + variableName = sis.readString("variableName"); + if (hasText) { + initialText = sis.readString("initialText"); + } + + } + + @Override + public void getNeededCharacters(Set needed) { + if (hasFont) { + needed.add(fontId); + } + } + + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + if (fontId == oldCharacterId) { + fontId = newCharacterId; + setModified(true); + return true; + } + return false; + } + + @Override + public boolean removeCharacter(int characterId) { + if (fontId == characterId) { + hasFont = false; + fontId = 0; + setModified(true); + return true; + } + return false; + } + + @Override + public int getUsedParameters() { + return 0; + } + + @Override + public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, Matrix transformation, ColorTransform colorTransform) { + render(false, image, transformation, colorTransform); + } + + @Override + public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, double zoom) { + // todo: implement + } + + @Override + public String toHtmlCanvas(double unitDivisor) { + return render(true, null, new Matrix(), new ColorTransform()); + } + + private String render(boolean canvas, SerializableImage image, Matrix transformation, ColorTransform colorTransform) { + if (border) { + // border is always black, fill color is always white? + RGB borderColor = new RGBA(Color.black); + RGB fillColor = new RGBA(Color.white); + if (!canvas) { + drawBorder(swf, image, borderColor, fillColor, getRect(), getTextMatrix(), transformation, colorTransform); + } else { + // TODO: draw border + } + } + if (hasText) { + DynamicTextModel textModel = new DynamicTextModel(); + List txt = getTextWithStyle(); + TextStyle lastStyle = null; + char prevChar = 0; + boolean lastWasWhiteSpace = false; + for (int i = 0; i < txt.size(); i++) { + CharacterWithStyle cs = txt.get(i); + char c = cs.character; + if (c != '\r' && c != '\n') { + // create new SameStyleTextRecord for all words and all diffrent style text parts + if (lastWasWhiteSpace && !Character.isWhitespace(c)) { + textModel.newWord(); + lastWasWhiteSpace = false; + } + if (cs.style != lastStyle) { + lastStyle = cs.style; + textModel.style = lastStyle; + textModel.newRecord(); + } + Character nextChar = null; + if (i + 1 < txt.size()) { + nextChar = txt.get(i + 1).character; + } + int advance; + FontTag font = lastStyle.font; + GLYPHENTRY ge = new GLYPHENTRY(); + ge.glyphIndex = font == null ? -1 : font.charToGlyph(c); + if (font != null && font.hasLayout()) { + int kerningAdjustment = 0; + if (nextChar != null) { + kerningAdjustment = font.getCharKerningAdjustment(c, nextChar); + kerningAdjustment /= font.getDivider(); + } + advance = (int) Math.round(Math.round((double) lastStyle.fontHeight * (font.getGlyphAdvance(ge.glyphIndex) + kerningAdjustment) / (font.getDivider() * 1024.0))); + } else { + String fontName = FontTag.defaultFontName; + int fontStyle = font == null ? 0 : font.getFontStyle(); + advance = (int) Math.round(SWF.unitDivisor * FontTag.getSystemFontAdvance(fontName, fontStyle, (int) (lastStyle.fontHeight / SWF.unitDivisor), c, nextChar)); + } + ge.glyphAdvance = advance; + textModel.addGlyph(c, ge); + if (Character.isWhitespace(c)) { + lastWasWhiteSpace = true; + } + } else { + if (multiline) { + textModel.newParagraph(); + } + } + prevChar = c; + } + + textModel.calculateTextWidths(); + List> lines; + if (multiline && wordWrap) { + lines = new ArrayList<>(); + for (Paragraph paragraph : textModel.paragraphs) { + List line = new ArrayList<>(); + int lineLength = 0; + for (Word word : paragraph.words) { + if (lineLength + word.width <= bounds.getWidth()) { + line.addAll(word.records); + lineLength += word.width; + } else { + lines.add(line); + line = new ArrayList<>(); + line.addAll(word.records); + lineLength = 0; + } + } + if (!line.isEmpty()) { + lines.add(line); + } + } + } else { + lines = new ArrayList<>(); + for (Paragraph paragraph : textModel.paragraphs) { + List line = new ArrayList<>(); + for (Word word : paragraph.words) { + for (SameStyleTextRecord tr : word.records) { + line.add(tr); + } + } + lines.add(line); + } + } + + // remove spaces after last word + for (List line : lines) { + boolean removed = true; + while (removed) { + removed = false; + while (line.size() > 0 && line.get(line.size() - 1).glyphEntries.isEmpty()) { + line.remove(line.size() - 1); + removed = true; + } + if (line.size() > 0) { + SameStyleTextRecord lastRecord = line.get(line.size() - 1); + while (lastRecord.glyphEntries.size() > 0 + && Character.isWhitespace(lastRecord.glyphEntries.get(lastRecord.glyphEntries.size() - 1).character)) { + lastRecord.glyphEntries.remove(lastRecord.glyphEntries.size() - 1); + removed = true; + } + } + } + } + + textModel.calculateTextWidths(); + + List allTextRecords = new ArrayList<>(); + int lastHeight = 0; + int yOffset = 0; + for (List line : lines) { + int width = 0; + int currentOffset = 0; + if (line.isEmpty()) { + currentOffset = lastHeight; + } else { + for (SameStyleTextRecord tr : line) { + width += tr.width; + int lineHeight = tr.style.fontHeight + tr.style.fontLeading; + lastHeight = lineHeight; + if (lineHeight > currentOffset) { + currentOffset = lineHeight; + } + } + } + yOffset += currentOffset; + int alignOffset = 0; + switch (align) { + case 0: // left + alignOffset = 0; + break; + case 1: // right + alignOffset = bounds.getWidth() - width; + break; + case 2: // center + alignOffset = (bounds.getWidth() - width) / 2; + break; + case 3: // justify + // todo; + break; + } + for (SameStyleTextRecord tr : line) { + tr.xOffset = alignOffset; + alignOffset += tr.width; + } + for (SameStyleTextRecord tr : line) { + TEXTRECORD tr2 = new TEXTRECORD(); + tr2.styleFlagsHasFont = fontId != 0; + tr2.fontId = fontId; + tr2.textHeight = tr.style.fontHeight; + if (tr.style.textColor != null) { + tr2.styleFlagsHasColor = true; + tr2.textColorA = tr.style.textColor; + } + // always add xOffset, because no xOffset and 0 xOffset is diffrent in text rendering + tr2.styleFlagsHasXOffset = true; + tr2.xOffset = tr.xOffset; + if (yOffset != 0) { + tr2.styleFlagsHasYOffset = true; + tr2.yOffset = yOffset; + } + tr2.glyphEntries = new ArrayList<>(tr.glyphEntries.size()); + for (GlyphCharacter ge : tr.glyphEntries) { + tr2.glyphEntries.add(ge.glyphEntry); + } + allTextRecords.add(tr2); + } + } + + if (canvas) { + return staticTextToHtmlCanvas(1, swf, allTextRecords, 2, getBounds(), getTextMatrix(), colorTransform); + } else { + staticTextToImage(swf, allTextRecords, 2, image, getTextMatrix(), transformation, colorTransform); + } + } + + return ""; + } + + @Override + public ExportRectangle calculateTextBounds() { + return null; + } + + @Override + public int getNumFrames() { + return 1; + } + + @Override + public boolean isSingleFrame() { + return true; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont2Tag.java index 89cda2b0d..75613ba01 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont2Tag.java @@ -1,507 +1,509 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.helpers.FontHelper; -import com.jpexs.decompiler.flash.tags.base.FontTag; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.KERNINGRECORD; -import com.jpexs.decompiler.flash.types.LANGCODE; -import com.jpexs.decompiler.flash.types.RECT; -import com.jpexs.decompiler.flash.types.SHAPE; -import com.jpexs.decompiler.flash.types.annotations.Conditional; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD; -import com.jpexs.helpers.ByteArrayRange; -import com.jpexs.helpers.utf8.Utf8Helper; -import java.awt.Font; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -/** - * - * @author JPEXS - */ -public class DefineFont2Tag extends FontTag { - - @SWFType(BasicType.UI16) - public int fontId; - - public boolean fontFlagsHasLayout; - - public boolean fontFlagsShiftJIS; - - public boolean fontFlagsSmallText; - - public boolean fontFlagsANSI; - - public boolean fontFlagsWideOffsets; - - public boolean fontFlagsWideCodes; - - public boolean fontFlagsItalic; - - public boolean fontFlagsBold; - - public LANGCODE languageCode; - - public String fontName; - - public List glyphShapeTable; - - @SWFType(value = BasicType.UI8, alternateValue = BasicType.UI16, alternateCondition = "fontFlagsWideCodes") - public List codeTable; - - @SWFType(BasicType.UI16) - @Conditional("fontFlagsHasLayout") - public int fontAscent; - - @SWFType(BasicType.UI16) - @Conditional("fontFlagsHasLayout") - public int fontDescent; - - @SWFType(BasicType.SI16) - @Conditional("fontFlagsHasLayout") - public int fontLeading; - - @SWFType(BasicType.SI16) - @Conditional("fontFlagsHasLayout") - public List fontAdvanceTable; - - @Conditional("fontFlagsHasLayout") - public List fontBoundsTable; - - @Conditional("fontFlagsHasLayout") - public List fontKerningTable; - - public static final int ID = 48; - - @Override - public boolean isSmall() { - return fontFlagsSmallText; - } - - @Override - public int getGlyphWidth(int glyphIndex) { - return glyphShapeTable.get(glyphIndex).getBounds().getWidth(); - } - - @Override - public RECT getGlyphBounds(int glyphIndex) { - if (fontFlagsHasLayout) { - return fontBoundsTable.get(glyphIndex); - } - return super.getGlyphBounds(glyphIndex); - } - - @Override - public double getGlyphAdvance(int glyphIndex) { - if (fontFlagsHasLayout) { - return fontAdvanceTable.get(glyphIndex); - } else { - return -1; - } - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - SWFOutputStream sos = new SWFOutputStream(baos, getVersion()); - try { - sos.writeUI16(fontId); - sos.writeUB(1, fontFlagsHasLayout ? 1 : 0); - sos.writeUB(1, fontFlagsShiftJIS ? 1 : 0); - sos.writeUB(1, fontFlagsSmallText ? 1 : 0); - sos.writeUB(1, fontFlagsANSI ? 1 : 0); - sos.writeUB(1, fontFlagsWideOffsets ? 1 : 0); - sos.writeUB(1, fontFlagsWideCodes ? 1 : 0); - sos.writeUB(1, fontFlagsItalic ? 1 : 0); - sos.writeUB(1, fontFlagsBold ? 1 : 0); - sos.writeLANGCODE(languageCode); - byte[] fontNameBytes = Utf8Helper.getBytes(fontName); - sos.writeUI8(fontNameBytes.length); - sos.write(fontNameBytes); - int numGlyphs = glyphShapeTable.size(); - sos.writeUI16(numGlyphs); - - List offsetTable = new ArrayList<>(); - ByteArrayOutputStream baosGlyphShapes = new ByteArrayOutputStream(); - - SWFOutputStream sos3 = new SWFOutputStream(baosGlyphShapes, getVersion()); - for (int i = 0; i < numGlyphs; i++) { - offsetTable.add((glyphShapeTable.size() + 1/*CodeTableOffset*/) * (fontFlagsWideOffsets ? 4 : 2) + sos3.getPos()); - sos3.writeSHAPE(glyphShapeTable.get(i), 1); - } - byte[] baGlyphShapes = baosGlyphShapes.toByteArray(); - for (Long offset : offsetTable) { - if (fontFlagsWideOffsets) { - sos.writeUI32(offset); - } else { - sos.writeUI16((int) (long) offset); - } - } - if (numGlyphs > 0) { - long offset = (glyphShapeTable.size() + 1/*CodeTableOffset*/) * (fontFlagsWideOffsets ? 4 : 2) + baGlyphShapes.length; - if (fontFlagsWideOffsets) { - sos.writeUI32(offset); - } else { - sos.writeUI16((int) offset); - } - sos.write(baGlyphShapes); - - for (int i = 0; i < numGlyphs; i++) { - if (fontFlagsWideCodes) { - sos.writeUI16(codeTable.get(i)); - } else { - sos.writeUI8(codeTable.get(i)); - } - } - } - if (fontFlagsHasLayout) { - sos.writeSI16(fontAscent); - sos.writeSI16(fontDescent); - sos.writeSI16(fontLeading); - for (int i = 0; i < numGlyphs; i++) { - sos.writeSI16(fontAdvanceTable.get(i)); - } - for (int i = 0; i < numGlyphs; i++) { - sos.writeRECT(fontBoundsTable.get(i)); - } - sos.writeUI16(fontKerningTable.size()); - for (int k = 0; k < fontKerningTable.size(); k++) { - sos.writeKERNINGRECORD(fontKerningTable.get(k), fontFlagsWideCodes); - } - } - - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - - /** - * Constructor - * - * @param swf - */ - public DefineFont2Tag(SWF swf) { - super(swf, ID, "DefineFont2", null); - fontId = swf.getNextCharacterId(); - languageCode = new LANGCODE(); - fontName = "New font"; - glyphShapeTable = new ArrayList<>(); - codeTable = new ArrayList<>(); - } - - /** - * Constructor - * - * @param sis - * @param data - * @throws IOException - */ - public DefineFont2Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DefineFont2", data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - fontId = sis.readUI16("fontId"); - fontFlagsHasLayout = sis.readUB(1, "fontFlagsHasLayout") == 1; - fontFlagsShiftJIS = sis.readUB(1, "fontFlagsShiftJIS") == 1; - fontFlagsSmallText = sis.readUB(1, "fontFlagsSmallText") == 1; - fontFlagsANSI = sis.readUB(1, "fontFlagsANSI") == 1; - fontFlagsWideOffsets = sis.readUB(1, "fontFlagsWideOffsets") == 1; - fontFlagsWideCodes = sis.readUB(1, "fontFlagsWideCodes") == 1; - fontFlagsItalic = sis.readUB(1, "fontFlagsItalic") == 1; - fontFlagsBold = sis.readUB(1, "fontFlagsBold") == 1; - languageCode = sis.readLANGCODE("languageCode"); - int fontNameLen = sis.readUI8("fontNameLen"); - if (swf.version >= 6) { - fontName = new String(sis.readBytesEx(fontNameLen, "fontName"), Utf8Helper.charset); - } else { - fontName = new String(sis.readBytesEx(fontNameLen, "fontName")); - } - int numGlyphs = sis.readUI16("numGlyphs"); - long[] offsetTable = new long[numGlyphs]; - long pos = sis.getPos(); - for (int i = 0; i < numGlyphs; i++) { //offsetTable - if (fontFlagsWideOffsets) { - offsetTable[i] = sis.readUI32("offset"); - } else { - offsetTable[i] = sis.readUI16("offset"); - } - } - if (numGlyphs > 0) { //codeTableOffset - if (fontFlagsWideOffsets) { - sis.readUI32("codeTableOffset"); - } else { - sis.readUI16("codeTableOffset"); - } - } - - glyphShapeTable = new ArrayList<>(); - for (int i = 0; i < numGlyphs; i++) { - sis.seek(pos + offsetTable[i]); - glyphShapeTable.add(sis.readSHAPE(1, false, "shape")); - } - - codeTable = new ArrayList<>(); //[numGlyphs]; - for (int i = 0; i < numGlyphs; i++) { - if (fontFlagsWideCodes) { - codeTable.add(sis.readUI16("code")); - } else { - codeTable.add(sis.readUI8("code")); - } - } - - if (fontFlagsHasLayout) { - fontAscent = sis.readUI16("fontAscent"); - fontDescent = sis.readUI16("fontDescent"); - fontLeading = sis.readSI16("fontLeading"); - fontAdvanceTable = new ArrayList<>(); - for (int i = 0; i < numGlyphs; i++) { - fontAdvanceTable.add(sis.readSI16("fontAdvance")); - } - fontBoundsTable = new ArrayList<>(); - for (int i = 0; i < numGlyphs; i++) { - fontBoundsTable.add(sis.readRECT("rect")); - } - int kerningCount = sis.readUI16("kerningCount"); - fontKerningTable = new ArrayList<>(); - for (int i = 0; i < kerningCount; i++) { - fontKerningTable.add(sis.readKERNINGRECORD(fontFlagsWideCodes, "record")); - } - } - } - - @Override - public int getFontId() { - return fontId; - } - - @Override - public List getGlyphShapeTable() { - return glyphShapeTable; - } - - @Override - public int getCharacterId() { - return fontId; - } - - @Override - public void setCharacterId(int characterId) { - this.fontId = characterId; - } - - @Override - public char glyphToChar(int glyphIndex) { - return (char) (int) codeTable.get(glyphIndex); - } - - @Override - public int charToGlyph(char c) { - return codeTable.indexOf((int) c); - } - - @Override - public String getFontNameIntag() { - String ret = fontName; - if (ret.contains("" + (char) 0)) { - ret = ret.substring(0, ret.indexOf(0)); - } - return ret; - } - - @Override - public boolean isBold() { - return fontFlagsBold; - } - - @Override - public boolean isItalic() { - return fontFlagsItalic; - } - - @Override - public boolean isSmallEditable() { - return true; - } - - @Override - public boolean isBoldEditable() { - return true; - } - - @Override - public boolean isItalicEditable() { - return true; - } - - @Override - public void setSmall(boolean value) { - fontFlagsSmallText = value; - } - - @Override - public void setBold(boolean value) { - fontFlagsBold = value; - } - - @Override - public void setItalic(boolean value) { - fontFlagsItalic = value; - } - - @Override - public double getDivider() { - return 1; - } - - @Override - public int getAscent() { - if (fontFlagsHasLayout) { - return fontAscent; - } - return -1; - } - - @Override - public int getDescent() { - if (fontFlagsHasLayout) { - return fontDescent; - } - return -1; - } - - @Override - public int getLeading() { - if (fontFlagsHasLayout) { - return fontLeading; - } - return -1; - } - - @Override - public void addCharacter(char character, Font font) { - int fontStyle = getFontStyle(); - - SHAPE shp = SHAPERECORD.fontCharacterToSHAPE(font, (int) Math.round(getDivider() * 1024), character); - - int code = (int) character; - int pos = -1; - boolean exists = false; - for (int i = 0; i < codeTable.size(); i++) { - if (codeTable.get(i) >= code) { - if (codeTable.get(i) == code) { - exists = true; - } - pos = i; - break; - } - } - if (pos == -1) { - pos = codeTable.size(); - } - - if (!exists) { - shiftGlyphIndices(fontId, pos); - glyphShapeTable.add(pos, shp); - codeTable.add(pos, (int) character); - } else { - glyphShapeTable.set(pos, shp); - } - - if (fontFlagsHasLayout) { - Font fnt = new Font(fontName, fontStyle, 1024); - if (!exists) { - fontBoundsTable.add(pos, shp.getBounds()); - fontAdvanceTable.add(pos, (int) getDivider() * Math.round(FontHelper.getFontAdvance(fnt, character))); - } else { - fontBoundsTable.set(pos, shp.getBounds()); - fontAdvanceTable.set(pos, (int) getDivider() * Math.round(FontHelper.getFontAdvance(fnt, character))); - } - } - - setModified(true); - } - - @Override - public void setAdvanceValues(Font font) { - boolean hasLayout = fontFlagsHasLayout; - fontFlagsHasLayout = true; - fontAdvanceTable = new ArrayList<>(); - if (!hasLayout) { - fontBoundsTable = new ArrayList<>(); - fontKerningTable = new ArrayList<>(); - } - - for (Integer character : codeTable) { - char ch = (char) (int) character; - SHAPE shp = SHAPERECORD.fontCharacterToSHAPE(font, (int) Math.round(getDivider() * 1024), ch); - fontBoundsTable.add(shp.getBounds()); - int fontStyle = getFontStyle(); - Font fnt = new Font(font.getFontName(), fontStyle, 1024); // Not multiplied with divider as it causes problems to create font with height around 20k - fontAdvanceTable.add((int) getDivider() * Math.round(FontHelper.getFontAdvance(fnt, ch))); - } - } - - @Override - public String getCharacters(List tags) { - StringBuilder ret = new StringBuilder(); - for (int i : codeTable) { - ret.append((char) i); - } - return ret.toString(); - } - - @Override - public boolean hasLayout() { - return fontFlagsHasLayout; - } - - @Override - public int getGlyphKerningAdjustment(int glyphIndex, int nextGlyphIndex) { - char c1 = glyphToChar(glyphIndex); - char c2 = glyphToChar(nextGlyphIndex); - return getCharKerningAdjustment(c1, c2); - } - - @Override - public int getCharKerningAdjustment(char c1, char c2) { - int kerningAdjustment = 0; - for (KERNINGRECORD ker : fontKerningTable) { - if (ker.fontKerningCode1 == c1 && ker.fontKerningCode2 == c2) { - kerningAdjustment = ker.fontKerningAdjustment; - break; - } - } - return kerningAdjustment; - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.helpers.FontHelper; +import com.jpexs.decompiler.flash.tags.base.FontTag; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.KERNINGRECORD; +import com.jpexs.decompiler.flash.types.LANGCODE; +import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.decompiler.flash.types.SHAPE; +import com.jpexs.decompiler.flash.types.annotations.Conditional; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD; +import com.jpexs.helpers.ByteArrayRange; +import com.jpexs.helpers.utf8.Utf8Helper; +import java.awt.Font; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author JPEXS + */ +public class DefineFont2Tag extends FontTag { + + @SWFType(BasicType.UI16) + public int fontId; + + public boolean fontFlagsHasLayout; + + public boolean fontFlagsShiftJIS; + + public boolean fontFlagsSmallText; + + public boolean fontFlagsANSI; + + public boolean fontFlagsWideOffsets; + + public boolean fontFlagsWideCodes; + + public boolean fontFlagsItalic; + + public boolean fontFlagsBold; + + public LANGCODE languageCode; + + public String fontName; + + public List glyphShapeTable; + + @SWFType(value = BasicType.UI8, alternateValue = BasicType.UI16, alternateCondition = "fontFlagsWideCodes") + public List codeTable; + + @SWFType(BasicType.UI16) + @Conditional("fontFlagsHasLayout") + public int fontAscent; + + @SWFType(BasicType.UI16) + @Conditional("fontFlagsHasLayout") + public int fontDescent; + + @SWFType(BasicType.SI16) + @Conditional("fontFlagsHasLayout") + public int fontLeading; + + @SWFType(BasicType.SI16) + @Conditional("fontFlagsHasLayout") + public List fontAdvanceTable; + + @Conditional("fontFlagsHasLayout") + public List fontBoundsTable; + + @Conditional("fontFlagsHasLayout") + public List fontKerningTable; + + public static final int ID = 48; + + public static final String NAME = "DefineFont2"; + + @Override + public boolean isSmall() { + return fontFlagsSmallText; + } + + @Override + public int getGlyphWidth(int glyphIndex) { + return glyphShapeTable.get(glyphIndex).getBounds().getWidth(); + } + + @Override + public RECT getGlyphBounds(int glyphIndex) { + if (fontFlagsHasLayout) { + return fontBoundsTable.get(glyphIndex); + } + return super.getGlyphBounds(glyphIndex); + } + + @Override + public double getGlyphAdvance(int glyphIndex) { + if (fontFlagsHasLayout) { + return fontAdvanceTable.get(glyphIndex); + } else { + return -1; + } + } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + SWFOutputStream sos = new SWFOutputStream(baos, getVersion()); + try { + sos.writeUI16(fontId); + sos.writeUB(1, fontFlagsHasLayout ? 1 : 0); + sos.writeUB(1, fontFlagsShiftJIS ? 1 : 0); + sos.writeUB(1, fontFlagsSmallText ? 1 : 0); + sos.writeUB(1, fontFlagsANSI ? 1 : 0); + sos.writeUB(1, fontFlagsWideOffsets ? 1 : 0); + sos.writeUB(1, fontFlagsWideCodes ? 1 : 0); + sos.writeUB(1, fontFlagsItalic ? 1 : 0); + sos.writeUB(1, fontFlagsBold ? 1 : 0); + sos.writeLANGCODE(languageCode); + byte[] fontNameBytes = Utf8Helper.getBytes(fontName); + sos.writeUI8(fontNameBytes.length); + sos.write(fontNameBytes); + int numGlyphs = glyphShapeTable.size(); + sos.writeUI16(numGlyphs); + + List offsetTable = new ArrayList<>(); + ByteArrayOutputStream baosGlyphShapes = new ByteArrayOutputStream(); + + SWFOutputStream sos3 = new SWFOutputStream(baosGlyphShapes, getVersion()); + for (int i = 0; i < numGlyphs; i++) { + offsetTable.add((glyphShapeTable.size() + 1/*CodeTableOffset*/) * (fontFlagsWideOffsets ? 4 : 2) + sos3.getPos()); + sos3.writeSHAPE(glyphShapeTable.get(i), 1); + } + byte[] baGlyphShapes = baosGlyphShapes.toByteArray(); + for (Long offset : offsetTable) { + if (fontFlagsWideOffsets) { + sos.writeUI32(offset); + } else { + sos.writeUI16((int) (long) offset); + } + } + if (numGlyphs > 0) { + long offset = (glyphShapeTable.size() + 1/*CodeTableOffset*/) * (fontFlagsWideOffsets ? 4 : 2) + baGlyphShapes.length; + if (fontFlagsWideOffsets) { + sos.writeUI32(offset); + } else { + sos.writeUI16((int) offset); + } + sos.write(baGlyphShapes); + + for (int i = 0; i < numGlyphs; i++) { + if (fontFlagsWideCodes) { + sos.writeUI16(codeTable.get(i)); + } else { + sos.writeUI8(codeTable.get(i)); + } + } + } + if (fontFlagsHasLayout) { + sos.writeSI16(fontAscent); + sos.writeSI16(fontDescent); + sos.writeSI16(fontLeading); + for (int i = 0; i < numGlyphs; i++) { + sos.writeSI16(fontAdvanceTable.get(i)); + } + for (int i = 0; i < numGlyphs; i++) { + sos.writeRECT(fontBoundsTable.get(i)); + } + sos.writeUI16(fontKerningTable.size()); + for (int k = 0; k < fontKerningTable.size(); k++) { + sos.writeKERNINGRECORD(fontKerningTable.get(k), fontFlagsWideCodes); + } + } + + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + /** + * Constructor + * + * @param swf + */ + public DefineFont2Tag(SWF swf) { + super(swf, ID, NAME, null); + fontId = swf.getNextCharacterId(); + languageCode = new LANGCODE(); + fontName = "New font"; + glyphShapeTable = new ArrayList<>(); + codeTable = new ArrayList<>(); + } + + /** + * Constructor + * + * @param sis + * @param data + * @throws IOException + */ + public DefineFont2Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + fontId = sis.readUI16("fontId"); + fontFlagsHasLayout = sis.readUB(1, "fontFlagsHasLayout") == 1; + fontFlagsShiftJIS = sis.readUB(1, "fontFlagsShiftJIS") == 1; + fontFlagsSmallText = sis.readUB(1, "fontFlagsSmallText") == 1; + fontFlagsANSI = sis.readUB(1, "fontFlagsANSI") == 1; + fontFlagsWideOffsets = sis.readUB(1, "fontFlagsWideOffsets") == 1; + fontFlagsWideCodes = sis.readUB(1, "fontFlagsWideCodes") == 1; + fontFlagsItalic = sis.readUB(1, "fontFlagsItalic") == 1; + fontFlagsBold = sis.readUB(1, "fontFlagsBold") == 1; + languageCode = sis.readLANGCODE("languageCode"); + int fontNameLen = sis.readUI8("fontNameLen"); + if (swf.version >= 6) { + fontName = new String(sis.readBytesEx(fontNameLen, "fontName"), Utf8Helper.charset); + } else { + fontName = new String(sis.readBytesEx(fontNameLen, "fontName")); + } + int numGlyphs = sis.readUI16("numGlyphs"); + long[] offsetTable = new long[numGlyphs]; + long pos = sis.getPos(); + for (int i = 0; i < numGlyphs; i++) { //offsetTable + if (fontFlagsWideOffsets) { + offsetTable[i] = sis.readUI32("offset"); + } else { + offsetTable[i] = sis.readUI16("offset"); + } + } + if (numGlyphs > 0) { //codeTableOffset + if (fontFlagsWideOffsets) { + sis.readUI32("codeTableOffset"); + } else { + sis.readUI16("codeTableOffset"); + } + } + + glyphShapeTable = new ArrayList<>(); + for (int i = 0; i < numGlyphs; i++) { + sis.seek(pos + offsetTable[i]); + glyphShapeTable.add(sis.readSHAPE(1, false, "shape")); + } + + codeTable = new ArrayList<>(); //[numGlyphs]; + for (int i = 0; i < numGlyphs; i++) { + if (fontFlagsWideCodes) { + codeTable.add(sis.readUI16("code")); + } else { + codeTable.add(sis.readUI8("code")); + } + } + + if (fontFlagsHasLayout) { + fontAscent = sis.readUI16("fontAscent"); + fontDescent = sis.readUI16("fontDescent"); + fontLeading = sis.readSI16("fontLeading"); + fontAdvanceTable = new ArrayList<>(); + for (int i = 0; i < numGlyphs; i++) { + fontAdvanceTable.add(sis.readSI16("fontAdvance")); + } + fontBoundsTable = new ArrayList<>(); + for (int i = 0; i < numGlyphs; i++) { + fontBoundsTable.add(sis.readRECT("rect")); + } + int kerningCount = sis.readUI16("kerningCount"); + fontKerningTable = new ArrayList<>(); + for (int i = 0; i < kerningCount; i++) { + fontKerningTable.add(sis.readKERNINGRECORD(fontFlagsWideCodes, "record")); + } + } + } + + @Override + public int getFontId() { + return fontId; + } + + @Override + public List getGlyphShapeTable() { + return glyphShapeTable; + } + + @Override + public int getCharacterId() { + return fontId; + } + + @Override + public void setCharacterId(int characterId) { + this.fontId = characterId; + } + + @Override + public char glyphToChar(int glyphIndex) { + return (char) (int) codeTable.get(glyphIndex); + } + + @Override + public int charToGlyph(char c) { + return codeTable.indexOf((int) c); + } + + @Override + public String getFontNameIntag() { + String ret = fontName; + if (ret.contains("" + (char) 0)) { + ret = ret.substring(0, ret.indexOf(0)); + } + return ret; + } + + @Override + public boolean isBold() { + return fontFlagsBold; + } + + @Override + public boolean isItalic() { + return fontFlagsItalic; + } + + @Override + public boolean isSmallEditable() { + return true; + } + + @Override + public boolean isBoldEditable() { + return true; + } + + @Override + public boolean isItalicEditable() { + return true; + } + + @Override + public void setSmall(boolean value) { + fontFlagsSmallText = value; + } + + @Override + public void setBold(boolean value) { + fontFlagsBold = value; + } + + @Override + public void setItalic(boolean value) { + fontFlagsItalic = value; + } + + @Override + public double getDivider() { + return 1; + } + + @Override + public int getAscent() { + if (fontFlagsHasLayout) { + return fontAscent; + } + return -1; + } + + @Override + public int getDescent() { + if (fontFlagsHasLayout) { + return fontDescent; + } + return -1; + } + + @Override + public int getLeading() { + if (fontFlagsHasLayout) { + return fontLeading; + } + return -1; + } + + @Override + public void addCharacter(char character, Font font) { + int fontStyle = getFontStyle(); + + SHAPE shp = SHAPERECORD.fontCharacterToSHAPE(font, (int) Math.round(getDivider() * 1024), character); + + int code = (int) character; + int pos = -1; + boolean exists = false; + for (int i = 0; i < codeTable.size(); i++) { + if (codeTable.get(i) >= code) { + if (codeTable.get(i) == code) { + exists = true; + } + pos = i; + break; + } + } + if (pos == -1) { + pos = codeTable.size(); + } + + if (!exists) { + shiftGlyphIndices(fontId, pos); + glyphShapeTable.add(pos, shp); + codeTable.add(pos, (int) character); + } else { + glyphShapeTable.set(pos, shp); + } + + if (fontFlagsHasLayout) { + Font fnt = new Font(fontName, fontStyle, 1024); + if (!exists) { + fontBoundsTable.add(pos, shp.getBounds()); + fontAdvanceTable.add(pos, (int) getDivider() * Math.round(FontHelper.getFontAdvance(fnt, character))); + } else { + fontBoundsTable.set(pos, shp.getBounds()); + fontAdvanceTable.set(pos, (int) getDivider() * Math.round(FontHelper.getFontAdvance(fnt, character))); + } + } + + setModified(true); + } + + @Override + public void setAdvanceValues(Font font) { + boolean hasLayout = fontFlagsHasLayout; + fontFlagsHasLayout = true; + fontAdvanceTable = new ArrayList<>(); + if (!hasLayout) { + fontBoundsTable = new ArrayList<>(); + fontKerningTable = new ArrayList<>(); + } + + for (Integer character : codeTable) { + char ch = (char) (int) character; + SHAPE shp = SHAPERECORD.fontCharacterToSHAPE(font, (int) Math.round(getDivider() * 1024), ch); + fontBoundsTable.add(shp.getBounds()); + int fontStyle = getFontStyle(); + Font fnt = new Font(font.getFontName(), fontStyle, 1024); // Not multiplied with divider as it causes problems to create font with height around 20k + fontAdvanceTable.add((int) getDivider() * Math.round(FontHelper.getFontAdvance(fnt, ch))); + } + } + + @Override + public String getCharacters(List tags) { + StringBuilder ret = new StringBuilder(); + for (int i : codeTable) { + ret.append((char) i); + } + return ret.toString(); + } + + @Override + public boolean hasLayout() { + return fontFlagsHasLayout; + } + + @Override + public int getGlyphKerningAdjustment(int glyphIndex, int nextGlyphIndex) { + char c1 = glyphToChar(glyphIndex); + char c2 = glyphToChar(nextGlyphIndex); + return getCharKerningAdjustment(c1, c2); + } + + @Override + public int getCharKerningAdjustment(char c1, char c2) { + int kerningAdjustment = 0; + for (KERNINGRECORD ker : fontKerningTable) { + if (ker.fontKerningCode1 == c1 && ker.fontKerningCode2 == c2) { + kerningAdjustment = ker.fontKerningAdjustment; + break; + } + } + return kerningAdjustment; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont3Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont3Tag.java index 3bbe962ee..a51368dcf 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont3Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont3Tag.java @@ -1,527 +1,529 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.abc.CopyOutputStream; -import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.decompiler.flash.helpers.FontHelper; -import com.jpexs.decompiler.flash.tags.base.FontTag; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.KERNINGRECORD; -import com.jpexs.decompiler.flash.types.LANGCODE; -import com.jpexs.decompiler.flash.types.RECT; -import com.jpexs.decompiler.flash.types.SHAPE; -import com.jpexs.decompiler.flash.types.annotations.Conditional; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD; -import com.jpexs.helpers.ByteArrayRange; -import com.jpexs.helpers.utf8.Utf8Helper; -import java.awt.Font; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; - -/** - * - * @author JPEXS - */ -public class DefineFont3Tag extends FontTag { - - @SWFType(BasicType.UI16) - public int fontId; - - public boolean fontFlagsHasLayout; - - public boolean fontFlagsShiftJIS; - - public boolean fontFlagsSmallText; - - public boolean fontFlagsANSI; - - public boolean fontFlagsWideOffsets; - - public boolean fontFlagsWideCodes; - - public boolean fontFlagsItalic; - - public boolean fontFlagsBold; - - public LANGCODE languageCode; - - public String fontName; - - public List glyphShapeTable; - - @SWFType(value = BasicType.UI8, alternateValue = BasicType.UI16, alternateCondition = "fontFlagsWideCodes") - public List codeTable; - - @SWFType(BasicType.UI16) - @Conditional("fontFlagsHasLayout") - public int fontAscent; - - @SWFType(BasicType.UI16) - @Conditional("fontFlagsHasLayout") - public int fontDescent; - - @SWFType(BasicType.SI16) - @Conditional("fontFlagsHasLayout") - public int fontLeading; - - @SWFType(BasicType.SI16) - @Conditional("fontFlagsHasLayout") - public List fontAdvanceTable; - - @Conditional("fontFlagsHasLayout") - public List fontBoundsTable; - - @Conditional("fontFlagsHasLayout") - public List fontKerningTable; - - public static final int ID = 75; - - @Override - public boolean isSmall() { - return fontFlagsSmallText; - } - - @Override - public int getGlyphWidth(int glyphIndex) { - return glyphShapeTable.get(glyphIndex).getBounds().getWidth(); - } - - @Override - public double getGlyphAdvance(int glyphIndex) { - if (fontFlagsHasLayout && glyphIndex != -1) { - return fontAdvanceTable.get(glyphIndex); - } else { - return -1; - } - } - - @Override - public char glyphToChar(int glyphIndex) { - return (char) (int) codeTable.get(glyphIndex); - } - - @Override - public int charToGlyph(char c) { - return codeTable.indexOf((int) c); - } - - /** - * Constructor - * - * @param swf - */ - public DefineFont3Tag(SWF swf) { - super(swf, ID, "DefineFont3", null); - fontId = swf.getNextCharacterId(); - languageCode = new LANGCODE(); - fontName = "New font"; - glyphShapeTable = new ArrayList<>(); - codeTable = new ArrayList<>(); - } - - public DefineFont3Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DefineFont3", data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - fontId = sis.readUI16("fontId"); - fontFlagsHasLayout = sis.readUB(1, "fontFlagsHasLayout") == 1; - fontFlagsShiftJIS = sis.readUB(1, "fontFlagsShiftJIS") == 1; - fontFlagsSmallText = sis.readUB(1, "fontFlagsSmallText") == 1; - fontFlagsANSI = sis.readUB(1, "fontFlagsANSI") == 1; - fontFlagsWideOffsets = sis.readUB(1, "fontFlagsWideOffsets") == 1; - fontFlagsWideCodes = sis.readUB(1, "fontFlagsWideCodes") == 1; - fontFlagsItalic = sis.readUB(1, "fontFlagsItalic") == 1; - fontFlagsBold = sis.readUB(1, "fontFlagsBold") == 1; - languageCode = sis.readLANGCODE("languageCode"); - int fontNameLen = sis.readUI8("fontNameLen"); - if (swf.version >= 6) { - fontName = new String(sis.readBytesEx(fontNameLen, "fontName"), Utf8Helper.charset); - } else { - fontName = new String(sis.readBytesEx(fontNameLen, "fontName")); - } - int numGlyphs = sis.readUI16("numGlyphs"); - long[] offsetTable = new long[numGlyphs]; - long pos = sis.getPos(); - for (int i = 0; i < numGlyphs; i++) { //offsetTable - if (fontFlagsWideOffsets) { - offsetTable[i] = sis.readUI32("offset"); - } else { - offsetTable[i] = sis.readUI16("offset"); - } - } - if (numGlyphs > 0) { - if (fontFlagsWideOffsets) { - sis.readUI32("codeTableOffset"); //codeTableOffset - } else { - sis.readUI16("codeTableOffset"); //codeTableOffset - } - } - glyphShapeTable = new ArrayList<>(); - for (int i = 0; i < numGlyphs; i++) { - sis.seek(pos + offsetTable[i]); - glyphShapeTable.add(sis.readSHAPE(1, false, "shape")); - } - codeTable = new ArrayList<>(); - for (int i = 0; i < numGlyphs; i++) { - if (fontFlagsWideCodes) { - codeTable.add(sis.readUI16("code")); - } else { - codeTable.add(sis.readUI8("code")); - } - } - if (fontFlagsHasLayout) { - fontAscent = sis.readUI16("fontAscent"); - fontDescent = sis.readUI16("fontDescent"); - fontLeading = sis.readSI16("fontLeading"); - fontAdvanceTable = new ArrayList<>(); - for (int i = 0; i < numGlyphs; i++) { - fontAdvanceTable.add(sis.readSI16("fontAdvance")); - } - fontBoundsTable = new ArrayList<>(); - for (int i = 0; i < numGlyphs; i++) { - fontBoundsTable.add(sis.readRECT("rect")); - } - int kerningCount = sis.readUI16("kerningCount"); - fontKerningTable = new ArrayList<>(); - for (int i = 0; i < kerningCount; i++) { - fontKerningTable.add(sis.readKERNINGRECORD(fontFlagsWideCodes, "record")); - } - } - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - if (Configuration.debugCopy.get()) { - sos = new SWFOutputStream(new CopyOutputStream(sos, new ByteArrayInputStream(getOriginalData())), getVersion()); - } - try { - List offsetTable = new ArrayList<>(); - ByteArrayOutputStream baosGlyphShapes = new ByteArrayOutputStream(); - SWFOutputStream sos3 = new SWFOutputStream(baosGlyphShapes, getVersion()); - int numGlyphs = glyphShapeTable.size(); - for (int i = 0; i < numGlyphs; i++) { - offsetTable.add(sos3.getPos()); - sos3.writeSHAPE(glyphShapeTable.get(i), 1); - } - byte[] baGlyphShapes = baosGlyphShapes.toByteArray(); - - if (!fontFlagsWideOffsets && numGlyphs > 0) { - // Set wide offsets when necessary - long maxOffset = (glyphShapeTable.size() + 1/*CodeTableOffset*/) * 2 + baGlyphShapes.length; - if (maxOffset > 65535) { - fontFlagsWideOffsets = true; - } - } - - sos.writeUI16(fontId); - sos.writeUB(1, fontFlagsHasLayout ? 1 : 0); - sos.writeUB(1, fontFlagsShiftJIS ? 1 : 0); - sos.writeUB(1, fontFlagsSmallText ? 1 : 0); - sos.writeUB(1, fontFlagsANSI ? 1 : 0); - sos.writeUB(1, fontFlagsWideOffsets ? 1 : 0); - sos.writeUB(1, fontFlagsWideCodes ? 1 : 0); - sos.writeUB(1, fontFlagsItalic ? 1 : 0); - sos.writeUB(1, fontFlagsBold ? 1 : 0); - sos.writeLANGCODE(languageCode); - byte[] fontNameBytes = Utf8Helper.getBytes(fontName); - sos.writeUI8(fontNameBytes.length); - sos.write(fontNameBytes); - sos.writeUI16(numGlyphs); - - for (long offset : offsetTable) { - long offset2 = (glyphShapeTable.size() + 1/*CodeTableOffset*/) * (fontFlagsWideOffsets ? 4 : 2) + offset; - if (fontFlagsWideOffsets) { - sos.writeUI32(offset2); - } else { - sos.writeUI16((int) offset2); - } - } - if (numGlyphs > 0) { - long offset = (glyphShapeTable.size() + 1/*CodeTableOffset*/) * (fontFlagsWideOffsets ? 4 : 2) + baGlyphShapes.length; - if (fontFlagsWideOffsets) { - sos.writeUI32(offset); - } else { - sos.writeUI16((int) offset); - } - sos.write(baGlyphShapes); - - for (int i = 0; i < numGlyphs; i++) { - if (fontFlagsWideCodes) { - sos.writeUI16(codeTable.get(i)); - } else { - sos.writeUI8(codeTable.get(i)); - } - } - } - if (fontFlagsHasLayout) { - sos.writeSI16(fontAscent); - sos.writeSI16(fontDescent); - sos.writeSI16(fontLeading); - for (int i = 0; i < numGlyphs; i++) { - sos.writeSI16(fontAdvanceTable.get(i)); - } - for (int i = 0; i < numGlyphs; i++) { - sos.writeRECT(fontBoundsTable.get(i)); - } - sos.writeUI16(fontKerningTable.size()); - for (int k = 0; k < fontKerningTable.size(); k++) { - sos.writeKERNINGRECORD(fontKerningTable.get(k), fontFlagsWideCodes); - } - } - - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - - @Override - public int getFontId() { - return fontId; - } - - @Override - public List getGlyphShapeTable() { - return glyphShapeTable; - } - - @Override - public int getCharacterId() { - return fontId; - } - - @Override - public void setCharacterId(int characterId) { - this.fontId = characterId; - } - - @Override - public String getFontNameIntag() { - String ret = fontName; - if (ret.contains("" + (char) 0)) { - ret = ret.substring(0, ret.indexOf(0)); - } - return ret; - } - - @Override - public boolean isBold() { - return fontFlagsBold; - } - - @Override - public boolean isItalic() { - return fontFlagsItalic; - } - - @Override - public boolean isSmallEditable() { - return true; - } - - @Override - public boolean isBoldEditable() { - return true; - } - - @Override - public boolean isItalicEditable() { - return true; - } - - @Override - public void setSmall(boolean value) { - fontFlagsSmallText = value; - } - - @Override - public void setBold(boolean value) { - fontFlagsBold = value; - } - - @Override - public void setItalic(boolean value) { - fontFlagsItalic = value; - } - - @Override - public double getDivider() { - return 20; - } - - @Override - public int getAscent() { - if (fontFlagsHasLayout) { - return fontAscent; - } - return -1; - } - - @Override - public int getDescent() { - if (fontFlagsHasLayout) { - return fontDescent; - } - return -1; - } - - @Override - public int getLeading() { - if (fontFlagsHasLayout) { - return fontLeading; - } - return -1; - } - - @Override - public void addCharacter(char character, Font font) { - - //Font Align Zones will be removed as adding new character zones is not supported:-( - for (int i = 0; i < swf.tags.size(); i++) { - Tag t = swf.tags.get(i); - if (t instanceof DefineFontAlignZonesTag) { - DefineFontAlignZonesTag fa = (DefineFontAlignZonesTag) t; - if (fa.fontID == fontId) { - swf.tags.remove(i); - i--; - } - } - } - int fontStyle = getFontStyle(); - SHAPE shp = SHAPERECORD.fontCharacterToSHAPE(font, (int) Math.round(getDivider() * 1024), character); - int code = (int) character; - int pos = -1; - boolean exists = false; - for (int i = 0; i < codeTable.size(); i++) { - if (codeTable.get(i) >= code) { - if (codeTable.get(i) == code) { - exists = true; - } - pos = i; - break; - } - } - if (pos == -1) { - pos = codeTable.size(); - } - - if (!exists) { - shiftGlyphIndices(fontId, pos); - glyphShapeTable.add(pos, shp); - codeTable.add(pos, (int) character); - } else { - glyphShapeTable.set(pos, shp); - } - if (fontFlagsHasLayout) { - - Font fnt = new Font(fontName, fontStyle, 1024); // Not multiplied with divider as it causes problems to create font with height around 20k - if (!exists) { - fontBoundsTable.add(pos, shp.getBounds()); - fontAdvanceTable.add(pos, (int) getDivider() * Math.round(FontHelper.getFontAdvance(fnt, character))); - } else { - fontBoundsTable.set(pos, shp.getBounds()); - fontAdvanceTable.set(pos, (int) getDivider() * Math.round(FontHelper.getFontAdvance(fnt, character))); - } - } - - setModified(true); - } - - @Override - public void setAdvanceValues(Font font) { - boolean hasLayout = fontFlagsHasLayout; - fontFlagsHasLayout = true; - fontAdvanceTable = new ArrayList<>(); - if (!hasLayout) { - fontBoundsTable = new ArrayList<>(); - fontKerningTable = new ArrayList<>(); - } - - for (Integer character : codeTable) { - char ch = (char) (int) character; - SHAPE shp = SHAPERECORD.fontCharacterToSHAPE(font, (int) Math.round(getDivider() * 1024), ch); - fontBoundsTable.add(shp.getBounds()); - int fontStyle = getFontStyle(); - Font fnt = new Font(font.getFontName(), fontStyle, 1024); // Not multiplied with divider as it causes problems to create font with height around 20k - fontAdvanceTable.add((int) getDivider() * Math.round(FontHelper.getFontAdvance(fnt, ch))); - } - } - - @Override - public String getCharacters(List tags) { - StringBuilder ret = new StringBuilder(); - for (int i : codeTable) { - ret.append((char) i); - } - return ret.toString(); - } - - @Override - public boolean hasLayout() { - return fontFlagsHasLayout; - } - - @Override - public RECT getGlyphBounds(int glyphIndex) { - if (fontFlagsHasLayout) { - return fontBoundsTable.get(glyphIndex); - } - return super.getGlyphBounds(glyphIndex); - } - - @Override - public int getGlyphKerningAdjustment(int glyphIndex, int nextGlyphIndex) { - if (glyphIndex == -1 || nextGlyphIndex == -1) { - return 0; - } - char c1 = glyphToChar(glyphIndex); - char c2 = glyphToChar(nextGlyphIndex); - return getCharKerningAdjustment(c1, c2); - } - - @Override - public int getCharKerningAdjustment(char c1, char c2) { - int kerningAdjustment = 0; - for (KERNINGRECORD ker : fontKerningTable) { - if (ker.fontKerningCode1 == c1 && ker.fontKerningCode2 == c2) { - kerningAdjustment = ker.fontKerningAdjustment; - break; - } - } - return kerningAdjustment; - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.abc.CopyOutputStream; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.helpers.FontHelper; +import com.jpexs.decompiler.flash.tags.base.FontTag; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.KERNINGRECORD; +import com.jpexs.decompiler.flash.types.LANGCODE; +import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.decompiler.flash.types.SHAPE; +import com.jpexs.decompiler.flash.types.annotations.Conditional; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD; +import com.jpexs.helpers.ByteArrayRange; +import com.jpexs.helpers.utf8.Utf8Helper; +import java.awt.Font; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author JPEXS + */ +public class DefineFont3Tag extends FontTag { + + @SWFType(BasicType.UI16) + public int fontId; + + public boolean fontFlagsHasLayout; + + public boolean fontFlagsShiftJIS; + + public boolean fontFlagsSmallText; + + public boolean fontFlagsANSI; + + public boolean fontFlagsWideOffsets; + + public boolean fontFlagsWideCodes; + + public boolean fontFlagsItalic; + + public boolean fontFlagsBold; + + public LANGCODE languageCode; + + public String fontName; + + public List glyphShapeTable; + + @SWFType(value = BasicType.UI8, alternateValue = BasicType.UI16, alternateCondition = "fontFlagsWideCodes") + public List codeTable; + + @SWFType(BasicType.UI16) + @Conditional("fontFlagsHasLayout") + public int fontAscent; + + @SWFType(BasicType.UI16) + @Conditional("fontFlagsHasLayout") + public int fontDescent; + + @SWFType(BasicType.SI16) + @Conditional("fontFlagsHasLayout") + public int fontLeading; + + @SWFType(BasicType.SI16) + @Conditional("fontFlagsHasLayout") + public List fontAdvanceTable; + + @Conditional("fontFlagsHasLayout") + public List fontBoundsTable; + + @Conditional("fontFlagsHasLayout") + public List fontKerningTable; + + public static final int ID = 75; + + public static final String NAME = "DefineFont3"; + + @Override + public boolean isSmall() { + return fontFlagsSmallText; + } + + @Override + public int getGlyphWidth(int glyphIndex) { + return glyphShapeTable.get(glyphIndex).getBounds().getWidth(); + } + + @Override + public double getGlyphAdvance(int glyphIndex) { + if (fontFlagsHasLayout && glyphIndex != -1) { + return fontAdvanceTable.get(glyphIndex); + } else { + return -1; + } + } + + @Override + public char glyphToChar(int glyphIndex) { + return (char) (int) codeTable.get(glyphIndex); + } + + @Override + public int charToGlyph(char c) { + return codeTable.indexOf((int) c); + } + + /** + * Constructor + * + * @param swf + */ + public DefineFont3Tag(SWF swf) { + super(swf, ID, NAME, null); + fontId = swf.getNextCharacterId(); + languageCode = new LANGCODE(); + fontName = "New font"; + glyphShapeTable = new ArrayList<>(); + codeTable = new ArrayList<>(); + } + + public DefineFont3Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + fontId = sis.readUI16("fontId"); + fontFlagsHasLayout = sis.readUB(1, "fontFlagsHasLayout") == 1; + fontFlagsShiftJIS = sis.readUB(1, "fontFlagsShiftJIS") == 1; + fontFlagsSmallText = sis.readUB(1, "fontFlagsSmallText") == 1; + fontFlagsANSI = sis.readUB(1, "fontFlagsANSI") == 1; + fontFlagsWideOffsets = sis.readUB(1, "fontFlagsWideOffsets") == 1; + fontFlagsWideCodes = sis.readUB(1, "fontFlagsWideCodes") == 1; + fontFlagsItalic = sis.readUB(1, "fontFlagsItalic") == 1; + fontFlagsBold = sis.readUB(1, "fontFlagsBold") == 1; + languageCode = sis.readLANGCODE("languageCode"); + int fontNameLen = sis.readUI8("fontNameLen"); + if (swf.version >= 6) { + fontName = new String(sis.readBytesEx(fontNameLen, "fontName"), Utf8Helper.charset); + } else { + fontName = new String(sis.readBytesEx(fontNameLen, "fontName")); + } + int numGlyphs = sis.readUI16("numGlyphs"); + long[] offsetTable = new long[numGlyphs]; + long pos = sis.getPos(); + for (int i = 0; i < numGlyphs; i++) { //offsetTable + if (fontFlagsWideOffsets) { + offsetTable[i] = sis.readUI32("offset"); + } else { + offsetTable[i] = sis.readUI16("offset"); + } + } + if (numGlyphs > 0) { + if (fontFlagsWideOffsets) { + sis.readUI32("codeTableOffset"); //codeTableOffset + } else { + sis.readUI16("codeTableOffset"); //codeTableOffset + } + } + glyphShapeTable = new ArrayList<>(); + for (int i = 0; i < numGlyphs; i++) { + sis.seek(pos + offsetTable[i]); + glyphShapeTable.add(sis.readSHAPE(1, false, "shape")); + } + codeTable = new ArrayList<>(); + for (int i = 0; i < numGlyphs; i++) { + if (fontFlagsWideCodes) { + codeTable.add(sis.readUI16("code")); + } else { + codeTable.add(sis.readUI8("code")); + } + } + if (fontFlagsHasLayout) { + fontAscent = sis.readUI16("fontAscent"); + fontDescent = sis.readUI16("fontDescent"); + fontLeading = sis.readSI16("fontLeading"); + fontAdvanceTable = new ArrayList<>(); + for (int i = 0; i < numGlyphs; i++) { + fontAdvanceTable.add(sis.readSI16("fontAdvance")); + } + fontBoundsTable = new ArrayList<>(); + for (int i = 0; i < numGlyphs; i++) { + fontBoundsTable.add(sis.readRECT("rect")); + } + int kerningCount = sis.readUI16("kerningCount"); + fontKerningTable = new ArrayList<>(); + for (int i = 0; i < kerningCount; i++) { + fontKerningTable.add(sis.readKERNINGRECORD(fontFlagsWideCodes, "record")); + } + } + } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + if (Configuration.debugCopy.get()) { + sos = new SWFOutputStream(new CopyOutputStream(sos, new ByteArrayInputStream(getOriginalData())), getVersion()); + } + try { + List offsetTable = new ArrayList<>(); + ByteArrayOutputStream baosGlyphShapes = new ByteArrayOutputStream(); + SWFOutputStream sos3 = new SWFOutputStream(baosGlyphShapes, getVersion()); + int numGlyphs = glyphShapeTable.size(); + for (int i = 0; i < numGlyphs; i++) { + offsetTable.add(sos3.getPos()); + sos3.writeSHAPE(glyphShapeTable.get(i), 1); + } + byte[] baGlyphShapes = baosGlyphShapes.toByteArray(); + + if (!fontFlagsWideOffsets && numGlyphs > 0) { + // Set wide offsets when necessary + long maxOffset = (glyphShapeTable.size() + 1/*CodeTableOffset*/) * 2 + baGlyphShapes.length; + if (maxOffset > 65535) { + fontFlagsWideOffsets = true; + } + } + + sos.writeUI16(fontId); + sos.writeUB(1, fontFlagsHasLayout ? 1 : 0); + sos.writeUB(1, fontFlagsShiftJIS ? 1 : 0); + sos.writeUB(1, fontFlagsSmallText ? 1 : 0); + sos.writeUB(1, fontFlagsANSI ? 1 : 0); + sos.writeUB(1, fontFlagsWideOffsets ? 1 : 0); + sos.writeUB(1, fontFlagsWideCodes ? 1 : 0); + sos.writeUB(1, fontFlagsItalic ? 1 : 0); + sos.writeUB(1, fontFlagsBold ? 1 : 0); + sos.writeLANGCODE(languageCode); + byte[] fontNameBytes = Utf8Helper.getBytes(fontName); + sos.writeUI8(fontNameBytes.length); + sos.write(fontNameBytes); + sos.writeUI16(numGlyphs); + + for (long offset : offsetTable) { + long offset2 = (glyphShapeTable.size() + 1/*CodeTableOffset*/) * (fontFlagsWideOffsets ? 4 : 2) + offset; + if (fontFlagsWideOffsets) { + sos.writeUI32(offset2); + } else { + sos.writeUI16((int) offset2); + } + } + if (numGlyphs > 0) { + long offset = (glyphShapeTable.size() + 1/*CodeTableOffset*/) * (fontFlagsWideOffsets ? 4 : 2) + baGlyphShapes.length; + if (fontFlagsWideOffsets) { + sos.writeUI32(offset); + } else { + sos.writeUI16((int) offset); + } + sos.write(baGlyphShapes); + + for (int i = 0; i < numGlyphs; i++) { + if (fontFlagsWideCodes) { + sos.writeUI16(codeTable.get(i)); + } else { + sos.writeUI8(codeTable.get(i)); + } + } + } + if (fontFlagsHasLayout) { + sos.writeSI16(fontAscent); + sos.writeSI16(fontDescent); + sos.writeSI16(fontLeading); + for (int i = 0; i < numGlyphs; i++) { + sos.writeSI16(fontAdvanceTable.get(i)); + } + for (int i = 0; i < numGlyphs; i++) { + sos.writeRECT(fontBoundsTable.get(i)); + } + sos.writeUI16(fontKerningTable.size()); + for (int k = 0; k < fontKerningTable.size(); k++) { + sos.writeKERNINGRECORD(fontKerningTable.get(k), fontFlagsWideCodes); + } + } + + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + @Override + public int getFontId() { + return fontId; + } + + @Override + public List getGlyphShapeTable() { + return glyphShapeTable; + } + + @Override + public int getCharacterId() { + return fontId; + } + + @Override + public void setCharacterId(int characterId) { + this.fontId = characterId; + } + + @Override + public String getFontNameIntag() { + String ret = fontName; + if (ret.contains("" + (char) 0)) { + ret = ret.substring(0, ret.indexOf(0)); + } + return ret; + } + + @Override + public boolean isBold() { + return fontFlagsBold; + } + + @Override + public boolean isItalic() { + return fontFlagsItalic; + } + + @Override + public boolean isSmallEditable() { + return true; + } + + @Override + public boolean isBoldEditable() { + return true; + } + + @Override + public boolean isItalicEditable() { + return true; + } + + @Override + public void setSmall(boolean value) { + fontFlagsSmallText = value; + } + + @Override + public void setBold(boolean value) { + fontFlagsBold = value; + } + + @Override + public void setItalic(boolean value) { + fontFlagsItalic = value; + } + + @Override + public double getDivider() { + return 20; + } + + @Override + public int getAscent() { + if (fontFlagsHasLayout) { + return fontAscent; + } + return -1; + } + + @Override + public int getDescent() { + if (fontFlagsHasLayout) { + return fontDescent; + } + return -1; + } + + @Override + public int getLeading() { + if (fontFlagsHasLayout) { + return fontLeading; + } + return -1; + } + + @Override + public void addCharacter(char character, Font font) { + + //Font Align Zones will be removed as adding new character zones is not supported:-( + for (int i = 0; i < swf.tags.size(); i++) { + Tag t = swf.tags.get(i); + if (t instanceof DefineFontAlignZonesTag) { + DefineFontAlignZonesTag fa = (DefineFontAlignZonesTag) t; + if (fa.fontID == fontId) { + swf.tags.remove(i); + i--; + } + } + } + int fontStyle = getFontStyle(); + SHAPE shp = SHAPERECORD.fontCharacterToSHAPE(font, (int) Math.round(getDivider() * 1024), character); + int code = (int) character; + int pos = -1; + boolean exists = false; + for (int i = 0; i < codeTable.size(); i++) { + if (codeTable.get(i) >= code) { + if (codeTable.get(i) == code) { + exists = true; + } + pos = i; + break; + } + } + if (pos == -1) { + pos = codeTable.size(); + } + + if (!exists) { + shiftGlyphIndices(fontId, pos); + glyphShapeTable.add(pos, shp); + codeTable.add(pos, (int) character); + } else { + glyphShapeTable.set(pos, shp); + } + if (fontFlagsHasLayout) { + + Font fnt = new Font(fontName, fontStyle, 1024); // Not multiplied with divider as it causes problems to create font with height around 20k + if (!exists) { + fontBoundsTable.add(pos, shp.getBounds()); + fontAdvanceTable.add(pos, (int) getDivider() * Math.round(FontHelper.getFontAdvance(fnt, character))); + } else { + fontBoundsTable.set(pos, shp.getBounds()); + fontAdvanceTable.set(pos, (int) getDivider() * Math.round(FontHelper.getFontAdvance(fnt, character))); + } + } + + setModified(true); + } + + @Override + public void setAdvanceValues(Font font) { + boolean hasLayout = fontFlagsHasLayout; + fontFlagsHasLayout = true; + fontAdvanceTable = new ArrayList<>(); + if (!hasLayout) { + fontBoundsTable = new ArrayList<>(); + fontKerningTable = new ArrayList<>(); + } + + for (Integer character : codeTable) { + char ch = (char) (int) character; + SHAPE shp = SHAPERECORD.fontCharacterToSHAPE(font, (int) Math.round(getDivider() * 1024), ch); + fontBoundsTable.add(shp.getBounds()); + int fontStyle = getFontStyle(); + Font fnt = new Font(font.getFontName(), fontStyle, 1024); // Not multiplied with divider as it causes problems to create font with height around 20k + fontAdvanceTable.add((int) getDivider() * Math.round(FontHelper.getFontAdvance(fnt, ch))); + } + } + + @Override + public String getCharacters(List tags) { + StringBuilder ret = new StringBuilder(); + for (int i : codeTable) { + ret.append((char) i); + } + return ret.toString(); + } + + @Override + public boolean hasLayout() { + return fontFlagsHasLayout; + } + + @Override + public RECT getGlyphBounds(int glyphIndex) { + if (fontFlagsHasLayout) { + return fontBoundsTable.get(glyphIndex); + } + return super.getGlyphBounds(glyphIndex); + } + + @Override + public int getGlyphKerningAdjustment(int glyphIndex, int nextGlyphIndex) { + if (glyphIndex == -1 || nextGlyphIndex == -1) { + return 0; + } + char c1 = glyphToChar(glyphIndex); + char c2 = glyphToChar(nextGlyphIndex); + return getCharKerningAdjustment(c1, c2); + } + + @Override + public int getCharKerningAdjustment(char c1, char c2) { + int kerningAdjustment = 0; + for (KERNINGRECORD ker : fontKerningTable) { + if (ker.fontKerningCode1 == c1 && ker.fontKerningCode2 == c2) { + kerningAdjustment = ker.fontKerningAdjustment; + break; + } + } + return kerningAdjustment; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont4Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont4Tag.java index 6cc53d254..416248103 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont4Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont4Tag.java @@ -1,117 +1,119 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.tags.base.CharacterTag; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.annotations.Reserved; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.helpers.ByteArrayRange; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -/** - * - * @author JPEXS - */ -public class DefineFont4Tag extends CharacterTag { - - @SWFType(BasicType.UI16) - public int fontID; - - @Reserved - @SWFType(value = BasicType.UB, count = 5) - public int reserved; - - public boolean fontFlagsHasFontData; - - public boolean fontFlagsItalic; - - public boolean fontFlagsBold; - - public String fontName; - - public byte[] fontData; - - public static final int ID = 91; - - @Override - public int getCharacterId() { - return fontID; - } - - @Override - public void setCharacterId(int characterId) { - this.fontID = characterId; - } - - /** - * Constructor - * - * @param swf - */ - public DefineFont4Tag(SWF swf) { - super(swf, ID, "DefineFont4", null); - fontID = swf.getNextCharacterId(); - fontName = "New font"; - fontData = new byte[0]; - } - - public DefineFont4Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DefineFont4", data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - fontID = sis.readUI16("fontID"); - reserved = (int) sis.readUB(5, "reserved"); - fontFlagsHasFontData = sis.readUB(1, "fontFlagsHasFontData") == 1; - fontFlagsItalic = sis.readUB(1, "fontFlagsItalic") == 1; - fontFlagsBold = sis.readUB(1, "fontFlagsBold") == 1; - fontName = sis.readString("fontName"); - fontData = sis.readBytesEx(sis.available(), "fontData"); - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(fontID); - sos.writeUB(5, reserved); - sos.writeUB(1, fontFlagsHasFontData ? 1 : 0); - sos.writeUB(1, fontFlagsItalic ? 1 : 0); - sos.writeUB(1, fontFlagsBold ? 1 : 0); - sos.writeString(fontName); - sos.write(fontData); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.tags.base.CharacterTag; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.annotations.Reserved; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.helpers.ByteArrayRange; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * + * @author JPEXS + */ +public class DefineFont4Tag extends CharacterTag { + + @SWFType(BasicType.UI16) + public int fontID; + + @Reserved + @SWFType(value = BasicType.UB, count = 5) + public int reserved; + + public boolean fontFlagsHasFontData; + + public boolean fontFlagsItalic; + + public boolean fontFlagsBold; + + public String fontName; + + public byte[] fontData; + + public static final int ID = 91; + + public static final String NAME = "DefineFont4"; + + @Override + public int getCharacterId() { + return fontID; + } + + @Override + public void setCharacterId(int characterId) { + this.fontID = characterId; + } + + /** + * Constructor + * + * @param swf + */ + public DefineFont4Tag(SWF swf) { + super(swf, ID, NAME, null); + fontID = swf.getNextCharacterId(); + fontName = "New font"; + fontData = new byte[0]; + } + + public DefineFont4Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + fontID = sis.readUI16("fontID"); + reserved = (int) sis.readUB(5, "reserved"); + fontFlagsHasFontData = sis.readUB(1, "fontFlagsHasFontData") == 1; + fontFlagsItalic = sis.readUB(1, "fontFlagsItalic") == 1; + fontFlagsBold = sis.readUB(1, "fontFlagsBold") == 1; + fontName = sis.readString("fontName"); + fontData = sis.readBytesEx(sis.available(), "fontData"); + } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(fontID); + sos.writeUB(5, reserved); + sos.writeUB(1, fontFlagsHasFontData ? 1 : 0); + sos.writeUB(1, fontFlagsItalic ? 1 : 0); + sos.writeUB(1, fontFlagsBold ? 1 : 0); + sos.writeString(fontName); + sos.write(fontData); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontAlignZonesTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontAlignZonesTag.java index cbcd0039b..9f2eea4a0 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontAlignZonesTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontAlignZonesTag.java @@ -1,115 +1,117 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.tags.base.CharacterIdTag; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.ZONERECORD; -import com.jpexs.decompiler.flash.types.annotations.Reserved; -import com.jpexs.decompiler.flash.types.annotations.SWFArray; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.helpers.ByteArrayRange; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; - -/** - * - * @author JPEXS - */ -public class DefineFontAlignZonesTag extends Tag implements CharacterIdTag { - - @SWFType(BasicType.UI16) - public int fontID; - - @SWFType(value = BasicType.UB, count = 2) - public int CSMTableHint; - - @Reserved - @SWFType(value = BasicType.UB, count = 6) - public int reserved; - - @SWFArray(value = "zone", countField = "glyphCount") - public List zoneTable; - - public static final int ID = 73; - - /** - * Constructor - * - * @param swf - */ - public DefineFontAlignZonesTag(SWF swf) { - super(swf, ID, "DefineFontAlignZones", null); - zoneTable = new ArrayList<>(); - } - - public DefineFontAlignZonesTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DefineFontAlignZones", data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - fontID = sis.readUI16("fontID"); - CSMTableHint = (int) sis.readUB(2, "CSMTableHint"); - reserved = (int) sis.readUB(6, "reserved"); - zoneTable = new ArrayList<>(); - while (sis.available() > 0) { - ZONERECORD zr = sis.readZONERECORD("record"); - zoneTable.add(zr); - } - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(fontID); - sos.writeUB(2, CSMTableHint); - sos.writeUB(6, reserved); - for (ZONERECORD z : zoneTable) { - sos.writeZONERECORD(z); - } - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - - @Override - public int getCharacterId() { - return fontID; - } - - @Override - public void setCharacterId(int characterId) { - this.fontID = characterId; - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.tags.base.CharacterIdTag; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.ZONERECORD; +import com.jpexs.decompiler.flash.types.annotations.Reserved; +import com.jpexs.decompiler.flash.types.annotations.SWFArray; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.helpers.ByteArrayRange; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author JPEXS + */ +public class DefineFontAlignZonesTag extends Tag implements CharacterIdTag { + + @SWFType(BasicType.UI16) + public int fontID; + + @SWFType(value = BasicType.UB, count = 2) + public int CSMTableHint; + + @Reserved + @SWFType(value = BasicType.UB, count = 6) + public int reserved; + + @SWFArray(value = "zone", countField = "glyphCount") + public List zoneTable; + + public static final int ID = 73; + + public static final String NAME = "DefineFontAlignZones"; + + /** + * Constructor + * + * @param swf + */ + public DefineFontAlignZonesTag(SWF swf) { + super(swf, ID, NAME, null); + zoneTable = new ArrayList<>(); + } + + public DefineFontAlignZonesTag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + fontID = sis.readUI16("fontID"); + CSMTableHint = (int) sis.readUB(2, "CSMTableHint"); + reserved = (int) sis.readUB(6, "reserved"); + zoneTable = new ArrayList<>(); + while (sis.available() > 0) { + ZONERECORD zr = sis.readZONERECORD("record"); + zoneTable.add(zr); + } + } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(fontID); + sos.writeUB(2, CSMTableHint); + sos.writeUB(6, reserved); + for (ZONERECORD z : zoneTable) { + sos.writeZONERECORD(z); + } + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + @Override + public int getCharacterId() { + return fontID; + } + + @Override + public void setCharacterId(int characterId) { + this.fontID = characterId; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfo2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfo2Tag.java index f4c5be3ff..5870d5cef 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfo2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfo2Tag.java @@ -1,158 +1,160 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.tags.base.CharacterIdTag; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.LANGCODE; -import com.jpexs.decompiler.flash.types.annotations.Reserved; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.helpers.ByteArrayRange; -import com.jpexs.helpers.utf8.Utf8Helper; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; - -/** - * - * @author JPEXS - */ -public class DefineFontInfo2Tag extends Tag implements CharacterIdTag { - - @SWFType(BasicType.UI16) - public int fontID; - - public String fontName; - - @Reserved - @SWFType(value = BasicType.UB, count = 2) - public int reserved; - - public boolean fontFlagsSmallText; - - public boolean fontFlagsShiftJIS; - - public boolean fontFlagsANSI; - - public boolean fontFlagsItalic; - - public boolean fontFlagsBold; - - public boolean fontFlagsWideCodes; //always 1 - - public LANGCODE languageCode; - - @SWFType(BasicType.UI16) - public List codeTable; - - public static final int ID = 62; - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(fontID); - byte[] fontNameBytes = Utf8Helper.getBytes(fontName); - sos.writeUI8(fontNameBytes.length); - sos.write(fontNameBytes); - sos.writeUB(2, reserved); - sos.writeUB(1, fontFlagsSmallText ? 1 : 0); - sos.writeUB(1, fontFlagsShiftJIS ? 1 : 0); - sos.writeUB(1, fontFlagsANSI ? 1 : 0); - sos.writeUB(1, fontFlagsItalic ? 1 : 0); - sos.writeUB(1, fontFlagsBold ? 1 : 0); - sos.writeUB(1, fontFlagsWideCodes ? 1 : 0); - sos.writeLANGCODE(languageCode); - for (int c : codeTable) { - sos.writeUI16(c); - } - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - - /** - * Constructor - * - * @param swf - */ - public DefineFontInfo2Tag(SWF swf) { - super(swf, ID, "DefineFontInfo2", null); - fontName = "New Font Info Name"; - languageCode = new LANGCODE(); - codeTable = new ArrayList<>(); - } - - /** - * Constructor - * - * @param sis - * @param data - * @throws IOException - */ - public DefineFontInfo2Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DefineFontInfo2", data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - fontID = sis.readUI16("fontID"); - int fontNameLen = sis.readUI8("fontNameLen"); - if (swf.version >= 6) { - fontName = new String(sis.readBytesEx(fontNameLen, "fontName"), Utf8Helper.charset); - } else { - fontName = new String(sis.readBytesEx(fontNameLen, "fontName")); - } - reserved = (int) sis.readUB(2, "reserved"); - fontFlagsSmallText = sis.readUB(1, "fontFlagsSmallText") == 1; - fontFlagsShiftJIS = sis.readUB(1, "fontFlagsShiftJIS") == 1; - fontFlagsANSI = sis.readUB(1, "fontFlagsANSI") == 1; - fontFlagsItalic = sis.readUB(1, "fontFlagsItalic") == 1; - fontFlagsBold = sis.readUB(1, "fontFlagsBold") == 1; - fontFlagsWideCodes = sis.readUB(1, "fontFlagsWideCodes") == 1; //Always 1 - languageCode = sis.readLANGCODE("languageCode"); - int ctLen = sis.available() / 2; - codeTable = new ArrayList<>(); - for (int i = 0; i < ctLen; i++) { - codeTable.add(sis.readUI16("code")); - } - } - - @Override - public int getCharacterId() { - return fontID; - } - - @Override - public void setCharacterId(int characterId) { - this.fontID = characterId; - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.tags.base.CharacterIdTag; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.LANGCODE; +import com.jpexs.decompiler.flash.types.annotations.Reserved; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.helpers.ByteArrayRange; +import com.jpexs.helpers.utf8.Utf8Helper; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author JPEXS + */ +public class DefineFontInfo2Tag extends Tag implements CharacterIdTag { + + @SWFType(BasicType.UI16) + public int fontID; + + public String fontName; + + @Reserved + @SWFType(value = BasicType.UB, count = 2) + public int reserved; + + public boolean fontFlagsSmallText; + + public boolean fontFlagsShiftJIS; + + public boolean fontFlagsANSI; + + public boolean fontFlagsItalic; + + public boolean fontFlagsBold; + + public boolean fontFlagsWideCodes; //always 1 + + public LANGCODE languageCode; + + @SWFType(BasicType.UI16) + public List codeTable; + + public static final int ID = 62; + + public static final String NAME = "DefineFontInfo2"; + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(fontID); + byte[] fontNameBytes = Utf8Helper.getBytes(fontName); + sos.writeUI8(fontNameBytes.length); + sos.write(fontNameBytes); + sos.writeUB(2, reserved); + sos.writeUB(1, fontFlagsSmallText ? 1 : 0); + sos.writeUB(1, fontFlagsShiftJIS ? 1 : 0); + sos.writeUB(1, fontFlagsANSI ? 1 : 0); + sos.writeUB(1, fontFlagsItalic ? 1 : 0); + sos.writeUB(1, fontFlagsBold ? 1 : 0); + sos.writeUB(1, fontFlagsWideCodes ? 1 : 0); + sos.writeLANGCODE(languageCode); + for (int c : codeTable) { + sos.writeUI16(c); + } + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + /** + * Constructor + * + * @param swf + */ + public DefineFontInfo2Tag(SWF swf) { + super(swf, ID, NAME, null); + fontName = "New Font Info Name"; + languageCode = new LANGCODE(); + codeTable = new ArrayList<>(); + } + + /** + * Constructor + * + * @param sis + * @param data + * @throws IOException + */ + public DefineFontInfo2Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + fontID = sis.readUI16("fontID"); + int fontNameLen = sis.readUI8("fontNameLen"); + if (swf.version >= 6) { + fontName = new String(sis.readBytesEx(fontNameLen, "fontName"), Utf8Helper.charset); + } else { + fontName = new String(sis.readBytesEx(fontNameLen, "fontName")); + } + reserved = (int) sis.readUB(2, "reserved"); + fontFlagsSmallText = sis.readUB(1, "fontFlagsSmallText") == 1; + fontFlagsShiftJIS = sis.readUB(1, "fontFlagsShiftJIS") == 1; + fontFlagsANSI = sis.readUB(1, "fontFlagsANSI") == 1; + fontFlagsItalic = sis.readUB(1, "fontFlagsItalic") == 1; + fontFlagsBold = sis.readUB(1, "fontFlagsBold") == 1; + fontFlagsWideCodes = sis.readUB(1, "fontFlagsWideCodes") == 1; //Always 1 + languageCode = sis.readLANGCODE("languageCode"); + int ctLen = sis.available() / 2; + codeTable = new ArrayList<>(); + for (int i = 0; i < ctLen; i++) { + codeTable.add(sis.readUI16("code")); + } + } + + @Override + public int getCharacterId() { + return fontID; + } + + @Override + public void setCharacterId(int characterId) { + this.fontID = characterId; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfoTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfoTag.java index 268aa2afa..313b369a4 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfoTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfoTag.java @@ -1,159 +1,161 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.tags.base.CharacterIdTag; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.annotations.Reserved; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.helpers.ByteArrayRange; -import com.jpexs.helpers.utf8.Utf8Helper; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; - -/** - * - * @author JPEXS - */ -public class DefineFontInfoTag extends Tag implements CharacterIdTag { - - @SWFType(BasicType.UI16) - public int fontId; - - public String fontName; - - @Reserved - @SWFType(value = BasicType.UB, count = 2) - public int reserved; - - public boolean fontFlagsSmallText; - - public boolean fontFlagsShiftJIS; - - public boolean fontFlagsANSI; - - public boolean fontFlagsItalic; - - public boolean fontFlagsBold; - - public boolean fontFlagsWideCodes; - - @SWFType(value = BasicType.UI8, alternateValue = BasicType.UI16, alternateCondition = "fontFlagsWideCodes") - public List codeTable; - - public static final int ID = 13; - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(fontId); - byte[] fontNameBytes = Utf8Helper.getBytes(fontName); - sos.writeUI8(fontNameBytes.length); - sos.write(fontNameBytes); - sos.writeUB(2, reserved); - sos.writeUB(1, fontFlagsSmallText ? 1 : 0); - sos.writeUB(1, fontFlagsShiftJIS ? 1 : 0); - sos.writeUB(1, fontFlagsANSI ? 1 : 0); - sos.writeUB(1, fontFlagsItalic ? 1 : 0); - sos.writeUB(1, fontFlagsBold ? 1 : 0); - sos.writeUB(1, fontFlagsWideCodes ? 1 : 0); - for (int code : codeTable) { - if (fontFlagsWideCodes) { - sos.writeUI16(code); - } else { - sos.writeUI8(code); - } - } - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - - /** - * Constructor - * - * @param swf - */ - public DefineFontInfoTag(SWF swf) { - super(swf, ID, "DefineFontInfo", null); - fontName = "New Font Info Name"; - codeTable = new ArrayList<>(); - } - - /** - * Constructor - * - * @param sis - * @param data - * @throws IOException - */ - public DefineFontInfoTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DefineFontInfo", data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - fontId = sis.readUI16("fontId"); - int fontNameLen = sis.readUI8("fontNameLen"); - if (swf.version >= 6) { - fontName = new String(sis.readBytesEx(fontNameLen, "fontName"), Utf8Helper.charset); - } else { - fontName = new String(sis.readBytesEx(fontNameLen, "fontName")); - } - reserved = (int) sis.readUB(2, "reserved"); - fontFlagsSmallText = sis.readUB(1, "fontFlagsSmallText") == 1; - fontFlagsShiftJIS = sis.readUB(1, "fontFlagsShiftJIS") == 1; - fontFlagsANSI = sis.readUB(1, "fontFlagsANSI") == 1; - fontFlagsItalic = sis.readUB(1, "fontFlagsItalic") == 1; - fontFlagsBold = sis.readUB(1, "fontFlagsBold") == 1; - fontFlagsWideCodes = sis.readUB(1, "fontFlagsWideCodes") == 1; - codeTable = new ArrayList<>(); - while (sis.available() > 0) { - if (fontFlagsWideCodes) { - codeTable.add(sis.readUI16("code")); - } else { - codeTable.add(sis.readUI8("code")); - } - } - } - - @Override - public int getCharacterId() { - return fontId; - } - - @Override - public void setCharacterId(int characterId) { - this.fontId = characterId; - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.tags.base.CharacterIdTag; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.annotations.Reserved; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.helpers.ByteArrayRange; +import com.jpexs.helpers.utf8.Utf8Helper; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author JPEXS + */ +public class DefineFontInfoTag extends Tag implements CharacterIdTag { + + @SWFType(BasicType.UI16) + public int fontId; + + public String fontName; + + @Reserved + @SWFType(value = BasicType.UB, count = 2) + public int reserved; + + public boolean fontFlagsSmallText; + + public boolean fontFlagsShiftJIS; + + public boolean fontFlagsANSI; + + public boolean fontFlagsItalic; + + public boolean fontFlagsBold; + + public boolean fontFlagsWideCodes; + + @SWFType(value = BasicType.UI8, alternateValue = BasicType.UI16, alternateCondition = "fontFlagsWideCodes") + public List codeTable; + + public static final int ID = 13; + + public static final String NAME = "DefineFontInfo"; + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(fontId); + byte[] fontNameBytes = Utf8Helper.getBytes(fontName); + sos.writeUI8(fontNameBytes.length); + sos.write(fontNameBytes); + sos.writeUB(2, reserved); + sos.writeUB(1, fontFlagsSmallText ? 1 : 0); + sos.writeUB(1, fontFlagsShiftJIS ? 1 : 0); + sos.writeUB(1, fontFlagsANSI ? 1 : 0); + sos.writeUB(1, fontFlagsItalic ? 1 : 0); + sos.writeUB(1, fontFlagsBold ? 1 : 0); + sos.writeUB(1, fontFlagsWideCodes ? 1 : 0); + for (int code : codeTable) { + if (fontFlagsWideCodes) { + sos.writeUI16(code); + } else { + sos.writeUI8(code); + } + } + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + /** + * Constructor + * + * @param swf + */ + public DefineFontInfoTag(SWF swf) { + super(swf, ID, NAME, null); + fontName = "New Font Info Name"; + codeTable = new ArrayList<>(); + } + + /** + * Constructor + * + * @param sis + * @param data + * @throws IOException + */ + public DefineFontInfoTag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + fontId = sis.readUI16("fontId"); + int fontNameLen = sis.readUI8("fontNameLen"); + if (swf.version >= 6) { + fontName = new String(sis.readBytesEx(fontNameLen, "fontName"), Utf8Helper.charset); + } else { + fontName = new String(sis.readBytesEx(fontNameLen, "fontName")); + } + reserved = (int) sis.readUB(2, "reserved"); + fontFlagsSmallText = sis.readUB(1, "fontFlagsSmallText") == 1; + fontFlagsShiftJIS = sis.readUB(1, "fontFlagsShiftJIS") == 1; + fontFlagsANSI = sis.readUB(1, "fontFlagsANSI") == 1; + fontFlagsItalic = sis.readUB(1, "fontFlagsItalic") == 1; + fontFlagsBold = sis.readUB(1, "fontFlagsBold") == 1; + fontFlagsWideCodes = sis.readUB(1, "fontFlagsWideCodes") == 1; + codeTable = new ArrayList<>(); + while (sis.available() > 0) { + if (fontFlagsWideCodes) { + codeTable.add(sis.readUI16("code")); + } else { + codeTable.add(sis.readUI8("code")); + } + } + } + + @Override + public int getCharacterId() { + return fontId; + } + + @Override + public void setCharacterId(int characterId) { + this.fontId = characterId; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontNameTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontNameTag.java index e003004ea..b919a4c97 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontNameTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontNameTag.java @@ -1,97 +1,99 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.tags.base.CharacterIdTag; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.helpers.ByteArrayRange; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -/** - * - * @author JPEXS - */ -public class DefineFontNameTag extends Tag implements CharacterIdTag { - - @SWFType(BasicType.UI16) - public int fontId; - - public String fontName; - - public String fontCopyright; - - public static final int ID = 88; - - /** - * Constructor - * - * @param swf - */ - public DefineFontNameTag(SWF swf) { - super(swf, ID, "DefineFontName", null); - fontName = "New Font Name"; - fontCopyright = "Copyright text"; - } - - public DefineFontNameTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DefineFontName", data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - fontId = sis.readUI16("fontId"); - fontName = sis.readString("fontName"); - fontCopyright = sis.readString("fontCopyright"); - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(fontId); - sos.writeString(fontName); - sos.writeString(fontCopyright); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - - @Override - public int getCharacterId() { - return fontId; - } - - @Override - public void setCharacterId(int characterId) { - this.fontId = characterId; - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.tags.base.CharacterIdTag; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.helpers.ByteArrayRange; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * + * @author JPEXS + */ +public class DefineFontNameTag extends Tag implements CharacterIdTag { + + @SWFType(BasicType.UI16) + public int fontId; + + public String fontName; + + public String fontCopyright; + + public static final int ID = 88; + + public static final String NAME = "DefineFontName"; + + /** + * Constructor + * + * @param swf + */ + public DefineFontNameTag(SWF swf) { + super(swf, ID, NAME, null); + fontName = "New Font Name"; + fontCopyright = "Copyright text"; + } + + public DefineFontNameTag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + fontId = sis.readUI16("fontId"); + fontName = sis.readString("fontName"); + fontCopyright = sis.readString("fontCopyright"); + } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(fontId); + sos.writeString(fontName); + sos.writeString(fontCopyright); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + @Override + public int getCharacterId() { + return fontId; + } + + @Override + public void setCharacterId(int characterId) { + this.fontId = characterId; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontTag.java index 80597408c..43b683b58 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontTag.java @@ -1,368 +1,370 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.tags.base.FontTag; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.SHAPE; -import com.jpexs.decompiler.flash.types.annotations.Internal; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD; -import com.jpexs.helpers.ByteArrayRange; -import java.awt.Font; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; - -/** - * - * @author JPEXS - */ -public class DefineFontTag extends FontTag { - - @SWFType(BasicType.UI16) - public int fontId; - - public List glyphShapeTable; - - @Internal - private DefineFontInfoTag fontInfoTag = null; - - @Internal - private DefineFontInfo2Tag fontInfo2Tag = null; - - public static final int ID = 10; - - @Override - public boolean isSmall() { - return false; - } - - @Override - public double getGlyphAdvance(int glyphIndex) { - return -1; - } - - @Override - public int getGlyphWidth(int glyphIndex) { - return glyphShapeTable.get(glyphIndex).getBounds().getWidth(); - } - - private void ensureFontInfo() { - if (fontInfoTag == null) { - for (Tag t : swf.tags) { - if (t instanceof DefineFontInfoTag) { - if (((DefineFontInfoTag) t).fontId == fontId) { - fontInfoTag = (DefineFontInfoTag) t; - break; - } - } - if (t instanceof DefineFontInfo2Tag) { - if (((DefineFontInfo2Tag) t).fontID == fontId) { - fontInfo2Tag = (DefineFontInfo2Tag) t; - break; - } - } - } - } - } - - @Override - public char glyphToChar(int glyphIndex) { - ensureFontInfo(); - if (fontInfo2Tag != null) { - return (char) (int) fontInfo2Tag.codeTable.get(glyphIndex); - } else if (fontInfoTag != null) { - return (char) (int) fontInfoTag.codeTable.get(glyphIndex); - } else { - return '?'; - } - } - - @Override - public int charToGlyph(char c) { - ensureFontInfo(); - if (fontInfo2Tag != null) { - return fontInfo2Tag.codeTable.indexOf((int) c); - } else if (fontInfoTag != null) { - return fontInfoTag.codeTable.indexOf((int) c); - } - return -1; - - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(fontId); - ByteArrayOutputStream baos2 = new ByteArrayOutputStream(); - List offsetTable = new ArrayList<>(); - SWFOutputStream sos2 = new SWFOutputStream(baos2, getVersion()); - for (SHAPE shape : glyphShapeTable) { - offsetTable.add(glyphShapeTable.size() * 2 + (int) sos2.getPos()); - sos2.writeSHAPE(shape, 1); - } - for (int offset : offsetTable) { - sos.writeUI16(offset); - } - sos.write(baos2.toByteArray()); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - - /** - * Constructor - * - * @param swf - */ - public DefineFontTag(SWF swf) { - super(swf, ID, "DefineFont", null); - fontId = swf.getNextCharacterId(); - glyphShapeTable = new ArrayList<>(); - } - - /** - * Constructor - * - * @param sis - * @param data - * @throws IOException - */ - public DefineFontTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DefineFont", data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - fontId = sis.readUI16("fontId"); - glyphShapeTable = new ArrayList<>(); - - if (sis.available() > 0) { - long pos = sis.getPos(); - int firstOffset = sis.readUI16("firstOffset"); - int nGlyphs = firstOffset / 2; - - long[] offsetTable = new long[nGlyphs]; - offsetTable[0] = firstOffset; - for (int i = 1; i < nGlyphs; i++) { - offsetTable[i] = sis.readUI16("offset"); - } - for (int i = 0; i < nGlyphs; i++) { - sis.seek(pos + offsetTable[i]); - glyphShapeTable.add(sis.readSHAPE(1, false, "shape")); - } - } - } - - @Override - public int getFontId() { - return fontId; - } - - @Override - public List getGlyphShapeTable() { - return glyphShapeTable; - } - - @Override - public int getCharacterId() { - return fontId; - } - - @Override - public void setCharacterId(int characterId) { - this.fontId = characterId; - } - - @Override - public String getFontNameIntag() { - ensureFontInfo(); - if (fontInfo2Tag != null) { - return fontInfo2Tag.fontName; - } - if (fontInfoTag != null) { - return fontInfoTag.fontName; - } - return null; - } - - @Override - public boolean isBold() { - if (fontInfo2Tag != null) { - return fontInfo2Tag.fontFlagsBold; - } - if (fontInfoTag != null) { - return fontInfoTag.fontFlagsBold; - } - return false; - } - - @Override - public boolean isItalic() { - if (fontInfo2Tag != null) { - return fontInfo2Tag.fontFlagsItalic; - } - if (fontInfoTag != null) { - return fontInfoTag.fontFlagsItalic; - } - return false; - } - - @Override - public boolean isSmallEditable() { - return false; - } - - @Override - public boolean isBoldEditable() { - return fontInfo2Tag != null || fontInfoTag != null; - } - - @Override - public boolean isItalicEditable() { - return fontInfo2Tag != null || fontInfoTag != null; - } - - @Override - public void setSmall(boolean value) { - } - - @Override - public void setBold(boolean value) { - if (fontInfo2Tag != null) { - fontInfo2Tag.fontFlagsBold = value; - } - if (fontInfoTag != null) { - fontInfoTag.fontFlagsBold = value; - } - } - - @Override - public void setItalic(boolean value) { - if (fontInfo2Tag != null) { - fontInfo2Tag.fontFlagsItalic = value; - } - if (fontInfoTag != null) { - fontInfoTag.fontFlagsItalic = value; - } - } - - @Override - public int getAscent() { - return -1; - } - - @Override - public int getDescent() { - return -1; - } - - @Override - public int getLeading() { - return -1; - } - - @Override - public double getDivider() { - return 1; - } - - @Override - public void addCharacter(char character, Font font) { - SHAPE shp = SHAPERECORD.fontCharacterToSHAPE(font, (int) Math.round(getDivider() * 1024), character); - List codeTable = new ArrayList<>(); - ensureFontInfo(); - if (fontInfoTag != null) { - codeTable = fontInfoTag.codeTable; - } - if (fontInfo2Tag != null) { - codeTable = fontInfo2Tag.codeTable; - } - int code = (int) character; - int pos = -1; - boolean exists = false; - for (int i = 0; i < codeTable.size(); i++) { - if (codeTable.get(i) >= code) { - if (codeTable.get(i) == code) { - exists = true; - } - pos = i; - break; - } - } - if (pos == -1) { - pos = codeTable.size(); - } - if (!exists) { - shiftGlyphIndices(fontId, pos); - glyphShapeTable.add(pos, shp); - codeTable.add(pos, (int) character); - } else { - glyphShapeTable.set(pos, shp); - } - - setModified(true); - } - - @Override - public void setAdvanceValues(Font font) { - throw new UnsupportedOperationException("Setting the advance values for DefineFontTag is not supported."); - } - - @Override - public String getCharacters(List tags) { - StringBuilder ret = new StringBuilder(); - ensureFontInfo(); - if (fontInfoTag != null) { - for (int i : fontInfoTag.codeTable) { - ret.append((char) i); - } - } - if (fontInfo2Tag != null) { - for (int i : fontInfo2Tag.codeTable) { - ret.append((char) i); - } - } - return ret.toString(); - } - - @Override - public int getGlyphKerningAdjustment(int glyphIndex, int nextGlyphIndex) { - return 0; - } - - @Override - public int getCharKerningAdjustment(char c1, char c2) { - return 0; - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.tags.base.FontTag; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.SHAPE; +import com.jpexs.decompiler.flash.types.annotations.Internal; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD; +import com.jpexs.helpers.ByteArrayRange; +import java.awt.Font; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author JPEXS + */ +public class DefineFontTag extends FontTag { + + @SWFType(BasicType.UI16) + public int fontId; + + public List glyphShapeTable; + + @Internal + private DefineFontInfoTag fontInfoTag = null; + + @Internal + private DefineFontInfo2Tag fontInfo2Tag = null; + + public static final int ID = 10; + + public static final String NAME = "DefineFont"; + + @Override + public boolean isSmall() { + return false; + } + + @Override + public double getGlyphAdvance(int glyphIndex) { + return -1; + } + + @Override + public int getGlyphWidth(int glyphIndex) { + return glyphShapeTable.get(glyphIndex).getBounds().getWidth(); + } + + private void ensureFontInfo() { + if (fontInfoTag == null) { + for (Tag t : swf.tags) { + if (t instanceof DefineFontInfoTag) { + if (((DefineFontInfoTag) t).fontId == fontId) { + fontInfoTag = (DefineFontInfoTag) t; + break; + } + } + if (t instanceof DefineFontInfo2Tag) { + if (((DefineFontInfo2Tag) t).fontID == fontId) { + fontInfo2Tag = (DefineFontInfo2Tag) t; + break; + } + } + } + } + } + + @Override + public char glyphToChar(int glyphIndex) { + ensureFontInfo(); + if (fontInfo2Tag != null) { + return (char) (int) fontInfo2Tag.codeTable.get(glyphIndex); + } else if (fontInfoTag != null) { + return (char) (int) fontInfoTag.codeTable.get(glyphIndex); + } else { + return '?'; + } + } + + @Override + public int charToGlyph(char c) { + ensureFontInfo(); + if (fontInfo2Tag != null) { + return fontInfo2Tag.codeTable.indexOf((int) c); + } else if (fontInfoTag != null) { + return fontInfoTag.codeTable.indexOf((int) c); + } + return -1; + + } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(fontId); + ByteArrayOutputStream baos2 = new ByteArrayOutputStream(); + List offsetTable = new ArrayList<>(); + SWFOutputStream sos2 = new SWFOutputStream(baos2, getVersion()); + for (SHAPE shape : glyphShapeTable) { + offsetTable.add(glyphShapeTable.size() * 2 + (int) sos2.getPos()); + sos2.writeSHAPE(shape, 1); + } + for (int offset : offsetTable) { + sos.writeUI16(offset); + } + sos.write(baos2.toByteArray()); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + /** + * Constructor + * + * @param swf + */ + public DefineFontTag(SWF swf) { + super(swf, ID, NAME, null); + fontId = swf.getNextCharacterId(); + glyphShapeTable = new ArrayList<>(); + } + + /** + * Constructor + * + * @param sis + * @param data + * @throws IOException + */ + public DefineFontTag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + fontId = sis.readUI16("fontId"); + glyphShapeTable = new ArrayList<>(); + + if (sis.available() > 0) { + long pos = sis.getPos(); + int firstOffset = sis.readUI16("firstOffset"); + int nGlyphs = firstOffset / 2; + + long[] offsetTable = new long[nGlyphs]; + offsetTable[0] = firstOffset; + for (int i = 1; i < nGlyphs; i++) { + offsetTable[i] = sis.readUI16("offset"); + } + for (int i = 0; i < nGlyphs; i++) { + sis.seek(pos + offsetTable[i]); + glyphShapeTable.add(sis.readSHAPE(1, false, "shape")); + } + } + } + + @Override + public int getFontId() { + return fontId; + } + + @Override + public List getGlyphShapeTable() { + return glyphShapeTable; + } + + @Override + public int getCharacterId() { + return fontId; + } + + @Override + public void setCharacterId(int characterId) { + this.fontId = characterId; + } + + @Override + public String getFontNameIntag() { + ensureFontInfo(); + if (fontInfo2Tag != null) { + return fontInfo2Tag.fontName; + } + if (fontInfoTag != null) { + return fontInfoTag.fontName; + } + return null; + } + + @Override + public boolean isBold() { + if (fontInfo2Tag != null) { + return fontInfo2Tag.fontFlagsBold; + } + if (fontInfoTag != null) { + return fontInfoTag.fontFlagsBold; + } + return false; + } + + @Override + public boolean isItalic() { + if (fontInfo2Tag != null) { + return fontInfo2Tag.fontFlagsItalic; + } + if (fontInfoTag != null) { + return fontInfoTag.fontFlagsItalic; + } + return false; + } + + @Override + public boolean isSmallEditable() { + return false; + } + + @Override + public boolean isBoldEditable() { + return fontInfo2Tag != null || fontInfoTag != null; + } + + @Override + public boolean isItalicEditable() { + return fontInfo2Tag != null || fontInfoTag != null; + } + + @Override + public void setSmall(boolean value) { + } + + @Override + public void setBold(boolean value) { + if (fontInfo2Tag != null) { + fontInfo2Tag.fontFlagsBold = value; + } + if (fontInfoTag != null) { + fontInfoTag.fontFlagsBold = value; + } + } + + @Override + public void setItalic(boolean value) { + if (fontInfo2Tag != null) { + fontInfo2Tag.fontFlagsItalic = value; + } + if (fontInfoTag != null) { + fontInfoTag.fontFlagsItalic = value; + } + } + + @Override + public int getAscent() { + return -1; + } + + @Override + public int getDescent() { + return -1; + } + + @Override + public int getLeading() { + return -1; + } + + @Override + public double getDivider() { + return 1; + } + + @Override + public void addCharacter(char character, Font font) { + SHAPE shp = SHAPERECORD.fontCharacterToSHAPE(font, (int) Math.round(getDivider() * 1024), character); + List codeTable = new ArrayList<>(); + ensureFontInfo(); + if (fontInfoTag != null) { + codeTable = fontInfoTag.codeTable; + } + if (fontInfo2Tag != null) { + codeTable = fontInfo2Tag.codeTable; + } + int code = (int) character; + int pos = -1; + boolean exists = false; + for (int i = 0; i < codeTable.size(); i++) { + if (codeTable.get(i) >= code) { + if (codeTable.get(i) == code) { + exists = true; + } + pos = i; + break; + } + } + if (pos == -1) { + pos = codeTable.size(); + } + if (!exists) { + shiftGlyphIndices(fontId, pos); + glyphShapeTable.add(pos, shp); + codeTable.add(pos, (int) character); + } else { + glyphShapeTable.set(pos, shp); + } + + setModified(true); + } + + @Override + public void setAdvanceValues(Font font) { + throw new UnsupportedOperationException("Setting the advance values for DefineFontTag is not supported."); + } + + @Override + public String getCharacters(List tags) { + StringBuilder ret = new StringBuilder(); + ensureFontInfo(); + if (fontInfoTag != null) { + for (int i : fontInfoTag.codeTable) { + ret.append((char) i); + } + } + if (fontInfo2Tag != null) { + for (int i : fontInfo2Tag.codeTable) { + ret.append((char) i); + } + } + return ret.toString(); + } + + @Override + public int getGlyphKerningAdjustment(int glyphIndex, int nextGlyphIndex) { + return 0; + } + + @Override + public int getCharKerningAdjustment(char c1, char c2) { + return 0; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java index 2f8a1886c..64e1f38a8 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java @@ -54,6 +54,8 @@ public class DefineMorphShape2Tag extends MorphShapeTag { public static final int ID = 84; + public static final String NAME = "DefineMorphShape2"; + /** * Gets data bytes * @@ -94,7 +96,7 @@ public class DefineMorphShape2Tag extends MorphShapeTag { * @param swf */ public DefineMorphShape2Tag(SWF swf) { - super(swf, ID, "DefineMorphShape2", null); + super(swf, ID, NAME, null); characterId = swf.getNextCharacterId(); startBounds = new RECT(); endBounds = new RECT(); @@ -116,7 +118,7 @@ public class DefineMorphShape2Tag extends MorphShapeTag { * @throws IOException */ public DefineMorphShape2Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DefineMorphShape2", data); + super(sis.getSwf(), ID, NAME, data); readData(sis, data, 0, false, false, false); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShapeTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShapeTag.java index 2d7f100f8..53c1fe614 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShapeTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShapeTag.java @@ -39,6 +39,8 @@ public class DefineMorphShapeTag extends MorphShapeTag { public static final int ID = 46; + public static final String NAME = "DefineMorphShape"; + /** * Gets data bytes * @@ -74,7 +76,7 @@ public class DefineMorphShapeTag extends MorphShapeTag { * @param swf */ public DefineMorphShapeTag(SWF swf) { - super(swf, ID, "DefineMorphShape", null); + super(swf, ID, NAME, null); characterId = swf.getNextCharacterId(); startBounds = new RECT(); endBounds = new RECT(); @@ -94,7 +96,7 @@ public class DefineMorphShapeTag extends MorphShapeTag { * @throws IOException */ public DefineMorphShapeTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DefineMorphShape", data); + super(sis.getSwf(), ID, NAME, data); readData(sis, data, 0, false, false, false); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineScalingGridTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineScalingGridTag.java index 3539736a9..5fd55cd89 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineScalingGridTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineScalingGridTag.java @@ -1,93 +1,95 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.tags.base.CharacterIdTag; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.RECT; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.helpers.ByteArrayRange; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -/** - * - * @author JPEXS - */ -public class DefineScalingGridTag extends Tag implements CharacterIdTag { - - @SWFType(BasicType.UI16) - public int characterId; - - public RECT splitter; - - public static final int ID = 78; - - /** - * Constructor - * - * @param swf - */ - public DefineScalingGridTag(SWF swf) { - super(swf, ID, "DefineScalingGrid", null); - splitter = new RECT(); - } - - public DefineScalingGridTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DefineScalingGrid", data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - characterId = sis.readUI16("characterId"); - splitter = sis.readRECT("splitter"); - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(characterId); - sos.writeRECT(splitter); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - - @Override - public int getCharacterId() { - return characterId; - } - - @Override - public void setCharacterId(int characterId) { - this.characterId = characterId; - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.tags.base.CharacterIdTag; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.helpers.ByteArrayRange; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * + * @author JPEXS + */ +public class DefineScalingGridTag extends Tag implements CharacterIdTag { + + @SWFType(BasicType.UI16) + public int characterId; + + public RECT splitter; + + public static final int ID = 78; + + public static final String NAME = "DefineScalingGrid"; + + /** + * Constructor + * + * @param swf + */ + public DefineScalingGridTag(SWF swf) { + super(swf, ID, NAME, null); + splitter = new RECT(); + } + + public DefineScalingGridTag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + characterId = sis.readUI16("characterId"); + splitter = sis.readRECT("splitter"); + } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(characterId); + sos.writeRECT(splitter); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + @Override + public int getCharacterId() { + return characterId; + } + + @Override + public void setCharacterId(int characterId) { + this.characterId = characterId; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSceneAndFrameLabelDataTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSceneAndFrameLabelDataTag.java index 36332d763..8351ca919 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSceneAndFrameLabelDataTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSceneAndFrameLabelDataTag.java @@ -49,6 +49,8 @@ public class DefineSceneAndFrameLabelDataTag extends Tag { public static final int ID = 86; + public static final String NAME = "DefineSceneAndFrameLabelData"; + /** * Gets data bytes * @@ -84,7 +86,7 @@ public class DefineSceneAndFrameLabelDataTag extends Tag { * @param swf */ public DefineSceneAndFrameLabelDataTag(SWF swf) { - super(swf, ID, "DefineSceneAndFrameLabelData", null); + super(swf, ID, NAME, null); sceneOffsets = new long[0]; sceneNames = new String[0]; frameNums = new long[0]; @@ -99,7 +101,7 @@ public class DefineSceneAndFrameLabelDataTag extends Tag { * @throws IOException */ public DefineSceneAndFrameLabelDataTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DefineSceneAndFrameLabelData", data); + super(sis.getSwf(), ID, NAME, data); readData(sis, data, 0, false, false, false); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShape2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShape2Tag.java index 6f5634c81..fe9b303e1 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShape2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShape2Tag.java @@ -1,158 +1,160 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.tags.base.BoundedTag; -import com.jpexs.decompiler.flash.tags.base.ShapeTag; -import com.jpexs.decompiler.flash.types.RECT; -import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE; -import com.jpexs.helpers.ByteArrayRange; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - * @author JPEXS - */ -public class DefineShape2Tag extends ShapeTag { - - public static final int ID = 22; - - private ByteArrayRange shapeData; - - @Override - public int getShapeNum() { - return 2; - } - - @Override - public SHAPEWITHSTYLE getShapes() { - if (shapes == null && shapeData != null) { - try { - SWFInputStream sis = new SWFInputStream(swf, shapeData.getArray(), 0, shapeData.getPos() + shapeData.getLength()); - sis.seek(shapeData.getPos()); - shapes = sis.readSHAPEWITHSTYLE(getShapeNum(), false, "shapes"); - shapeData = null; // not needed anymore, give it to GC - } catch (IOException ex) { - Logger.getLogger(DefineShape2Tag.class.getName()).log(Level.SEVERE, null, ex); - } - } - - return shapes; - } - - @Override - public void getNeededCharacters(Set needed) { - getShapes().getNeededCharacters(needed); - } - - @Override - public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { - boolean modified = getShapes().replaceCharacter(oldCharacterId, newCharacterId); - if (modified) { - setModified(true); - } - return modified; - } - - @Override - public boolean removeCharacter(int characterId) { - boolean modified = getShapes().removeCharacter(characterId); - if (modified) { - setModified(true); - } - return modified; - } - - @Override - public RECT getRect(Set added) { - return shapeBounds; - } - - /** - * Constructor - * - * @param swf - */ - public DefineShape2Tag(SWF swf) { - super(swf, ID, "DefineShape2", null); - shapeId = swf.getNextCharacterId(); - shapeBounds = new RECT(); - shapes = SHAPEWITHSTYLE.createEmpty(2); - } - - public DefineShape2Tag(SWFInputStream sis, ByteArrayRange data, boolean lazy) throws IOException { - super(sis.getSwf(), ID, "DefineShape2", data); - readData(sis, data, 0, false, false, lazy); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - shapeId = sis.readUI16("shapeId"); - shapeBounds = sis.readRECT("shapeBounds"); - if (!lazy) { - shapes = sis.readSHAPEWITHSTYLE(getShapeNum(), false, "shapes"); - } else { - shapeData = new ByteArrayRange(data.getArray(), (int) sis.getPos(), sis.available()); - } - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - SWFOutputStream sos = new SWFOutputStream(baos, getVersion()); - try { - sos.writeUI16(shapeId); - sos.writeRECT(shapeBounds); - sos.writeSHAPEWITHSTYLE(getShapes(), getShapeNum()); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - - @Override - public int getNumFrames() { - return 1; - } - - @Override - public boolean isSingleFrame() { - return true; - } - - @Override - public int getCharacterId() { - return shapeId; - } - - @Override - public void setCharacterId(int characterId) { - this.shapeId = characterId; - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.tags.base.BoundedTag; +import com.jpexs.decompiler.flash.tags.base.ShapeTag; +import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE; +import com.jpexs.helpers.ByteArrayRange; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author JPEXS + */ +public class DefineShape2Tag extends ShapeTag { + + public static final int ID = 22; + + public static final String NAME = "DefineShape2"; + + private ByteArrayRange shapeData; + + @Override + public int getShapeNum() { + return 2; + } + + @Override + public SHAPEWITHSTYLE getShapes() { + if (shapes == null && shapeData != null) { + try { + SWFInputStream sis = new SWFInputStream(swf, shapeData.getArray(), 0, shapeData.getPos() + shapeData.getLength()); + sis.seek(shapeData.getPos()); + shapes = sis.readSHAPEWITHSTYLE(getShapeNum(), false, "shapes"); + shapeData = null; // not needed anymore, give it to GC + } catch (IOException ex) { + Logger.getLogger(DefineShape2Tag.class.getName()).log(Level.SEVERE, null, ex); + } + } + + return shapes; + } + + @Override + public void getNeededCharacters(Set needed) { + getShapes().getNeededCharacters(needed); + } + + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + boolean modified = getShapes().replaceCharacter(oldCharacterId, newCharacterId); + if (modified) { + setModified(true); + } + return modified; + } + + @Override + public boolean removeCharacter(int characterId) { + boolean modified = getShapes().removeCharacter(characterId); + if (modified) { + setModified(true); + } + return modified; + } + + @Override + public RECT getRect(Set added) { + return shapeBounds; + } + + /** + * Constructor + * + * @param swf + */ + public DefineShape2Tag(SWF swf) { + super(swf, ID, NAME, null); + shapeId = swf.getNextCharacterId(); + shapeBounds = new RECT(); + shapes = SHAPEWITHSTYLE.createEmpty(2); + } + + public DefineShape2Tag(SWFInputStream sis, ByteArrayRange data, boolean lazy) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, lazy); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + shapeId = sis.readUI16("shapeId"); + shapeBounds = sis.readRECT("shapeBounds"); + if (!lazy) { + shapes = sis.readSHAPEWITHSTYLE(getShapeNum(), false, "shapes"); + } else { + shapeData = new ByteArrayRange(data.getArray(), (int) sis.getPos(), sis.available()); + } + } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + SWFOutputStream sos = new SWFOutputStream(baos, getVersion()); + try { + sos.writeUI16(shapeId); + sos.writeRECT(shapeBounds); + sos.writeSHAPEWITHSTYLE(getShapes(), getShapeNum()); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + @Override + public int getNumFrames() { + return 1; + } + + @Override + public boolean isSingleFrame() { + return true; + } + + @Override + public int getCharacterId() { + return shapeId; + } + + @Override + public void setCharacterId(int characterId) { + this.shapeId = characterId; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShape3Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShape3Tag.java index 07626809d..40aa56fe3 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShape3Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShape3Tag.java @@ -1,160 +1,162 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.tags.base.BoundedTag; -import com.jpexs.decompiler.flash.tags.base.ShapeTag; -import com.jpexs.decompiler.flash.types.RECT; -import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE; -import com.jpexs.helpers.ByteArrayRange; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - * @author JPEXS - */ -public class DefineShape3Tag extends ShapeTag { - - public static final int ID = 32; - - private ByteArrayRange shapeData; - - @Override - public int getShapeNum() { - return 3; - } - - @Override - public SHAPEWITHSTYLE getShapes() { - if (shapes == null && shapeData != null) { - try { - SWFInputStream sis = new SWFInputStream(swf, shapeData.getArray(), 0, shapeData.getPos() + shapeData.getLength()); - sis.seek(shapeData.getPos()); - shapes = sis.readSHAPEWITHSTYLE(3, false, "shapes"); - shapeData = null; // not needed anymore, give it to GC - } catch (IOException ex) { - Logger.getLogger(DefineShape3Tag.class.getName()).log(Level.SEVERE, null, ex); - } - } - - return shapes; - } - - @Override - public void getNeededCharacters(Set needed) { - getShapes().getNeededCharacters(needed); - } - - @Override - public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { - boolean modified = getShapes().replaceCharacter(oldCharacterId, newCharacterId); - if (modified) { - setModified(true); - } - return modified; - } - - @Override - public boolean removeCharacter(int characterId) { - boolean modified = getShapes().removeCharacter(characterId); - if (modified) { - setModified(true); - } - return modified; - } - - @Override - public RECT getRect(Set added) { - return shapeBounds; - } - - /** - * Constructor - * - * @param swf - */ - public DefineShape3Tag(SWF swf) { - super(swf, ID, "DefineShape3", null); - shapeId = swf.getNextCharacterId(); - shapeBounds = new RECT(); - shapes = SHAPEWITHSTYLE.createEmpty(3); - } - - public DefineShape3Tag(SWFInputStream sis, ByteArrayRange data, boolean lazy) throws IOException { - super(sis.getSwf(), ID, "DefineShape3", data); - readData(sis, data, 0, false, false, lazy); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - shapeId = sis.readUI16("shapeId"); - shapeBounds = sis.readRECT("shapeBounds"); - if (!lazy) { - shapes = sis.readSHAPEWITHSTYLE(3, false, "shapes"); - } else { - shapeData = new ByteArrayRange(data.getArray(), (int) sis.getPos(), sis.available()); - } - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(shapeId); - sos.writeRECT(shapeBounds); - sos.writeSHAPEWITHSTYLE(getShapes(), 3); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - - @Override - public int getNumFrames() { - return 1; - } - - @Override - public boolean isSingleFrame() { - return true; - } - - @Override - public int getCharacterId() { - return shapeId; - } - - @Override - public void setCharacterId(int characterId) { - this.shapeId = characterId; - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.tags.base.BoundedTag; +import com.jpexs.decompiler.flash.tags.base.ShapeTag; +import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE; +import com.jpexs.helpers.ByteArrayRange; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author JPEXS + */ +public class DefineShape3Tag extends ShapeTag { + + public static final int ID = 32; + + public static final String NAME = "DefineShape3"; + + private ByteArrayRange shapeData; + + @Override + public int getShapeNum() { + return 3; + } + + @Override + public SHAPEWITHSTYLE getShapes() { + if (shapes == null && shapeData != null) { + try { + SWFInputStream sis = new SWFInputStream(swf, shapeData.getArray(), 0, shapeData.getPos() + shapeData.getLength()); + sis.seek(shapeData.getPos()); + shapes = sis.readSHAPEWITHSTYLE(3, false, "shapes"); + shapeData = null; // not needed anymore, give it to GC + } catch (IOException ex) { + Logger.getLogger(DefineShape3Tag.class.getName()).log(Level.SEVERE, null, ex); + } + } + + return shapes; + } + + @Override + public void getNeededCharacters(Set needed) { + getShapes().getNeededCharacters(needed); + } + + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + boolean modified = getShapes().replaceCharacter(oldCharacterId, newCharacterId); + if (modified) { + setModified(true); + } + return modified; + } + + @Override + public boolean removeCharacter(int characterId) { + boolean modified = getShapes().removeCharacter(characterId); + if (modified) { + setModified(true); + } + return modified; + } + + @Override + public RECT getRect(Set added) { + return shapeBounds; + } + + /** + * Constructor + * + * @param swf + */ + public DefineShape3Tag(SWF swf) { + super(swf, ID, NAME, null); + shapeId = swf.getNextCharacterId(); + shapeBounds = new RECT(); + shapes = SHAPEWITHSTYLE.createEmpty(3); + } + + public DefineShape3Tag(SWFInputStream sis, ByteArrayRange data, boolean lazy) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, lazy); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + shapeId = sis.readUI16("shapeId"); + shapeBounds = sis.readRECT("shapeBounds"); + if (!lazy) { + shapes = sis.readSHAPEWITHSTYLE(3, false, "shapes"); + } else { + shapeData = new ByteArrayRange(data.getArray(), (int) sis.getPos(), sis.available()); + } + } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(shapeId); + sos.writeRECT(shapeBounds); + sos.writeSHAPEWITHSTYLE(getShapes(), 3); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + @Override + public int getNumFrames() { + return 1; + } + + @Override + public boolean isSingleFrame() { + return true; + } + + @Override + public int getCharacterId() { + return shapeId; + } + + @Override + public void setCharacterId(int characterId) { + this.shapeId = characterId; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShape4Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShape4Tag.java index f1477b51e..38596a0b3 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShape4Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShape4Tag.java @@ -1,186 +1,188 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.tags.base.BoundedTag; -import com.jpexs.decompiler.flash.tags.base.ShapeTag; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.RECT; -import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE; -import com.jpexs.decompiler.flash.types.annotations.Reserved; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.helpers.ByteArrayRange; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - * @author JPEXS - */ -public class DefineShape4Tag extends ShapeTag { - - public RECT edgeBounds; - - @Reserved - @SWFType(value = BasicType.UB, count = 5) - public int reserved; - - public boolean usesFillWindingRule; - - public boolean usesNonScalingStrokes; - - public boolean usesScalingStrokes; - - public static final int ID = 83; - - private ByteArrayRange shapeData; - - @Override - public int getShapeNum() { - return 4; - } - - @Override - public SHAPEWITHSTYLE getShapes() { - if (shapes == null && shapeData != null) { - try { - SWFInputStream sis = new SWFInputStream(swf, shapeData.getArray(), 0, shapeData.getPos() + shapeData.getLength()); - sis.seek(shapeData.getPos()); - shapes = sis.readSHAPEWITHSTYLE(4, false, "shapes"); - shapeData = null; // not needed anymore, give it to GC - } catch (IOException ex) { - Logger.getLogger(DefineShape4Tag.class.getName()).log(Level.SEVERE, null, ex); - } - } - - return shapes; - } - - @Override - public void getNeededCharacters(Set needed) { - getShapes().getNeededCharacters(needed); - } - - @Override - public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { - boolean modified = getShapes().replaceCharacter(oldCharacterId, newCharacterId); - if (modified) { - setModified(true); - } - return modified; - } - - @Override - public boolean removeCharacter(int characterId) { - boolean modified = getShapes().removeCharacter(characterId); - if (modified) { - setModified(true); - } - return modified; - } - - @Override - public RECT getRect(Set added) { - return shapeBounds; - } - - /** - * Constructor - * - * @param swf - */ - public DefineShape4Tag(SWF swf) { - super(swf, ID, "DefineShape4", null); - shapeId = swf.getNextCharacterId(); - shapeBounds = new RECT(); - edgeBounds = new RECT(); - shapes = SHAPEWITHSTYLE.createEmpty(4); - } - - public DefineShape4Tag(SWFInputStream sis, ByteArrayRange data, boolean lazy) throws IOException { - super(sis.getSwf(), ID, "DefineShape4", data); - readData(sis, data, 0, false, false, lazy); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - shapeId = sis.readUI16("shapeId"); - shapeBounds = sis.readRECT("shapeBounds"); - edgeBounds = sis.readRECT("edgeBounds"); - reserved = (int) sis.readUB(5, "reserved"); - usesFillWindingRule = sis.readUB(1, "usesFillWindingRule") == 1; - usesNonScalingStrokes = sis.readUB(1, "usesNonScalingStrokes") == 1; - usesScalingStrokes = sis.readUB(1, "usesScalingStrokes") == 1; - if (!lazy) { - shapes = sis.readSHAPEWITHSTYLE(4, false, "shapes"); - } else { - shapeData = new ByteArrayRange(data.getArray(), (int) sis.getPos(), sis.available()); - } - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(shapeId); - sos.writeRECT(shapeBounds); - sos.writeRECT(edgeBounds); - sos.writeUB(5, reserved); - sos.writeUB(1, usesFillWindingRule ? 1 : 0); - sos.writeUB(1, usesNonScalingStrokes ? 1 : 0); - sos.writeUB(1, usesScalingStrokes ? 1 : 0); - sos.writeSHAPEWITHSTYLE(getShapes(), 4); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - - @Override - public int getNumFrames() { - return 1; - } - - @Override - public boolean isSingleFrame() { - return true; - } - - @Override - public int getCharacterId() { - return shapeId; - } - - @Override - public void setCharacterId(int characterId) { - this.shapeId = characterId; - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.tags.base.BoundedTag; +import com.jpexs.decompiler.flash.tags.base.ShapeTag; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE; +import com.jpexs.decompiler.flash.types.annotations.Reserved; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.helpers.ByteArrayRange; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author JPEXS + */ +public class DefineShape4Tag extends ShapeTag { + + public RECT edgeBounds; + + @Reserved + @SWFType(value = BasicType.UB, count = 5) + public int reserved; + + public boolean usesFillWindingRule; + + public boolean usesNonScalingStrokes; + + public boolean usesScalingStrokes; + + public static final int ID = 83; + + public static final String NAME = "DefineShape4"; + + private ByteArrayRange shapeData; + + @Override + public int getShapeNum() { + return 4; + } + + @Override + public SHAPEWITHSTYLE getShapes() { + if (shapes == null && shapeData != null) { + try { + SWFInputStream sis = new SWFInputStream(swf, shapeData.getArray(), 0, shapeData.getPos() + shapeData.getLength()); + sis.seek(shapeData.getPos()); + shapes = sis.readSHAPEWITHSTYLE(4, false, "shapes"); + shapeData = null; // not needed anymore, give it to GC + } catch (IOException ex) { + Logger.getLogger(DefineShape4Tag.class.getName()).log(Level.SEVERE, null, ex); + } + } + + return shapes; + } + + @Override + public void getNeededCharacters(Set needed) { + getShapes().getNeededCharacters(needed); + } + + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + boolean modified = getShapes().replaceCharacter(oldCharacterId, newCharacterId); + if (modified) { + setModified(true); + } + return modified; + } + + @Override + public boolean removeCharacter(int characterId) { + boolean modified = getShapes().removeCharacter(characterId); + if (modified) { + setModified(true); + } + return modified; + } + + @Override + public RECT getRect(Set added) { + return shapeBounds; + } + + /** + * Constructor + * + * @param swf + */ + public DefineShape4Tag(SWF swf) { + super(swf, ID, NAME, null); + shapeId = swf.getNextCharacterId(); + shapeBounds = new RECT(); + edgeBounds = new RECT(); + shapes = SHAPEWITHSTYLE.createEmpty(4); + } + + public DefineShape4Tag(SWFInputStream sis, ByteArrayRange data, boolean lazy) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, lazy); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + shapeId = sis.readUI16("shapeId"); + shapeBounds = sis.readRECT("shapeBounds"); + edgeBounds = sis.readRECT("edgeBounds"); + reserved = (int) sis.readUB(5, "reserved"); + usesFillWindingRule = sis.readUB(1, "usesFillWindingRule") == 1; + usesNonScalingStrokes = sis.readUB(1, "usesNonScalingStrokes") == 1; + usesScalingStrokes = sis.readUB(1, "usesScalingStrokes") == 1; + if (!lazy) { + shapes = sis.readSHAPEWITHSTYLE(4, false, "shapes"); + } else { + shapeData = new ByteArrayRange(data.getArray(), (int) sis.getPos(), sis.available()); + } + } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(shapeId); + sos.writeRECT(shapeBounds); + sos.writeRECT(edgeBounds); + sos.writeUB(5, reserved); + sos.writeUB(1, usesFillWindingRule ? 1 : 0); + sos.writeUB(1, usesNonScalingStrokes ? 1 : 0); + sos.writeUB(1, usesScalingStrokes ? 1 : 0); + sos.writeSHAPEWITHSTYLE(getShapes(), 4); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + @Override + public int getNumFrames() { + return 1; + } + + @Override + public boolean isSingleFrame() { + return true; + } + + @Override + public int getCharacterId() { + return shapeId; + } + + @Override + public void setCharacterId(int characterId) { + this.shapeId = characterId; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShapeTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShapeTag.java index 1181eb21b..51a24d983 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShapeTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShapeTag.java @@ -1,158 +1,160 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.tags.base.BoundedTag; -import com.jpexs.decompiler.flash.tags.base.ShapeTag; -import com.jpexs.decompiler.flash.types.RECT; -import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE; -import com.jpexs.helpers.ByteArrayRange; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - * @author JPEXS - */ -public class DefineShapeTag extends ShapeTag { - - public static final int ID = 2; - - private ByteArrayRange shapeData; - - @Override - public int getShapeNum() { - return 1; - } - - @Override - public SHAPEWITHSTYLE getShapes() { - if (shapes == null && shapeData != null) { - try { - SWFInputStream sis = new SWFInputStream(swf, shapeData.getArray(), 0, shapeData.getPos() + shapeData.getLength()); - sis.seek(shapeData.getPos()); - shapes = sis.readSHAPEWITHSTYLE(getShapeNum(), false, "shapes"); - shapeData = null; // not needed anymore, give it to GC - } catch (IOException ex) { - Logger.getLogger(DefineShapeTag.class.getName()).log(Level.SEVERE, null, ex); - } - } - - return shapes; - } - - @Override - public void getNeededCharacters(Set needed) { - getShapes().getNeededCharacters(needed); - } - - @Override - public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { - boolean modified = getShapes().replaceCharacter(oldCharacterId, newCharacterId); - if (modified) { - setModified(true); - } - return modified; - } - - @Override - public boolean removeCharacter(int characterId) { - boolean modified = getShapes().removeCharacter(characterId); - if (modified) { - setModified(true); - } - return modified; - } - - @Override - public RECT getRect(Set added) { - return shapeBounds; - } - - /** - * Constructor - * - * @param swf - */ - public DefineShapeTag(SWF swf) { - super(swf, ID, "DefineShape", null); - shapeId = swf.getNextCharacterId(); - shapeBounds = new RECT(); - shapes = SHAPEWITHSTYLE.createEmpty(1); - } - - public DefineShapeTag(SWFInputStream sis, ByteArrayRange data, boolean lazy) throws IOException { - super(sis.getSwf(), ID, "DefineShape", data); - readData(sis, data, 0, false, false, lazy); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - shapeId = sis.readUI16("shapeId"); - shapeBounds = sis.readRECT("shapeBounds"); - if (!lazy) { - shapes = sis.readSHAPEWITHSTYLE(getShapeNum(), false, "shapes"); - } else { - shapeData = new ByteArrayRange(data.getArray(), (int) sis.getPos(), sis.available()); - } - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - SWFOutputStream sos = new SWFOutputStream(baos, getVersion()); - try { - sos.writeUI16(shapeId); - sos.writeRECT(shapeBounds); - sos.writeSHAPEWITHSTYLE(getShapes(), getShapeNum()); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - - @Override - public int getNumFrames() { - return 1; - } - - @Override - public boolean isSingleFrame() { - return true; - } - - @Override - public int getCharacterId() { - return shapeId; - } - - @Override - public void setCharacterId(int characterId) { - this.shapeId = characterId; - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.tags.base.BoundedTag; +import com.jpexs.decompiler.flash.tags.base.ShapeTag; +import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE; +import com.jpexs.helpers.ByteArrayRange; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author JPEXS + */ +public class DefineShapeTag extends ShapeTag { + + public static final int ID = 2; + + public static final String NAME = "DefineShape"; + + private ByteArrayRange shapeData; + + @Override + public int getShapeNum() { + return 1; + } + + @Override + public SHAPEWITHSTYLE getShapes() { + if (shapes == null && shapeData != null) { + try { + SWFInputStream sis = new SWFInputStream(swf, shapeData.getArray(), 0, shapeData.getPos() + shapeData.getLength()); + sis.seek(shapeData.getPos()); + shapes = sis.readSHAPEWITHSTYLE(getShapeNum(), false, "shapes"); + shapeData = null; // not needed anymore, give it to GC + } catch (IOException ex) { + Logger.getLogger(DefineShapeTag.class.getName()).log(Level.SEVERE, null, ex); + } + } + + return shapes; + } + + @Override + public void getNeededCharacters(Set needed) { + getShapes().getNeededCharacters(needed); + } + + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + boolean modified = getShapes().replaceCharacter(oldCharacterId, newCharacterId); + if (modified) { + setModified(true); + } + return modified; + } + + @Override + public boolean removeCharacter(int characterId) { + boolean modified = getShapes().removeCharacter(characterId); + if (modified) { + setModified(true); + } + return modified; + } + + @Override + public RECT getRect(Set added) { + return shapeBounds; + } + + /** + * Constructor + * + * @param swf + */ + public DefineShapeTag(SWF swf) { + super(swf, ID, NAME, null); + shapeId = swf.getNextCharacterId(); + shapeBounds = new RECT(); + shapes = SHAPEWITHSTYLE.createEmpty(1); + } + + public DefineShapeTag(SWFInputStream sis, ByteArrayRange data, boolean lazy) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, lazy); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + shapeId = sis.readUI16("shapeId"); + shapeBounds = sis.readRECT("shapeBounds"); + if (!lazy) { + shapes = sis.readSHAPEWITHSTYLE(getShapeNum(), false, "shapes"); + } else { + shapeData = new ByteArrayRange(data.getArray(), (int) sis.getPos(), sis.available()); + } + } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + SWFOutputStream sos = new SWFOutputStream(baos, getVersion()); + try { + sos.writeUI16(shapeId); + sos.writeRECT(shapeBounds); + sos.writeSHAPEWITHSTYLE(getShapes(), getShapeNum()); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + @Override + public int getNumFrames() { + return 1; + } + + @Override + public boolean isSingleFrame() { + return true; + } + + @Override + public int getCharacterId() { + return shapeId; + } + + @Override + public void setCharacterId(int characterId) { + this.shapeId = characterId; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSoundTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSoundTag.java index 341ac04df..dfc32c0dd 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSoundTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSoundTag.java @@ -1,362 +1,364 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.tags.base.CharacterTag; -import com.jpexs.decompiler.flash.tags.base.SoundTag; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.decompiler.flash.types.sound.MP3FRAME; -import com.jpexs.decompiler.flash.types.sound.MP3SOUNDDATA; -import com.jpexs.decompiler.flash.types.sound.SoundFormat; -import com.jpexs.helpers.ByteArrayRange; -import com.jpexs.helpers.Helper; -import java.io.BufferedInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import javax.sound.sampled.AudioFormat; -import javax.sound.sampled.AudioInputStream; -import javax.sound.sampled.AudioSystem; -import javax.sound.sampled.UnsupportedAudioFileException; - -/** - * - * @author JPEXS - */ -public class DefineSoundTag extends CharacterTag implements SoundTag { - - @SWFType(BasicType.UI16) - public int soundId; - - @SWFType(value = BasicType.UB, count = 4) - public int soundFormat; - - @SWFType(value = BasicType.UB, count = 2) - public int soundRate; - - public boolean soundSize; - - public boolean soundType; - - @SWFType(BasicType.UI32) - public long soundSampleCount; - - public ByteArrayRange soundData; - - public static final int ID = 14; - - @Override - public int getCharacterId() { - return soundId; - } - - @Override - public void setCharacterId(int characterId) { - this.soundId = characterId; - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(soundId); - sos.writeUB(4, soundFormat); - sos.writeUB(2, soundRate); - sos.writeUB(1, soundSize ? 1 : 0); - sos.writeUB(1, soundType ? 1 : 0); - sos.writeUI32(soundSampleCount); - sos.write(soundData); - - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - - /** - * Constructor - * - * @param swf - */ - public DefineSoundTag(SWF swf) { - super(swf, ID, "DefineSound", null); - soundId = swf.getNextCharacterId(); - soundData = ByteArrayRange.EMPTY; - } - - /** - * Constructor - * - * @param sis - * @param data - * @throws IOException - */ - public DefineSoundTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DefineSound", data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - soundId = sis.readUI16("soundId"); - soundFormat = (int) sis.readUB(4, "soundFormat"); - soundRate = (int) sis.readUB(2, "soundRate"); - soundSize = sis.readUB(1, "soundSize") == 1; - soundType = sis.readUB(1, "soundType") == 1; - soundSampleCount = sis.readUI32("soundSampleCount"); - soundData = sis.readByteRangeEx(sis.available(), "soundData"); - } - - @Override - public String getExportFormat() { - if (soundFormat == SoundFormat.FORMAT_MP3) { - return "mp3"; - } - if (soundFormat == SoundFormat.FORMAT_ADPCM) { - return "wav"; - } - if (soundFormat == SoundFormat.FORMAT_UNCOMPRESSED_LITTLE_ENDIAN) { - return "wav"; - } - if (soundFormat == SoundFormat.FORMAT_UNCOMPRESSED_NATIVE_ENDIAN) { - return "wav"; - } - if (soundFormat == SoundFormat.FORMAT_NELLYMOSER || soundFormat == SoundFormat.FORMAT_NELLYMOSER16KHZ || soundFormat == SoundFormat.FORMAT_NELLYMOSER8KHZ) { - return "wav"; - } - return "flv"; - } - - private void loadID3v2(InputStream in) { - int size = -1; - try { - // Read ID3v2 header (10 bytes). - in.mark(10); - size = readID3v2Header(in); - } catch (IOException e) { - } finally { - try { - // Unread ID3v2 header (10 bytes). - in.reset(); - } catch (IOException e) { - } - } - // Load ID3v2 tags. - try { - if (size > 0) { - byte[] rawid3v2 = new byte[size]; - in.read(rawid3v2, 0, rawid3v2.length); - } - } catch (IOException e) { - } - } - - /** - * Parse ID3v2 tag header to find out size of ID3v2 frames. - * - * @param in MP3 InputStream - * @return size of ID3v2 frames + header - * @throws IOException - * @author JavaZOOM - */ - private int readID3v2Header(InputStream in) throws IOException { - byte[] id3header = new byte[4]; - int size = -10; - in.read(id3header, 0, 3); - // Look for ID3v2 - if ((id3header[0] == 'I') && (id3header[1] == 'D') && (id3header[2] == '3')) { - in.read(id3header, 0, 3); - int majorVersion = id3header[0]; - int revision = id3header[1]; - in.read(id3header, 0, 4); - size = (int) (id3header[0] << 21) + (id3header[1] << 14) + (id3header[2] << 7) + (id3header[3]); - } - return (size + 10); - } - - @Override - public boolean setSound(InputStream is, int newSoundFormat) { - int newSoundRate = -1; - boolean newSoundSize = false; - boolean newSoundType = false; - long newSoundSampleCount = -1; - byte[] newSoundData; - switch (newSoundFormat) { - case SoundFormat.FORMAT_UNCOMPRESSED_LITTLE_ENDIAN: - try (AudioInputStream audioIs = AudioSystem.getAudioInputStream(new BufferedInputStream(is))) { - AudioFormat fmt = audioIs.getFormat(); - newSoundType = fmt.getChannels() == 2; - newSoundSize = fmt.getSampleSizeInBits() == 16; - newSoundSampleCount = audioIs.getFrameLength(); - newSoundData = Helper.readStream(audioIs); - newSoundRate = (int) Math.round(fmt.getSampleRate()); - switch (newSoundRate) { - case 5512: - newSoundRate = 0; - break; - case 11025: - newSoundRate = 1; - break; - case 22050: - newSoundRate = 2; - break; - case 44100: - newSoundRate = 3; - break; - default: - return false; - } - } catch (UnsupportedAudioFileException | IOException ex) { - return false; - } - break; - case SoundFormat.FORMAT_MP3: - BufferedInputStream bis = new BufferedInputStream(is); - loadID3v2(bis); - byte[] mp3data = Helper.readStream(bis); - - final int ID3_V1_LENTGH = 128; - final int ID3_V1_EXT_LENGTH = 227; - - if (mp3data.length > ID3_V1_LENTGH) { - //ID3v1 - if (mp3data[mp3data.length - ID3_V1_LENTGH] == 'T' && mp3data[mp3data.length - ID3_V1_LENTGH + 1] == 'A' && mp3data[mp3data.length - ID3_V1_LENTGH + 2] == 'G') { - mp3data = Arrays.copyOf(mp3data, mp3data.length - ID3_V1_LENTGH); - if (mp3data.length > ID3_V1_EXT_LENGTH) { - //ID3v1 extended - if (mp3data[mp3data.length - ID3_V1_EXT_LENGTH] == 'T' && mp3data[mp3data.length - ID3_V1_EXT_LENGTH + 1] == 'A' && mp3data[mp3data.length - ID3_V1_EXT_LENGTH + 2] == 'G' && mp3data[mp3data.length - ID3_V1_EXT_LENGTH + 3] == '+') { - mp3data = Arrays.copyOf(mp3data, mp3data.length - ID3_V1_EXT_LENGTH); - } - } - } - } - try { - MP3SOUNDDATA snd = new MP3SOUNDDATA(new SWFInputStream(swf, mp3data), true); - if (!snd.frames.isEmpty()) { - MP3FRAME fr = snd.frames.get(0); - newSoundRate = fr.getSamplingRate(); - switch (newSoundRate) { - case 11025: - newSoundRate = 1; - break; - case 22050: - newSoundRate = 2; - break; - case 44100: - newSoundRate = 3; - break; - default: - return false; - } - newSoundSize = true; - newSoundType = fr.isStereo(); - int len = snd.sampleCount(); - if (fr.isStereo()) { - len = len / 2; - } - newSoundSampleCount = len; - - } - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - SWFOutputStream sos = new SWFOutputStream(baos, SWF.DEFAULT_VERSION); - sos.writeSI16(0); //Latency - how to calculate it? - sos.write(mp3data); - newSoundData = baos.toByteArray(); - } catch (IOException ex) { - return false; - } - break; - default: - return false; - } - if (newSoundData != null) { - this.soundSize = newSoundSize; - this.soundRate = newSoundRate; - this.soundSampleCount = newSoundSampleCount; - this.soundData = new ByteArrayRange(newSoundData); - this.soundType = newSoundType; - this.soundFormat = newSoundFormat; - setModified(true); - return true; - } - return false; - - } - - @Override - public boolean importSupported() { - return true; - } - - @Override - public int getSoundRate() { - return soundRate; - } - - @Override - public boolean getSoundType() { - return soundType; - } - - @Override - public List getRawSoundData() { - List ret = new ArrayList<>(); - if (soundFormat == SoundFormat.FORMAT_MP3) { - ret.add(soundData.getRangeData(2, soundData.getLength() - 2)); - return ret; - } - - ret.add(soundData.getRangeData()); - return ret; - } - - @Override - public int getSoundFormatId() { - return soundFormat; - } - - @Override - public long getTotalSoundSampleCount() { - return soundSampleCount; - } - - @Override - public boolean getSoundSize() { - return soundSize; - } - - @Override - public SoundFormat getSoundFormat() { - final int[] rateMap = {5512, 11025, 22050, 44100}; - return new SoundFormat(getSoundFormatId(), rateMap[getSoundRate()], getSoundType()); - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.tags.base.CharacterTag; +import com.jpexs.decompiler.flash.tags.base.SoundTag; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.decompiler.flash.types.sound.MP3FRAME; +import com.jpexs.decompiler.flash.types.sound.MP3SOUNDDATA; +import com.jpexs.decompiler.flash.types.sound.SoundFormat; +import com.jpexs.helpers.ByteArrayRange; +import com.jpexs.helpers.Helper; +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.UnsupportedAudioFileException; + +/** + * + * @author JPEXS + */ +public class DefineSoundTag extends CharacterTag implements SoundTag { + + @SWFType(BasicType.UI16) + public int soundId; + + @SWFType(value = BasicType.UB, count = 4) + public int soundFormat; + + @SWFType(value = BasicType.UB, count = 2) + public int soundRate; + + public boolean soundSize; + + public boolean soundType; + + @SWFType(BasicType.UI32) + public long soundSampleCount; + + public ByteArrayRange soundData; + + public static final int ID = 14; + + public static final String NAME = "DefineSound"; + + @Override + public int getCharacterId() { + return soundId; + } + + @Override + public void setCharacterId(int characterId) { + this.soundId = characterId; + } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(soundId); + sos.writeUB(4, soundFormat); + sos.writeUB(2, soundRate); + sos.writeUB(1, soundSize ? 1 : 0); + sos.writeUB(1, soundType ? 1 : 0); + sos.writeUI32(soundSampleCount); + sos.write(soundData); + + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + /** + * Constructor + * + * @param swf + */ + public DefineSoundTag(SWF swf) { + super(swf, ID, NAME, null); + soundId = swf.getNextCharacterId(); + soundData = ByteArrayRange.EMPTY; + } + + /** + * Constructor + * + * @param sis + * @param data + * @throws IOException + */ + public DefineSoundTag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + soundId = sis.readUI16("soundId"); + soundFormat = (int) sis.readUB(4, "soundFormat"); + soundRate = (int) sis.readUB(2, "soundRate"); + soundSize = sis.readUB(1, "soundSize") == 1; + soundType = sis.readUB(1, "soundType") == 1; + soundSampleCount = sis.readUI32("soundSampleCount"); + soundData = sis.readByteRangeEx(sis.available(), "soundData"); + } + + @Override + public String getExportFormat() { + if (soundFormat == SoundFormat.FORMAT_MP3) { + return "mp3"; + } + if (soundFormat == SoundFormat.FORMAT_ADPCM) { + return "wav"; + } + if (soundFormat == SoundFormat.FORMAT_UNCOMPRESSED_LITTLE_ENDIAN) { + return "wav"; + } + if (soundFormat == SoundFormat.FORMAT_UNCOMPRESSED_NATIVE_ENDIAN) { + return "wav"; + } + if (soundFormat == SoundFormat.FORMAT_NELLYMOSER || soundFormat == SoundFormat.FORMAT_NELLYMOSER16KHZ || soundFormat == SoundFormat.FORMAT_NELLYMOSER8KHZ) { + return "wav"; + } + return "flv"; + } + + private void loadID3v2(InputStream in) { + int size = -1; + try { + // Read ID3v2 header (10 bytes). + in.mark(10); + size = readID3v2Header(in); + } catch (IOException e) { + } finally { + try { + // Unread ID3v2 header (10 bytes). + in.reset(); + } catch (IOException e) { + } + } + // Load ID3v2 tags. + try { + if (size > 0) { + byte[] rawid3v2 = new byte[size]; + in.read(rawid3v2, 0, rawid3v2.length); + } + } catch (IOException e) { + } + } + + /** + * Parse ID3v2 tag header to find out size of ID3v2 frames. + * + * @param in MP3 InputStream + * @return size of ID3v2 frames + header + * @throws IOException + * @author JavaZOOM + */ + private int readID3v2Header(InputStream in) throws IOException { + byte[] id3header = new byte[4]; + int size = -10; + in.read(id3header, 0, 3); + // Look for ID3v2 + if ((id3header[0] == 'I') && (id3header[1] == 'D') && (id3header[2] == '3')) { + in.read(id3header, 0, 3); + int majorVersion = id3header[0]; + int revision = id3header[1]; + in.read(id3header, 0, 4); + size = (int) (id3header[0] << 21) + (id3header[1] << 14) + (id3header[2] << 7) + (id3header[3]); + } + return (size + 10); + } + + @Override + public boolean setSound(InputStream is, int newSoundFormat) { + int newSoundRate = -1; + boolean newSoundSize = false; + boolean newSoundType = false; + long newSoundSampleCount = -1; + byte[] newSoundData; + switch (newSoundFormat) { + case SoundFormat.FORMAT_UNCOMPRESSED_LITTLE_ENDIAN: + try (AudioInputStream audioIs = AudioSystem.getAudioInputStream(new BufferedInputStream(is))) { + AudioFormat fmt = audioIs.getFormat(); + newSoundType = fmt.getChannels() == 2; + newSoundSize = fmt.getSampleSizeInBits() == 16; + newSoundSampleCount = audioIs.getFrameLength(); + newSoundData = Helper.readStream(audioIs); + newSoundRate = (int) Math.round(fmt.getSampleRate()); + switch (newSoundRate) { + case 5512: + newSoundRate = 0; + break; + case 11025: + newSoundRate = 1; + break; + case 22050: + newSoundRate = 2; + break; + case 44100: + newSoundRate = 3; + break; + default: + return false; + } + } catch (UnsupportedAudioFileException | IOException ex) { + return false; + } + break; + case SoundFormat.FORMAT_MP3: + BufferedInputStream bis = new BufferedInputStream(is); + loadID3v2(bis); + byte[] mp3data = Helper.readStream(bis); + + final int ID3_V1_LENTGH = 128; + final int ID3_V1_EXT_LENGTH = 227; + + if (mp3data.length > ID3_V1_LENTGH) { + //ID3v1 + if (mp3data[mp3data.length - ID3_V1_LENTGH] == 'T' && mp3data[mp3data.length - ID3_V1_LENTGH + 1] == 'A' && mp3data[mp3data.length - ID3_V1_LENTGH + 2] == 'G') { + mp3data = Arrays.copyOf(mp3data, mp3data.length - ID3_V1_LENTGH); + if (mp3data.length > ID3_V1_EXT_LENGTH) { + //ID3v1 extended + if (mp3data[mp3data.length - ID3_V1_EXT_LENGTH] == 'T' && mp3data[mp3data.length - ID3_V1_EXT_LENGTH + 1] == 'A' && mp3data[mp3data.length - ID3_V1_EXT_LENGTH + 2] == 'G' && mp3data[mp3data.length - ID3_V1_EXT_LENGTH + 3] == '+') { + mp3data = Arrays.copyOf(mp3data, mp3data.length - ID3_V1_EXT_LENGTH); + } + } + } + } + try { + MP3SOUNDDATA snd = new MP3SOUNDDATA(new SWFInputStream(swf, mp3data), true); + if (!snd.frames.isEmpty()) { + MP3FRAME fr = snd.frames.get(0); + newSoundRate = fr.getSamplingRate(); + switch (newSoundRate) { + case 11025: + newSoundRate = 1; + break; + case 22050: + newSoundRate = 2; + break; + case 44100: + newSoundRate = 3; + break; + default: + return false; + } + newSoundSize = true; + newSoundType = fr.isStereo(); + int len = snd.sampleCount(); + if (fr.isStereo()) { + len = len / 2; + } + newSoundSampleCount = len; + + } + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + SWFOutputStream sos = new SWFOutputStream(baos, SWF.DEFAULT_VERSION); + sos.writeSI16(0); //Latency - how to calculate it? + sos.write(mp3data); + newSoundData = baos.toByteArray(); + } catch (IOException ex) { + return false; + } + break; + default: + return false; + } + if (newSoundData != null) { + this.soundSize = newSoundSize; + this.soundRate = newSoundRate; + this.soundSampleCount = newSoundSampleCount; + this.soundData = new ByteArrayRange(newSoundData); + this.soundType = newSoundType; + this.soundFormat = newSoundFormat; + setModified(true); + return true; + } + return false; + + } + + @Override + public boolean importSupported() { + return true; + } + + @Override + public int getSoundRate() { + return soundRate; + } + + @Override + public boolean getSoundType() { + return soundType; + } + + @Override + public List getRawSoundData() { + List ret = new ArrayList<>(); + if (soundFormat == SoundFormat.FORMAT_MP3) { + ret.add(soundData.getRangeData(2, soundData.getLength() - 2)); + return ret; + } + + ret.add(soundData.getRangeData()); + return ret; + } + + @Override + public int getSoundFormatId() { + return soundFormat; + } + + @Override + public long getTotalSoundSampleCount() { + return soundSampleCount; + } + + @Override + public boolean getSoundSize() { + return soundSize; + } + + @Override + public SoundFormat getSoundFormat() { + final int[] rateMap = {5512, 11025, 22050, 44100}; + return new SoundFormat(getSoundFormatId(), rateMap[getSoundRate()], getSoundType()); + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java index 2049761c7..d8924ad8d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java @@ -1,394 +1,396 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.abc.CopyOutputStream; -import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; -import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; -import com.jpexs.decompiler.flash.tags.base.BoundedTag; -import com.jpexs.decompiler.flash.tags.base.CharacterIdTag; -import com.jpexs.decompiler.flash.tags.base.CharacterTag; -import com.jpexs.decompiler.flash.tags.base.DrawableTag; -import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag; -import com.jpexs.decompiler.flash.tags.base.RenderContext; -import com.jpexs.decompiler.flash.timeline.Timeline; -import com.jpexs.decompiler.flash.timeline.Timelined; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.ColorTransform; -import com.jpexs.decompiler.flash.types.MATRIX; -import com.jpexs.decompiler.flash.types.RECT; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.helpers.ByteArrayRange; -import com.jpexs.helpers.Cache; -import com.jpexs.helpers.SerializableImage; -import java.awt.Shape; -import java.awt.geom.AffineTransform; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -/** - * Defines a sprite character - * - * @author JPEXS - */ -public class DefineSpriteTag extends CharacterTag implements DrawableTag, Timelined { - - /** - * Character ID of sprite - */ - @SWFType(BasicType.UI16) - public int spriteId; - - /** - * Number of frames in sprite - */ - @SWFType(BasicType.UI16) - public int frameCount; - - /** - * A series of tags - */ - public List subTags; - - public boolean hasEndTag; - - public static final int ID = 39; - - private Timeline timeline; - - private boolean isSingleFrameInitialized; - - private boolean isSingleFrame; - - private static final Cache rectCache = Cache.getInstance(true, true, "rect_sprite"); - - @Override - public Timeline getTimeline() { - if (timeline == null) { - timeline = new Timeline(swf, this, subTags, spriteId, getRect()); - } - return timeline; - } - - @Override - public void resetTimeline() { - if (timeline != null) { - timeline.reset(swf, this, subTags, spriteId, getRect()); - } - } - - @Override - public int getCharacterId() { - return spriteId; - } - - @Override - public void setCharacterId(int characterId) { - this.spriteId = characterId; - } - - private RECT getCharacterBounds(Set characters, Set added) { - RECT ret = new RECT(Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE); - boolean foundSomething = false; - for (int c : characters) { - Tag t = swf.getCharacter(c); - RECT r = null; - if (t instanceof BoundedTag) { - BoundedTag bt = (BoundedTag) t; - if (!added.contains(bt)) { - added.add(bt); - r = bt.getRect(added); - added.remove(bt); - } - } - if (r != null) { - foundSomething = true; - ret.Xmin = Math.min(r.Xmin, ret.Xmin); - ret.Ymin = Math.min(r.Ymin, ret.Ymin); - ret.Xmax = Math.max(r.Xmax, ret.Xmax); - ret.Ymax = Math.max(r.Ymax, ret.Ymax); - } - } - if (!foundSomething) { - return new RECT(); - } - return ret; - } - - @Override - public RECT getRect() { - return getRect(new HashSet<>()); - } - - @Override - public RECT getRect(Set added) { - if (rectCache.contains(this)) { - return rectCache.get(this); - } - RECT ret = new RECT(Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE); - HashMap depthMap = new HashMap<>(); - boolean foundSomething = false; - for (Tag t : subTags) { - MATRIX m = null; - int characterId = -1; - if (t instanceof PlaceObjectTypeTag) { - PlaceObjectTypeTag pot = (PlaceObjectTypeTag) t; - m = pot.getMatrix(); - int charId = pot.getCharacterId(); - if (charId > -1) { - depthMap.put(pot.getDepth(), charId); - characterId = charId; - } else { - Integer chi = depthMap.get(pot.getDepth()); - if (chi != null) { - characterId = chi; - } - } - } - if (characterId == -1) { - continue; - } - Set need = new HashSet<>(); - need.add(characterId); - RECT r = getCharacterBounds(need, added); - - if (m != null) { - AffineTransform trans = SWF.matrixToTransform(m); - - java.awt.Point topleft = new java.awt.Point(); - trans.transform(new java.awt.Point(r.Xmin, r.Ymin), topleft); - java.awt.Point topright = new java.awt.Point(); - trans.transform(new java.awt.Point(r.Xmax, r.Ymin), topright); - java.awt.Point bottomright = new java.awt.Point(); - trans.transform(new java.awt.Point(r.Xmax, r.Ymax), bottomright); - java.awt.Point bottomleft = new java.awt.Point(); - trans.transform(new java.awt.Point(r.Xmin, r.Ymax), bottomleft); - - r.Xmin = (int) Math.min(Math.min(Math.min(topleft.x, topright.x), bottomleft.x), bottomright.x); - r.Ymin = (int) Math.min(Math.min(Math.min(topleft.y, topright.y), bottomleft.y), bottomright.y); - r.Xmax = (int) Math.max(Math.max(Math.max(topleft.x, topright.x), bottomleft.x), bottomright.x); - r.Ymax = (int) Math.max(Math.max(Math.max(topleft.y, topright.y), bottomleft.y), bottomright.y); - - } - ret.Xmin = Math.min(r.Xmin, ret.Xmin); - ret.Ymin = Math.min(r.Ymin, ret.Ymin); - ret.Xmax = Math.max(r.Xmax, ret.Xmax); - ret.Ymax = Math.max(r.Ymax, ret.Ymax); - foundSomething = true; - } - if (!foundSomething) { - ret = new RECT(); - } - rectCache.put(this, ret); - return ret; - } - - /** - * Constructor - * - * @param swf - */ - public DefineSpriteTag(SWF swf) { - super(swf, ID, "DefineSprite", null); - spriteId = swf.getNextCharacterId(); - subTags = new ArrayList<>(); - } - - /** - * Constructor - * - * @param sis - * @param data - * @param level - * @param parallel - * @param skipUnusualTags - * @throws IOException - * @throws java.lang.InterruptedException - */ - public DefineSpriteTag(SWFInputStream sis, int level, ByteArrayRange data, boolean parallel, boolean skipUnusualTags) throws IOException, InterruptedException { - super(sis.getSwf(), ID, "DefineSprite", data); - readData(sis, data, level, parallel, skipUnusualTags, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException, InterruptedException { - spriteId = sis.readUI16("spriteId"); - frameCount = sis.readUI16("frameCount"); - List subTags = sis.readTagList(this, level + 1, parallel, skipUnusualTags, true, lazy); - if (subTags.size() > 0 && subTags.get(subTags.size() - 1).getId() == EndTag.ID) { - hasEndTag = true; - subTags.remove(subTags.size() - 1); - } - this.subTags = subTags; - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - if (Configuration.debugCopy.get()) { - os = new CopyOutputStream(os, new ByteArrayInputStream(getOriginalData())); - } - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(spriteId); - sos.writeUI16(frameCount); - sos.writeTags(subTags); - if (hasEndTag) { - sos.writeUI16(0); - } - sos.close(); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - - public List getSubTags() { - return subTags; - } - - @Override - public void setModified(boolean value) { - if (!value) { - for (Tag subTag : subTags) { - subTag.setModified(false); - } - } - - super.setModified(value); - } - - @Override - public void createOriginalData() { - super.createOriginalData(); - for (Tag subTag : subTags) { - subTag.createOriginalData(); - } - } - - public static void clearCache() { - rectCache.clear(); - } - - @Override - public void getNeededCharacters(Set needed) { - for (Tag t : subTags) { - if (t instanceof CharacterIdTag) { - needed.add(((CharacterIdTag) t).getCharacterId()); - } - } - } - - @Override - public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { - boolean modified = getTimeline().replaceCharacter(oldCharacterId, newCharacterId); - if (modified) { - setModified(true); - } - return modified; - } - - @Override - public boolean removeCharacter(int characterId) { - boolean modified = getTimeline().removeCharacter(characterId); - if (modified) { - setModified(true); - } - return modified; - } - - @Override - public int getUsedParameters() { - return PARAMETER_FRAME | PARAMETER_TIME | PARAMETER_RATIO; // inner tags can contain morphshapes, too - } - - @Override - public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation) { - return getTimeline().getOutline(frame, time, ratio, renderContext, transformation); - } - - @Override - public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, Matrix transformation, ColorTransform colorTransform) { - SWF.frameToImage(getTimeline(), frame, time, renderContext, image, transformation, colorTransform); - } - - @Override - public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, double zoom) throws IOException { - SWF.frameToSvg(getTimeline(), 0, 0, null, 0, exporter, colorTransform, level + 1, zoom); - } - - @Override - public String toHtmlCanvas(double unitDivisor) { - return getTimeline().toHtmlCanvas(unitDivisor, null); - } - - @Override - public int getNumFrames() { - // flashplayer ignores the count stored in frameCount - return getTimeline().getFrameCount(); // frameCount - } - - @Override - public boolean isSingleFrame() { - if (!isSingleFrameInitialized) { - initialiteIsSingleFrame(); - } - return isSingleFrame; - } - - private synchronized void initialiteIsSingleFrame() { - if (!isSingleFrameInitialized) { - if (getTimeline().getRealFrameCount() > 1) { - isSingleFrameInitialized = true; - return; - } - - isSingleFrame = getTimeline().isSingleFrame(); - isSingleFrameInitialized = true; - } - } - - @Override - public boolean isModified() { - if (super.isModified()) { - return true; - } - for (Tag t : subTags) { - if (t.isModified()) { - return true; - } - } - return false; - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.abc.CopyOutputStream; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; +import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; +import com.jpexs.decompiler.flash.tags.base.BoundedTag; +import com.jpexs.decompiler.flash.tags.base.CharacterIdTag; +import com.jpexs.decompiler.flash.tags.base.CharacterTag; +import com.jpexs.decompiler.flash.tags.base.DrawableTag; +import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag; +import com.jpexs.decompiler.flash.tags.base.RenderContext; +import com.jpexs.decompiler.flash.timeline.Timeline; +import com.jpexs.decompiler.flash.timeline.Timelined; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.ColorTransform; +import com.jpexs.decompiler.flash.types.MATRIX; +import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.helpers.ByteArrayRange; +import com.jpexs.helpers.Cache; +import com.jpexs.helpers.SerializableImage; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * Defines a sprite character + * + * @author JPEXS + */ +public class DefineSpriteTag extends CharacterTag implements DrawableTag, Timelined { + + /** + * Character ID of sprite + */ + @SWFType(BasicType.UI16) + public int spriteId; + + /** + * Number of frames in sprite + */ + @SWFType(BasicType.UI16) + public int frameCount; + + /** + * A series of tags + */ + public List subTags; + + public boolean hasEndTag; + + public static final int ID = 39; + + public static final String NAME = "DefineSprite"; + + private Timeline timeline; + + private boolean isSingleFrameInitialized; + + private boolean isSingleFrame; + + private static final Cache rectCache = Cache.getInstance(true, true, "rect_sprite"); + + @Override + public Timeline getTimeline() { + if (timeline == null) { + timeline = new Timeline(swf, this, subTags, spriteId, getRect()); + } + return timeline; + } + + @Override + public void resetTimeline() { + if (timeline != null) { + timeline.reset(swf, this, subTags, spriteId, getRect()); + } + } + + @Override + public int getCharacterId() { + return spriteId; + } + + @Override + public void setCharacterId(int characterId) { + this.spriteId = characterId; + } + + private RECT getCharacterBounds(Set characters, Set added) { + RECT ret = new RECT(Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE); + boolean foundSomething = false; + for (int c : characters) { + Tag t = swf.getCharacter(c); + RECT r = null; + if (t instanceof BoundedTag) { + BoundedTag bt = (BoundedTag) t; + if (!added.contains(bt)) { + added.add(bt); + r = bt.getRect(added); + added.remove(bt); + } + } + if (r != null) { + foundSomething = true; + ret.Xmin = Math.min(r.Xmin, ret.Xmin); + ret.Ymin = Math.min(r.Ymin, ret.Ymin); + ret.Xmax = Math.max(r.Xmax, ret.Xmax); + ret.Ymax = Math.max(r.Ymax, ret.Ymax); + } + } + if (!foundSomething) { + return new RECT(); + } + return ret; + } + + @Override + public RECT getRect() { + return getRect(new HashSet<>()); + } + + @Override + public RECT getRect(Set added) { + if (rectCache.contains(this)) { + return rectCache.get(this); + } + RECT ret = new RECT(Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE); + HashMap depthMap = new HashMap<>(); + boolean foundSomething = false; + for (Tag t : subTags) { + MATRIX m = null; + int characterId = -1; + if (t instanceof PlaceObjectTypeTag) { + PlaceObjectTypeTag pot = (PlaceObjectTypeTag) t; + m = pot.getMatrix(); + int charId = pot.getCharacterId(); + if (charId > -1) { + depthMap.put(pot.getDepth(), charId); + characterId = charId; + } else { + Integer chi = depthMap.get(pot.getDepth()); + if (chi != null) { + characterId = chi; + } + } + } + if (characterId == -1) { + continue; + } + Set need = new HashSet<>(); + need.add(characterId); + RECT r = getCharacterBounds(need, added); + + if (m != null) { + AffineTransform trans = SWF.matrixToTransform(m); + + java.awt.Point topleft = new java.awt.Point(); + trans.transform(new java.awt.Point(r.Xmin, r.Ymin), topleft); + java.awt.Point topright = new java.awt.Point(); + trans.transform(new java.awt.Point(r.Xmax, r.Ymin), topright); + java.awt.Point bottomright = new java.awt.Point(); + trans.transform(new java.awt.Point(r.Xmax, r.Ymax), bottomright); + java.awt.Point bottomleft = new java.awt.Point(); + trans.transform(new java.awt.Point(r.Xmin, r.Ymax), bottomleft); + + r.Xmin = (int) Math.min(Math.min(Math.min(topleft.x, topright.x), bottomleft.x), bottomright.x); + r.Ymin = (int) Math.min(Math.min(Math.min(topleft.y, topright.y), bottomleft.y), bottomright.y); + r.Xmax = (int) Math.max(Math.max(Math.max(topleft.x, topright.x), bottomleft.x), bottomright.x); + r.Ymax = (int) Math.max(Math.max(Math.max(topleft.y, topright.y), bottomleft.y), bottomright.y); + + } + ret.Xmin = Math.min(r.Xmin, ret.Xmin); + ret.Ymin = Math.min(r.Ymin, ret.Ymin); + ret.Xmax = Math.max(r.Xmax, ret.Xmax); + ret.Ymax = Math.max(r.Ymax, ret.Ymax); + foundSomething = true; + } + if (!foundSomething) { + ret = new RECT(); + } + rectCache.put(this, ret); + return ret; + } + + /** + * Constructor + * + * @param swf + */ + public DefineSpriteTag(SWF swf) { + super(swf, ID, NAME, null); + spriteId = swf.getNextCharacterId(); + subTags = new ArrayList<>(); + } + + /** + * Constructor + * + * @param sis + * @param data + * @param level + * @param parallel + * @param skipUnusualTags + * @throws IOException + * @throws java.lang.InterruptedException + */ + public DefineSpriteTag(SWFInputStream sis, int level, ByteArrayRange data, boolean parallel, boolean skipUnusualTags) throws IOException, InterruptedException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, level, parallel, skipUnusualTags, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException, InterruptedException { + spriteId = sis.readUI16("spriteId"); + frameCount = sis.readUI16("frameCount"); + List subTags = sis.readTagList(this, level + 1, parallel, skipUnusualTags, true, lazy); + if (subTags.size() > 0 && subTags.get(subTags.size() - 1).getId() == EndTag.ID) { + hasEndTag = true; + subTags.remove(subTags.size() - 1); + } + this.subTags = subTags; + } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + if (Configuration.debugCopy.get()) { + os = new CopyOutputStream(os, new ByteArrayInputStream(getOriginalData())); + } + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(spriteId); + sos.writeUI16(frameCount); + sos.writeTags(subTags); + if (hasEndTag) { + sos.writeUI16(0); + } + sos.close(); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + public List getSubTags() { + return subTags; + } + + @Override + public void setModified(boolean value) { + if (!value) { + for (Tag subTag : subTags) { + subTag.setModified(false); + } + } + + super.setModified(value); + } + + @Override + public void createOriginalData() { + super.createOriginalData(); + for (Tag subTag : subTags) { + subTag.createOriginalData(); + } + } + + public static void clearCache() { + rectCache.clear(); + } + + @Override + public void getNeededCharacters(Set needed) { + for (Tag t : subTags) { + if (t instanceof CharacterIdTag) { + needed.add(((CharacterIdTag) t).getCharacterId()); + } + } + } + + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + boolean modified = getTimeline().replaceCharacter(oldCharacterId, newCharacterId); + if (modified) { + setModified(true); + } + return modified; + } + + @Override + public boolean removeCharacter(int characterId) { + boolean modified = getTimeline().removeCharacter(characterId); + if (modified) { + setModified(true); + } + return modified; + } + + @Override + public int getUsedParameters() { + return PARAMETER_FRAME | PARAMETER_TIME | PARAMETER_RATIO; // inner tags can contain morphshapes, too + } + + @Override + public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation) { + return getTimeline().getOutline(frame, time, ratio, renderContext, transformation); + } + + @Override + public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, Matrix transformation, ColorTransform colorTransform) { + SWF.frameToImage(getTimeline(), frame, time, renderContext, image, transformation, colorTransform); + } + + @Override + public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, double zoom) throws IOException { + SWF.frameToSvg(getTimeline(), 0, 0, null, 0, exporter, colorTransform, level + 1, zoom); + } + + @Override + public String toHtmlCanvas(double unitDivisor) { + return getTimeline().toHtmlCanvas(unitDivisor, null); + } + + @Override + public int getNumFrames() { + // flashplayer ignores the count stored in frameCount + return getTimeline().getFrameCount(); // frameCount + } + + @Override + public boolean isSingleFrame() { + if (!isSingleFrameInitialized) { + initialiteIsSingleFrame(); + } + return isSingleFrame; + } + + private synchronized void initialiteIsSingleFrame() { + if (!isSingleFrameInitialized) { + if (getTimeline().getRealFrameCount() > 1) { + isSingleFrameInitialized = true; + return; + } + + isSingleFrame = getTimeline().isSingleFrame(); + isSingleFrameInitialized = true; + } + } + + @Override + public boolean isModified() { + if (super.isModified()) { + return true; + } + for (Tag t : subTags) { + if (t.isModified()) { + return true; + } + } + return false; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineText2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineText2Tag.java index 8e6d612cd..ed9e3a9bf 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineText2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineText2Tag.java @@ -1,67 +1,69 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.tags.base.StaticTextTag; -import com.jpexs.decompiler.flash.types.MATRIX; -import com.jpexs.decompiler.flash.types.RECT; -import com.jpexs.helpers.ByteArrayRange; -import java.io.IOException; -import java.util.ArrayList; - -/** - * - * @author JPEXS - */ -public class DefineText2Tag extends StaticTextTag { - - public static final int ID = 33; - - /** - * Constructor - * - * @param swf - */ - public DefineText2Tag(SWF swf) { - super(swf, ID, "DefineText2", null); - characterID = swf.getNextCharacterId(); - textBounds = new RECT(); - textMatrix = new MATRIX(); - textRecords = new ArrayList<>(); - glyphBits = 0; - advanceBits = 0; - } - - /** - * Constructor - * - * @param sis - * @param data - * @throws IOException - */ - public DefineText2Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DefineText2", data); - readData(sis, data, 0, false, false, false); - } - - @Override - public int getTextNum() { - return 2; - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.tags.base.StaticTextTag; +import com.jpexs.decompiler.flash.types.MATRIX; +import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.helpers.ByteArrayRange; +import java.io.IOException; +import java.util.ArrayList; + +/** + * + * @author JPEXS + */ +public class DefineText2Tag extends StaticTextTag { + + public static final int ID = 33; + + public static final String NAME = "DefineText2"; + + /** + * Constructor + * + * @param swf + */ + public DefineText2Tag(SWF swf) { + super(swf, ID, NAME, null); + characterID = swf.getNextCharacterId(); + textBounds = new RECT(); + textMatrix = new MATRIX(); + textRecords = new ArrayList<>(); + glyphBits = 0; + advanceBits = 0; + } + + /** + * Constructor + * + * @param sis + * @param data + * @throws IOException + */ + public DefineText2Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public int getTextNum() { + return 2; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineTextTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineTextTag.java index c100393a2..63f243c91 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineTextTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineTextTag.java @@ -1,79 +1,81 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.tags.base.StaticTextTag; -import com.jpexs.decompiler.flash.types.MATRIX; -import com.jpexs.decompiler.flash.types.RECT; -import com.jpexs.decompiler.flash.types.TEXTRECORD; -import com.jpexs.helpers.ByteArrayRange; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -/** - * - * @author JPEXS - */ -public class DefineTextTag extends StaticTextTag { - - public static final int ID = 11; - - /** - * Constructor - * - * @param swf - */ - public DefineTextTag(SWF swf) { - super(swf, ID, "DefineText", null); - characterID = swf.getNextCharacterId(); - textBounds = new RECT(); - textMatrix = new MATRIX(); - textRecords = new ArrayList<>(); - glyphBits = 0; - advanceBits = 0; - } - - public DefineTextTag(SWF swf, int characterID, RECT textBounds, MATRIX textMatrix, List textRecords) { - super(swf, ID, "DefineText", null); - this.characterID = characterID; - this.textBounds = textBounds; - this.textMatrix = textMatrix; - this.textRecords = textRecords; - this.glyphBits = 0; - this.advanceBits = 0; - } - - /** - * Constructor - * - * @param sis - * @param data - * @throws IOException - */ - public DefineTextTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DefineText", data); - readData(sis, data, 0, false, false, false); - } - - @Override - public int getTextNum() { - return 1; - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.tags.base.StaticTextTag; +import com.jpexs.decompiler.flash.types.MATRIX; +import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.decompiler.flash.types.TEXTRECORD; +import com.jpexs.helpers.ByteArrayRange; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author JPEXS + */ +public class DefineTextTag extends StaticTextTag { + + public static final int ID = 11; + + public static final String NAME = "DefineText"; + + /** + * Constructor + * + * @param swf + */ + public DefineTextTag(SWF swf) { + super(swf, ID, NAME, null); + characterID = swf.getNextCharacterId(); + textBounds = new RECT(); + textMatrix = new MATRIX(); + textRecords = new ArrayList<>(); + glyphBits = 0; + advanceBits = 0; + } + + public DefineTextTag(SWF swf, int characterID, RECT textBounds, MATRIX textMatrix, List textRecords) { + super(swf, ID, NAME, null); + this.characterID = characterID; + this.textBounds = textBounds; + this.textMatrix = textMatrix; + this.textRecords = textRecords; + this.glyphBits = 0; + this.advanceBits = 0; + } + + /** + * Constructor + * + * @param sis + * @param data + * @throws IOException + */ + public DefineTextTag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public int getTextNum() { + return 1; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineVideoStreamTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineVideoStreamTag.java index f557f9e0d..951a00ae0 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineVideoStreamTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineVideoStreamTag.java @@ -1,152 +1,154 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.tags.base.BoundedTag; -import com.jpexs.decompiler.flash.tags.base.CharacterTag; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.RECT; -import com.jpexs.decompiler.flash.types.annotations.Reserved; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.helpers.ByteArrayRange; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.Set; - -/** - * - * @author JPEXS - */ -public class DefineVideoStreamTag extends CharacterTag implements BoundedTag { - - @SWFType(BasicType.UI16) - public int characterID; - - @SWFType(BasicType.UI16) - public int numFrames; - - @SWFType(BasicType.UI16) - public int width; - - @SWFType(BasicType.UI16) - public int height; - - @Reserved - @SWFType(value = BasicType.UB, count = 4) - public int reserved; - - @SWFType(value = BasicType.UB, count = 3) - public int videoFlagsDeblocking; - - public boolean videoFlagsSmoothing; - - @SWFType(BasicType.UI8) - public int codecID; - - public static final int CODEC_SORENSON_H263 = 2; - - public static final int CODEC_SCREEN_VIDEO = 3; - - public static final int CODEC_VP6 = 4; - - public static final int CODEC_VP6_ALPHA = 5; - - public static final int ID = 60; - - @Override - public int getCharacterId() { - return characterID; - } - - @Override - public void setCharacterId(int characterId) { - this.characterID = characterId; - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(characterID); - sos.writeUI16(numFrames); - sos.writeUI16(width); - sos.writeUI16(height); - sos.writeUB(4, reserved); - sos.writeUB(3, videoFlagsDeblocking); - sos.writeUB(1, videoFlagsSmoothing ? 1 : 0); - sos.writeUI8(codecID); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - - /** - * Constructor - * - * @param swf - */ - public DefineVideoStreamTag(SWF swf) { - super(swf, ID, "DefineVideoStream", null); - characterID = swf.getNextCharacterId(); - } - - /** - * Constructor - * - * @param sis - * @param data - * @throws IOException - */ - public DefineVideoStreamTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DefineVideoStream", data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - characterID = sis.readUI16("characterID"); - numFrames = sis.readUI16("numFrames"); - width = sis.readUI16("width"); - height = sis.readUI16("height"); - reserved = (int) sis.readUB(4, "reserved"); - videoFlagsDeblocking = (int) sis.readUB(3, "videoFlagsDeblocking"); - videoFlagsSmoothing = sis.readUB(1, "videoFlagsSmoothing") == 1; - codecID = sis.readUI8("codecID"); - } - - @Override - public RECT getRect() { - return getRect(null); // parameter not used - } - - @Override - public RECT getRect(Set added) { - return new RECT(0, (int) (SWF.unitDivisor * width), 0, (int) (SWF.unitDivisor * height)); - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.tags.base.BoundedTag; +import com.jpexs.decompiler.flash.tags.base.CharacterTag; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.decompiler.flash.types.annotations.Reserved; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.helpers.ByteArrayRange; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Set; + +/** + * + * @author JPEXS + */ +public class DefineVideoStreamTag extends CharacterTag implements BoundedTag { + + @SWFType(BasicType.UI16) + public int characterID; + + @SWFType(BasicType.UI16) + public int numFrames; + + @SWFType(BasicType.UI16) + public int width; + + @SWFType(BasicType.UI16) + public int height; + + @Reserved + @SWFType(value = BasicType.UB, count = 4) + public int reserved; + + @SWFType(value = BasicType.UB, count = 3) + public int videoFlagsDeblocking; + + public boolean videoFlagsSmoothing; + + @SWFType(BasicType.UI8) + public int codecID; + + public static final int CODEC_SORENSON_H263 = 2; + + public static final int CODEC_SCREEN_VIDEO = 3; + + public static final int CODEC_VP6 = 4; + + public static final int CODEC_VP6_ALPHA = 5; + + public static final int ID = 60; + + public static final String NAME = "DefineVideoStream"; + + @Override + public int getCharacterId() { + return characterID; + } + + @Override + public void setCharacterId(int characterId) { + this.characterID = characterId; + } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(characterID); + sos.writeUI16(numFrames); + sos.writeUI16(width); + sos.writeUI16(height); + sos.writeUB(4, reserved); + sos.writeUB(3, videoFlagsDeblocking); + sos.writeUB(1, videoFlagsSmoothing ? 1 : 0); + sos.writeUI8(codecID); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + /** + * Constructor + * + * @param swf + */ + public DefineVideoStreamTag(SWF swf) { + super(swf, ID, NAME, null); + characterID = swf.getNextCharacterId(); + } + + /** + * Constructor + * + * @param sis + * @param data + * @throws IOException + */ + public DefineVideoStreamTag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + characterID = sis.readUI16("characterID"); + numFrames = sis.readUI16("numFrames"); + width = sis.readUI16("width"); + height = sis.readUI16("height"); + reserved = (int) sis.readUB(4, "reserved"); + videoFlagsDeblocking = (int) sis.readUB(3, "videoFlagsDeblocking"); + videoFlagsSmoothing = sis.readUB(1, "videoFlagsSmoothing") == 1; + codecID = sis.readUI8("codecID"); + } + + @Override + public RECT getRect() { + return getRect(null); // parameter not used + } + + @Override + public RECT getRect(Set added) { + return new RECT(0, (int) (SWF.unitDivisor * width), 0, (int) (SWF.unitDivisor * height)); + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoABCDefineTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoABCDefineTag.java index eff6b7bc6..313a0c57c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoABCDefineTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoABCDefineTag.java @@ -1,156 +1,158 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.abc.ABC; -import com.jpexs.decompiler.flash.abc.ABCInputStream; -import com.jpexs.decompiler.flash.abc.CopyOutputStream; -import com.jpexs.decompiler.flash.abc.types.ScriptInfo; -import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit; -import com.jpexs.decompiler.flash.types.annotations.SWFField; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.helpers.ByteArrayRange; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -/** - * Defines a series of ActionScript 3 bytecodes to be executed - * - * @author JPEXS - */ -public class DoABCDefineTag extends Tag implements ABCContainerTag { - - /** - * ActionScript 3 bytecodes - */ - @HideInRawEdit - @SWFField - private ABC abc; - - /** - * A 32-bit flags value, which may contain the following bits set: - * kDoAbcLazyInitializeFlag = 1: Indicates that the ABC block should not be - * executed immediately, but only parsed. A later finddef may cause its - * scripts to execute. - */ - @SWFType(BasicType.UI32) - public long flags; - - /** - * The name assigned to the bytecode. - */ - public String name; - - public static final int ID = 82; - - @Override - public ABC getABC() { - return abc; - } - - @Override - public String getName() { - return "DoABCDefine (" + name + ")"; - } - - /** - * Constructor - * - * @param swf - */ - public DoABCDefineTag(SWF swf) { - super(swf, ID, "DoABCDefine", null); - name = "New DoABC"; - abc = new ABC(this); - } - - /** - * Constructor - * - * @param sis - * @param data - * @throws IOException - */ - public DoABCDefineTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DoABCDefine", data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - flags = sis.readUI32("flags"); - name = sis.readString("name"); - - ABCInputStream ais = new ABCInputStream(sis.getBaseStream()); - // put it to the dumpview: - sis.readByteRangeEx(sis.available(), "abcBytes"); - abc = new ABC(ais, swf, this); - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - try { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - OutputStream os = bos; - if (Configuration.debugCopy.get()) { - os = new CopyOutputStream(os, new ByteArrayInputStream(getOriginalData())); - } - try (SWFOutputStream sos = new SWFOutputStream(os, getVersion())) { - sos.writeUI32(flags); - sos.writeString(name); - abc.saveToStream(sos); - } - return bos.toByteArray(); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - } - - @Override - public int compareTo(ABCContainerTag o) { - if (o instanceof DoABCDefineTag) { - DoABCDefineTag n = (DoABCDefineTag) o; - int lastCmp = name.compareTo(n.name); - return (lastCmp != 0 ? lastCmp - : name.compareTo(n.name)); - } - return 0; - } - - @Override - public void setModified(boolean value) { - super.setModified(value); - if (value == false && !isModified()) { - ABC abc = getABC(); - for (ScriptInfo si : abc.script_info) { - si.setModified(false); - } - } - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.abc.ABC; +import com.jpexs.decompiler.flash.abc.ABCInputStream; +import com.jpexs.decompiler.flash.abc.CopyOutputStream; +import com.jpexs.decompiler.flash.abc.types.ScriptInfo; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit; +import com.jpexs.decompiler.flash.types.annotations.SWFField; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.helpers.ByteArrayRange; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * Defines a series of ActionScript 3 bytecodes to be executed + * + * @author JPEXS + */ +public class DoABCDefineTag extends Tag implements ABCContainerTag { + + /** + * ActionScript 3 bytecodes + */ + @HideInRawEdit + @SWFField + private ABC abc; + + /** + * A 32-bit flags value, which may contain the following bits set: + * kDoAbcLazyInitializeFlag = 1: Indicates that the ABC block should not be + * executed immediately, but only parsed. A later finddef may cause its + * scripts to execute. + */ + @SWFType(BasicType.UI32) + public long flags; + + /** + * The name assigned to the bytecode. + */ + public String name; + + public static final int ID = 82; + + public static final String NAME = "DoABCDefine"; + + @Override + public ABC getABC() { + return abc; + } + + @Override + public String getName() { + return super.getName() + " (" + name + ")"; + } + + /** + * Constructor + * + * @param swf + */ + public DoABCDefineTag(SWF swf) { + super(swf, ID, NAME, null); + name = "New DoABC"; + abc = new ABC(this); + } + + /** + * Constructor + * + * @param sis + * @param data + * @throws IOException + */ + public DoABCDefineTag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + flags = sis.readUI32("flags"); + name = sis.readString("name"); + + ABCInputStream ais = new ABCInputStream(sis.getBaseStream()); + // put it to the dumpview: + sis.readByteRangeEx(sis.available(), "abcBytes"); + abc = new ABC(ais, swf, this); + } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + try { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + OutputStream os = bos; + if (Configuration.debugCopy.get()) { + os = new CopyOutputStream(os, new ByteArrayInputStream(getOriginalData())); + } + try (SWFOutputStream sos = new SWFOutputStream(os, getVersion())) { + sos.writeUI32(flags); + sos.writeString(name); + abc.saveToStream(sos); + } + return bos.toByteArray(); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + } + + @Override + public int compareTo(ABCContainerTag o) { + if (o instanceof DoABCDefineTag) { + DoABCDefineTag n = (DoABCDefineTag) o; + int lastCmp = name.compareTo(n.name); + return (lastCmp != 0 ? lastCmp + : name.compareTo(n.name)); + } + return 0; + } + + @Override + public void setModified(boolean value) { + super.setModified(value); + if (value == false && !isModified()) { + ABC abc = getABC(); + for (ScriptInfo si : abc.script_info) { + si.setModified(false); + } + } + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoABCTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoABCTag.java index bab1cbf81..255c781e2 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoABCTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoABCTag.java @@ -1,128 +1,125 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.abc.ABC; -import com.jpexs.decompiler.flash.abc.ABCInputStream; -import com.jpexs.decompiler.flash.abc.CopyOutputStream; -import com.jpexs.decompiler.flash.abc.types.ScriptInfo; -import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit; -import com.jpexs.decompiler.flash.types.annotations.SWFField; -import com.jpexs.helpers.ByteArrayRange; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -/** - * Defines a series of ActionScript 3 bytecodes to be executed - * - * @author JPEXS - */ -public class DoABCTag extends Tag implements ABCContainerTag { - - /** - * ActionScript 3 bytecodes - */ - @HideInRawEdit - @SWFField - private ABC abc; - - public static final int ID = 72; - - @Override - public ABC getABC() { - return abc; - } - - @Override - public String getName() { - return "DoABC"; - } - - /** - * Constructor - * - * @param swf - */ - public DoABCTag(SWF swf) { - super(swf, ID, "DoABC", null); - abc = new ABC(this); - } - - /** - * Constructor - * - * @param sis - * @param data - * @throws IOException - */ - public DoABCTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DoABC", data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - ABCInputStream ais = new ABCInputStream(sis.getBaseStream()); - // put it to the dumpview: - sis.readByteRangeEx(sis.available(), "abcBytes"); - abc = new ABC(ais, swf, this); - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - try { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - OutputStream os = bos; - if (Configuration.debugCopy.get()) { - os = new CopyOutputStream(os, new ByteArrayInputStream(getOriginalData())); - } - try (SWFOutputStream sos = new SWFOutputStream(os, getVersion())) { - abc.saveToStream(sos); - } - return bos.toByteArray(); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - } - - @Override - public int compareTo(ABCContainerTag o) { - return 0; - } - - @Override - public void setModified(boolean value) { - super.setModified(value); - if (value == false && !isModified()) { - ABC abc = getABC(); - for (ScriptInfo si : abc.script_info) { - si.setModified(false); - } - } - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.abc.ABC; +import com.jpexs.decompiler.flash.abc.ABCInputStream; +import com.jpexs.decompiler.flash.abc.CopyOutputStream; +import com.jpexs.decompiler.flash.abc.types.ScriptInfo; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit; +import com.jpexs.decompiler.flash.types.annotations.SWFField; +import com.jpexs.helpers.ByteArrayRange; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * Defines a series of ActionScript 3 bytecodes to be executed + * + * @author JPEXS + */ +public class DoABCTag extends Tag implements ABCContainerTag { + + /** + * ActionScript 3 bytecodes + */ + @HideInRawEdit + @SWFField + private ABC abc; + + public static final int ID = 72; + + public static final String NAME = "DoABC"; + + @Override + public ABC getABC() { + return abc; + } + + /** + * Constructor + * + * @param swf + */ + public DoABCTag(SWF swf) { + super(swf, ID, NAME, null); + abc = new ABC(this); + } + + /** + * Constructor + * + * @param sis + * @param data + * @throws IOException + */ + public DoABCTag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + ABCInputStream ais = new ABCInputStream(sis.getBaseStream()); + // put it to the dumpview: + sis.readByteRangeEx(sis.available(), "abcBytes"); + abc = new ABC(ais, swf, this); + } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + try { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + OutputStream os = bos; + if (Configuration.debugCopy.get()) { + os = new CopyOutputStream(os, new ByteArrayInputStream(getOriginalData())); + } + try (SWFOutputStream sos = new SWFOutputStream(os, getVersion())) { + abc.saveToStream(sos); + } + return bos.toByteArray(); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + } + + @Override + public int compareTo(ABCContainerTag o) { + return 0; + } + + @Override + public void setModified(boolean value) { + super.setModified(value); + if (value == false && !isModified()) { + ABC abc = getABC(); + for (ScriptInfo si : abc.script_info) { + si.setModified(false); + } + } + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoActionTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoActionTag.java index 4645aadc8..b2dd8a27f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoActionTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoActionTag.java @@ -1,210 +1,212 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.DisassemblyListener; -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.action.Action; -import com.jpexs.decompiler.flash.action.ActionList; -import com.jpexs.decompiler.flash.action.ActionListReader; -import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; -import com.jpexs.decompiler.flash.helpers.GraphTextWriter; -import com.jpexs.decompiler.flash.tags.base.ASMSource; -import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit; -import com.jpexs.helpers.ByteArrayRange; -import com.jpexs.helpers.Helper; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Instructs Flash Player to perform a list of actions when the current frame is - * complete. - * - * @author JPEXS - */ -public class DoActionTag extends Tag implements ASMSource { - - /** - * List of actions to perform - */ - //public List actions = new ArrayList(); - @HideInRawEdit - public ByteArrayRange actionBytes; - - public static final int ID = 12; - - /** - * Constructor - * - * @param swf - */ - public DoActionTag(SWF swf) { - super(swf, ID, "DoAction", null); - } - - /** - * Constructor - * - * @param sis - * @param data - * @throws java.io.IOException - */ - public DoActionTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DoAction", data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - actionBytes = sis.readByteRangeEx(sis.available(), "actionBytes"); - } - - /** - * Constructor - * - * @param swf - * @param data - */ - public DoActionTag(SWF swf, ByteArrayRange data) { - super(swf, ID, "DoAction", data); - actionBytes = ByteArrayRange.EMPTY; - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - return getActionBytes(); - } - - /** - * Converts actions to ASM source - * - * @param exportMode PCode or hex? - * @param writer - * @param actions - * @return ASM source - * @throws java.lang.InterruptedException - */ - @Override - public GraphTextWriter getASMSource(ScriptExportMode exportMode, GraphTextWriter writer, ActionList actions) throws InterruptedException { - if (actions == null) { - actions = getActions(); - } - - return Action.actionsToString(listeners, 0, actions, swf.version, exportMode, writer); - } - - /** - * Whether or not this object contains ASM source - * - * @return True when contains - */ - @Override - public boolean containsSource() { - return true; - } - - @Override - public ActionList getActions() throws InterruptedException { - try { - int prevLength = actionBytes.getPos(); - SWFInputStream rri = new SWFInputStream(swf, actionBytes.getArray()); - if (prevLength != 0) { - rri.seek(prevLength); - } - - ActionList list = ActionListReader.readActionListTimeout(listeners, rri, getVersion(), prevLength, prevLength + actionBytes.getLength(), toString()/*FIXME?*/); - return list; - } catch (InterruptedException ex) { - throw ex; - } catch (Exception ex) { - Logger.getLogger(DoActionTag.class.getName()).log(Level.SEVERE, null, ex); - return new ActionList(); - } - } - - @Override - public void setActions(List actions) { - byte[] bytes = Action.actionsToBytes(actions, true, swf.version); - actionBytes = new ByteArrayRange(bytes, 0, bytes.length); - } - - @Override - public byte[] getActionBytes() { - return actionBytes.getRangeData(); - } - - @Override - public void setActionBytes(byte[] actionBytes) { - this.actionBytes = new ByteArrayRange(actionBytes); - } - - @Override - public void setModified() { - setModified(true); - } - - @Override - public GraphTextWriter getActionBytesAsHex(GraphTextWriter writer) { - return Helper.byteArrayToHexWithHeader(writer, actionBytes.getRangeData()); - } - - List listeners = new ArrayList<>(); - - @Override - public void addDisassemblyListener(DisassemblyListener listener) { - listeners.add(listener); - } - - @Override - public void removeDisassemblyListener(DisassemblyListener listener) { - listeners.remove(listener); - } - - @Override - public GraphTextWriter getActionSourcePrefix(GraphTextWriter writer) { - return writer; - } - - @Override - public GraphTextWriter getActionSourceSuffix(GraphTextWriter writer) { - return writer; - } - - @Override - public int getPrefixLineCount() { - return 0; - } - - @Override - public String removePrefixAndSuffix(String source) { - return source; - } - - @Override - public Tag getSourceTag() { - return this; - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.DisassemblyListener; +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.action.Action; +import com.jpexs.decompiler.flash.action.ActionList; +import com.jpexs.decompiler.flash.action.ActionListReader; +import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; +import com.jpexs.decompiler.flash.helpers.GraphTextWriter; +import com.jpexs.decompiler.flash.tags.base.ASMSource; +import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit; +import com.jpexs.helpers.ByteArrayRange; +import com.jpexs.helpers.Helper; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Instructs Flash Player to perform a list of actions when the current frame is + * complete. + * + * @author JPEXS + */ +public class DoActionTag extends Tag implements ASMSource { + + /** + * List of actions to perform + */ + //public List actions = new ArrayList(); + @HideInRawEdit + public ByteArrayRange actionBytes; + + public static final int ID = 12; + + public static final String NAME = "DoAction"; + + /** + * Constructor + * + * @param swf + */ + public DoActionTag(SWF swf) { + super(swf, ID, NAME, null); + } + + /** + * Constructor + * + * @param sis + * @param data + * @throws java.io.IOException + */ + public DoActionTag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + actionBytes = sis.readByteRangeEx(sis.available(), "actionBytes"); + } + + /** + * Constructor + * + * @param swf + * @param data + */ + public DoActionTag(SWF swf, ByteArrayRange data) { + super(swf, ID, NAME, data); + actionBytes = ByteArrayRange.EMPTY; + } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + return getActionBytes(); + } + + /** + * Converts actions to ASM source + * + * @param exportMode PCode or hex? + * @param writer + * @param actions + * @return ASM source + * @throws java.lang.InterruptedException + */ + @Override + public GraphTextWriter getASMSource(ScriptExportMode exportMode, GraphTextWriter writer, ActionList actions) throws InterruptedException { + if (actions == null) { + actions = getActions(); + } + + return Action.actionsToString(listeners, 0, actions, swf.version, exportMode, writer); + } + + /** + * Whether or not this object contains ASM source + * + * @return True when contains + */ + @Override + public boolean containsSource() { + return true; + } + + @Override + public ActionList getActions() throws InterruptedException { + try { + int prevLength = actionBytes.getPos(); + SWFInputStream rri = new SWFInputStream(swf, actionBytes.getArray()); + if (prevLength != 0) { + rri.seek(prevLength); + } + + ActionList list = ActionListReader.readActionListTimeout(listeners, rri, getVersion(), prevLength, prevLength + actionBytes.getLength(), toString()/*FIXME?*/); + return list; + } catch (InterruptedException ex) { + throw ex; + } catch (Exception ex) { + Logger.getLogger(DoActionTag.class.getName()).log(Level.SEVERE, null, ex); + return new ActionList(); + } + } + + @Override + public void setActions(List actions) { + byte[] bytes = Action.actionsToBytes(actions, true, swf.version); + actionBytes = new ByteArrayRange(bytes, 0, bytes.length); + } + + @Override + public byte[] getActionBytes() { + return actionBytes.getRangeData(); + } + + @Override + public void setActionBytes(byte[] actionBytes) { + this.actionBytes = new ByteArrayRange(actionBytes); + } + + @Override + public void setModified() { + setModified(true); + } + + @Override + public GraphTextWriter getActionBytesAsHex(GraphTextWriter writer) { + return Helper.byteArrayToHexWithHeader(writer, actionBytes.getRangeData()); + } + + List listeners = new ArrayList<>(); + + @Override + public void addDisassemblyListener(DisassemblyListener listener) { + listeners.add(listener); + } + + @Override + public void removeDisassemblyListener(DisassemblyListener listener) { + listeners.remove(listener); + } + + @Override + public GraphTextWriter getActionSourcePrefix(GraphTextWriter writer) { + return writer; + } + + @Override + public GraphTextWriter getActionSourceSuffix(GraphTextWriter writer) { + return writer; + } + + @Override + public int getPrefixLineCount() { + return 0; + } + + @Override + public String removePrefixAndSuffix(String source) { + return source; + } + + @Override + public Tag getSourceTag() { + return this; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoInitActionTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoInitActionTag.java index 9577090b5..464e0b468 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoInitActionTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoInitActionTag.java @@ -1,258 +1,260 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.DisassemblyListener; -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.action.Action; -import com.jpexs.decompiler.flash.action.ActionList; -import com.jpexs.decompiler.flash.action.ActionListReader; -import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; -import com.jpexs.decompiler.flash.helpers.GraphTextWriter; -import com.jpexs.decompiler.flash.tags.base.ASMSource; -import com.jpexs.decompiler.flash.tags.base.CharacterIdTag; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.helpers.ByteArrayRange; -import com.jpexs.helpers.Helper; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - * @author JPEXS - */ -public class DoInitActionTag extends Tag implements CharacterIdTag, ASMSource { - - /** - * Identifier of Sprite - */ - @SWFType(BasicType.UI16) - public int spriteId = 0; - - /** - * List of actions to perform - */ - //public List actions = new ArrayList(); - @HideInRawEdit - public ByteArrayRange actionBytes; - - public static final int ID = 59; - - /** - * Constructor - * - * @param swf - */ - public DoInitActionTag(SWF swf) { - super(swf, ID, "DoInitAction", null); - } - - /** - * Constructor - * - * @param sis - * @param data - * @throws IOException - */ - public DoInitActionTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DoInitAction", data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - spriteId = sis.readUI16("spriteId"); - actionBytes = sis.readByteRangeEx(sis.available(), "actionBytes"); - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - SWFOutputStream sos = new SWFOutputStream(baos, getVersion()); - try { - sos.writeUI16(spriteId); - sos.write(getActionBytes()); - //sos.write(Action.actionsToBytes(actions, true, version)); - sos.close(); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - - /** - * Whether or not this object contains ASM source - * - * @return True when contains - */ - @Override - public boolean containsSource() { - return true; - } - - /** - * Converts actions to ASM source - * - * @param exportMode PCode or hex? - * @param writer - * @param actions - * @return ASM source - * @throws java.lang.InterruptedException - */ - @Override - public GraphTextWriter getASMSource(ScriptExportMode exportMode, GraphTextWriter writer, ActionList actions) throws InterruptedException { - if (actions == null) { - actions = getActions(); - } - return Action.actionsToString(listeners, 0, actions, swf.version, exportMode, writer); - } - - @Override - public ActionList getActions() throws InterruptedException { - try { - int prevLength = actionBytes.getPos(); - SWFInputStream rri = new SWFInputStream(swf, actionBytes.getArray()); - if (prevLength != 0) { - rri.seek(prevLength); - } - - ActionList list = ActionListReader.readActionListTimeout(listeners, rri, getVersion(), prevLength, prevLength + actionBytes.getLength(), toString()/*FIXME?*/); - return list; - } catch (InterruptedException ex) { - throw ex; - } catch (Exception ex) { - Logger.getLogger(DoInitActionTag.class.getName()).log(Level.SEVERE, null, ex); - return new ActionList(); - } - } - - @Override - public void setActions(List actions) { - byte[] bytes = Action.actionsToBytes(actions, true, swf.version); - actionBytes = new ByteArrayRange(bytes, 0, bytes.length); - } - - @Override - public byte[] getActionBytes() { - return actionBytes.getRangeData(); - } - - @Override - public void setActionBytes(byte[] actionBytes) { - this.actionBytes = new ByteArrayRange(actionBytes); - } - - @Override - public void setModified() { - setModified(true); - } - - @Override - public GraphTextWriter getActionBytesAsHex(GraphTextWriter writer) { - return Helper.byteArrayToHexWithHeader(writer, actionBytes.getRangeData()); - } - - @Override - public int getCharacterId() { - return spriteId; - } - - @Override - public void setCharacterId(int characterId) { - this.spriteId = characterId; - } - - List listeners = new ArrayList<>(); - - @Override - public void addDisassemblyListener(DisassemblyListener listener) { - listeners.add(listener); - } - - @Override - public void removeDisassemblyListener(DisassemblyListener listener) { - listeners.remove(listener); - } - - @Override - public String getExportFileName() { - String expName = swf.getExportName(spriteId); - if ((expName == null) || expName.isEmpty()) { - return super.getExportFileName(); - } - String[] pathParts; - if (expName.contains(".")) { - pathParts = expName.split("\\."); - } else { - pathParts = new String[]{expName}; - } - return pathParts[pathParts.length - 1]; - } - - @Override - public String getName() { - String expName = swf == null ? "" : swf.getExportName(spriteId); - if ((expName == null) || expName.isEmpty()) { - return super.getName(); - } - String[] pathParts; - if (expName.contains(".")) { - pathParts = expName.split("\\."); - } else { - pathParts = new String[]{expName}; - } - return pathParts[pathParts.length - 1]; - } - - @Override - public GraphTextWriter getActionSourcePrefix(GraphTextWriter writer) { - return writer; - } - - @Override - public GraphTextWriter getActionSourceSuffix(GraphTextWriter writer) { - return writer; - } - - @Override - public int getPrefixLineCount() { - return 0; - } - - @Override - public String removePrefixAndSuffix(String source) { - return source; - } - - @Override - public Tag getSourceTag() { - return this; - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.DisassemblyListener; +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.action.Action; +import com.jpexs.decompiler.flash.action.ActionList; +import com.jpexs.decompiler.flash.action.ActionListReader; +import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; +import com.jpexs.decompiler.flash.helpers.GraphTextWriter; +import com.jpexs.decompiler.flash.tags.base.ASMSource; +import com.jpexs.decompiler.flash.tags.base.CharacterIdTag; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.helpers.ByteArrayRange; +import com.jpexs.helpers.Helper; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author JPEXS + */ +public class DoInitActionTag extends Tag implements CharacterIdTag, ASMSource { + + /** + * Identifier of Sprite + */ + @SWFType(BasicType.UI16) + public int spriteId = 0; + + /** + * List of actions to perform + */ + //public List actions = new ArrayList(); + @HideInRawEdit + public ByteArrayRange actionBytes; + + public static final int ID = 59; + + public static final String NAME = "DoInitAction"; + + /** + * Constructor + * + * @param swf + */ + public DoInitActionTag(SWF swf) { + super(swf, ID, NAME, null); + } + + /** + * Constructor + * + * @param sis + * @param data + * @throws IOException + */ + public DoInitActionTag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + spriteId = sis.readUI16("spriteId"); + actionBytes = sis.readByteRangeEx(sis.available(), "actionBytes"); + } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + SWFOutputStream sos = new SWFOutputStream(baos, getVersion()); + try { + sos.writeUI16(spriteId); + sos.write(getActionBytes()); + //sos.write(Action.actionsToBytes(actions, true, version)); + sos.close(); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + /** + * Whether or not this object contains ASM source + * + * @return True when contains + */ + @Override + public boolean containsSource() { + return true; + } + + /** + * Converts actions to ASM source + * + * @param exportMode PCode or hex? + * @param writer + * @param actions + * @return ASM source + * @throws java.lang.InterruptedException + */ + @Override + public GraphTextWriter getASMSource(ScriptExportMode exportMode, GraphTextWriter writer, ActionList actions) throws InterruptedException { + if (actions == null) { + actions = getActions(); + } + return Action.actionsToString(listeners, 0, actions, swf.version, exportMode, writer); + } + + @Override + public ActionList getActions() throws InterruptedException { + try { + int prevLength = actionBytes.getPos(); + SWFInputStream rri = new SWFInputStream(swf, actionBytes.getArray()); + if (prevLength != 0) { + rri.seek(prevLength); + } + + ActionList list = ActionListReader.readActionListTimeout(listeners, rri, getVersion(), prevLength, prevLength + actionBytes.getLength(), toString()/*FIXME?*/); + return list; + } catch (InterruptedException ex) { + throw ex; + } catch (Exception ex) { + Logger.getLogger(DoInitActionTag.class.getName()).log(Level.SEVERE, null, ex); + return new ActionList(); + } + } + + @Override + public void setActions(List actions) { + byte[] bytes = Action.actionsToBytes(actions, true, swf.version); + actionBytes = new ByteArrayRange(bytes, 0, bytes.length); + } + + @Override + public byte[] getActionBytes() { + return actionBytes.getRangeData(); + } + + @Override + public void setActionBytes(byte[] actionBytes) { + this.actionBytes = new ByteArrayRange(actionBytes); + } + + @Override + public void setModified() { + setModified(true); + } + + @Override + public GraphTextWriter getActionBytesAsHex(GraphTextWriter writer) { + return Helper.byteArrayToHexWithHeader(writer, actionBytes.getRangeData()); + } + + @Override + public int getCharacterId() { + return spriteId; + } + + @Override + public void setCharacterId(int characterId) { + this.spriteId = characterId; + } + + List listeners = new ArrayList<>(); + + @Override + public void addDisassemblyListener(DisassemblyListener listener) { + listeners.add(listener); + } + + @Override + public void removeDisassemblyListener(DisassemblyListener listener) { + listeners.remove(listener); + } + + @Override + public String getExportFileName() { + String expName = swf.getExportName(spriteId); + if ((expName == null) || expName.isEmpty()) { + return super.getExportFileName(); + } + String[] pathParts; + if (expName.contains(".")) { + pathParts = expName.split("\\."); + } else { + pathParts = new String[]{expName}; + } + return pathParts[pathParts.length - 1]; + } + + @Override + public String getName() { + String expName = swf == null ? "" : swf.getExportName(spriteId); + if ((expName == null) || expName.isEmpty()) { + return super.getName(); + } + String[] pathParts; + if (expName.contains(".")) { + pathParts = expName.split("\\."); + } else { + pathParts = new String[]{expName}; + } + return pathParts[pathParts.length - 1]; + } + + @Override + public GraphTextWriter getActionSourcePrefix(GraphTextWriter writer) { + return writer; + } + + @Override + public GraphTextWriter getActionSourceSuffix(GraphTextWriter writer) { + return writer; + } + + @Override + public int getPrefixLineCount() { + return 0; + } + + @Override + public String removePrefixAndSuffix(String source) { + return source; + } + + @Override + public Tag getSourceTag() { + return this; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/EnableDebugger2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/EnableDebugger2Tag.java index 14afbcedc..fe382b6ab 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/EnableDebugger2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/EnableDebugger2Tag.java @@ -45,6 +45,8 @@ public class EnableDebugger2Tag extends Tag { public static final int ID = 64; + public static final String NAME = "EnableDebugger2"; + /** * Gets data bytes * @@ -71,7 +73,7 @@ public class EnableDebugger2Tag extends Tag { * @param swf */ public EnableDebugger2Tag(SWF swf) { - super(swf, ID, "EnableDebugger2", null); + super(swf, ID, NAME, null); passwordHash = "PasswordHash"; } @@ -83,7 +85,7 @@ public class EnableDebugger2Tag extends Tag { * @throws IOException */ public EnableDebugger2Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "EnableDebugger2", data); + super(sis.getSwf(), ID, NAME, data); readData(sis, data, 0, false, false, false); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/EnableDebuggerTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/EnableDebuggerTag.java index f84f74c3e..d0fed05a3 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/EnableDebuggerTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/EnableDebuggerTag.java @@ -38,6 +38,8 @@ public class EnableDebuggerTag extends Tag { public static final int ID = 58; + public static final String NAME = "EnableDebugger"; + /** * Gets data bytes * @@ -64,7 +66,7 @@ public class EnableDebuggerTag extends Tag { * @param swf */ public EnableDebuggerTag(SWF swf) { - super(swf, ID, "EnableDebugger", null); + super(swf, ID, NAME, null); passwordHash = "PasswordHash"; } @@ -76,7 +78,7 @@ public class EnableDebuggerTag extends Tag { * @throws IOException */ public EnableDebuggerTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "EnableDebugger", data); + super(sis.getSwf(), ID, NAME, data); readData(sis, data, 0, false, false, false); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/EnableTelemetryTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/EnableTelemetryTag.java index 87f173720..77240b236 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/EnableTelemetryTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/EnableTelemetryTag.java @@ -37,6 +37,8 @@ public class EnableTelemetryTag extends Tag { public static final int ID = 93; + public static final String NAME = "EnableTelemetry"; + @SWFType(value = BasicType.UB, count = 16) @Reserved public int reserved; @@ -72,7 +74,7 @@ public class EnableTelemetryTag extends Tag { * @param swf */ public EnableTelemetryTag(SWF swf) { - super(swf, ID, "EnableTelemetry", null); + super(swf, ID, NAME, null); passwordHash = new byte[32]; } @@ -84,7 +86,7 @@ public class EnableTelemetryTag extends Tag { * @throws IOException */ public EnableTelemetryTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "", data); + super(sis.getSwf(), ID, NAME, data); readData(sis, data, 0, false, false, false); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/EndTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/EndTag.java index 64f89d90b..75c7c296c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/EndTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/EndTag.java @@ -40,13 +40,15 @@ public class EndTag extends Tag { public static final int ID = 0; + public static final String NAME = "End"; + /** * Constructor * * @param swf */ public EndTag(SWF swf) { - super(swf, ID, "End", null); + super(swf, ID, NAME, null); } /** @@ -57,7 +59,7 @@ public class EndTag extends Tag { * @throws IOException */ public EndTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "End", data); + super(sis.getSwf(), ID, NAME, data); readData(sis, data, 0, false, false, false); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ExportAssetsTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ExportAssetsTag.java index 0ac28093f..a1b24b629 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ExportAssetsTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ExportAssetsTag.java @@ -49,13 +49,15 @@ public class ExportAssetsTag extends SymbolClassTypeTag { public static final int ID = 56; + public static final String NAME = "ExportAssets"; + /** * Constructor * * @param swf */ public ExportAssetsTag(SWF swf) { - super(swf, ID, "ExportAssets", null); + super(swf, ID, NAME, null); tags = new ArrayList<>(); names = new ArrayList<>(); } @@ -68,7 +70,7 @@ public class ExportAssetsTag extends SymbolClassTypeTag { * @throws IOException */ public ExportAssetsTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "ExportAssets", data); + super(sis.getSwf(), ID, NAME, data); readData(sis, data, 0, false, false, false); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/FileAttributesTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/FileAttributesTag.java index 9150d48f7..ba8e84763 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/FileAttributesTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/FileAttributesTag.java @@ -53,17 +53,19 @@ public class FileAttributesTag extends Tag { public static final int ID = 69; + public static final String NAME = "FileAttributes"; + /** * Constructor * * @param swf */ public FileAttributesTag(SWF swf) { - super(swf, ID, "FileAttributes", null); + super(swf, ID, NAME, null); } public FileAttributesTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "FileAttributes", data); + super(sis.getSwf(), ID, NAME, data); readData(sis, data, 0, false, false, false); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/FrameLabelTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/FrameLabelTag.java index 96ff71508..1172eca45 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/FrameLabelTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/FrameLabelTag.java @@ -32,6 +32,8 @@ public class FrameLabelTag extends Tag { public static final int ID = 43; + public static final String NAME = "FrameLabel"; + public String getLabelName() { return name; } @@ -46,12 +48,12 @@ public class FrameLabelTag extends Tag { * @param swf */ public FrameLabelTag(SWF swf) { - super(swf, ID, "FrameLabel", null); + super(swf, ID, NAME, null); name = "New frame label"; } public FrameLabelTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "FrameLabel", data); + super(sis.getSwf(), ID, NAME, data); readData(sis, data, 0, false, false, false); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ImportAssets2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ImportAssets2Tag.java index e3a7e6dcd..087b32898 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ImportAssets2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ImportAssets2Tag.java @@ -62,13 +62,15 @@ public class ImportAssets2Tag extends Tag implements ImportTag { public static final int ID = 71; + public static final String NAME = "ImportAssets2"; + /** * Constructor * * @param swf */ public ImportAssets2Tag(SWF swf) { - super(swf, ID, "ImportAssets2", null); + super(swf, ID, NAME, null); url = ""; tags = new ArrayList<>(); } @@ -81,7 +83,7 @@ public class ImportAssets2Tag extends Tag implements ImportTag { * @throws IOException */ public ImportAssets2Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "ImportAssets2", data); + super(sis.getSwf(), ID, NAME, data); readData(sis, data, 0, false, false, false); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ImportAssetsTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ImportAssetsTag.java index aa0634f4f..c5f1086ce 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ImportAssetsTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ImportAssetsTag.java @@ -53,13 +53,15 @@ public class ImportAssetsTag extends Tag implements ImportTag { public static final int ID = 57; + public static final String NAME = "ImportAssets"; + /** * Constructor * * @param swf */ public ImportAssetsTag(SWF swf) { - super(swf, ID, "ImportAssets", null); + super(swf, ID, NAME, null); url = ""; tags = new ArrayList<>(); } @@ -72,7 +74,7 @@ public class ImportAssetsTag extends Tag implements ImportTag { * @throws IOException */ public ImportAssetsTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "ImportAssets", data); + super(sis.getSwf(), ID, NAME, data); readData(sis, data, 0, false, false, false); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/JPEGTablesTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/JPEGTablesTag.java index 0a0f4a719..9de207067 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/JPEGTablesTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/JPEGTablesTag.java @@ -29,6 +29,8 @@ public class JPEGTablesTag extends Tag { public static final int ID = 8; + public static final String NAME = "JPEGTables"; + @HideInRawEdit public byte[] jpegData; @@ -38,12 +40,12 @@ public class JPEGTablesTag extends Tag { * @param swf */ public JPEGTablesTag(SWF swf) { - super(swf, ID, "JPEGTables", null); + super(swf, ID, NAME, null); jpegData = new byte[0]; } public JPEGTablesTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "JPEGTables", data); + super(sis.getSwf(), ID, NAME, data); readData(sis, data, 0, false, false, false); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/MetadataTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/MetadataTag.java index 020615c80..f138f7443 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/MetadataTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/MetadataTag.java @@ -32,18 +32,20 @@ public class MetadataTag extends Tag { public static final int ID = 77; + public static final String NAME = "Metadata"; + /** * Constructor * * @param swf */ public MetadataTag(SWF swf) { - super(swf, ID, "Metadata", null); + super(swf, ID, NAME, null); xmlMetadata = ""; } public MetadataTag(SWFInputStream sis, ByteArrayRange data) { - super(sis.getSwf(), ID, "Metadata", data); + super(sis.getSwf(), ID, NAME, data); readData(sis, data, 0, false, false, false); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject2Tag.java index cbf2e83ea..09a0d1f9a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject2Tag.java @@ -1,440 +1,442 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.abc.CopyOutputStream; -import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.decompiler.flash.tags.base.ASMSourceContainer; -import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.CLIPACTIONRECORD; -import com.jpexs.decompiler.flash.types.CLIPACTIONS; -import com.jpexs.decompiler.flash.types.CXFORMWITHALPHA; -import com.jpexs.decompiler.flash.types.ColorTransform; -import com.jpexs.decompiler.flash.types.MATRIX; -import com.jpexs.decompiler.flash.types.RGBA; -import com.jpexs.decompiler.flash.types.annotations.Conditional; -import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.decompiler.flash.types.filters.FILTER; -import com.jpexs.helpers.ByteArrayRange; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -/** - * Extends the functionality of the PlaceObject2Tag - * - * @author JPEXS - */ -public class PlaceObject2Tag extends PlaceObjectTypeTag implements ASMSourceContainer { - - /** - * @since SWF 5 Has clip actions (sprite characters only) - */ - public boolean placeFlagHasClipActions; - - /** - * Has clip depth - */ - public boolean placeFlagHasClipDepth; - - /** - * Has name - */ - public boolean placeFlagHasName; - - /** - * Has ratio - */ - public boolean placeFlagHasRatio; - - /** - * Has color transform - */ - public boolean placeFlagHasColorTransform; - - /** - * Has matrix - */ - public boolean placeFlagHasMatrix; - - /** - * Places a character - */ - public boolean placeFlagHasCharacter; - - /** - * Defines a character to be moved - */ - public boolean placeFlagMove; - - /** - * Depth of character - */ - @SWFType(BasicType.UI16) - public int depth; - - /** - * If PlaceFlagHasCharacter, ID of character to place - */ - @SWFType(BasicType.UI16) - @Conditional("placeFlagHasCharacter") - public int characterId; - - /** - * If PlaceFlagHasMatrix, Transform matrix data - */ - @Conditional("placeFlagHasMatrix") - public MATRIX matrix; - - /** - * If PlaceFlagHasColorTransform, Color transform data - */ - @Conditional("placeFlagHasColorTransform") - public CXFORMWITHALPHA colorTransform; - - /** - * If PlaceFlagHasRatio, ratio - */ - @SWFType(BasicType.UI16) - @Conditional("placeFlagHasRatio") - public int ratio; - - /** - * If PlaceFlagHasName, Name of character - */ - @Conditional("placeFlagHasName") - public String name; - - /** - * If PlaceFlagHasClipDepth, Clip depth - */ - @Conditional("placeFlagHasClipDepth") - public int clipDepth; - - /** - * @since SWF 5 If PlaceFlagHasClipActions, Clip Actions Data - */ - @Conditional("placeFlagHasClipActions") - @HideInRawEdit //TODO: make editable - public CLIPACTIONS clipActions; - - public static final int ID = 26; - - @Override - public int getClipDepth() { - if (placeFlagHasClipDepth) { - return clipDepth; - } - return -1; - } - - @Override - public List getFilters() { - return null; - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - if (Configuration.debugCopy.get()) { - os = new CopyOutputStream(os, new ByteArrayInputStream(getOriginalData())); - } - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUB(1, placeFlagHasClipActions ? 1 : 0); - sos.writeUB(1, placeFlagHasClipDepth ? 1 : 0); - sos.writeUB(1, placeFlagHasName ? 1 : 0); - sos.writeUB(1, placeFlagHasRatio ? 1 : 0); - sos.writeUB(1, placeFlagHasColorTransform ? 1 : 0); - sos.writeUB(1, placeFlagHasMatrix ? 1 : 0); - sos.writeUB(1, placeFlagHasCharacter ? 1 : 0); - sos.writeUB(1, placeFlagMove ? 1 : 0); - sos.writeUI16(depth); - if (placeFlagHasCharacter) { - sos.writeUI16(characterId); - } - if (placeFlagHasMatrix) { - sos.writeMatrix(matrix); - } - if (placeFlagHasColorTransform) { - sos.writeCXFORMWITHALPHA(colorTransform); - } - if (placeFlagHasRatio) { - sos.writeUI16(ratio); - } - if (placeFlagHasName) { - sos.writeString(name); - } - if (placeFlagHasClipDepth) { - sos.writeUI16(clipDepth); - } - if (placeFlagHasClipActions) { - sos.writeCLIPACTIONS(clipActions); - } - sos.close(); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - - /** - * Constructor - * - * @param swf - */ - public PlaceObject2Tag(SWF swf) { - super(swf, ID, "PlaceObject2", null); - } - - public PlaceObject2Tag(SWF swf, boolean placeFlagHasClipActions, boolean placeFlagHasClipDepth, boolean placeFlagHasName, boolean placeFlagHasRatio, boolean placeFlagHasColorTransform, boolean placeFlagHasMatrix, boolean placeFlagHasCharacter, boolean placeFlagMove, int depth, int characterId, MATRIX matrix, CXFORMWITHALPHA colorTransform, int ratio, String name, int clipDepth, CLIPACTIONS clipActions) { - super(swf, ID, "PlaceObject2", null); - this.placeFlagHasClipActions = placeFlagHasClipActions; - this.placeFlagHasClipDepth = placeFlagHasClipDepth; - this.placeFlagHasName = placeFlagHasName; - this.placeFlagHasRatio = placeFlagHasRatio; - this.placeFlagHasColorTransform = placeFlagHasColorTransform; - this.placeFlagHasMatrix = placeFlagHasMatrix; - this.placeFlagHasCharacter = placeFlagHasCharacter; - this.placeFlagMove = placeFlagMove; - this.depth = depth; - this.characterId = characterId; - this.matrix = matrix; - this.colorTransform = colorTransform; - this.ratio = ratio; - this.name = name; - this.clipDepth = clipDepth; - this.clipActions = clipActions; - } - - /** - * Constructor - * - * @param sis - * @param data - * @throws IOException - */ - public PlaceObject2Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "PlaceObject2", data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - placeFlagHasClipActions = sis.readUB(1, "placeFlagHasClipActions") == 1; - placeFlagHasClipDepth = sis.readUB(1, "placeFlagHasClipDepth") == 1; - placeFlagHasName = sis.readUB(1, "placeFlagHasName") == 1; - placeFlagHasRatio = sis.readUB(1, "placeFlagHasRatio") == 1; - placeFlagHasColorTransform = sis.readUB(1, "placeFlagHasColorTransform") == 1; - placeFlagHasMatrix = sis.readUB(1, "placeFlagHasMatrix") == 1; - placeFlagHasCharacter = sis.readUB(1, "placeFlagHasCharacter") == 1; - placeFlagMove = sis.readUB(1, "placeFlagMove") == 1; - - depth = sis.readUI16("depth"); - if (placeFlagHasCharacter) { - characterId = sis.readUI16("characterId"); - } - if (placeFlagHasMatrix) { - matrix = sis.readMatrix("matrix"); - } - if (placeFlagHasColorTransform) { - colorTransform = sis.readCXFORMWITHALPHA("colorTransform"); - } - if (placeFlagHasRatio) { - ratio = sis.readUI16("ratio"); - } - if (placeFlagHasName) { - name = sis.readString("name"); - } - if (placeFlagHasClipDepth) { - clipDepth = sis.readUI16("clipDepth"); - } - if (placeFlagHasClipActions) { - clipActions = sis.readCLIPACTIONS(swf, this, "clipActions"); - } - } - - /** - * Returns all sub-items - * - * @return List of sub-items - */ - @Override - public List getSubItems() { - if (placeFlagHasClipActions) { - return clipActions.clipActionRecords; - } - return new ArrayList<>(); - } - - @Override - public void getNeededCharacters(Set needed) { - if (placeFlagHasCharacter) { - needed.add(characterId); - } - } - - @Override - public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { - return false; - } - - @Override - public boolean removeCharacter(int characterId) { - // the place object tag will be removed - return false; - } - - @Override - public int getCharacterId() { - if (placeFlagHasCharacter) { - return characterId; - } else { - return -1; - } - } - - @Override - public void setCharacterId(int characterId) { - placeFlagHasCharacter = true; - this.characterId = characterId; - } - - @Override - public int getDepth() { - return depth; - } - - @Override - public MATRIX getMatrix() { - if (placeFlagHasMatrix) { - return matrix; - } else { - return null; - } - } - - @Override - public String getInstanceName() { - if (placeFlagHasName) { - return name; - } - return null; - } - - @Override - public ColorTransform getColorTransform() { - if (placeFlagHasColorTransform) { - return colorTransform; - } else { - return null; - } - } - - @Override - public int getBlendMode() { - return 0; - } - - @Override - public boolean cacheAsBitmap() { - return false; - } - - @Override - public String getClassName() { - return null; - } - - @Override - public boolean isVisible() { - return true; - } - - @Override - public RGBA getBackgroundColor() { - return null; - } - - @Override - public boolean flagMove() { - return placeFlagMove; - } - - @Override - public int getRatio() { - if (!placeFlagHasRatio) { - return -1; - } - return ratio; - } - - @Override - public void setInstanceName(String name) { - placeFlagHasName = true; - this.name = name; - } - - @Override - public void setClassName(String className) { - //not supported - } - - @Override - public String getName() { - if (placeFlagHasName) { - return super.getName() + " (" + name + ")"; - } else { - return super.getName(); - } - } - - @Override - public CLIPACTIONS getClipActions() { - if (placeFlagHasClipActions) { - return clipActions; - } else { - return null; - } - } - - @Override - public void writeTagWithMatrix(SWFOutputStream sos, MATRIX m) throws IOException { - MATRIX old = matrix; - matrix = m; - boolean mod = isModified(); - setModified(true); - super.writeTag(sos); - setModified(mod); - matrix = old; - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.abc.CopyOutputStream; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.tags.base.ASMSourceContainer; +import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.CLIPACTIONRECORD; +import com.jpexs.decompiler.flash.types.CLIPACTIONS; +import com.jpexs.decompiler.flash.types.CXFORMWITHALPHA; +import com.jpexs.decompiler.flash.types.ColorTransform; +import com.jpexs.decompiler.flash.types.MATRIX; +import com.jpexs.decompiler.flash.types.RGBA; +import com.jpexs.decompiler.flash.types.annotations.Conditional; +import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.decompiler.flash.types.filters.FILTER; +import com.jpexs.helpers.ByteArrayRange; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** + * Extends the functionality of the PlaceObject2Tag + * + * @author JPEXS + */ +public class PlaceObject2Tag extends PlaceObjectTypeTag implements ASMSourceContainer { + + /** + * @since SWF 5 Has clip actions (sprite characters only) + */ + public boolean placeFlagHasClipActions; + + /** + * Has clip depth + */ + public boolean placeFlagHasClipDepth; + + /** + * Has name + */ + public boolean placeFlagHasName; + + /** + * Has ratio + */ + public boolean placeFlagHasRatio; + + /** + * Has color transform + */ + public boolean placeFlagHasColorTransform; + + /** + * Has matrix + */ + public boolean placeFlagHasMatrix; + + /** + * Places a character + */ + public boolean placeFlagHasCharacter; + + /** + * Defines a character to be moved + */ + public boolean placeFlagMove; + + /** + * Depth of character + */ + @SWFType(BasicType.UI16) + public int depth; + + /** + * If PlaceFlagHasCharacter, ID of character to place + */ + @SWFType(BasicType.UI16) + @Conditional("placeFlagHasCharacter") + public int characterId; + + /** + * If PlaceFlagHasMatrix, Transform matrix data + */ + @Conditional("placeFlagHasMatrix") + public MATRIX matrix; + + /** + * If PlaceFlagHasColorTransform, Color transform data + */ + @Conditional("placeFlagHasColorTransform") + public CXFORMWITHALPHA colorTransform; + + /** + * If PlaceFlagHasRatio, ratio + */ + @SWFType(BasicType.UI16) + @Conditional("placeFlagHasRatio") + public int ratio; + + /** + * If PlaceFlagHasName, Name of character + */ + @Conditional("placeFlagHasName") + public String name; + + /** + * If PlaceFlagHasClipDepth, Clip depth + */ + @Conditional("placeFlagHasClipDepth") + public int clipDepth; + + /** + * @since SWF 5 If PlaceFlagHasClipActions, Clip Actions Data + */ + @Conditional("placeFlagHasClipActions") + @HideInRawEdit //TODO: make editable + public CLIPACTIONS clipActions; + + public static final int ID = 26; + + public static final String NAME = "PlaceObject2"; + + @Override + public int getClipDepth() { + if (placeFlagHasClipDepth) { + return clipDepth; + } + return -1; + } + + @Override + public List getFilters() { + return null; + } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + if (Configuration.debugCopy.get()) { + os = new CopyOutputStream(os, new ByteArrayInputStream(getOriginalData())); + } + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUB(1, placeFlagHasClipActions ? 1 : 0); + sos.writeUB(1, placeFlagHasClipDepth ? 1 : 0); + sos.writeUB(1, placeFlagHasName ? 1 : 0); + sos.writeUB(1, placeFlagHasRatio ? 1 : 0); + sos.writeUB(1, placeFlagHasColorTransform ? 1 : 0); + sos.writeUB(1, placeFlagHasMatrix ? 1 : 0); + sos.writeUB(1, placeFlagHasCharacter ? 1 : 0); + sos.writeUB(1, placeFlagMove ? 1 : 0); + sos.writeUI16(depth); + if (placeFlagHasCharacter) { + sos.writeUI16(characterId); + } + if (placeFlagHasMatrix) { + sos.writeMatrix(matrix); + } + if (placeFlagHasColorTransform) { + sos.writeCXFORMWITHALPHA(colorTransform); + } + if (placeFlagHasRatio) { + sos.writeUI16(ratio); + } + if (placeFlagHasName) { + sos.writeString(name); + } + if (placeFlagHasClipDepth) { + sos.writeUI16(clipDepth); + } + if (placeFlagHasClipActions) { + sos.writeCLIPACTIONS(clipActions); + } + sos.close(); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + /** + * Constructor + * + * @param swf + */ + public PlaceObject2Tag(SWF swf) { + super(swf, ID, NAME, null); + } + + public PlaceObject2Tag(SWF swf, boolean placeFlagHasClipActions, boolean placeFlagHasClipDepth, boolean placeFlagHasName, boolean placeFlagHasRatio, boolean placeFlagHasColorTransform, boolean placeFlagHasMatrix, boolean placeFlagHasCharacter, boolean placeFlagMove, int depth, int characterId, MATRIX matrix, CXFORMWITHALPHA colorTransform, int ratio, String name, int clipDepth, CLIPACTIONS clipActions) { + super(swf, ID, NAME, null); + this.placeFlagHasClipActions = placeFlagHasClipActions; + this.placeFlagHasClipDepth = placeFlagHasClipDepth; + this.placeFlagHasName = placeFlagHasName; + this.placeFlagHasRatio = placeFlagHasRatio; + this.placeFlagHasColorTransform = placeFlagHasColorTransform; + this.placeFlagHasMatrix = placeFlagHasMatrix; + this.placeFlagHasCharacter = placeFlagHasCharacter; + this.placeFlagMove = placeFlagMove; + this.depth = depth; + this.characterId = characterId; + this.matrix = matrix; + this.colorTransform = colorTransform; + this.ratio = ratio; + this.name = name; + this.clipDepth = clipDepth; + this.clipActions = clipActions; + } + + /** + * Constructor + * + * @param sis + * @param data + * @throws IOException + */ + public PlaceObject2Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + placeFlagHasClipActions = sis.readUB(1, "placeFlagHasClipActions") == 1; + placeFlagHasClipDepth = sis.readUB(1, "placeFlagHasClipDepth") == 1; + placeFlagHasName = sis.readUB(1, "placeFlagHasName") == 1; + placeFlagHasRatio = sis.readUB(1, "placeFlagHasRatio") == 1; + placeFlagHasColorTransform = sis.readUB(1, "placeFlagHasColorTransform") == 1; + placeFlagHasMatrix = sis.readUB(1, "placeFlagHasMatrix") == 1; + placeFlagHasCharacter = sis.readUB(1, "placeFlagHasCharacter") == 1; + placeFlagMove = sis.readUB(1, "placeFlagMove") == 1; + + depth = sis.readUI16("depth"); + if (placeFlagHasCharacter) { + characterId = sis.readUI16("characterId"); + } + if (placeFlagHasMatrix) { + matrix = sis.readMatrix("matrix"); + } + if (placeFlagHasColorTransform) { + colorTransform = sis.readCXFORMWITHALPHA("colorTransform"); + } + if (placeFlagHasRatio) { + ratio = sis.readUI16("ratio"); + } + if (placeFlagHasName) { + name = sis.readString("name"); + } + if (placeFlagHasClipDepth) { + clipDepth = sis.readUI16("clipDepth"); + } + if (placeFlagHasClipActions) { + clipActions = sis.readCLIPACTIONS(swf, this, "clipActions"); + } + } + + /** + * Returns all sub-items + * + * @return List of sub-items + */ + @Override + public List getSubItems() { + if (placeFlagHasClipActions) { + return clipActions.clipActionRecords; + } + return new ArrayList<>(); + } + + @Override + public void getNeededCharacters(Set needed) { + if (placeFlagHasCharacter) { + needed.add(characterId); + } + } + + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + return false; + } + + @Override + public boolean removeCharacter(int characterId) { + // the place object tag will be removed + return false; + } + + @Override + public int getCharacterId() { + if (placeFlagHasCharacter) { + return characterId; + } else { + return -1; + } + } + + @Override + public void setCharacterId(int characterId) { + placeFlagHasCharacter = true; + this.characterId = characterId; + } + + @Override + public int getDepth() { + return depth; + } + + @Override + public MATRIX getMatrix() { + if (placeFlagHasMatrix) { + return matrix; + } else { + return null; + } + } + + @Override + public String getInstanceName() { + if (placeFlagHasName) { + return name; + } + return null; + } + + @Override + public ColorTransform getColorTransform() { + if (placeFlagHasColorTransform) { + return colorTransform; + } else { + return null; + } + } + + @Override + public int getBlendMode() { + return 0; + } + + @Override + public boolean cacheAsBitmap() { + return false; + } + + @Override + public String getClassName() { + return null; + } + + @Override + public boolean isVisible() { + return true; + } + + @Override + public RGBA getBackgroundColor() { + return null; + } + + @Override + public boolean flagMove() { + return placeFlagMove; + } + + @Override + public int getRatio() { + if (!placeFlagHasRatio) { + return -1; + } + return ratio; + } + + @Override + public void setInstanceName(String name) { + placeFlagHasName = true; + this.name = name; + } + + @Override + public void setClassName(String className) { + //not supported + } + + @Override + public String getName() { + if (placeFlagHasName) { + return super.getName() + " (" + name + ")"; + } else { + return super.getName(); + } + } + + @Override + public CLIPACTIONS getClipActions() { + if (placeFlagHasClipActions) { + return clipActions; + } else { + return null; + } + } + + @Override + public void writeTagWithMatrix(SWFOutputStream sos, MATRIX m) throws IOException { + MATRIX old = matrix; + matrix = m; + boolean mod = isModified(); + setModified(true); + super.writeTag(sos); + setModified(mod); + matrix = old; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject3Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject3Tag.java index 8d33e9e9a..eaf13f95b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject3Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject3Tag.java @@ -1,585 +1,587 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.EndOfStreamException; -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.abc.CopyOutputStream; -import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.decompiler.flash.tags.base.ASMSourceContainer; -import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.CLIPACTIONRECORD; -import com.jpexs.decompiler.flash.types.CLIPACTIONS; -import com.jpexs.decompiler.flash.types.CXFORMWITHALPHA; -import com.jpexs.decompiler.flash.types.ColorTransform; -import com.jpexs.decompiler.flash.types.MATRIX; -import com.jpexs.decompiler.flash.types.RGBA; -import com.jpexs.decompiler.flash.types.annotations.Conditional; -import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit; -import com.jpexs.decompiler.flash.types.annotations.Internal; -import com.jpexs.decompiler.flash.types.annotations.Reserved; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.decompiler.flash.types.filters.FILTER; -import com.jpexs.helpers.ByteArrayRange; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -/** - * Extends the functionality of the PlaceObject2Tag - * - * @author JPEXS - */ -public class PlaceObject3Tag extends PlaceObjectTypeTag implements ASMSourceContainer { - - /** - * @since SWF 5 has clip actions (sprite characters only) - */ - public boolean placeFlagHasClipActions; - - /** - * Has clip depth - */ - public boolean placeFlagHasClipDepth; - - /** - * Has name - */ - public boolean placeFlagHasName; - - /** - * Has ratio - */ - public boolean placeFlagHasRatio; - - /** - * Has color transform - */ - public boolean placeFlagHasColorTransform; - - /** - * Has matrix - */ - public boolean placeFlagHasMatrix; - - /** - * Places a character - */ - public boolean placeFlagHasCharacter; - - /** - * Defines a character to be moved - */ - public boolean placeFlagMove; - - /** - * Has class name or character ID of bitmap to place. If - * PlaceFlagHasClassName, use ClassName. If PlaceFlagHasCharacter, use - * CharacterId - */ - public boolean placeFlagHasImage; - - /** - * Has class name of object to place - */ - public boolean placeFlagHasClassName; - - /** - * Enables bitmap caching - */ - public boolean placeFlagHasCacheAsBitmap; - - /** - * Has blend mode - */ - public boolean placeFlagHasBlendMode; - - /** - * Has filter list - */ - public boolean placeFlagHasFilterList; - - /** - * Has opaque background. SWF 11 and higher. - */ - public boolean placeFlagOpaqueBackground; - - /** - * Has visibility flag. SWF 11 and higher. - */ - public boolean placeFlagHasVisible; - - /** - * Depth of character - */ - @SWFType(BasicType.UI16) - public int depth; - - /** - * If PlaceFlagHasClassName or (PlaceFlagHasImage and - * PlaceFlagHasCharacter), Name of the class to place - */ - @Conditional("placeFlagHasClassName") - public String className; - - /** - * If PlaceFlagHasCharacter, ID of character to place - */ - @SWFType(BasicType.UI16) - @Conditional("placeFlagHasCharacter") - public int characterId; - - /** - * If PlaceFlagHasMatrix, Transform matrix data - */ - @Conditional("placeFlagHasMatrix") - public MATRIX matrix; - - /** - * If PlaceFlagHasColorTransform, Color transform data - */ - @Conditional("placeFlagHasColorTransform") - public CXFORMWITHALPHA colorTransform; - - /** - * If PlaceFlagHasRatio, Ratio - */ - @SWFType(BasicType.UI16) - @Conditional("placeFlagHasRatio") - public int ratio; - - /** - * If PlaceFlagHasName, Name of character - */ - @Conditional("placeFlagHasName") - public String name; - - /** - * If PlaceFlagHasClipDepth, Clip depth - */ - @SWFType(BasicType.UI16) - @Conditional("placeFlagHasClipDepth") - public int clipDepth; - - /** - * If PlaceFlagHasFilterList, List of filters on this object - */ - @Conditional("placeFlagHasFilterList") - public List surfaceFilterList; - - /** - * If PlaceFlagHasBlendMode, Blend mode - */ - @SWFType(BasicType.UI8) - @Conditional("placeFlagHasBlendMode") - public int blendMode; - - /** - * If PlaceFlagHasCacheAsBitmap, 0 = Bitmap cache disabled, 1-255 = Bitmap - * cache enabled - */ - @SWFType(BasicType.UI8) - @Conditional("placeFlagHasCacheAsBitmap") - public int bitmapCache; - - /** - * @since SWF 5 If PlaceFlagHasClipActions, Clip Actions Data - */ - @Conditional(value = "placeFlagHasClipActions", minSwfVersion = 5) - @HideInRawEdit //TODO: make editable - public CLIPACTIONS clipActions; - - /** - * If PlaceFlagHasVisible, 0 = Place invisible, 1 = Place visible - */ - @Conditional("placeFlagHasVisible") - public int visible; - - /** - * If PlaceFlagHasVisible, Background color - */ - @Conditional("placeFlagOpaqueBackground") - public RGBA backgroundColor; - - // FIXME bug found in ecoDrive.swf, - @Internal - private boolean bitmapCacheBug; - - @Reserved - public boolean reserved; - - public static final int ID = 70; - - @Override - public List getFilters() { - if (placeFlagHasFilterList) { - return surfaceFilterList; - } else { - return null; - } - } - - @Override - public int getClipDepth() { - if (placeFlagHasClipDepth) { - return clipDepth; - } - return -1; - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - if (Configuration.debugCopy.get()) { - os = new CopyOutputStream(os, new ByteArrayInputStream(getOriginalData())); - } - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUB(1, placeFlagHasClipActions ? 1 : 0); - sos.writeUB(1, placeFlagHasClipDepth ? 1 : 0); - sos.writeUB(1, placeFlagHasName ? 1 : 0); - sos.writeUB(1, placeFlagHasRatio ? 1 : 0); - sos.writeUB(1, placeFlagHasColorTransform ? 1 : 0); - sos.writeUB(1, placeFlagHasMatrix ? 1 : 0); - sos.writeUB(1, placeFlagHasCharacter ? 1 : 0); - sos.writeUB(1, placeFlagMove ? 1 : 0); - sos.writeUB(1, reserved ? 1 : 0); - sos.writeUB(1, placeFlagOpaqueBackground ? 1 : 0); //SWF11 - sos.writeUB(1, placeFlagHasVisible ? 1 : 0); //SWF11 - sos.writeUB(1, placeFlagHasImage ? 1 : 0); - sos.writeUB(1, placeFlagHasClassName ? 1 : 0); - sos.writeUB(1, placeFlagHasCacheAsBitmap ? 1 : 0); - sos.writeUB(1, placeFlagHasBlendMode ? 1 : 0); - sos.writeUB(1, placeFlagHasFilterList ? 1 : 0); - sos.writeUI16(depth); - - if (placeFlagHasClassName) { - sos.writeString(className); - } - if (placeFlagHasCharacter) { - sos.writeUI16(characterId); - } - if (placeFlagHasMatrix) { - sos.writeMatrix(matrix); - } - if (placeFlagHasColorTransform) { - sos.writeCXFORMWITHALPHA(colorTransform); - } - if (placeFlagHasRatio) { - sos.writeUI16(ratio); - } - if (placeFlagHasName) { - sos.writeString(name); - } - if (placeFlagHasClipDepth) { - sos.writeUI16(clipDepth); - } - if (placeFlagHasFilterList) { - sos.writeFILTERLIST(surfaceFilterList); - } - if (placeFlagHasBlendMode) { - sos.writeUI8(blendMode); - } - if (placeFlagHasCacheAsBitmap) { - if (!bitmapCacheBug) { - sos.writeUI8(bitmapCache); - } - } - if (placeFlagHasVisible) { - sos.writeUI8(visible); - } - if (placeFlagOpaqueBackground) { - sos.writeRGBA(backgroundColor); - } - if (placeFlagHasClipActions) { - sos.writeCLIPACTIONS(clipActions); - } - sos.close(); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - - /** - * Constructor - * - * @param swf - */ - public PlaceObject3Tag(SWF swf) { - super(swf, ID, "PlaceObject3", null); - } - - /** - * Constructor - * - * @param sis - * @param data - * @throws IOException - */ - public PlaceObject3Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "PlaceObject3", data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - placeFlagHasClipActions = sis.readUB(1, "placeFlagHasClipActions") == 1; - placeFlagHasClipDepth = sis.readUB(1, "placeFlagHasClipDepth") == 1; - placeFlagHasName = sis.readUB(1, "placeFlagHasName") == 1; - placeFlagHasRatio = sis.readUB(1, "placeFlagHasRatio") == 1; - placeFlagHasColorTransform = sis.readUB(1, "placeFlagHasColorTransform") == 1; - placeFlagHasMatrix = sis.readUB(1, "placeFlagHasMatrix") == 1; - placeFlagHasCharacter = sis.readUB(1, "placeFlagHasCharacter") == 1; - placeFlagMove = sis.readUB(1, "placeFlagMove") == 1; - reserved = sis.readUB(1, "reserved") == 1; - placeFlagOpaqueBackground = sis.readUB(1, "placeFlagOpaqueBackground") == 1; //SWF11 - placeFlagHasVisible = sis.readUB(1, "placeFlagHasVisible") == 1; //SWF11 - placeFlagHasImage = sis.readUB(1, "placeFlagHasImage") == 1; - placeFlagHasClassName = sis.readUB(1, "placeFlagHasClassName") == 1; - placeFlagHasCacheAsBitmap = sis.readUB(1, "placeFlagHasCacheAsBitmap") == 1; - placeFlagHasBlendMode = sis.readUB(1, "placeFlagHasBlendMode") == 1; - placeFlagHasFilterList = sis.readUB(1, "placeFlagHasFilterList") == 1; - - depth = sis.readUI16("depth"); - if (placeFlagHasClassName) { - className = sis.readString("className"); - } - if (placeFlagHasCharacter) { - characterId = sis.readUI16("characterId"); - } - if (placeFlagHasMatrix) { - matrix = sis.readMatrix("matrix"); - } - if (placeFlagHasColorTransform) { - colorTransform = sis.readCXFORMWITHALPHA("colorTransform"); - } - if (placeFlagHasRatio) { - ratio = sis.readUI16("ratio"); - } - if (placeFlagHasName) { - name = sis.readString("name"); - } - if (placeFlagHasClipDepth) { - clipDepth = sis.readUI16("clipDepth"); - } - if (placeFlagHasFilterList) { - surfaceFilterList = sis.readFILTERLIST("surfaceFilterList"); - } - if (placeFlagHasBlendMode) { - blendMode = sis.readUI8("blendMode"); - } - bitmapCacheBug = false; - if (placeFlagHasCacheAsBitmap) { - try { - bitmapCache = sis.readUI8("bitmapCache"); - } catch (EndOfStreamException eex) { - bitmapCacheBug = true; - bitmapCache = 1; - } - } - - if (placeFlagHasVisible) { - visible = sis.readUI8("visible"); - } - if (placeFlagOpaqueBackground) { - backgroundColor = sis.readRGBA("backgroundColor"); - } - - if (placeFlagHasClipActions) { - clipActions = sis.readCLIPACTIONS(swf, this, "clipActions"); - } - } - - /** - * Returns all sub-items - * - * @return List of sub-items - */ - @Override - public List getSubItems() { - if (placeFlagHasClipActions) { - return clipActions.clipActionRecords; - } - return new ArrayList<>(); - } - - @Override - public void getNeededCharacters(Set needed) { - if (placeFlagHasCharacter) { - needed.add(characterId); - } - } - - @Override - public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { - return false; - } - - @Override - public boolean removeCharacter(int characterId) { - // the place object tag will be removed - return false; - } - - @Override - public int getCharacterId() { - if (placeFlagHasCharacter) { - return characterId; - } else { - return -1; - } - } - - @Override - public void setCharacterId(int characterId) { - placeFlagHasCharacter = true; - this.characterId = characterId; - } - - @Override - public int getDepth() { - return depth; - } - - @Override - public MATRIX getMatrix() { - if (placeFlagHasMatrix) { - return matrix; - } else { - return null; - } - } - - @Override - public String getInstanceName() { - if (placeFlagHasName) { - return name; - } - return null; - } - - @Override - public ColorTransform getColorTransform() { - if (placeFlagHasColorTransform) { - return colorTransform; - } else { - return null; - } - } - - @Override - public int getBlendMode() { - return blendMode; - } - - @Override - public String getClassName() { - if (placeFlagHasClassName) { - return className; - } - return null; - } - - @Override - public boolean cacheAsBitmap() { - return placeFlagHasCacheAsBitmap; - } - - @Override - public boolean isVisible() { - if (placeFlagHasVisible) { - return visible == 1; - } - return true; - } - - @Override - public RGBA getBackgroundColor() { - if (placeFlagOpaqueBackground) { - return backgroundColor; - } - return null; - } - - @Override - public boolean flagMove() { - return placeFlagMove; - } - - @Override - public int getRatio() { - if (!placeFlagHasRatio) { - return -1; - } - return ratio; - } - - @Override - public void setInstanceName(String name) { - placeFlagHasName = true; - this.name = name; - } - - @Override - public void setClassName(String className) { - placeFlagHasClassName = true; - this.className = className; - } - - @Override - public String getName() { - if (placeFlagHasName) { - return super.getName() + " (" + name + ")"; - } else { - return super.getName(); - } - } - - @Override - public CLIPACTIONS getClipActions() { - if (placeFlagHasClipActions) { - return clipActions; - } else { - return null; - } - } - - @Override - public void writeTagWithMatrix(SWFOutputStream sos, MATRIX m) throws IOException { - MATRIX old = matrix; - matrix = m; - boolean mod = isModified(); - setModified(true); - super.writeTag(sos); - setModified(mod); - matrix = old; - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.EndOfStreamException; +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.abc.CopyOutputStream; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.tags.base.ASMSourceContainer; +import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.CLIPACTIONRECORD; +import com.jpexs.decompiler.flash.types.CLIPACTIONS; +import com.jpexs.decompiler.flash.types.CXFORMWITHALPHA; +import com.jpexs.decompiler.flash.types.ColorTransform; +import com.jpexs.decompiler.flash.types.MATRIX; +import com.jpexs.decompiler.flash.types.RGBA; +import com.jpexs.decompiler.flash.types.annotations.Conditional; +import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit; +import com.jpexs.decompiler.flash.types.annotations.Internal; +import com.jpexs.decompiler.flash.types.annotations.Reserved; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.decompiler.flash.types.filters.FILTER; +import com.jpexs.helpers.ByteArrayRange; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** + * Extends the functionality of the PlaceObject2Tag + * + * @author JPEXS + */ +public class PlaceObject3Tag extends PlaceObjectTypeTag implements ASMSourceContainer { + + /** + * @since SWF 5 has clip actions (sprite characters only) + */ + public boolean placeFlagHasClipActions; + + /** + * Has clip depth + */ + public boolean placeFlagHasClipDepth; + + /** + * Has name + */ + public boolean placeFlagHasName; + + /** + * Has ratio + */ + public boolean placeFlagHasRatio; + + /** + * Has color transform + */ + public boolean placeFlagHasColorTransform; + + /** + * Has matrix + */ + public boolean placeFlagHasMatrix; + + /** + * Places a character + */ + public boolean placeFlagHasCharacter; + + /** + * Defines a character to be moved + */ + public boolean placeFlagMove; + + /** + * Has class name or character ID of bitmap to place. If + * PlaceFlagHasClassName, use ClassName. If PlaceFlagHasCharacter, use + * CharacterId + */ + public boolean placeFlagHasImage; + + /** + * Has class name of object to place + */ + public boolean placeFlagHasClassName; + + /** + * Enables bitmap caching + */ + public boolean placeFlagHasCacheAsBitmap; + + /** + * Has blend mode + */ + public boolean placeFlagHasBlendMode; + + /** + * Has filter list + */ + public boolean placeFlagHasFilterList; + + /** + * Has opaque background. SWF 11 and higher. + */ + public boolean placeFlagOpaqueBackground; + + /** + * Has visibility flag. SWF 11 and higher. + */ + public boolean placeFlagHasVisible; + + /** + * Depth of character + */ + @SWFType(BasicType.UI16) + public int depth; + + /** + * If PlaceFlagHasClassName or (PlaceFlagHasImage and + * PlaceFlagHasCharacter), Name of the class to place + */ + @Conditional("placeFlagHasClassName") + public String className; + + /** + * If PlaceFlagHasCharacter, ID of character to place + */ + @SWFType(BasicType.UI16) + @Conditional("placeFlagHasCharacter") + public int characterId; + + /** + * If PlaceFlagHasMatrix, Transform matrix data + */ + @Conditional("placeFlagHasMatrix") + public MATRIX matrix; + + /** + * If PlaceFlagHasColorTransform, Color transform data + */ + @Conditional("placeFlagHasColorTransform") + public CXFORMWITHALPHA colorTransform; + + /** + * If PlaceFlagHasRatio, Ratio + */ + @SWFType(BasicType.UI16) + @Conditional("placeFlagHasRatio") + public int ratio; + + /** + * If PlaceFlagHasName, Name of character + */ + @Conditional("placeFlagHasName") + public String name; + + /** + * If PlaceFlagHasClipDepth, Clip depth + */ + @SWFType(BasicType.UI16) + @Conditional("placeFlagHasClipDepth") + public int clipDepth; + + /** + * If PlaceFlagHasFilterList, List of filters on this object + */ + @Conditional("placeFlagHasFilterList") + public List surfaceFilterList; + + /** + * If PlaceFlagHasBlendMode, Blend mode + */ + @SWFType(BasicType.UI8) + @Conditional("placeFlagHasBlendMode") + public int blendMode; + + /** + * If PlaceFlagHasCacheAsBitmap, 0 = Bitmap cache disabled, 1-255 = Bitmap + * cache enabled + */ + @SWFType(BasicType.UI8) + @Conditional("placeFlagHasCacheAsBitmap") + public int bitmapCache; + + /** + * @since SWF 5 If PlaceFlagHasClipActions, Clip Actions Data + */ + @Conditional(value = "placeFlagHasClipActions", minSwfVersion = 5) + @HideInRawEdit //TODO: make editable + public CLIPACTIONS clipActions; + + /** + * If PlaceFlagHasVisible, 0 = Place invisible, 1 = Place visible + */ + @Conditional("placeFlagHasVisible") + public int visible; + + /** + * If PlaceFlagHasVisible, Background color + */ + @Conditional("placeFlagOpaqueBackground") + public RGBA backgroundColor; + + // FIXME bug found in ecoDrive.swf, + @Internal + private boolean bitmapCacheBug; + + @Reserved + public boolean reserved; + + public static final int ID = 70; + + public static final String NAME = "PlaceObject3"; + + @Override + public List getFilters() { + if (placeFlagHasFilterList) { + return surfaceFilterList; + } else { + return null; + } + } + + @Override + public int getClipDepth() { + if (placeFlagHasClipDepth) { + return clipDepth; + } + return -1; + } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + if (Configuration.debugCopy.get()) { + os = new CopyOutputStream(os, new ByteArrayInputStream(getOriginalData())); + } + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUB(1, placeFlagHasClipActions ? 1 : 0); + sos.writeUB(1, placeFlagHasClipDepth ? 1 : 0); + sos.writeUB(1, placeFlagHasName ? 1 : 0); + sos.writeUB(1, placeFlagHasRatio ? 1 : 0); + sos.writeUB(1, placeFlagHasColorTransform ? 1 : 0); + sos.writeUB(1, placeFlagHasMatrix ? 1 : 0); + sos.writeUB(1, placeFlagHasCharacter ? 1 : 0); + sos.writeUB(1, placeFlagMove ? 1 : 0); + sos.writeUB(1, reserved ? 1 : 0); + sos.writeUB(1, placeFlagOpaqueBackground ? 1 : 0); //SWF11 + sos.writeUB(1, placeFlagHasVisible ? 1 : 0); //SWF11 + sos.writeUB(1, placeFlagHasImage ? 1 : 0); + sos.writeUB(1, placeFlagHasClassName ? 1 : 0); + sos.writeUB(1, placeFlagHasCacheAsBitmap ? 1 : 0); + sos.writeUB(1, placeFlagHasBlendMode ? 1 : 0); + sos.writeUB(1, placeFlagHasFilterList ? 1 : 0); + sos.writeUI16(depth); + + if (placeFlagHasClassName) { + sos.writeString(className); + } + if (placeFlagHasCharacter) { + sos.writeUI16(characterId); + } + if (placeFlagHasMatrix) { + sos.writeMatrix(matrix); + } + if (placeFlagHasColorTransform) { + sos.writeCXFORMWITHALPHA(colorTransform); + } + if (placeFlagHasRatio) { + sos.writeUI16(ratio); + } + if (placeFlagHasName) { + sos.writeString(name); + } + if (placeFlagHasClipDepth) { + sos.writeUI16(clipDepth); + } + if (placeFlagHasFilterList) { + sos.writeFILTERLIST(surfaceFilterList); + } + if (placeFlagHasBlendMode) { + sos.writeUI8(blendMode); + } + if (placeFlagHasCacheAsBitmap) { + if (!bitmapCacheBug) { + sos.writeUI8(bitmapCache); + } + } + if (placeFlagHasVisible) { + sos.writeUI8(visible); + } + if (placeFlagOpaqueBackground) { + sos.writeRGBA(backgroundColor); + } + if (placeFlagHasClipActions) { + sos.writeCLIPACTIONS(clipActions); + } + sos.close(); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + /** + * Constructor + * + * @param swf + */ + public PlaceObject3Tag(SWF swf) { + super(swf, ID, NAME, null); + } + + /** + * Constructor + * + * @param sis + * @param data + * @throws IOException + */ + public PlaceObject3Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + placeFlagHasClipActions = sis.readUB(1, "placeFlagHasClipActions") == 1; + placeFlagHasClipDepth = sis.readUB(1, "placeFlagHasClipDepth") == 1; + placeFlagHasName = sis.readUB(1, "placeFlagHasName") == 1; + placeFlagHasRatio = sis.readUB(1, "placeFlagHasRatio") == 1; + placeFlagHasColorTransform = sis.readUB(1, "placeFlagHasColorTransform") == 1; + placeFlagHasMatrix = sis.readUB(1, "placeFlagHasMatrix") == 1; + placeFlagHasCharacter = sis.readUB(1, "placeFlagHasCharacter") == 1; + placeFlagMove = sis.readUB(1, "placeFlagMove") == 1; + reserved = sis.readUB(1, "reserved") == 1; + placeFlagOpaqueBackground = sis.readUB(1, "placeFlagOpaqueBackground") == 1; //SWF11 + placeFlagHasVisible = sis.readUB(1, "placeFlagHasVisible") == 1; //SWF11 + placeFlagHasImage = sis.readUB(1, "placeFlagHasImage") == 1; + placeFlagHasClassName = sis.readUB(1, "placeFlagHasClassName") == 1; + placeFlagHasCacheAsBitmap = sis.readUB(1, "placeFlagHasCacheAsBitmap") == 1; + placeFlagHasBlendMode = sis.readUB(1, "placeFlagHasBlendMode") == 1; + placeFlagHasFilterList = sis.readUB(1, "placeFlagHasFilterList") == 1; + + depth = sis.readUI16("depth"); + if (placeFlagHasClassName) { + className = sis.readString("className"); + } + if (placeFlagHasCharacter) { + characterId = sis.readUI16("characterId"); + } + if (placeFlagHasMatrix) { + matrix = sis.readMatrix("matrix"); + } + if (placeFlagHasColorTransform) { + colorTransform = sis.readCXFORMWITHALPHA("colorTransform"); + } + if (placeFlagHasRatio) { + ratio = sis.readUI16("ratio"); + } + if (placeFlagHasName) { + name = sis.readString("name"); + } + if (placeFlagHasClipDepth) { + clipDepth = sis.readUI16("clipDepth"); + } + if (placeFlagHasFilterList) { + surfaceFilterList = sis.readFILTERLIST("surfaceFilterList"); + } + if (placeFlagHasBlendMode) { + blendMode = sis.readUI8("blendMode"); + } + bitmapCacheBug = false; + if (placeFlagHasCacheAsBitmap) { + try { + bitmapCache = sis.readUI8("bitmapCache"); + } catch (EndOfStreamException eex) { + bitmapCacheBug = true; + bitmapCache = 1; + } + } + + if (placeFlagHasVisible) { + visible = sis.readUI8("visible"); + } + if (placeFlagOpaqueBackground) { + backgroundColor = sis.readRGBA("backgroundColor"); + } + + if (placeFlagHasClipActions) { + clipActions = sis.readCLIPACTIONS(swf, this, "clipActions"); + } + } + + /** + * Returns all sub-items + * + * @return List of sub-items + */ + @Override + public List getSubItems() { + if (placeFlagHasClipActions) { + return clipActions.clipActionRecords; + } + return new ArrayList<>(); + } + + @Override + public void getNeededCharacters(Set needed) { + if (placeFlagHasCharacter) { + needed.add(characterId); + } + } + + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + return false; + } + + @Override + public boolean removeCharacter(int characterId) { + // the place object tag will be removed + return false; + } + + @Override + public int getCharacterId() { + if (placeFlagHasCharacter) { + return characterId; + } else { + return -1; + } + } + + @Override + public void setCharacterId(int characterId) { + placeFlagHasCharacter = true; + this.characterId = characterId; + } + + @Override + public int getDepth() { + return depth; + } + + @Override + public MATRIX getMatrix() { + if (placeFlagHasMatrix) { + return matrix; + } else { + return null; + } + } + + @Override + public String getInstanceName() { + if (placeFlagHasName) { + return name; + } + return null; + } + + @Override + public ColorTransform getColorTransform() { + if (placeFlagHasColorTransform) { + return colorTransform; + } else { + return null; + } + } + + @Override + public int getBlendMode() { + return blendMode; + } + + @Override + public String getClassName() { + if (placeFlagHasClassName) { + return className; + } + return null; + } + + @Override + public boolean cacheAsBitmap() { + return placeFlagHasCacheAsBitmap; + } + + @Override + public boolean isVisible() { + if (placeFlagHasVisible) { + return visible == 1; + } + return true; + } + + @Override + public RGBA getBackgroundColor() { + if (placeFlagOpaqueBackground) { + return backgroundColor; + } + return null; + } + + @Override + public boolean flagMove() { + return placeFlagMove; + } + + @Override + public int getRatio() { + if (!placeFlagHasRatio) { + return -1; + } + return ratio; + } + + @Override + public void setInstanceName(String name) { + placeFlagHasName = true; + this.name = name; + } + + @Override + public void setClassName(String className) { + placeFlagHasClassName = true; + this.className = className; + } + + @Override + public String getName() { + if (placeFlagHasName) { + return super.getName() + " (" + name + ")"; + } else { + return super.getName(); + } + } + + @Override + public CLIPACTIONS getClipActions() { + if (placeFlagHasClipActions) { + return clipActions; + } else { + return null; + } + } + + @Override + public void writeTagWithMatrix(SWFOutputStream sos, MATRIX m) throws IOException { + MATRIX old = matrix; + matrix = m; + boolean mod = isModified(); + setModified(true); + super.writeTag(sos); + setModified(mod); + matrix = old; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject4Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject4Tag.java index 3aa01f350..2d13e115f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject4Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject4Tag.java @@ -1,588 +1,590 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.EndOfStreamException; -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.abc.CopyOutputStream; -import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.decompiler.flash.tags.base.ASMSourceContainer; -import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.CLIPACTIONRECORD; -import com.jpexs.decompiler.flash.types.CLIPACTIONS; -import com.jpexs.decompiler.flash.types.CXFORMWITHALPHA; -import com.jpexs.decompiler.flash.types.ColorTransform; -import com.jpexs.decompiler.flash.types.MATRIX; -import com.jpexs.decompiler.flash.types.RGBA; -import com.jpexs.decompiler.flash.types.annotations.Conditional; -import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit; -import com.jpexs.decompiler.flash.types.annotations.Internal; -import com.jpexs.decompiler.flash.types.annotations.Reserved; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.decompiler.flash.types.filters.FILTER; -import com.jpexs.helpers.ByteArrayRange; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -/** - * Same as PlaceObject3Tag except additional AMF data - * - * @author JPEXS - */ -public class PlaceObject4Tag extends PlaceObjectTypeTag implements ASMSourceContainer { - - /** - * @since SWF 5 has clip actions (sprite characters only) - */ - public boolean placeFlagHasClipActions; - - /** - * Has clip depth - */ - public boolean placeFlagHasClipDepth; - - /** - * Has name - */ - public boolean placeFlagHasName; - - /** - * Has ratio - */ - public boolean placeFlagHasRatio; - - /** - * Has color transform - */ - public boolean placeFlagHasColorTransform; - - /** - * Has matrix - */ - public boolean placeFlagHasMatrix; - - /** - * Places a character - */ - public boolean placeFlagHasCharacter; - - /** - * Defines a character to be moved - */ - public boolean placeFlagMove; - - /** - * Has class name or character ID of bitmap to place. If - * PlaceFlagHasClassName, use ClassName. If PlaceFlagHasCharacter, use - * CharacterId - */ - public boolean placeFlagHasImage; - - /** - * Has class name of object to place - */ - public boolean placeFlagHasClassName; - - /** - * Enables bitmap caching - */ - public boolean placeFlagHasCacheAsBitmap; - - /** - * Has blend mode - */ - public boolean placeFlagHasBlendMode; - - /** - * Has filter list - */ - public boolean placeFlagHasFilterList; - - /** - * Has opaque background. SWF 11 and higher. - */ - public boolean placeFlagOpaqueBackground; - - /** - * Has visibility flag. SWF 11 and higher. - */ - public boolean placeFlagHasVisible; - - /** - * Depth of character - */ - @SWFType(BasicType.UI16) - public int depth; - - /** - * If PlaceFlagHasClassName or (PlaceFlagHasImage and - * PlaceFlagHasCharacter), Name of the class to place - */ - @Conditional("placeFlagHasClassName") - public String className; - - /** - * If PlaceFlagHasCharacter, ID of character to place - */ - @SWFType(BasicType.UI16) - @Conditional("placeFlagHasCharacter") - public int characterId; - - /** - * If PlaceFlagHasMatrix, Transform matrix data - */ - @Conditional("placeFlagHasMatrix") - public MATRIX matrix; - - /** - * If PlaceFlagHasColorTransform, Color transform data - */ - @Conditional("placeFlagHasColorTransform") - public CXFORMWITHALPHA colorTransform; - - /** - * If PlaceFlagHasRatio, Ratio - */ - @SWFType(BasicType.UI16) - @Conditional("placeFlagHasRatio") - public int ratio; - - /** - * If PlaceFlagHasName, Name of character - */ - @Conditional("placeFlagHasName") - public String name; - - /** - * If PlaceFlagHasClipDepth, Clip depth - */ - @SWFType(BasicType.UI16) - @Conditional("placeFlagHasClipDepth") - public int clipDepth; - - /** - * If PlaceFlagHasFilterList, List of filters on this object - */ - @Conditional("placeFlagHasFilterList") - public List surfaceFilterList; - - /** - * If PlaceFlagHasBlendMode, Blend mode - */ - @SWFType(BasicType.UI8) - @Conditional("placeFlagHasBlendMode") - public int blendMode; - - /** - * If PlaceFlagHasCacheAsBitmap, 0 = Bitmap cache disabled, 1-255 = Bitmap - * cache enabled - */ - @SWFType(BasicType.UI8) - @Conditional("placeFlagHasCacheAsBitmap") - public int bitmapCache; - - /** - * @since SWF 5 If PlaceFlagHasClipActions, Clip Actions Data - */ - @Conditional(value = "placeFlagHasClipActions", minSwfVersion = 5) - @HideInRawEdit //TODO: make editable - public CLIPACTIONS clipActions; - - /** - * If PlaceFlagHasVisible, 0 = Place invisible, 1 = Place visible - */ - @Conditional("placeFlagHasVisible") - public int visible; - - /** - * If PlaceFlagHasVisible, Background color - */ - @Conditional("placeFlagOpaqueBackground") - public RGBA backgroundColor; - - // FIXME bug found in ecoDrive.swf, - @Internal - private boolean bitmapCacheBug; - - @Reserved - public boolean reserved; - - public static final int ID = 94; - - public byte[] amfData; //TODO: Parse AMF data? - - @Override - public List getFilters() { - if (placeFlagHasFilterList) { - return surfaceFilterList; - } else { - return null; - } - } - - @Override - public int getClipDepth() { - if (placeFlagHasClipDepth) { - return clipDepth; - } - return -1; - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - if (Configuration.debugCopy.get()) { - os = new CopyOutputStream(os, new ByteArrayInputStream(getOriginalData())); - } - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUB(1, placeFlagHasClipActions ? 1 : 0); - sos.writeUB(1, placeFlagHasClipDepth ? 1 : 0); - sos.writeUB(1, placeFlagHasName ? 1 : 0); - sos.writeUB(1, placeFlagHasRatio ? 1 : 0); - sos.writeUB(1, placeFlagHasColorTransform ? 1 : 0); - sos.writeUB(1, placeFlagHasMatrix ? 1 : 0); - sos.writeUB(1, placeFlagHasCharacter ? 1 : 0); - sos.writeUB(1, placeFlagMove ? 1 : 0); - sos.writeUB(1, reserved ? 1 : 0); - sos.writeUB(1, placeFlagOpaqueBackground ? 1 : 0); //SWF11 - sos.writeUB(1, placeFlagHasVisible ? 1 : 0); //SWF11 - sos.writeUB(1, placeFlagHasImage ? 1 : 0); - sos.writeUB(1, placeFlagHasClassName ? 1 : 0); - sos.writeUB(1, placeFlagHasCacheAsBitmap ? 1 : 0); - sos.writeUB(1, placeFlagHasBlendMode ? 1 : 0); - sos.writeUB(1, placeFlagHasFilterList ? 1 : 0); - sos.writeUI16(depth); - - if (placeFlagHasClassName) { - sos.writeString(className); - } - if (placeFlagHasCharacter) { - sos.writeUI16(characterId); - } - if (placeFlagHasMatrix) { - sos.writeMatrix(matrix); - } - if (placeFlagHasColorTransform) { - sos.writeCXFORMWITHALPHA(colorTransform); - } - if (placeFlagHasRatio) { - sos.writeUI16(ratio); - } - if (placeFlagHasName) { - sos.writeString(name); - } - if (placeFlagHasClipDepth) { - sos.writeUI16(clipDepth); - } - if (placeFlagHasFilterList) { - sos.writeFILTERLIST(surfaceFilterList); - } - if (placeFlagHasBlendMode) { - sos.writeUI8(blendMode); - } - if (placeFlagHasCacheAsBitmap) { - if (!bitmapCacheBug) { - sos.writeUI8(bitmapCache); - } - } - if (placeFlagHasVisible) { - sos.writeUI8(visible); - } - if (placeFlagOpaqueBackground) { - sos.writeRGBA(backgroundColor); - } - if (placeFlagHasClipActions) { - sos.writeCLIPACTIONS(clipActions); - } - sos.close(); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - - /** - * Constructor - * - * @param swf - */ - public PlaceObject4Tag(SWF swf) { - super(swf, ID, "PlaceObject4", null); - } - - /** - * Constructor - * - * @param sis - * @param data - * @throws IOException - */ - public PlaceObject4Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "PlaceObject4", data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - placeFlagHasClipActions = sis.readUB(1, "placeFlagHasClipActions") == 1; - placeFlagHasClipDepth = sis.readUB(1, "placeFlagHasClipDepth") == 1; - placeFlagHasName = sis.readUB(1, "placeFlagHasName") == 1; - placeFlagHasRatio = sis.readUB(1, "placeFlagHasRatio") == 1; - placeFlagHasColorTransform = sis.readUB(1, "placeFlagHasColorTransform") == 1; - placeFlagHasMatrix = sis.readUB(1, "placeFlagHasMatrix") == 1; - placeFlagHasCharacter = sis.readUB(1, "placeFlagHasCharacter") == 1; - placeFlagMove = sis.readUB(1, "placeFlagMove") == 1; - reserved = sis.readUB(1, "reserved") == 1; - placeFlagOpaqueBackground = sis.readUB(1, "placeFlagOpaqueBackground") == 1; //SWF11 - placeFlagHasVisible = sis.readUB(1, "placeFlagHasVisible") == 1; //SWF11 - placeFlagHasImage = sis.readUB(1, "placeFlagHasImage") == 1; - placeFlagHasClassName = sis.readUB(1, "placeFlagHasClassName") == 1; - placeFlagHasCacheAsBitmap = sis.readUB(1, "placeFlagHasCacheAsBitmap") == 1; - placeFlagHasBlendMode = sis.readUB(1, "placeFlagHasBlendMode") == 1; - placeFlagHasFilterList = sis.readUB(1, "placeFlagHasFilterList") == 1; - - depth = sis.readUI16("depth"); - if (placeFlagHasClassName) { - className = sis.readString("className"); - } - if (placeFlagHasCharacter) { - characterId = sis.readUI16("characterId"); - } - if (placeFlagHasMatrix) { - matrix = sis.readMatrix("matrix"); - } - if (placeFlagHasColorTransform) { - colorTransform = sis.readCXFORMWITHALPHA("colorTransform"); - } - if (placeFlagHasRatio) { - ratio = sis.readUI16("ratio"); - } - if (placeFlagHasName) { - name = sis.readString("name"); - } - if (placeFlagHasClipDepth) { - clipDepth = sis.readUI16("clipDepth"); - } - if (placeFlagHasFilterList) { - surfaceFilterList = sis.readFILTERLIST("surfaceFilterList"); - } - if (placeFlagHasBlendMode) { - blendMode = sis.readUI8("blendMode"); - } - bitmapCacheBug = false; - if (placeFlagHasCacheAsBitmap) { - try { - bitmapCache = sis.readUI8("bitmapCache"); - } catch (EndOfStreamException eex) { - bitmapCacheBug = true; - bitmapCache = 1; - } - } - - if (placeFlagHasVisible) { - visible = sis.readUI8("visible"); - } - if (placeFlagOpaqueBackground) { - backgroundColor = sis.readRGBA("backgroundColor"); - } - - if (placeFlagHasClipActions) { - clipActions = sis.readCLIPACTIONS(swf, this, "clipActions"); - } - amfData = sis.readBytesEx(sis.available(), "amfData"); - } - - /** - * Returns all sub-items - * - * @return List of sub-items - */ - @Override - public List getSubItems() { - if (placeFlagHasClipActions) { - return clipActions.clipActionRecords; - } - return new ArrayList<>(); - } - - @Override - public void getNeededCharacters(Set needed) { - if (placeFlagHasCharacter) { - needed.add(characterId); - } - } - - @Override - public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { - return false; - } - - @Override - public boolean removeCharacter(int characterId) { - // the place object tag will be removed - return false; - } - - @Override - public int getCharacterId() { - if (placeFlagHasCharacter) { - return characterId; - } else { - return -1; - } - } - - @Override - public void setCharacterId(int characterId) { - placeFlagHasCharacter = true; - this.characterId = characterId; - } - - @Override - public int getDepth() { - return depth; - } - - @Override - public MATRIX getMatrix() { - if (placeFlagHasMatrix) { - return matrix; - } else { - return null; - } - } - - @Override - public String getInstanceName() { - if (placeFlagHasName) { - return name; - } - return null; - } - - @Override - public ColorTransform getColorTransform() { - if (placeFlagHasColorTransform) { - return colorTransform; - } else { - return null; - } - } - - @Override - public int getBlendMode() { - return blendMode; - } - - @Override - public String getClassName() { - if (placeFlagHasClassName) { - return className; - } - return null; - } - - @Override - public boolean cacheAsBitmap() { - return placeFlagHasCacheAsBitmap; - } - - @Override - public boolean isVisible() { - if (placeFlagHasVisible) { - return visible == 1; - } - return true; - } - - @Override - public RGBA getBackgroundColor() { - if (placeFlagOpaqueBackground) { - return backgroundColor; - } - return null; - } - - @Override - public boolean flagMove() { - return placeFlagMove; - } - - @Override - public int getRatio() { - if (!placeFlagHasRatio) { - return -1; - } - return ratio; - } - - @Override - public void setInstanceName(String name) { - placeFlagHasName = true; - this.name = name; - } - - @Override - public void setClassName(String className) { - placeFlagHasClassName = true; - this.className = className; - } - - @Override - public String getName() { - if (placeFlagHasName) { - return super.getName() + " (" + name + ")"; - } else { - return super.getName(); - } - } - - @Override - public CLIPACTIONS getClipActions() { - if (placeFlagHasClipActions) { - return clipActions; - } else { - return null; - } - } - - @Override - public void writeTagWithMatrix(SWFOutputStream sos, MATRIX m) throws IOException { - MATRIX old = matrix; - matrix = m; - boolean mod = isModified(); - setModified(true); - super.writeTag(sos); - setModified(mod); - matrix = old; - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.EndOfStreamException; +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.abc.CopyOutputStream; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.tags.base.ASMSourceContainer; +import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.CLIPACTIONRECORD; +import com.jpexs.decompiler.flash.types.CLIPACTIONS; +import com.jpexs.decompiler.flash.types.CXFORMWITHALPHA; +import com.jpexs.decompiler.flash.types.ColorTransform; +import com.jpexs.decompiler.flash.types.MATRIX; +import com.jpexs.decompiler.flash.types.RGBA; +import com.jpexs.decompiler.flash.types.annotations.Conditional; +import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit; +import com.jpexs.decompiler.flash.types.annotations.Internal; +import com.jpexs.decompiler.flash.types.annotations.Reserved; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.decompiler.flash.types.filters.FILTER; +import com.jpexs.helpers.ByteArrayRange; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** + * Same as PlaceObject3Tag except additional AMF data + * + * @author JPEXS + */ +public class PlaceObject4Tag extends PlaceObjectTypeTag implements ASMSourceContainer { + + /** + * @since SWF 5 has clip actions (sprite characters only) + */ + public boolean placeFlagHasClipActions; + + /** + * Has clip depth + */ + public boolean placeFlagHasClipDepth; + + /** + * Has name + */ + public boolean placeFlagHasName; + + /** + * Has ratio + */ + public boolean placeFlagHasRatio; + + /** + * Has color transform + */ + public boolean placeFlagHasColorTransform; + + /** + * Has matrix + */ + public boolean placeFlagHasMatrix; + + /** + * Places a character + */ + public boolean placeFlagHasCharacter; + + /** + * Defines a character to be moved + */ + public boolean placeFlagMove; + + /** + * Has class name or character ID of bitmap to place. If + * PlaceFlagHasClassName, use ClassName. If PlaceFlagHasCharacter, use + * CharacterId + */ + public boolean placeFlagHasImage; + + /** + * Has class name of object to place + */ + public boolean placeFlagHasClassName; + + /** + * Enables bitmap caching + */ + public boolean placeFlagHasCacheAsBitmap; + + /** + * Has blend mode + */ + public boolean placeFlagHasBlendMode; + + /** + * Has filter list + */ + public boolean placeFlagHasFilterList; + + /** + * Has opaque background. SWF 11 and higher. + */ + public boolean placeFlagOpaqueBackground; + + /** + * Has visibility flag. SWF 11 and higher. + */ + public boolean placeFlagHasVisible; + + /** + * Depth of character + */ + @SWFType(BasicType.UI16) + public int depth; + + /** + * If PlaceFlagHasClassName or (PlaceFlagHasImage and + * PlaceFlagHasCharacter), Name of the class to place + */ + @Conditional("placeFlagHasClassName") + public String className; + + /** + * If PlaceFlagHasCharacter, ID of character to place + */ + @SWFType(BasicType.UI16) + @Conditional("placeFlagHasCharacter") + public int characterId; + + /** + * If PlaceFlagHasMatrix, Transform matrix data + */ + @Conditional("placeFlagHasMatrix") + public MATRIX matrix; + + /** + * If PlaceFlagHasColorTransform, Color transform data + */ + @Conditional("placeFlagHasColorTransform") + public CXFORMWITHALPHA colorTransform; + + /** + * If PlaceFlagHasRatio, Ratio + */ + @SWFType(BasicType.UI16) + @Conditional("placeFlagHasRatio") + public int ratio; + + /** + * If PlaceFlagHasName, Name of character + */ + @Conditional("placeFlagHasName") + public String name; + + /** + * If PlaceFlagHasClipDepth, Clip depth + */ + @SWFType(BasicType.UI16) + @Conditional("placeFlagHasClipDepth") + public int clipDepth; + + /** + * If PlaceFlagHasFilterList, List of filters on this object + */ + @Conditional("placeFlagHasFilterList") + public List surfaceFilterList; + + /** + * If PlaceFlagHasBlendMode, Blend mode + */ + @SWFType(BasicType.UI8) + @Conditional("placeFlagHasBlendMode") + public int blendMode; + + /** + * If PlaceFlagHasCacheAsBitmap, 0 = Bitmap cache disabled, 1-255 = Bitmap + * cache enabled + */ + @SWFType(BasicType.UI8) + @Conditional("placeFlagHasCacheAsBitmap") + public int bitmapCache; + + /** + * @since SWF 5 If PlaceFlagHasClipActions, Clip Actions Data + */ + @Conditional(value = "placeFlagHasClipActions", minSwfVersion = 5) + @HideInRawEdit //TODO: make editable + public CLIPACTIONS clipActions; + + /** + * If PlaceFlagHasVisible, 0 = Place invisible, 1 = Place visible + */ + @Conditional("placeFlagHasVisible") + public int visible; + + /** + * If PlaceFlagHasVisible, Background color + */ + @Conditional("placeFlagOpaqueBackground") + public RGBA backgroundColor; + + // FIXME bug found in ecoDrive.swf, + @Internal + private boolean bitmapCacheBug; + + @Reserved + public boolean reserved; + + public static final int ID = 94; + + public static final String NAME = "PlaceObject4"; + + public byte[] amfData; //TODO: Parse AMF data? + + @Override + public List getFilters() { + if (placeFlagHasFilterList) { + return surfaceFilterList; + } else { + return null; + } + } + + @Override + public int getClipDepth() { + if (placeFlagHasClipDepth) { + return clipDepth; + } + return -1; + } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + if (Configuration.debugCopy.get()) { + os = new CopyOutputStream(os, new ByteArrayInputStream(getOriginalData())); + } + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUB(1, placeFlagHasClipActions ? 1 : 0); + sos.writeUB(1, placeFlagHasClipDepth ? 1 : 0); + sos.writeUB(1, placeFlagHasName ? 1 : 0); + sos.writeUB(1, placeFlagHasRatio ? 1 : 0); + sos.writeUB(1, placeFlagHasColorTransform ? 1 : 0); + sos.writeUB(1, placeFlagHasMatrix ? 1 : 0); + sos.writeUB(1, placeFlagHasCharacter ? 1 : 0); + sos.writeUB(1, placeFlagMove ? 1 : 0); + sos.writeUB(1, reserved ? 1 : 0); + sos.writeUB(1, placeFlagOpaqueBackground ? 1 : 0); //SWF11 + sos.writeUB(1, placeFlagHasVisible ? 1 : 0); //SWF11 + sos.writeUB(1, placeFlagHasImage ? 1 : 0); + sos.writeUB(1, placeFlagHasClassName ? 1 : 0); + sos.writeUB(1, placeFlagHasCacheAsBitmap ? 1 : 0); + sos.writeUB(1, placeFlagHasBlendMode ? 1 : 0); + sos.writeUB(1, placeFlagHasFilterList ? 1 : 0); + sos.writeUI16(depth); + + if (placeFlagHasClassName) { + sos.writeString(className); + } + if (placeFlagHasCharacter) { + sos.writeUI16(characterId); + } + if (placeFlagHasMatrix) { + sos.writeMatrix(matrix); + } + if (placeFlagHasColorTransform) { + sos.writeCXFORMWITHALPHA(colorTransform); + } + if (placeFlagHasRatio) { + sos.writeUI16(ratio); + } + if (placeFlagHasName) { + sos.writeString(name); + } + if (placeFlagHasClipDepth) { + sos.writeUI16(clipDepth); + } + if (placeFlagHasFilterList) { + sos.writeFILTERLIST(surfaceFilterList); + } + if (placeFlagHasBlendMode) { + sos.writeUI8(blendMode); + } + if (placeFlagHasCacheAsBitmap) { + if (!bitmapCacheBug) { + sos.writeUI8(bitmapCache); + } + } + if (placeFlagHasVisible) { + sos.writeUI8(visible); + } + if (placeFlagOpaqueBackground) { + sos.writeRGBA(backgroundColor); + } + if (placeFlagHasClipActions) { + sos.writeCLIPACTIONS(clipActions); + } + sos.close(); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + /** + * Constructor + * + * @param swf + */ + public PlaceObject4Tag(SWF swf) { + super(swf, ID, NAME, null); + } + + /** + * Constructor + * + * @param sis + * @param data + * @throws IOException + */ + public PlaceObject4Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + placeFlagHasClipActions = sis.readUB(1, "placeFlagHasClipActions") == 1; + placeFlagHasClipDepth = sis.readUB(1, "placeFlagHasClipDepth") == 1; + placeFlagHasName = sis.readUB(1, "placeFlagHasName") == 1; + placeFlagHasRatio = sis.readUB(1, "placeFlagHasRatio") == 1; + placeFlagHasColorTransform = sis.readUB(1, "placeFlagHasColorTransform") == 1; + placeFlagHasMatrix = sis.readUB(1, "placeFlagHasMatrix") == 1; + placeFlagHasCharacter = sis.readUB(1, "placeFlagHasCharacter") == 1; + placeFlagMove = sis.readUB(1, "placeFlagMove") == 1; + reserved = sis.readUB(1, "reserved") == 1; + placeFlagOpaqueBackground = sis.readUB(1, "placeFlagOpaqueBackground") == 1; //SWF11 + placeFlagHasVisible = sis.readUB(1, "placeFlagHasVisible") == 1; //SWF11 + placeFlagHasImage = sis.readUB(1, "placeFlagHasImage") == 1; + placeFlagHasClassName = sis.readUB(1, "placeFlagHasClassName") == 1; + placeFlagHasCacheAsBitmap = sis.readUB(1, "placeFlagHasCacheAsBitmap") == 1; + placeFlagHasBlendMode = sis.readUB(1, "placeFlagHasBlendMode") == 1; + placeFlagHasFilterList = sis.readUB(1, "placeFlagHasFilterList") == 1; + + depth = sis.readUI16("depth"); + if (placeFlagHasClassName) { + className = sis.readString("className"); + } + if (placeFlagHasCharacter) { + characterId = sis.readUI16("characterId"); + } + if (placeFlagHasMatrix) { + matrix = sis.readMatrix("matrix"); + } + if (placeFlagHasColorTransform) { + colorTransform = sis.readCXFORMWITHALPHA("colorTransform"); + } + if (placeFlagHasRatio) { + ratio = sis.readUI16("ratio"); + } + if (placeFlagHasName) { + name = sis.readString("name"); + } + if (placeFlagHasClipDepth) { + clipDepth = sis.readUI16("clipDepth"); + } + if (placeFlagHasFilterList) { + surfaceFilterList = sis.readFILTERLIST("surfaceFilterList"); + } + if (placeFlagHasBlendMode) { + blendMode = sis.readUI8("blendMode"); + } + bitmapCacheBug = false; + if (placeFlagHasCacheAsBitmap) { + try { + bitmapCache = sis.readUI8("bitmapCache"); + } catch (EndOfStreamException eex) { + bitmapCacheBug = true; + bitmapCache = 1; + } + } + + if (placeFlagHasVisible) { + visible = sis.readUI8("visible"); + } + if (placeFlagOpaqueBackground) { + backgroundColor = sis.readRGBA("backgroundColor"); + } + + if (placeFlagHasClipActions) { + clipActions = sis.readCLIPACTIONS(swf, this, "clipActions"); + } + amfData = sis.readBytesEx(sis.available(), "amfData"); + } + + /** + * Returns all sub-items + * + * @return List of sub-items + */ + @Override + public List getSubItems() { + if (placeFlagHasClipActions) { + return clipActions.clipActionRecords; + } + return new ArrayList<>(); + } + + @Override + public void getNeededCharacters(Set needed) { + if (placeFlagHasCharacter) { + needed.add(characterId); + } + } + + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + return false; + } + + @Override + public boolean removeCharacter(int characterId) { + // the place object tag will be removed + return false; + } + + @Override + public int getCharacterId() { + if (placeFlagHasCharacter) { + return characterId; + } else { + return -1; + } + } + + @Override + public void setCharacterId(int characterId) { + placeFlagHasCharacter = true; + this.characterId = characterId; + } + + @Override + public int getDepth() { + return depth; + } + + @Override + public MATRIX getMatrix() { + if (placeFlagHasMatrix) { + return matrix; + } else { + return null; + } + } + + @Override + public String getInstanceName() { + if (placeFlagHasName) { + return name; + } + return null; + } + + @Override + public ColorTransform getColorTransform() { + if (placeFlagHasColorTransform) { + return colorTransform; + } else { + return null; + } + } + + @Override + public int getBlendMode() { + return blendMode; + } + + @Override + public String getClassName() { + if (placeFlagHasClassName) { + return className; + } + return null; + } + + @Override + public boolean cacheAsBitmap() { + return placeFlagHasCacheAsBitmap; + } + + @Override + public boolean isVisible() { + if (placeFlagHasVisible) { + return visible == 1; + } + return true; + } + + @Override + public RGBA getBackgroundColor() { + if (placeFlagOpaqueBackground) { + return backgroundColor; + } + return null; + } + + @Override + public boolean flagMove() { + return placeFlagMove; + } + + @Override + public int getRatio() { + if (!placeFlagHasRatio) { + return -1; + } + return ratio; + } + + @Override + public void setInstanceName(String name) { + placeFlagHasName = true; + this.name = name; + } + + @Override + public void setClassName(String className) { + placeFlagHasClassName = true; + this.className = className; + } + + @Override + public String getName() { + if (placeFlagHasName) { + return super.getName() + " (" + name + ")"; + } else { + return super.getName(); + } + } + + @Override + public CLIPACTIONS getClipActions() { + if (placeFlagHasClipActions) { + return clipActions; + } else { + return null; + } + } + + @Override + public void writeTagWithMatrix(SWFOutputStream sos, MATRIX m) throws IOException { + MATRIX old = matrix; + matrix = m; + boolean mod = isModified(); + setModified(true); + super.writeTag(sos); + setModified(mod); + matrix = old; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObjectTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObjectTag.java index f6f17b884..1eede5249 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObjectTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObjectTag.java @@ -1,250 +1,252 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.CLIPACTIONS; -import com.jpexs.decompiler.flash.types.CXFORM; -import com.jpexs.decompiler.flash.types.ColorTransform; -import com.jpexs.decompiler.flash.types.MATRIX; -import com.jpexs.decompiler.flash.types.RGBA; -import com.jpexs.decompiler.flash.types.annotations.Optional; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.decompiler.flash.types.filters.FILTER; -import com.jpexs.helpers.ByteArrayRange; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.List; -import java.util.Set; - -/** - * Adds character to the display list - * - * @author JPEXS - */ -public class PlaceObjectTag extends PlaceObjectTypeTag { - - /** - * ID of character to place - */ - @SWFType(BasicType.UI16) - public int characterId; - - /** - * Depth of character - */ - @SWFType(BasicType.UI16) - public int depth; - - /** - * Transform matrix data - */ - public MATRIX matrix; - - /** - * Color transform data - */ - @Optional - public CXFORM colorTransform; - - public static final int ID = 4; - - @Override - public List getFilters() { - return null; - } - - @Override - public int getClipDepth() { - return -1; - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(characterId); - sos.writeUI16(depth); - sos.writeMatrix(matrix); - if (colorTransform != null) { - sos.writeCXFORM(colorTransform); - } - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - - /** - * Constructor - * - * @param swf - */ - public PlaceObjectTag(SWF swf) { - super(swf, ID, "PlaceObject", null); - matrix = new MATRIX(); - } - - /** - * Constructor - * - * @param sis - * @param data - * @throws IOException - */ - public PlaceObjectTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "PlaceObject", data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - characterId = sis.readUI16("characterId"); - depth = sis.readUI16("depth"); - matrix = sis.readMatrix("matrix"); - if (sis.available() > 0) { - colorTransform = sis.readCXFORM("colorTransform"); - } - } - - public PlaceObjectTag(SWF swf, int characterId, int depth, MATRIX matrix, CXFORM colorTransform) { - super(swf, ID, "PlaceObject", null); - this.characterId = characterId; - this.depth = depth; - this.matrix = matrix; - this.colorTransform = colorTransform; - } - - @Override - public void getNeededCharacters(Set needed) { - needed.add(characterId); - } - - @Override - public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { - return false; - } - - @Override - public boolean removeCharacter(int characterId) { - // the place object tag will be removed - return false; - } - - @Override - public int getCharacterId() { - return characterId; - } - - @Override - public void setCharacterId(int characterId) { - this.characterId = characterId; - } - - @Override - public int getDepth() { - return depth; - } - - @Override - public MATRIX getMatrix() { - return matrix; - } - - @Override - public String getInstanceName() { - return null; - } - - @Override - public ColorTransform getColorTransform() { - return colorTransform; - } - - @Override - public int getBlendMode() { - return 0; - } - - @Override - public boolean cacheAsBitmap() { - return false; - } - - @Override - public String getClassName() { - return null; - } - - @Override - public boolean isVisible() { - return true; - } - - @Override - public RGBA getBackgroundColor() { - return null; - } - - @Override - public boolean flagMove() { - return false; - } - - @Override - public int getRatio() { - return -1; - } - - @Override - public void setInstanceName(String name) { - //not supported - } - - @Override - public void setClassName(String className) { - //not supported - } - - @Override - public CLIPACTIONS getClipActions() { - return null; - } - - @Override - public void writeTagWithMatrix(SWFOutputStream sos, MATRIX m) throws IOException { - MATRIX old = matrix; - matrix = m; - boolean mod = isModified(); - setModified(true); - super.writeTag(sos); - setModified(mod); - matrix = old; - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.CLIPACTIONS; +import com.jpexs.decompiler.flash.types.CXFORM; +import com.jpexs.decompiler.flash.types.ColorTransform; +import com.jpexs.decompiler.flash.types.MATRIX; +import com.jpexs.decompiler.flash.types.RGBA; +import com.jpexs.decompiler.flash.types.annotations.Optional; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.decompiler.flash.types.filters.FILTER; +import com.jpexs.helpers.ByteArrayRange; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.List; +import java.util.Set; + +/** + * Adds character to the display list + * + * @author JPEXS + */ +public class PlaceObjectTag extends PlaceObjectTypeTag { + + /** + * ID of character to place + */ + @SWFType(BasicType.UI16) + public int characterId; + + /** + * Depth of character + */ + @SWFType(BasicType.UI16) + public int depth; + + /** + * Transform matrix data + */ + public MATRIX matrix; + + /** + * Color transform data + */ + @Optional + public CXFORM colorTransform; + + public static final int ID = 4; + + public static final String NAME = "PlaceObject"; + + @Override + public List getFilters() { + return null; + } + + @Override + public int getClipDepth() { + return -1; + } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(characterId); + sos.writeUI16(depth); + sos.writeMatrix(matrix); + if (colorTransform != null) { + sos.writeCXFORM(colorTransform); + } + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + /** + * Constructor + * + * @param swf + */ + public PlaceObjectTag(SWF swf) { + super(swf, ID, NAME, null); + matrix = new MATRIX(); + } + + /** + * Constructor + * + * @param sis + * @param data + * @throws IOException + */ + public PlaceObjectTag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + characterId = sis.readUI16("characterId"); + depth = sis.readUI16("depth"); + matrix = sis.readMatrix("matrix"); + if (sis.available() > 0) { + colorTransform = sis.readCXFORM("colorTransform"); + } + } + + public PlaceObjectTag(SWF swf, int characterId, int depth, MATRIX matrix, CXFORM colorTransform) { + super(swf, ID, NAME, null); + this.characterId = characterId; + this.depth = depth; + this.matrix = matrix; + this.colorTransform = colorTransform; + } + + @Override + public void getNeededCharacters(Set needed) { + needed.add(characterId); + } + + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + return false; + } + + @Override + public boolean removeCharacter(int characterId) { + // the place object tag will be removed + return false; + } + + @Override + public int getCharacterId() { + return characterId; + } + + @Override + public void setCharacterId(int characterId) { + this.characterId = characterId; + } + + @Override + public int getDepth() { + return depth; + } + + @Override + public MATRIX getMatrix() { + return matrix; + } + + @Override + public String getInstanceName() { + return null; + } + + @Override + public ColorTransform getColorTransform() { + return colorTransform; + } + + @Override + public int getBlendMode() { + return 0; + } + + @Override + public boolean cacheAsBitmap() { + return false; + } + + @Override + public String getClassName() { + return null; + } + + @Override + public boolean isVisible() { + return true; + } + + @Override + public RGBA getBackgroundColor() { + return null; + } + + @Override + public boolean flagMove() { + return false; + } + + @Override + public int getRatio() { + return -1; + } + + @Override + public void setInstanceName(String name) { + //not supported + } + + @Override + public void setClassName(String className) { + //not supported + } + + @Override + public CLIPACTIONS getClipActions() { + return null; + } + + @Override + public void writeTagWithMatrix(SWFOutputStream sos, MATRIX m) throws IOException { + MATRIX old = matrix; + matrix = m; + boolean mod = isModified(); + setModified(true); + super.writeTag(sos); + setModified(mod); + matrix = old; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ProductInfoTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ProductInfoTag.java index ac0081e18..4c25c7103 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ProductInfoTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ProductInfoTag.java @@ -54,17 +54,19 @@ public class ProductInfoTag extends Tag { public static final int ID = 41; + public static final String NAME = "ProductInfo"; + /** * Constructor * * @param swf */ public ProductInfoTag(SWF swf) { - super(swf, ID, "ProductInfo", null); + super(swf, ID, NAME, null); } public ProductInfoTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "ProductInfo", data); + super(sis.getSwf(), ID, NAME, data); readData(sis, data, 0, false, false, false); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ProtectTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ProtectTag.java index ed3d2770d..fde991ecd 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ProtectTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ProtectTag.java @@ -38,6 +38,8 @@ public class ProtectTag extends Tag { public static final int ID = 24; + public static final String NAME = "Protect"; + /** * Gets data bytes * @@ -64,7 +66,7 @@ public class ProtectTag extends Tag { * @param swf */ public ProtectTag(SWF swf) { - super(swf, ID, "Protect", null); + super(swf, ID, NAME, null); passwordHash = ""; } @@ -76,7 +78,7 @@ public class ProtectTag extends Tag { * @throws IOException */ public ProtectTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "Protect", data); + super(sis.getSwf(), ID, NAME, data); readData(sis, data, 0, false, false, false); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/RemoveObject2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/RemoveObject2Tag.java index e5ac0c8af..14146345c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/RemoveObject2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/RemoveObject2Tag.java @@ -34,17 +34,19 @@ public class RemoveObject2Tag extends RemoveTag { public static final int ID = 28; + public static final String NAME = "RemoveObject2"; + /** * Constructor * * @param swf */ public RemoveObject2Tag(SWF swf) { - super(swf, ID, "RemoveObject2", null); + super(swf, ID, NAME, null); } public RemoveObject2Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "RemoveObject2", data); + super(sis.getSwf(), ID, NAME, data); readData(sis, data, 0, false, false, false); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/RemoveObjectTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/RemoveObjectTag.java index f70d20d5d..85d255d00 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/RemoveObjectTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/RemoveObjectTag.java @@ -1,113 +1,115 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.tags.base.CharacterIdTag; -import com.jpexs.decompiler.flash.tags.base.RemoveTag; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.helpers.ByteArrayRange; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -/** - * Removes the specified character - * - * @author JPEXS - */ -public class RemoveObjectTag extends RemoveTag implements CharacterIdTag { - - /** - * ID of character to place - */ - @SWFType(BasicType.UI16) - public int characterId; - - /** - * Depth of character - */ - @SWFType(BasicType.UI16) - public int depth; - - public static final int ID = 5; - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(characterId); - sos.writeUI16(depth); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - - /** - * Constructor - * - * @param swf - */ - public RemoveObjectTag(SWF swf) { - super(swf, ID, "RemoveObject", null); - characterId = swf.getNextCharacterId(); - } - - /** - * Constructor - * - * @param sis - * @param data - * @throws IOException - */ - public RemoveObjectTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "RemoveObject", data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - characterId = sis.readUI16("characterId"); - depth = sis.readUI16("depth"); - } - - @Override - public int getDepth() { - return depth; - } - - @Override - public int getCharacterId() { - return characterId; - } - - @Override - public void setCharacterId(int characterId) { - this.characterId = characterId; - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.tags.base.CharacterIdTag; +import com.jpexs.decompiler.flash.tags.base.RemoveTag; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.helpers.ByteArrayRange; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * Removes the specified character + * + * @author JPEXS + */ +public class RemoveObjectTag extends RemoveTag implements CharacterIdTag { + + /** + * ID of character to place + */ + @SWFType(BasicType.UI16) + public int characterId; + + /** + * Depth of character + */ + @SWFType(BasicType.UI16) + public int depth; + + public static final int ID = 5; + + public static final String NAME = "RemoveObject"; + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(characterId); + sos.writeUI16(depth); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + /** + * Constructor + * + * @param swf + */ + public RemoveObjectTag(SWF swf) { + super(swf, ID, NAME, null); + characterId = swf.getNextCharacterId(); + } + + /** + * Constructor + * + * @param sis + * @param data + * @throws IOException + */ + public RemoveObjectTag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + characterId = sis.readUI16("characterId"); + depth = sis.readUI16("depth"); + } + + @Override + public int getDepth() { + return depth; + } + + @Override + public int getCharacterId() { + return characterId; + } + + @Override + public void setCharacterId(int characterId) { + this.characterId = characterId; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ScriptLimitsTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ScriptLimitsTag.java index de3d44c64..68205ed03 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ScriptLimitsTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ScriptLimitsTag.java @@ -36,17 +36,19 @@ public class ScriptLimitsTag extends Tag { public static final int ID = 65; + public static final String NAME = "ScriptLimits"; + /** * Constructor * * @param swf */ public ScriptLimitsTag(SWF swf) { - super(swf, ID, "ScriptLimits", null); + super(swf, ID, NAME, null); } public ScriptLimitsTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "ScriptLimits", data); + super(sis.getSwf(), ID, NAME, data); readData(sis, data, 0, false, false, false); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SetBackgroundColorTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SetBackgroundColorTag.java index da46ba75c..991e4b9fe 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SetBackgroundColorTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SetBackgroundColorTag.java @@ -30,23 +30,25 @@ public class SetBackgroundColorTag extends Tag { public static final int ID = 9; + public static final String NAME = "SetBackgroundColor"; + /** * Constructor * * @param swf */ public SetBackgroundColorTag(SWF swf) { - super(swf, ID, "SetBackgroundColor", null); + super(swf, ID, NAME, null); backgroundColor = new RGB(); } public SetBackgroundColorTag(SWF swf, RGB backgroundColor) { - super(swf, ID, "SetBackgroundColor", null); + super(swf, ID, NAME, null); this.backgroundColor = backgroundColor; } public SetBackgroundColorTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "SetBackgroundColor", data); + super(sis.getSwf(), ID, NAME, data); readData(sis, data, 0, false, false, false); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SetTabIndexTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SetTabIndexTag.java index 193c78e77..050f4b1a1 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SetTabIndexTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SetTabIndexTag.java @@ -47,6 +47,8 @@ public class SetTabIndexTag extends Tag { public static final int ID = 66; + public static final String NAME = "SetTabIndex"; + /** * Gets data bytes * @@ -72,7 +74,7 @@ public class SetTabIndexTag extends Tag { * @param swf */ public SetTabIndexTag(SWF swf) { - super(swf, ID, "SetTabIndex", null); + super(swf, ID, NAME, null); } /** @@ -83,7 +85,7 @@ public class SetTabIndexTag extends Tag { * @throws IOException */ public SetTabIndexTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "SetTabIndex", data); + super(sis.getSwf(), ID, NAME, data); readData(sis, data, 0, false, false, false); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ShowFrameTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ShowFrameTag.java index 173d9c7a1..3266934d1 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ShowFrameTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/ShowFrameTag.java @@ -31,6 +31,8 @@ public class ShowFrameTag extends Tag { public static final int ID = 1; + public static final String NAME = "ShowFrame"; + private static List nestedTagTypeIds = new ArrayList() { { add(PlaceObjectTag.ID); @@ -55,7 +57,7 @@ public class ShowFrameTag extends Tag { * @param swf */ public ShowFrameTag(SWF swf) { - super(swf, ID, "ShowFrame", null); + super(swf, ID, NAME, null); } /** @@ -65,7 +67,7 @@ public class ShowFrameTag extends Tag { * @param data */ public ShowFrameTag(SWFInputStream sis, ByteArrayRange data) { - super(sis.getSwf(), ID, "ShowFrame", data); + super(sis.getSwf(), ID, NAME, data); readData(sis, data, 0, false, false, false); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamBlockTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamBlockTag.java index 96ea58607..62120ab86 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamBlockTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamBlockTag.java @@ -34,6 +34,8 @@ public class SoundStreamBlockTag extends Tag { public static final int ID = 19; + public static final String NAME = "SoundStreamBlock"; + @HideInRawEdit public ByteArrayRange streamSoundData; @@ -43,7 +45,7 @@ public class SoundStreamBlockTag extends Tag { * @param swf */ public SoundStreamBlockTag(SWF swf) { - super(swf, ID, "SoundStreamBlock", null); + super(swf, ID, NAME, null); streamSoundData = ByteArrayRange.EMPTY; } @@ -55,7 +57,7 @@ public class SoundStreamBlockTag extends Tag { * @throws IOException */ public SoundStreamBlockTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "SoundStreamBlock", data); + super(sis.getSwf(), ID, NAME, data); readData(sis, data, 0, false, false, false); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHead2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHead2Tag.java index e3f0a8540..958ecac6e 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHead2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHead2Tag.java @@ -1,251 +1,253 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.tags.base.SoundStreamHeadTypeTag; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.annotations.Conditional; -import com.jpexs.decompiler.flash.types.annotations.Internal; -import com.jpexs.decompiler.flash.types.annotations.Reserved; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.decompiler.flash.types.sound.SoundFormat; -import com.jpexs.helpers.ByteArrayRange; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; - -/** - * - * - * @author JPEXS - */ -public class SoundStreamHead2Tag extends Tag implements SoundStreamHeadTypeTag { - - @Reserved - @SWFType(value = BasicType.UB, count = 4) - public int reserved; - - @SWFType(value = BasicType.UB, count = 2) - public int playBackSoundRate; - - public boolean playBackSoundSize; - - public boolean playBackSoundType; - - @SWFType(value = BasicType.UB, count = 4) - public int streamSoundCompression; - - @SWFType(value = BasicType.UB, count = 2) - public int streamSoundRate; - - public boolean streamSoundSize; - - public boolean streamSoundType; - - @SWFType(BasicType.UI16) - public int streamSoundSampleCount; - - @SWFType(BasicType.SI16) - @Conditional(value = "streamSoundCompression", options = {2}) - public int latencySeek; - - @Internal - private int virtualCharacterId = 0; - - public static final int ID = 45; - - @Override - public int getCharacterId() { - return virtualCharacterId; - } - - @Override - public void setCharacterId(int characterId) { - virtualCharacterId = characterId; - } - - @Override - public String getExportFormat() { - if (streamSoundCompression == SoundFormat.FORMAT_MP3) { - return "mp3"; - } - if (streamSoundCompression == SoundFormat.FORMAT_ADPCM) { - return "wav"; - } - if (streamSoundCompression == SoundFormat.FORMAT_UNCOMPRESSED_LITTLE_ENDIAN) { - return "wav"; - } - if (streamSoundCompression == SoundFormat.FORMAT_UNCOMPRESSED_NATIVE_ENDIAN) { - return "wav"; - } - if (streamSoundCompression == SoundFormat.FORMAT_NELLYMOSER || streamSoundCompression == SoundFormat.FORMAT_NELLYMOSER16KHZ || streamSoundCompression == SoundFormat.FORMAT_NELLYMOSER8KHZ) { - return "wav"; - } - return "flv"; - } - - @Override - public long getSoundSampleCount() { - return streamSoundSampleCount; - } - - @Override - public void setVirtualCharacterId(int ch) { - virtualCharacterId = ch; - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUB(4, reserved); - sos.writeUB(2, playBackSoundRate); - sos.writeUB(1, playBackSoundSize ? 1 : 0); - sos.writeUB(1, playBackSoundType ? 1 : 0); - sos.writeUB(4, streamSoundCompression); - sos.writeUB(2, streamSoundRate); - sos.writeUB(1, streamSoundSize ? 1 : 0); - sos.writeUB(1, streamSoundType ? 1 : 0); - sos.writeUI16(streamSoundSampleCount); - if (streamSoundCompression == 2) { - sos.writeSI16(latencySeek); - } - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - - /** - * Constructor - * - * @param swf - */ - public SoundStreamHead2Tag(SWF swf) { - super(swf, ID, "SoundStreamHead2", null); - } - - /** - * Constructor - * - * @param sis - * @param data - * @throws IOException - */ - public SoundStreamHead2Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "SoundStreamHead2", data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - reserved = (int) sis.readUB(4, "reserved"); - playBackSoundRate = (int) sis.readUB(2, "playBackSoundRate"); - playBackSoundSize = sis.readUB(1, "playBackSoundSize") == 1; - playBackSoundType = sis.readUB(1, "playBackSoundType") == 1; - streamSoundCompression = (int) sis.readUB(4, "streamSoundCompression"); - streamSoundRate = (int) sis.readUB(2, "streamSoundRate"); - streamSoundSize = sis.readUB(1, "streamSoundSize") == 1; - streamSoundType = sis.readUB(1, "streamSoundType") == 1; - streamSoundSampleCount = sis.readUI16("streamSoundSampleCount"); - if (streamSoundCompression == 2) { - latencySeek = sis.readSI16("latencySeek"); - } - } - - @Override - public int getSoundFormatId() { - return streamSoundCompression; - } - - @Override - public int getSoundRate() { - return streamSoundRate; - } - - @Override - public boolean getSoundSize() { - return streamSoundSize; - } - - @Override - public boolean getSoundType() { - return streamSoundType; - } - - @Override - public List getBlocks() { - List ret = new ArrayList<>(); - SoundStreamHeadTag.populateSoundStreamBlocks(0, swf.tags, this, ret); - return ret; - - } - - @Override - public boolean importSupported() { - return false; - } - - @Override - public boolean setSound(InputStream is, int newSoundFormat) { - return false; - } - - @Override - public List getRawSoundData() { - List ret = new ArrayList<>(); - List blocks = getBlocks(); - for (SoundStreamBlockTag block : blocks) { - if (streamSoundCompression == SoundFormat.FORMAT_MP3) { - ret.add(block.streamSoundData.getRangeData(4, block.streamSoundData.getLength() - 4)); - } else { - ret.add(block.streamSoundData.getRangeData()); - } - } - return ret; - } - - @Override - public long getTotalSoundSampleCount() { - return getBlocks().size() * streamSoundSampleCount; - } - - @Override - public SoundFormat getSoundFormat() { - final int[] rateMap = {5512, 11025, 22050, 44100}; - return new SoundFormat(getSoundFormatId(), rateMap[getSoundRate()], getSoundType()); - } - - @Override - public String getCharacterExportFileName() { - String exportName = swf.getExportName(getCharacterId()); - return getCharacterId() + (exportName != null ? "_" + exportName : ""); - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.tags.base.SoundStreamHeadTypeTag; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.annotations.Conditional; +import com.jpexs.decompiler.flash.types.annotations.Internal; +import com.jpexs.decompiler.flash.types.annotations.Reserved; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.decompiler.flash.types.sound.SoundFormat; +import com.jpexs.helpers.ByteArrayRange; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; + +/** + * + * + * @author JPEXS + */ +public class SoundStreamHead2Tag extends Tag implements SoundStreamHeadTypeTag { + + @Reserved + @SWFType(value = BasicType.UB, count = 4) + public int reserved; + + @SWFType(value = BasicType.UB, count = 2) + public int playBackSoundRate; + + public boolean playBackSoundSize; + + public boolean playBackSoundType; + + @SWFType(value = BasicType.UB, count = 4) + public int streamSoundCompression; + + @SWFType(value = BasicType.UB, count = 2) + public int streamSoundRate; + + public boolean streamSoundSize; + + public boolean streamSoundType; + + @SWFType(BasicType.UI16) + public int streamSoundSampleCount; + + @SWFType(BasicType.SI16) + @Conditional(value = "streamSoundCompression", options = {2}) + public int latencySeek; + + @Internal + private int virtualCharacterId = 0; + + public static final int ID = 45; + + public static final String NAME = "SoundStreamHead2"; + + @Override + public int getCharacterId() { + return virtualCharacterId; + } + + @Override + public void setCharacterId(int characterId) { + virtualCharacterId = characterId; + } + + @Override + public String getExportFormat() { + if (streamSoundCompression == SoundFormat.FORMAT_MP3) { + return "mp3"; + } + if (streamSoundCompression == SoundFormat.FORMAT_ADPCM) { + return "wav"; + } + if (streamSoundCompression == SoundFormat.FORMAT_UNCOMPRESSED_LITTLE_ENDIAN) { + return "wav"; + } + if (streamSoundCompression == SoundFormat.FORMAT_UNCOMPRESSED_NATIVE_ENDIAN) { + return "wav"; + } + if (streamSoundCompression == SoundFormat.FORMAT_NELLYMOSER || streamSoundCompression == SoundFormat.FORMAT_NELLYMOSER16KHZ || streamSoundCompression == SoundFormat.FORMAT_NELLYMOSER8KHZ) { + return "wav"; + } + return "flv"; + } + + @Override + public long getSoundSampleCount() { + return streamSoundSampleCount; + } + + @Override + public void setVirtualCharacterId(int ch) { + virtualCharacterId = ch; + } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUB(4, reserved); + sos.writeUB(2, playBackSoundRate); + sos.writeUB(1, playBackSoundSize ? 1 : 0); + sos.writeUB(1, playBackSoundType ? 1 : 0); + sos.writeUB(4, streamSoundCompression); + sos.writeUB(2, streamSoundRate); + sos.writeUB(1, streamSoundSize ? 1 : 0); + sos.writeUB(1, streamSoundType ? 1 : 0); + sos.writeUI16(streamSoundSampleCount); + if (streamSoundCompression == 2) { + sos.writeSI16(latencySeek); + } + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + /** + * Constructor + * + * @param swf + */ + public SoundStreamHead2Tag(SWF swf) { + super(swf, ID, NAME, null); + } + + /** + * Constructor + * + * @param sis + * @param data + * @throws IOException + */ + public SoundStreamHead2Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + reserved = (int) sis.readUB(4, "reserved"); + playBackSoundRate = (int) sis.readUB(2, "playBackSoundRate"); + playBackSoundSize = sis.readUB(1, "playBackSoundSize") == 1; + playBackSoundType = sis.readUB(1, "playBackSoundType") == 1; + streamSoundCompression = (int) sis.readUB(4, "streamSoundCompression"); + streamSoundRate = (int) sis.readUB(2, "streamSoundRate"); + streamSoundSize = sis.readUB(1, "streamSoundSize") == 1; + streamSoundType = sis.readUB(1, "streamSoundType") == 1; + streamSoundSampleCount = sis.readUI16("streamSoundSampleCount"); + if (streamSoundCompression == 2) { + latencySeek = sis.readSI16("latencySeek"); + } + } + + @Override + public int getSoundFormatId() { + return streamSoundCompression; + } + + @Override + public int getSoundRate() { + return streamSoundRate; + } + + @Override + public boolean getSoundSize() { + return streamSoundSize; + } + + @Override + public boolean getSoundType() { + return streamSoundType; + } + + @Override + public List getBlocks() { + List ret = new ArrayList<>(); + SoundStreamHeadTag.populateSoundStreamBlocks(0, swf.tags, this, ret); + return ret; + + } + + @Override + public boolean importSupported() { + return false; + } + + @Override + public boolean setSound(InputStream is, int newSoundFormat) { + return false; + } + + @Override + public List getRawSoundData() { + List ret = new ArrayList<>(); + List blocks = getBlocks(); + for (SoundStreamBlockTag block : blocks) { + if (streamSoundCompression == SoundFormat.FORMAT_MP3) { + ret.add(block.streamSoundData.getRangeData(4, block.streamSoundData.getLength() - 4)); + } else { + ret.add(block.streamSoundData.getRangeData()); + } + } + return ret; + } + + @Override + public long getTotalSoundSampleCount() { + return getBlocks().size() * streamSoundSampleCount; + } + + @Override + public SoundFormat getSoundFormat() { + final int[] rateMap = {5512, 11025, 22050, 44100}; + return new SoundFormat(getSoundFormatId(), rateMap[getSoundRate()], getSoundType()); + } + + @Override + public String getCharacterExportFileName() { + String exportName = swf.getExportName(getCharacterId()); + return getCharacterId() + (exportName != null ? "_" + exportName : ""); + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHeadTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHeadTag.java index 771974259..22c1e44fe 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHeadTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHeadTag.java @@ -1,274 +1,276 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.tags.base.SoundStreamHeadTypeTag; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.annotations.Conditional; -import com.jpexs.decompiler.flash.types.annotations.Internal; -import com.jpexs.decompiler.flash.types.annotations.Reserved; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.decompiler.flash.types.sound.SoundFormat; -import com.jpexs.helpers.ByteArrayRange; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; - -/** - * - * - * @author JPEXS - */ -public class SoundStreamHeadTag extends Tag implements SoundStreamHeadTypeTag { - - @Reserved - @SWFType(value = BasicType.UB, count = 4) - public int reserved; - - @SWFType(value = BasicType.UB, count = 2) - public int playBackSoundRate; - - public boolean playBackSoundSize; - - public boolean playBackSoundType; - - @SWFType(value = BasicType.UB, count = 4) - public int streamSoundCompression; - - @SWFType(value = BasicType.UB, count = 2) - public int streamSoundRate; - - public boolean streamSoundSize; - - public boolean streamSoundType; - - @SWFType(value = BasicType.UI16) - public int streamSoundSampleCount; - - @Conditional(value = "streamSoundCompression", options = {2}) - public int latencySeek; - - @Internal - private int virtualCharacterId = 0; - - public static final int ID = 18; - - @Override - public String getExportFormat() { - if (streamSoundCompression == SoundFormat.FORMAT_MP3) { - return "mp3"; - } - if (streamSoundCompression == SoundFormat.FORMAT_ADPCM) { - return "wav"; - } - if (streamSoundCompression == SoundFormat.FORMAT_UNCOMPRESSED_LITTLE_ENDIAN) { - return "wav"; - } - if (streamSoundCompression == SoundFormat.FORMAT_UNCOMPRESSED_NATIVE_ENDIAN) { - return "wav"; - } - if (streamSoundCompression == SoundFormat.FORMAT_NELLYMOSER || streamSoundCompression == SoundFormat.FORMAT_NELLYMOSER16KHZ || streamSoundCompression == SoundFormat.FORMAT_NELLYMOSER8KHZ) { - return "wav"; - } - return "flv"; - } - - @Override - public int getCharacterId() { - return virtualCharacterId; - } - - @Override - public void setCharacterId(int characterId) { - virtualCharacterId = characterId; - } - - @Override - public void setVirtualCharacterId(int ch) { - virtualCharacterId = ch; - } - - @Override - public long getSoundSampleCount() { - return streamSoundSampleCount; - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUB(4, reserved); - sos.writeUB(2, playBackSoundRate); - sos.writeUB(1, playBackSoundSize ? 1 : 0); - sos.writeUB(1, playBackSoundType ? 1 : 0); - sos.writeUB(4, streamSoundCompression); - sos.writeUB(2, streamSoundRate); - sos.writeUB(1, streamSoundSize ? 1 : 0); - sos.writeUB(1, streamSoundType ? 1 : 0); - sos.writeUI16(streamSoundSampleCount); - if (streamSoundCompression == 2) { - sos.writeSI16(latencySeek); - } - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - - /** - * Constructor - * - * @param swf - */ - public SoundStreamHeadTag(SWF swf) { - super(swf, ID, "SoundStreamHead", null); - } - - /** - * Constructor - * - * @param sis - * @param data - * @throws IOException - */ - public SoundStreamHeadTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "SoundStreamHead", data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - reserved = (int) sis.readUB(4, "reserved"); - playBackSoundRate = (int) sis.readUB(2, "playBackSoundRate"); - playBackSoundSize = sis.readUB(1, "playBackSoundSize") == 1; - playBackSoundType = sis.readUB(1, "playBackSoundType") == 1; - streamSoundCompression = (int) sis.readUB(4, "streamSoundCompression"); - streamSoundRate = (int) sis.readUB(2, "streamSoundRate"); - streamSoundSize = sis.readUB(1, "streamSoundSize") == 1; - streamSoundType = sis.readUB(1, "streamSoundType") == 1; - streamSoundSampleCount = sis.readUI16("streamSoundSampleCount"); - if (streamSoundCompression == 2) { - latencySeek = sis.readSI16("latencySeek"); - } - } - - @Override - public int getSoundFormatId() { - return streamSoundCompression; - } - - @Override - public int getSoundRate() { - return streamSoundRate; - } - - @Override - public boolean getSoundSize() { - return streamSoundSize; - } - - @Override - public boolean getSoundType() { - return streamSoundType; - } - - public static void populateSoundStreamBlocks(int containerId, List tags, SoundStreamHeadTypeTag head, List output) { - boolean found = false; - for (Tag t : tags) { - if (t == head) { - found = true; - head.setVirtualCharacterId(containerId); - continue; - } - if (t instanceof DefineSpriteTag) { - DefineSpriteTag sprite = (DefineSpriteTag) t; - populateSoundStreamBlocks(sprite.getCharacterId(), sprite.getSubTags(), head, output); - } - if (!found) { - continue; - } - if (t instanceof SoundStreamBlockTag) { - output.add((SoundStreamBlockTag) t); - } - if (t instanceof SoundStreamHeadTypeTag) { - break; - } - } - } - - @Override - public List getBlocks() { - List ret = new ArrayList<>(); - populateSoundStreamBlocks(0, swf.tags, this, ret); - return ret; - - } - - @Override - public boolean importSupported() { - return false; - } - - @Override - public boolean setSound(InputStream is, int newSoundFormat) { - return false; - } - - @Override - public List getRawSoundData() { - List ret = new ArrayList<>(); - List blocks = getBlocks(); - for (SoundStreamBlockTag block : blocks) { - if (streamSoundCompression == SoundFormat.FORMAT_MP3) { - ret.add(block.streamSoundData.getRangeData(4, block.streamSoundData.getLength() - 4)); - } else { - ret.add(block.streamSoundData.getRangeData()); - } - } - return ret; - } - - @Override - public long getTotalSoundSampleCount() { - return getBlocks().size() * streamSoundSampleCount; - } - - @Override - public SoundFormat getSoundFormat() { - final int[] rateMap = {5512, 11025, 22050, 44100}; - return new SoundFormat(getSoundFormatId(), rateMap[getSoundRate()], getSoundType()); - } - - @Override - public String getCharacterExportFileName() { - String exportName = swf.getExportName(getCharacterId()); - return getCharacterId() + (exportName != null ? "_" + exportName : ""); - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.tags.base.SoundStreamHeadTypeTag; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.annotations.Conditional; +import com.jpexs.decompiler.flash.types.annotations.Internal; +import com.jpexs.decompiler.flash.types.annotations.Reserved; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.decompiler.flash.types.sound.SoundFormat; +import com.jpexs.helpers.ByteArrayRange; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; + +/** + * + * + * @author JPEXS + */ +public class SoundStreamHeadTag extends Tag implements SoundStreamHeadTypeTag { + + @Reserved + @SWFType(value = BasicType.UB, count = 4) + public int reserved; + + @SWFType(value = BasicType.UB, count = 2) + public int playBackSoundRate; + + public boolean playBackSoundSize; + + public boolean playBackSoundType; + + @SWFType(value = BasicType.UB, count = 4) + public int streamSoundCompression; + + @SWFType(value = BasicType.UB, count = 2) + public int streamSoundRate; + + public boolean streamSoundSize; + + public boolean streamSoundType; + + @SWFType(value = BasicType.UI16) + public int streamSoundSampleCount; + + @Conditional(value = "streamSoundCompression", options = {2}) + public int latencySeek; + + @Internal + private int virtualCharacterId = 0; + + public static final int ID = 18; + + public static final String NAME = "SoundStreamHead"; + + @Override + public String getExportFormat() { + if (streamSoundCompression == SoundFormat.FORMAT_MP3) { + return "mp3"; + } + if (streamSoundCompression == SoundFormat.FORMAT_ADPCM) { + return "wav"; + } + if (streamSoundCompression == SoundFormat.FORMAT_UNCOMPRESSED_LITTLE_ENDIAN) { + return "wav"; + } + if (streamSoundCompression == SoundFormat.FORMAT_UNCOMPRESSED_NATIVE_ENDIAN) { + return "wav"; + } + if (streamSoundCompression == SoundFormat.FORMAT_NELLYMOSER || streamSoundCompression == SoundFormat.FORMAT_NELLYMOSER16KHZ || streamSoundCompression == SoundFormat.FORMAT_NELLYMOSER8KHZ) { + return "wav"; + } + return "flv"; + } + + @Override + public int getCharacterId() { + return virtualCharacterId; + } + + @Override + public void setCharacterId(int characterId) { + virtualCharacterId = characterId; + } + + @Override + public void setVirtualCharacterId(int ch) { + virtualCharacterId = ch; + } + + @Override + public long getSoundSampleCount() { + return streamSoundSampleCount; + } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUB(4, reserved); + sos.writeUB(2, playBackSoundRate); + sos.writeUB(1, playBackSoundSize ? 1 : 0); + sos.writeUB(1, playBackSoundType ? 1 : 0); + sos.writeUB(4, streamSoundCompression); + sos.writeUB(2, streamSoundRate); + sos.writeUB(1, streamSoundSize ? 1 : 0); + sos.writeUB(1, streamSoundType ? 1 : 0); + sos.writeUI16(streamSoundSampleCount); + if (streamSoundCompression == 2) { + sos.writeSI16(latencySeek); + } + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + /** + * Constructor + * + * @param swf + */ + public SoundStreamHeadTag(SWF swf) { + super(swf, ID, NAME, null); + } + + /** + * Constructor + * + * @param sis + * @param data + * @throws IOException + */ + public SoundStreamHeadTag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + reserved = (int) sis.readUB(4, "reserved"); + playBackSoundRate = (int) sis.readUB(2, "playBackSoundRate"); + playBackSoundSize = sis.readUB(1, "playBackSoundSize") == 1; + playBackSoundType = sis.readUB(1, "playBackSoundType") == 1; + streamSoundCompression = (int) sis.readUB(4, "streamSoundCompression"); + streamSoundRate = (int) sis.readUB(2, "streamSoundRate"); + streamSoundSize = sis.readUB(1, "streamSoundSize") == 1; + streamSoundType = sis.readUB(1, "streamSoundType") == 1; + streamSoundSampleCount = sis.readUI16("streamSoundSampleCount"); + if (streamSoundCompression == 2) { + latencySeek = sis.readSI16("latencySeek"); + } + } + + @Override + public int getSoundFormatId() { + return streamSoundCompression; + } + + @Override + public int getSoundRate() { + return streamSoundRate; + } + + @Override + public boolean getSoundSize() { + return streamSoundSize; + } + + @Override + public boolean getSoundType() { + return streamSoundType; + } + + public static void populateSoundStreamBlocks(int containerId, List tags, SoundStreamHeadTypeTag head, List output) { + boolean found = false; + for (Tag t : tags) { + if (t == head) { + found = true; + head.setVirtualCharacterId(containerId); + continue; + } + if (t instanceof DefineSpriteTag) { + DefineSpriteTag sprite = (DefineSpriteTag) t; + populateSoundStreamBlocks(sprite.getCharacterId(), sprite.getSubTags(), head, output); + } + if (!found) { + continue; + } + if (t instanceof SoundStreamBlockTag) { + output.add((SoundStreamBlockTag) t); + } + if (t instanceof SoundStreamHeadTypeTag) { + break; + } + } + } + + @Override + public List getBlocks() { + List ret = new ArrayList<>(); + populateSoundStreamBlocks(0, swf.tags, this, ret); + return ret; + + } + + @Override + public boolean importSupported() { + return false; + } + + @Override + public boolean setSound(InputStream is, int newSoundFormat) { + return false; + } + + @Override + public List getRawSoundData() { + List ret = new ArrayList<>(); + List blocks = getBlocks(); + for (SoundStreamBlockTag block : blocks) { + if (streamSoundCompression == SoundFormat.FORMAT_MP3) { + ret.add(block.streamSoundData.getRangeData(4, block.streamSoundData.getLength() - 4)); + } else { + ret.add(block.streamSoundData.getRangeData()); + } + } + return ret; + } + + @Override + public long getTotalSoundSampleCount() { + return getBlocks().size() * streamSoundSampleCount; + } + + @Override + public SoundFormat getSoundFormat() { + final int[] rateMap = {5512, 11025, 22050, 44100}; + return new SoundFormat(getSoundFormatId(), rateMap[getSoundRate()], getSoundType()); + } + + @Override + public String getCharacterExportFileName() { + String exportName = swf.getExportName(getCharacterId()); + return getCharacterId() + (exportName != null ? "_" + exportName : ""); + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/StartSound2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/StartSound2Tag.java index f0ef211af..d2e4f832f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/StartSound2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/StartSound2Tag.java @@ -26,7 +26,6 @@ import java.io.IOException; import java.io.OutputStream; /** - * * * @author JPEXS */ @@ -38,6 +37,8 @@ public class StartSound2Tag extends Tag { public static final int ID = 89; + public static final String NAME = "StartSound2"; + /** * Gets data bytes * @@ -63,7 +64,7 @@ public class StartSound2Tag extends Tag { * @param swf */ public StartSound2Tag(SWF swf) { - super(swf, ID, "StartSound2", null); + super(swf, ID, NAME, null); soundClassName = "NewSoundClass"; soundInfo = new SOUNDINFO(); } @@ -76,7 +77,7 @@ public class StartSound2Tag extends Tag { * @throws IOException */ public StartSound2Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "StartSound2", data); + super(sis.getSwf(), ID, NAME, data); readData(sis, data, 0, false, false, false); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/StartSoundTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/StartSoundTag.java index a6af6a494..6d7b5c2e5 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/StartSoundTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/StartSoundTag.java @@ -41,6 +41,8 @@ public class StartSoundTag extends Tag { public static final int ID = 15; + public static final String NAME = "StartSound"; + /** * Gets data bytes * @@ -66,7 +68,7 @@ public class StartSoundTag extends Tag { * @param swf */ public StartSoundTag(SWF swf) { - super(swf, ID, "StartSound", null); + super(swf, ID, NAME, null); soundInfo = new SOUNDINFO(); } @@ -78,7 +80,7 @@ public class StartSoundTag extends Tag { * @throws IOException */ public StartSoundTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "StartSound", data); + super(sis.getSwf(), ID, NAME, data); readData(sis, data, 0, false, false, false); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SymbolClassTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SymbolClassTag.java index 8432e2fe0..cf23f3c59 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SymbolClassTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SymbolClassTag.java @@ -41,19 +41,21 @@ public class SymbolClassTag extends SymbolClassTypeTag { public static final int ID = 76; + public static final String NAME = "SymbolClass"; + /** * Constructor * * @param swf */ public SymbolClassTag(SWF swf) { - super(swf, ID, "SymbolClass", null); + super(swf, ID, NAME, null); tags = new ArrayList<>(); names = new ArrayList<>(); } public SymbolClassTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "SymbolClass", data); + super(sis.getSwf(), ID, NAME, data); readData(sis, data, 0, false, false, false); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/Tag.java index 7763ca488..d4746c062 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/Tag.java @@ -1,622 +1,564 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.tags.base.Exportable; -import com.jpexs.decompiler.flash.tags.base.NeedsCharacters; -import com.jpexs.decompiler.flash.tags.gfx.DefineCompactedFont; -import com.jpexs.decompiler.flash.tags.gfx.DefineExternalGradient; -import com.jpexs.decompiler.flash.tags.gfx.DefineExternalImage; -import com.jpexs.decompiler.flash.tags.gfx.DefineExternalImage2; -import com.jpexs.decompiler.flash.tags.gfx.DefineExternalSound; -import com.jpexs.decompiler.flash.tags.gfx.DefineExternalStreamSound; -import com.jpexs.decompiler.flash.tags.gfx.DefineGradientMap; -import com.jpexs.decompiler.flash.tags.gfx.DefineSubImage; -import com.jpexs.decompiler.flash.tags.gfx.ExporterInfo; -import com.jpexs.decompiler.flash.tags.gfx.FontTextureInfo; -import com.jpexs.decompiler.flash.timeline.Timelined; -import com.jpexs.decompiler.flash.types.annotations.Internal; -import com.jpexs.helpers.ByteArrayRange; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.Serializable; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * Represents Tag inside SWF file - */ -public abstract class Tag implements NeedsCharacters, Exportable, Serializable { - - /** - * Identifier of tag type - */ - protected int id; - - /** - * If true, then Tag is written to the stream as longer than 0x3f even if it - * is not - */ - @Internal - public boolean forceWriteAsLong = false; - - protected String tagName; - - @Internal - protected transient SWF swf; - - @Internal - protected transient Timelined timelined; - - @Internal - private boolean modified; - - /** - * Original tag data - */ - @Internal - private ByteArrayRange originalRange; - - private final HashSet listeners = new HashSet<>(); - - public String getTagName() { - return tagName; - } - - public String getName() { - return tagName; - } - - @Override - public String getExportFileName() { - return tagName; - } - - /** - * Returns identifier of tag type - * - * @return Identifier of tag type - */ - public int getId() { - return id; - } - - @Override - public SWF getSwf() { - return swf; - } - - public void setSwf(SWF swf) { - setSwf(swf, false); - } - - public void setSwf(SWF swf, boolean deep) { - this.swf = swf; - if (deep) { - if (this instanceof DefineSpriteTag) { - DefineSpriteTag sprite = (DefineSpriteTag) this; - for (Tag subTag : sprite.subTags) { - subTag.setSwf(swf); - } - } - } - } - - public Timelined getTimelined() { - return timelined; - } - - public void setTimelined(Timelined timelined) { - this.timelined = timelined; - } - - /** - * Constructor - * - * @param swf The SWF - * @param id Tag type identifier - * @param name Tag name - * @param data Original tag data - */ - public Tag(SWF swf, int id, String name, ByteArrayRange data) { - this.id = id; - this.tagName = name; - this.originalRange = data; - this.swf = swf; - if (swf == null) { - throw new Error("swf parameter cannot be null."); - } - if (data == null) { // it is tag build by constructor - modified = true; - } - } - - public abstract void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException, InterruptedException; - - private static final Object lockObject = new Object(); - - private volatile static List knownTagIds; - - private volatile static Map knownTagClasses; - - private volatile static List requiredTagIds; - - public static List getKnownTags() { - if (knownTagIds == null) { - synchronized (lockObject) { - if (knownTagIds == null) { - List tagIds = Arrays.asList( - CSMTextSettingsTag.ID, - DebugIDTag.ID, - DefineBinaryDataTag.ID, - DefineBitsJPEG2Tag.ID, - DefineBitsJPEG3Tag.ID, - DefineBitsJPEG4Tag.ID, - DefineBitsLossless2Tag.ID, - DefineBitsLosslessTag.ID, - DefineBitsTag.ID, - DefineButton2Tag.ID, - DefineButtonCxformTag.ID, - DefineButtonSoundTag.ID, - DefineButtonTag.ID, - DefineEditTextTag.ID, - DefineFont2Tag.ID, - DefineFont3Tag.ID, - DefineFont4Tag.ID, - DefineFontAlignZonesTag.ID, - DefineFontInfo2Tag.ID, - DefineFontInfoTag.ID, - DefineFontNameTag.ID, - DefineFontTag.ID, - DefineMorphShape2Tag.ID, - DefineMorphShapeTag.ID, - DefineScalingGridTag.ID, - DefineSceneAndFrameLabelDataTag.ID, - DefineShape2Tag.ID, - DefineShape3Tag.ID, - DefineShape4Tag.ID, - DefineShapeTag.ID, - DefineSoundTag.ID, - DefineSpriteTag.ID, - DefineText2Tag.ID, - DefineTextTag.ID, - DefineVideoStreamTag.ID, - DoABCDefineTag.ID, - DoABCTag.ID, - DoActionTag.ID, - DoInitActionTag.ID, - EnableDebugger2Tag.ID, - EnableDebuggerTag.ID, - EnableTelemetryTag.ID, - EndTag.ID, - ExportAssetsTag.ID, - FileAttributesTag.ID, - FrameLabelTag.ID, - ImportAssets2Tag.ID, - ImportAssetsTag.ID, - JPEGTablesTag.ID, - MetadataTag.ID, - PlaceObject2Tag.ID, - PlaceObject3Tag.ID, - PlaceObject4Tag.ID, - PlaceObjectTag.ID, - ProductInfoTag.ID, - ProtectTag.ID, - RemoveObject2Tag.ID, - RemoveObjectTag.ID, - ScriptLimitsTag.ID, - SetBackgroundColorTag.ID, - SetTabIndexTag.ID, - ShowFrameTag.ID, - SoundStreamBlockTag.ID, - SoundStreamHead2Tag.ID, - SoundStreamHeadTag.ID, - StartSound2Tag.ID, - StartSoundTag.ID, - SymbolClassTag.ID, - VideoFrameTag.ID, - DefineCompactedFont.ID, - DefineExternalGradient.ID, - DefineExternalImage.ID, - DefineExternalImage2.ID, - DefineExternalSound.ID, - DefineExternalStreamSound.ID, - DefineGradientMap.ID, - DefineSubImage.ID, - ExporterInfo.ID, - FontTextureInfo.ID); - knownTagIds = tagIds; - } - } - } - return knownTagIds; - } - - public static Map getKnownClasses() { - if (knownTagClasses == null) { - synchronized (lockObject) { - if (knownTagClasses == null) { - Map map = new HashMap<>(); - map.put(CSMTextSettingsTag.ID, CSMTextSettingsTag.class); - map.put(DebugIDTag.ID, DebugIDTag.class); - map.put(DefineBinaryDataTag.ID, DefineBinaryDataTag.class); - map.put(DefineBitsJPEG2Tag.ID, DefineBitsJPEG2Tag.class); - map.put(DefineBitsJPEG3Tag.ID, DefineBitsJPEG3Tag.class); - map.put(DefineBitsJPEG4Tag.ID, DefineBitsJPEG4Tag.class); - map.put(DefineBitsLossless2Tag.ID, DefineBitsLossless2Tag.class); - map.put(DefineBitsLosslessTag.ID, DefineBitsLosslessTag.class); - map.put(DefineBitsTag.ID, DefineBitsTag.class); - map.put(DefineButton2Tag.ID, DefineButton2Tag.class); - map.put(DefineButtonCxformTag.ID, DefineButtonCxformTag.class); - map.put(DefineButtonSoundTag.ID, DefineButtonSoundTag.class); - map.put(DefineButtonTag.ID, DefineButtonTag.class); - map.put(DefineEditTextTag.ID, DefineEditTextTag.class); - map.put(DefineFont2Tag.ID, DefineFont2Tag.class); - map.put(DefineFont3Tag.ID, DefineFont3Tag.class); - map.put(DefineFont4Tag.ID, DefineFont4Tag.class); - map.put(DefineFontAlignZonesTag.ID, DefineFontAlignZonesTag.class); - map.put(DefineFontInfo2Tag.ID, DefineFontInfo2Tag.class); - map.put(DefineFontInfoTag.ID, DefineFontInfoTag.class); - map.put(DefineFontNameTag.ID, DefineFontNameTag.class); - map.put(DefineFontTag.ID, DefineFontTag.class); - map.put(DefineMorphShape2Tag.ID, DefineMorphShape2Tag.class); - map.put(DefineMorphShapeTag.ID, DefineMorphShapeTag.class); - map.put(DefineScalingGridTag.ID, DefineScalingGridTag.class); - map.put(DefineSceneAndFrameLabelDataTag.ID, DefineSceneAndFrameLabelDataTag.class); - map.put(DefineShape2Tag.ID, DefineShape2Tag.class); - map.put(DefineShape3Tag.ID, DefineShape3Tag.class); - map.put(DefineShape4Tag.ID, DefineShape4Tag.class); - map.put(DefineShapeTag.ID, DefineShapeTag.class); - map.put(DefineSoundTag.ID, DefineSoundTag.class); - map.put(DefineSpriteTag.ID, DefineSpriteTag.class); - map.put(DefineText2Tag.ID, DefineText2Tag.class); - map.put(DefineTextTag.ID, DefineTextTag.class); - map.put(DefineVideoStreamTag.ID, DefineVideoStreamTag.class); - map.put(DoABCDefineTag.ID, DoABCDefineTag.class); - map.put(DoABCTag.ID, DoABCTag.class); - map.put(DoActionTag.ID, DoActionTag.class); - map.put(DoInitActionTag.ID, DoInitActionTag.class); - map.put(EnableDebugger2Tag.ID, EnableDebugger2Tag.class); - map.put(EnableDebuggerTag.ID, EnableDebuggerTag.class); - map.put(EnableTelemetryTag.ID, EnableTelemetryTag.class); - map.put(EndTag.ID, EndTag.class); - map.put(ExportAssetsTag.ID, ExportAssetsTag.class); - map.put(FileAttributesTag.ID, FileAttributesTag.class); - map.put(FrameLabelTag.ID, FrameLabelTag.class); - map.put(ImportAssets2Tag.ID, ImportAssets2Tag.class); - map.put(ImportAssetsTag.ID, ImportAssetsTag.class); - map.put(JPEGTablesTag.ID, JPEGTablesTag.class); - map.put(MetadataTag.ID, MetadataTag.class); - map.put(PlaceObject2Tag.ID, PlaceObject2Tag.class); - map.put(PlaceObject3Tag.ID, PlaceObject3Tag.class); - map.put(PlaceObject4Tag.ID, PlaceObject4Tag.class); - map.put(PlaceObjectTag.ID, PlaceObjectTag.class); - map.put(ProductInfoTag.ID, ProductInfoTag.class); - map.put(ProtectTag.ID, ProtectTag.class); - map.put(RemoveObject2Tag.ID, RemoveObject2Tag.class); - map.put(RemoveObjectTag.ID, RemoveObjectTag.class); - map.put(ScriptLimitsTag.ID, ScriptLimitsTag.class); - map.put(SetBackgroundColorTag.ID, SetBackgroundColorTag.class); - map.put(SetTabIndexTag.ID, SetTabIndexTag.class); - map.put(ShowFrameTag.ID, ShowFrameTag.class); - map.put(SoundStreamBlockTag.ID, SoundStreamBlockTag.class); - map.put(SoundStreamHead2Tag.ID, SoundStreamHead2Tag.class); - map.put(SoundStreamHeadTag.ID, SoundStreamHeadTag.class); - map.put(StartSound2Tag.ID, StartSound2Tag.class); - map.put(StartSoundTag.ID, StartSoundTag.class); - map.put(SymbolClassTag.ID, SymbolClassTag.class); - map.put(VideoFrameTag.ID, VideoFrameTag.class); - map.put(DefineCompactedFont.ID, DefineCompactedFont.class); - map.put(DefineExternalGradient.ID, DefineExternalGradient.class); - map.put(DefineExternalImage.ID, DefineExternalImage.class); - map.put(DefineExternalImage2.ID, DefineExternalImage2.class); - map.put(DefineExternalSound.ID, DefineExternalSound.class); - map.put(DefineExternalStreamSound.ID, DefineExternalStreamSound.class); - map.put(DefineGradientMap.ID, DefineGradientMap.class); - map.put(DefineSubImage.ID, DefineSubImage.class); - map.put(ExporterInfo.ID, ExporterInfo.class); - map.put(FontTextureInfo.ID, FontTextureInfo.class); - knownTagClasses = map; - } - } - } - return knownTagClasses; - } - - public static List getRequiredTags() { - if (requiredTagIds == null) { - synchronized (lockObject) { - if (requiredTagIds == null) { - List tagIds = Arrays.asList( - DefineBinaryDataTag.ID, - DefineBitsJPEG2Tag.ID, - DefineBitsJPEG3Tag.ID, - DefineBitsJPEG4Tag.ID, - DefineBitsLossless2Tag.ID, - DefineBitsLosslessTag.ID, - DefineBitsTag.ID, - DefineButton2Tag.ID, - DefineButtonCxformTag.ID, - DefineButtonSoundTag.ID, - DefineButtonTag.ID, - DefineEditTextTag.ID, - DefineFont2Tag.ID, - DefineFont3Tag.ID, - DefineFont4Tag.ID, - DefineFontAlignZonesTag.ID, - DefineFontInfo2Tag.ID, - DefineFontInfoTag.ID, - DefineFontNameTag.ID, - DefineFontTag.ID, - DefineMorphShape2Tag.ID, - DefineMorphShapeTag.ID, - DefineScalingGridTag.ID, - DefineSceneAndFrameLabelDataTag.ID, - DefineShape2Tag.ID, - DefineShape3Tag.ID, - DefineShape4Tag.ID, - DefineShapeTag.ID, - DefineSoundTag.ID, - DefineSpriteTag.ID, - DefineText2Tag.ID, - DefineTextTag.ID, - DefineVideoStreamTag.ID, - DoABCDefineTag.ID, - DoABCTag.ID, - DoActionTag.ID, - DoInitActionTag.ID, - ShowFrameTag.ID); - requiredTagIds = tagIds; - } - } - } - return requiredTagIds; - } - - public int getVersion() { - if (swf == null) { - return SWF.DEFAULT_VERSION; - } - return swf.version; - } - - protected byte[] getHeader(byte[] data) { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try { - - SWFOutputStream sos = new SWFOutputStream(baos, swf.version); - int tagLength = data.length; - int tagID = getId(); - int tagIDLength = (tagID << 6); - if ((tagLength <= 62) && (!forceWriteAsLong)) { - tagIDLength += tagLength; - sos.writeUI16(tagIDLength); - } else { - tagIDLength += 0x3f; - sos.writeUI16(tagIDLength); - sos.writeSI32(tagLength); - } - } catch (IOException iex) { - throw new Error("This should never happen.", iex); - } - return baos.toByteArray(); - } - - public static byte[] getTagHeader(int tagIDTagLength, long tagLength, boolean writeLong, int version) { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try { - - SWFOutputStream sos = new SWFOutputStream(baos, version); - sos.writeUI16(tagIDTagLength); - if (writeLong) { - sos.writeSI32(tagLength); - } - } catch (IOException iex) { - throw new Error("This should never happen.", iex); - } - return baos.toByteArray(); - } - - /** - * Writes Tag value to the stream - * - * @param sos SWF output stream - * @throws IOException - */ - public void writeTag(SWFOutputStream sos) throws IOException { - if (isModified()) { - byte[] newData = getData(); - byte[] newHeaderData = getHeader(newData); - sos.write(newHeaderData); - sos.write(newData); - } else { - sos.write(originalRange.getArray(), originalRange.getPos(), originalRange.getLength()); - } - } - - public Tag cloneTag() throws InterruptedException, IOException { - byte[] data = getData(); - SWFInputStream tagDataStream = new SWFInputStream(swf, data, getDataPos(), data.length); - TagStub copy = new TagStub(swf, getId(), "Unresolved", getOriginalRange(), tagDataStream); - copy.forceWriteAsLong = forceWriteAsLong; - return SWFInputStream.resolveTag(copy, 0, false, true, false); - } - - public Tag getOriginalTag() throws InterruptedException, IOException { - byte[] data = getOriginalData(); - SWFInputStream tagDataStream = new SWFInputStream(swf, data, getDataPos(), data.length); - TagStub copy = new TagStub(swf, getId(), "Unresolved", getOriginalRange(), tagDataStream); - copy.forceWriteAsLong = forceWriteAsLong; - return SWFInputStream.resolveTag(copy, 0, false, true, false); - } - - public void undo() throws InterruptedException, IOException { - byte[] data = getOriginalData(); - SWFInputStream tagDataStream = new SWFInputStream(swf, data, getDataPos(), data.length); - readData(tagDataStream, getOriginalRange(), 0, false, true, false); - setModified(false); - } - - /** - * Returns string representation of the object - * - * @return String representation of the object - */ - @Override - public String toString() { - return getName(); - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - public abstract byte[] getData(); - - public final ByteArrayRange getOriginalRange() { - return originalRange; - } - - /** - * Returns the original inner data of the tag, without the 2-6 bytes length - * header Call this method only from debug codes - * - * @return The data - */ - public final byte[] getOriginalData() { - if (originalRange == null) { - return null; - } - - int dataLength = getOriginalDataLength(); - int pos = (int) (originalRange.getPos() + originalRange.getLength() - dataLength); - - byte[] data = new byte[dataLength]; - System.arraycopy(originalRange.getArray(), pos, data, 0, dataLength); - return data; - } - - public final int getOriginalDataLength() { - if (originalRange == null) { - return 0; - } - - return originalRange.getLength() - (isLongOriginal() ? 6 : 2); - } - - private boolean isLongOriginal() { - int shortLength = originalRange.getArray()[(int) originalRange.getPos()] & 0x003F; - return shortLength == 0x3f; - } - - public long getPos() { - if (originalRange == null) { - return -1; - } - - return originalRange.getPos(); - } - - public long getDataPos() { - if (originalRange == null) { - return -1; - } - - return originalRange.getPos() + (isLongOriginal() ? 6 : 2); - } - - public void setModified(boolean value) { - modified = value; - if (value) { - informListeners(); - } - } - - public final void addEventListener(TagChangedListener listener) { - listeners.add(listener); - } - - public final void removeEventListener(TagChangedListener listener) { - listeners.remove(listener); - } - - protected void informListeners() { - for (TagChangedListener listener : listeners) { - listener.handleEvent(this); - } - } - - public void createOriginalData() { - byte[] data = getData(); - byte[] headerData = getHeader(data); - byte[] tagData = new byte[data.length + headerData.length]; - System.arraycopy(headerData, 0, tagData, 0, headerData.length); - System.arraycopy(data, 0, tagData, headerData.length, data.length); - originalRange = new ByteArrayRange(tagData, 0, tagData.length); - } - - public boolean isModified() { - return modified; - } - - @Override - public void getNeededCharacters(Set needed) { - } - - @Override - public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { - return false; - } - - @Override - public boolean removeCharacter(int characterId) { - return false; - } - - public void getNeededCharactersDeep(Set needed) { - Set visited = new HashSet<>(); - Set needed2 = new LinkedHashSet<>(); - getNeededCharacters(needed2); - - while (visited.size() != needed2.size()) { - for (Integer characterId : needed2) { - if (!visited.contains(characterId)) { - visited.add(characterId); - if (swf.getCharacters().containsKey(characterId)) { - swf.getCharacter(characterId).getNeededCharacters(needed2); - break; - } - } - } - } - - for (Integer characterId : needed2) { - if (swf.getCharacters().containsKey(characterId)) { - needed.add(characterId); - } - } - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.tags.base.Exportable; +import com.jpexs.decompiler.flash.tags.base.NeedsCharacters; +import com.jpexs.decompiler.flash.tags.gfx.DefineCompactedFont; +import com.jpexs.decompiler.flash.tags.gfx.DefineExternalGradient; +import com.jpexs.decompiler.flash.tags.gfx.DefineExternalImage; +import com.jpexs.decompiler.flash.tags.gfx.DefineExternalImage2; +import com.jpexs.decompiler.flash.tags.gfx.DefineExternalSound; +import com.jpexs.decompiler.flash.tags.gfx.DefineExternalStreamSound; +import com.jpexs.decompiler.flash.tags.gfx.DefineGradientMap; +import com.jpexs.decompiler.flash.tags.gfx.DefineSubImage; +import com.jpexs.decompiler.flash.tags.gfx.ExporterInfo; +import com.jpexs.decompiler.flash.tags.gfx.FontTextureInfo; +import com.jpexs.decompiler.flash.timeline.Timelined; +import com.jpexs.decompiler.flash.types.annotations.Internal; +import com.jpexs.helpers.ByteArrayRange; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.Serializable; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Represents Tag inside SWF file + * + * @author JPEXS + */ +public abstract class Tag implements NeedsCharacters, Exportable, Serializable { + + /** + * Identifier of tag type + */ + protected int id; + + /** + * If true, then Tag is written to the stream as longer than 0x3f even if it + * is not + */ + @Internal + public boolean forceWriteAsLong = false; + + protected String tagName; + + @Internal + protected transient SWF swf; + + @Internal + protected transient Timelined timelined; + + @Internal + private boolean modified; + + /** + * Original tag data + */ + @Internal + private ByteArrayRange originalRange; + + private final HashSet listeners = new HashSet<>(); + + public String getTagName() { + return tagName; + } + + public String getName() { + return tagName; + } + + @Override + public String getExportFileName() { + return tagName; + } + + /** + * Returns identifier of tag type + * + * @return Identifier of tag type + */ + public int getId() { + return id; + } + + @Override + public SWF getSwf() { + return swf; + } + + public void setSwf(SWF swf) { + setSwf(swf, false); + } + + public void setSwf(SWF swf, boolean deep) { + this.swf = swf; + if (deep) { + if (this instanceof DefineSpriteTag) { + DefineSpriteTag sprite = (DefineSpriteTag) this; + for (Tag subTag : sprite.subTags) { + subTag.setSwf(swf); + } + } + } + } + + public Timelined getTimelined() { + return timelined; + } + + public void setTimelined(Timelined timelined) { + this.timelined = timelined; + } + + /** + * Constructor + * + * @param swf The SWF + * @param id Tag type identifier + * @param name Tag name + * @param data Original tag data + */ + public Tag(SWF swf, int id, String name, ByteArrayRange data) { + this.id = id; + this.tagName = name; + this.originalRange = data; + this.swf = swf; + if (swf == null) { + throw new Error("swf parameter cannot be null."); + } + if (data == null) { // it is tag build by constructor + modified = true; + } + } + + public abstract void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException, InterruptedException; + + private static final Object lockObject = new Object(); + + private volatile static Integer[] knownTagIds; + + private volatile static Map knownTagInfosById; + + private volatile static Map knownTagInfosByName; + + private volatile static List requiredTagIds; + + public static Integer[] getKnownTags() { + if (knownTagIds == null) { + synchronized (lockObject) { + if (knownTagIds == null) { + Set keySet = getKnownClasses().keySet(); + Integer[] tagIds = keySet.toArray(new Integer[keySet.size()]); + knownTagIds = tagIds; + } + } + } + return knownTagIds; + } + + public static Map getKnownClasses() { + if (knownTagInfosById == null) { + synchronized (lockObject) { + if (knownTagInfosById == null) { + Map map = new HashMap<>(); + Map map2 = new HashMap<>(); + addTagInfo(map, map2, CSMTextSettingsTag.ID, CSMTextSettingsTag.class, CSMTextSettingsTag.NAME); + addTagInfo(map, map2, DebugIDTag.ID, DebugIDTag.class, DebugIDTag.NAME); + addTagInfo(map, map2, DefineBinaryDataTag.ID, DefineBinaryDataTag.class, DefineBinaryDataTag.NAME); + addTagInfo(map, map2, DefineBitsJPEG2Tag.ID, DefineBitsJPEG2Tag.class, DefineBitsJPEG2Tag.NAME); + addTagInfo(map, map2, DefineBitsJPEG3Tag.ID, DefineBitsJPEG3Tag.class, DefineBitsJPEG3Tag.NAME); + addTagInfo(map, map2, DefineBitsJPEG4Tag.ID, DefineBitsJPEG4Tag.class, DefineBitsJPEG4Tag.NAME); + addTagInfo(map, map2, DefineBitsLossless2Tag.ID, DefineBitsLossless2Tag.class, DefineBitsLossless2Tag.NAME); + addTagInfo(map, map2, DefineBitsLosslessTag.ID, DefineBitsLosslessTag.class, DefineBitsLosslessTag.NAME); + addTagInfo(map, map2, DefineBitsTag.ID, DefineBitsTag.class, DefineBitsTag.NAME); + addTagInfo(map, map2, DefineButton2Tag.ID, DefineButton2Tag.class, DefineButton2Tag.NAME); + addTagInfo(map, map2, DefineButtonCxformTag.ID, DefineButtonCxformTag.class, DefineButtonCxformTag.NAME); + addTagInfo(map, map2, DefineButtonSoundTag.ID, DefineButtonSoundTag.class, DefineButtonSoundTag.NAME); + addTagInfo(map, map2, DefineButtonTag.ID, DefineButtonTag.class, DefineButtonTag.NAME); + addTagInfo(map, map2, DefineEditTextTag.ID, DefineEditTextTag.class, DefineEditTextTag.NAME); + addTagInfo(map, map2, DefineFont2Tag.ID, DefineFont2Tag.class, DefineFont2Tag.NAME); + addTagInfo(map, map2, DefineFont3Tag.ID, DefineFont3Tag.class, DefineFont3Tag.NAME); + addTagInfo(map, map2, DefineFont4Tag.ID, DefineFont4Tag.class, DefineFont4Tag.NAME); + addTagInfo(map, map2, DefineFontAlignZonesTag.ID, DefineFontAlignZonesTag.class, DefineFontAlignZonesTag.NAME); + addTagInfo(map, map2, DefineFontInfo2Tag.ID, DefineFontInfo2Tag.class, DefineFontInfo2Tag.NAME); + addTagInfo(map, map2, DefineFontInfoTag.ID, DefineFontInfoTag.class, DefineFontInfoTag.NAME); + addTagInfo(map, map2, DefineFontNameTag.ID, DefineFontNameTag.class, DefineFontNameTag.NAME); + addTagInfo(map, map2, DefineFontTag.ID, DefineFontTag.class, DefineFontTag.NAME); + addTagInfo(map, map2, DefineMorphShape2Tag.ID, DefineMorphShape2Tag.class, DefineMorphShape2Tag.NAME); + addTagInfo(map, map2, DefineMorphShapeTag.ID, DefineMorphShapeTag.class, DefineMorphShapeTag.NAME); + addTagInfo(map, map2, DefineScalingGridTag.ID, DefineScalingGridTag.class, DefineScalingGridTag.NAME); + addTagInfo(map, map2, DefineSceneAndFrameLabelDataTag.ID, DefineSceneAndFrameLabelDataTag.class, DefineSceneAndFrameLabelDataTag.NAME); + addTagInfo(map, map2, DefineShape2Tag.ID, DefineShape2Tag.class, DefineShape2Tag.NAME); + addTagInfo(map, map2, DefineShape3Tag.ID, DefineShape3Tag.class, DefineShape3Tag.NAME); + addTagInfo(map, map2, DefineShape4Tag.ID, DefineShape4Tag.class, DefineShape4Tag.NAME); + addTagInfo(map, map2, DefineShapeTag.ID, DefineShapeTag.class, DefineShapeTag.NAME); + addTagInfo(map, map2, DefineSoundTag.ID, DefineSoundTag.class, DefineSoundTag.NAME); + addTagInfo(map, map2, DefineSpriteTag.ID, DefineSpriteTag.class, DefineSpriteTag.NAME); + addTagInfo(map, map2, DefineText2Tag.ID, DefineText2Tag.class, DefineText2Tag.NAME); + addTagInfo(map, map2, DefineTextTag.ID, DefineTextTag.class, DefineTextTag.NAME); + addTagInfo(map, map2, DefineVideoStreamTag.ID, DefineVideoStreamTag.class, DefineVideoStreamTag.NAME); + addTagInfo(map, map2, DoABCDefineTag.ID, DoABCDefineTag.class, DoABCDefineTag.NAME); + addTagInfo(map, map2, DoABCTag.ID, DoABCTag.class, DoABCTag.NAME); + addTagInfo(map, map2, DoActionTag.ID, DoActionTag.class, DoActionTag.NAME); + addTagInfo(map, map2, DoInitActionTag.ID, DoInitActionTag.class, DoInitActionTag.NAME); + addTagInfo(map, map2, EnableDebugger2Tag.ID, EnableDebugger2Tag.class, EnableDebugger2Tag.NAME); + addTagInfo(map, map2, EnableDebuggerTag.ID, EnableDebuggerTag.class, EnableDebuggerTag.NAME); + addTagInfo(map, map2, EnableTelemetryTag.ID, EnableTelemetryTag.class, EnableTelemetryTag.NAME); + addTagInfo(map, map2, EndTag.ID, EndTag.class, EndTag.NAME); + addTagInfo(map, map2, ExportAssetsTag.ID, ExportAssetsTag.class, ExportAssetsTag.NAME); + addTagInfo(map, map2, FileAttributesTag.ID, FileAttributesTag.class, FileAttributesTag.NAME); + addTagInfo(map, map2, FrameLabelTag.ID, FrameLabelTag.class, FrameLabelTag.NAME); + addTagInfo(map, map2, ImportAssets2Tag.ID, ImportAssets2Tag.class, ImportAssets2Tag.NAME); + addTagInfo(map, map2, ImportAssetsTag.ID, ImportAssetsTag.class, ImportAssetsTag.NAME); + addTagInfo(map, map2, JPEGTablesTag.ID, JPEGTablesTag.class, JPEGTablesTag.NAME); + addTagInfo(map, map2, MetadataTag.ID, MetadataTag.class, MetadataTag.NAME); + addTagInfo(map, map2, PlaceObject2Tag.ID, PlaceObject2Tag.class, PlaceObject2Tag.NAME); + addTagInfo(map, map2, PlaceObject3Tag.ID, PlaceObject3Tag.class, PlaceObject3Tag.NAME); + addTagInfo(map, map2, PlaceObject4Tag.ID, PlaceObject4Tag.class, PlaceObject4Tag.NAME); + addTagInfo(map, map2, PlaceObjectTag.ID, PlaceObjectTag.class, PlaceObjectTag.NAME); + addTagInfo(map, map2, ProductInfoTag.ID, ProductInfoTag.class, ProductInfoTag.NAME); + addTagInfo(map, map2, ProtectTag.ID, ProtectTag.class, ProtectTag.NAME); + addTagInfo(map, map2, RemoveObject2Tag.ID, RemoveObject2Tag.class, RemoveObject2Tag.NAME); + addTagInfo(map, map2, RemoveObjectTag.ID, RemoveObjectTag.class, RemoveObjectTag.NAME); + addTagInfo(map, map2, ScriptLimitsTag.ID, ScriptLimitsTag.class, ScriptLimitsTag.NAME); + addTagInfo(map, map2, SetBackgroundColorTag.ID, SetBackgroundColorTag.class, SetBackgroundColorTag.NAME); + addTagInfo(map, map2, SetTabIndexTag.ID, SetTabIndexTag.class, SetTabIndexTag.NAME); + addTagInfo(map, map2, ShowFrameTag.ID, ShowFrameTag.class, ShowFrameTag.NAME); + addTagInfo(map, map2, SoundStreamBlockTag.ID, SoundStreamBlockTag.class, SoundStreamBlockTag.NAME); + addTagInfo(map, map2, SoundStreamHead2Tag.ID, SoundStreamHead2Tag.class, SoundStreamHead2Tag.NAME); + addTagInfo(map, map2, SoundStreamHeadTag.ID, SoundStreamHeadTag.class, SoundStreamHeadTag.NAME); + addTagInfo(map, map2, StartSound2Tag.ID, StartSound2Tag.class, StartSound2Tag.NAME); + addTagInfo(map, map2, StartSoundTag.ID, StartSoundTag.class, StartSoundTag.NAME); + addTagInfo(map, map2, SymbolClassTag.ID, SymbolClassTag.class, SymbolClassTag.NAME); + addTagInfo(map, map2, VideoFrameTag.ID, VideoFrameTag.class, VideoFrameTag.NAME); + addTagInfo(map, map2, DefineCompactedFont.ID, DefineCompactedFont.class, DefineCompactedFont.NAME); + addTagInfo(map, map2, DefineExternalGradient.ID, DefineExternalGradient.class, DefineExternalGradient.NAME); + addTagInfo(map, map2, DefineExternalImage.ID, DefineExternalImage.class, DefineExternalImage.NAME); + addTagInfo(map, map2, DefineExternalImage2.ID, DefineExternalImage2.class, DefineExternalImage2.NAME); + addTagInfo(map, map2, DefineExternalSound.ID, DefineExternalSound.class, DefineExternalSound.NAME); + addTagInfo(map, map2, DefineExternalStreamSound.ID, DefineExternalStreamSound.class, DefineExternalStreamSound.NAME); + addTagInfo(map, map2, DefineGradientMap.ID, DefineGradientMap.class, DefineGradientMap.NAME); + addTagInfo(map, map2, DefineSubImage.ID, DefineSubImage.class, DefineSubImage.NAME); + addTagInfo(map, map2, ExporterInfo.ID, ExporterInfo.class, ExporterInfo.NAME); + addTagInfo(map, map2, FontTextureInfo.ID, FontTextureInfo.class, FontTextureInfo.NAME); + knownTagInfosById = map; + knownTagInfosByName = map2; + } + } + } + return knownTagInfosById; + } + + public static Map getKnownClassesByName() { + // map is filled together with knownTagInfosById + if (knownTagInfosByName == null) { + getKnownClasses(); + } + + return knownTagInfosByName; + } + + private static void addTagInfo(Map map, Map map2, int id, Class cls, String name) { + map.put(id, new TagInfo(id, cls, name)); + map2.put(name, new TagInfo(id, cls, name)); + } + + public static List getRequiredTags() { + if (requiredTagIds == null) { + synchronized (lockObject) { + if (requiredTagIds == null) { + List tagIds = Arrays.asList( + DefineBinaryDataTag.ID, + DefineBitsJPEG2Tag.ID, + DefineBitsJPEG3Tag.ID, + DefineBitsJPEG4Tag.ID, + DefineBitsLossless2Tag.ID, + DefineBitsLosslessTag.ID, + DefineBitsTag.ID, + DefineButton2Tag.ID, + DefineButtonCxformTag.ID, + DefineButtonSoundTag.ID, + DefineButtonTag.ID, + DefineEditTextTag.ID, + DefineFont2Tag.ID, + DefineFont3Tag.ID, + DefineFont4Tag.ID, + DefineFontAlignZonesTag.ID, + DefineFontInfo2Tag.ID, + DefineFontInfoTag.ID, + DefineFontNameTag.ID, + DefineFontTag.ID, + DefineMorphShape2Tag.ID, + DefineMorphShapeTag.ID, + DefineScalingGridTag.ID, + DefineSceneAndFrameLabelDataTag.ID, + DefineShape2Tag.ID, + DefineShape3Tag.ID, + DefineShape4Tag.ID, + DefineShapeTag.ID, + DefineSoundTag.ID, + DefineSpriteTag.ID, + DefineText2Tag.ID, + DefineTextTag.ID, + DefineVideoStreamTag.ID, + DoABCDefineTag.ID, + DoABCTag.ID, + DoActionTag.ID, + DoInitActionTag.ID, + ShowFrameTag.ID); + requiredTagIds = tagIds; + } + } + } + return requiredTagIds; + } + + public int getVersion() { + if (swf == null) { + return SWF.DEFAULT_VERSION; + } + return swf.version; + } + + protected byte[] getHeader(byte[] data) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try { + + SWFOutputStream sos = new SWFOutputStream(baos, swf.version); + int tagLength = data.length; + int tagID = getId(); + int tagIDLength = (tagID << 6); + if ((tagLength <= 62) && (!forceWriteAsLong)) { + tagIDLength += tagLength; + sos.writeUI16(tagIDLength); + } else { + tagIDLength += 0x3f; + sos.writeUI16(tagIDLength); + sos.writeSI32(tagLength); + } + } catch (IOException iex) { + throw new Error("This should never happen.", iex); + } + return baos.toByteArray(); + } + + public static byte[] getTagHeader(int tagIDTagLength, long tagLength, boolean writeLong, int version) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try { + + SWFOutputStream sos = new SWFOutputStream(baos, version); + sos.writeUI16(tagIDTagLength); + if (writeLong) { + sos.writeSI32(tagLength); + } + } catch (IOException iex) { + throw new Error("This should never happen.", iex); + } + return baos.toByteArray(); + } + + /** + * Writes Tag value to the stream + * + * @param sos SWF output stream + * @throws IOException + */ + public void writeTag(SWFOutputStream sos) throws IOException { + if (isModified()) { + byte[] newData = getData(); + byte[] newHeaderData = getHeader(newData); + sos.write(newHeaderData); + sos.write(newData); + } else { + sos.write(originalRange.getArray(), originalRange.getPos(), originalRange.getLength()); + } + } + + public Tag cloneTag() throws InterruptedException, IOException { + byte[] data = getData(); + SWFInputStream tagDataStream = new SWFInputStream(swf, data, getDataPos(), data.length); + TagStub copy = new TagStub(swf, getId(), "Unresolved", getOriginalRange(), tagDataStream); + copy.forceWriteAsLong = forceWriteAsLong; + return SWFInputStream.resolveTag(copy, 0, false, true, false); + } + + public Tag getOriginalTag() throws InterruptedException, IOException { + byte[] data = getOriginalData(); + SWFInputStream tagDataStream = new SWFInputStream(swf, data, getDataPos(), data.length); + TagStub copy = new TagStub(swf, getId(), "Unresolved", getOriginalRange(), tagDataStream); + copy.forceWriteAsLong = forceWriteAsLong; + return SWFInputStream.resolveTag(copy, 0, false, true, false); + } + + public void undo() throws InterruptedException, IOException { + byte[] data = getOriginalData(); + SWFInputStream tagDataStream = new SWFInputStream(swf, data, getDataPos(), data.length); + readData(tagDataStream, getOriginalRange(), 0, false, true, false); + setModified(false); + } + + /** + * Returns string representation of the object + * + * @return String representation of the object + */ + @Override + public String toString() { + return getName(); + } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + public abstract byte[] getData(); + + public final ByteArrayRange getOriginalRange() { + return originalRange; + } + + /** + * Returns the original inner data of the tag, without the 2-6 bytes length + * header Call this method only from debug codes + * + * @return The data + */ + public final byte[] getOriginalData() { + if (originalRange == null) { + return null; + } + + int dataLength = getOriginalDataLength(); + int pos = (int) (originalRange.getPos() + originalRange.getLength() - dataLength); + + byte[] data = new byte[dataLength]; + System.arraycopy(originalRange.getArray(), pos, data, 0, dataLength); + return data; + } + + public final int getOriginalDataLength() { + if (originalRange == null) { + return 0; + } + + return originalRange.getLength() - (isLongOriginal() ? 6 : 2); + } + + private boolean isLongOriginal() { + int shortLength = originalRange.getArray()[(int) originalRange.getPos()] & 0x003F; + return shortLength == 0x3f; + } + + public long getPos() { + if (originalRange == null) { + return -1; + } + + return originalRange.getPos(); + } + + public long getDataPos() { + if (originalRange == null) { + return -1; + } + + return originalRange.getPos() + (isLongOriginal() ? 6 : 2); + } + + public void setModified(boolean value) { + modified = value; + if (value) { + informListeners(); + } + } + + public final void addEventListener(TagChangedListener listener) { + listeners.add(listener); + } + + public final void removeEventListener(TagChangedListener listener) { + listeners.remove(listener); + } + + protected void informListeners() { + for (TagChangedListener listener : listeners) { + listener.handleEvent(this); + } + } + + public void createOriginalData() { + byte[] data = getData(); + byte[] headerData = getHeader(data); + byte[] tagData = new byte[data.length + headerData.length]; + System.arraycopy(headerData, 0, tagData, 0, headerData.length); + System.arraycopy(data, 0, tagData, headerData.length, data.length); + originalRange = new ByteArrayRange(tagData, 0, tagData.length); + } + + public boolean isModified() { + return modified; + } + + @Override + public void getNeededCharacters(Set needed) { + } + + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + return false; + } + + @Override + public boolean removeCharacter(int characterId) { + return false; + } + + public void getNeededCharactersDeep(Set needed) { + Set visited = new HashSet<>(); + Set needed2 = new LinkedHashSet<>(); + getNeededCharacters(needed2); + + while (visited.size() != needed2.size()) { + for (Integer characterId : needed2) { + if (!visited.contains(characterId)) { + visited.add(characterId); + if (swf.getCharacters().containsKey(characterId)) { + swf.getCharacter(characterId).getNeededCharacters(needed2); + break; + } + } + } + } + + for (Integer characterId : needed2) { + if (swf.getCharacters().containsKey(characterId)) { + needed.add(characterId); + } + } + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/TagInfo.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/TagInfo.java new file mode 100644 index 000000000..762c83af5 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/TagInfo.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +/** + * + * @author JPEXS + */ +public class TagInfo { + + public int id; + + public Class cls; + + public String name; + + public TagInfo(int id, Class cls, String name) { + this.id = id; + this.cls = cls; + this.name = name; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/VideoFrameTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/VideoFrameTag.java index e6a53e172..28f9538e7 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/VideoFrameTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/VideoFrameTag.java @@ -1,105 +1,107 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.tags.base.CharacterIdTag; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.helpers.ByteArrayRange; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -/** - * - * - * @author JPEXS - */ -public class VideoFrameTag extends Tag implements CharacterIdTag { - - @SWFType(BasicType.UI16) - public int streamID; - - @SWFType(BasicType.UI16) - public int frameNum; - - public ByteArrayRange videoData; - - public static final int ID = 61; - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(streamID); - sos.writeUI16(frameNum); - sos.write(videoData); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - - /** - * Constructor - * - * @param swf - */ - public VideoFrameTag(SWF swf) { - super(swf, ID, "VideoFrame", null); - videoData = ByteArrayRange.EMPTY; - } - - /** - * Constructor - * - * @param sis - * @param data - * @throws IOException - */ - public VideoFrameTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "VideoFrame", data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - streamID = sis.readUI16("streamID"); - frameNum = sis.readUI16("frameNum"); - videoData = sis.readByteRangeEx(sis.available(), "videoData"); //TODO: Parse video packets - } - - @Override - public int getCharacterId() { - return streamID; - } - - @Override - public void setCharacterId(int characterId) { - this.streamID = characterId; - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.tags.base.CharacterIdTag; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.helpers.ByteArrayRange; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * + * + * @author JPEXS + */ +public class VideoFrameTag extends Tag implements CharacterIdTag { + + @SWFType(BasicType.UI16) + public int streamID; + + @SWFType(BasicType.UI16) + public int frameNum; + + public ByteArrayRange videoData; + + public static final int ID = 61; + + public static final String NAME = "VideoFrame"; + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(streamID); + sos.writeUI16(frameNum); + sos.write(videoData); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + /** + * Constructor + * + * @param swf + */ + public VideoFrameTag(SWF swf) { + super(swf, ID, NAME, null); + videoData = ByteArrayRange.EMPTY; + } + + /** + * Constructor + * + * @param sis + * @param data + * @throws IOException + */ + public VideoFrameTag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + streamID = sis.readUI16("streamID"); + frameNum = sis.readUI16("frameNum"); + videoData = sis.readByteRangeEx(sis.available(), "videoData"); //TODO: Parse video packets + } + + @Override + public int getCharacterId() { + return streamID; + } + + @Override + public void setCharacterId(int characterId) { + this.streamID = characterId; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineCompactedFont.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineCompactedFont.java index 0dffca143..402bb91ab 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineCompactedFont.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineCompactedFont.java @@ -1,430 +1,432 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags.gfx; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.helpers.FontHelper; -import com.jpexs.decompiler.flash.tags.DefineFont2Tag; -import com.jpexs.decompiler.flash.tags.Tag; -import com.jpexs.decompiler.flash.tags.base.FontTag; -import com.jpexs.decompiler.flash.types.KERNINGRECORD; -import com.jpexs.decompiler.flash.types.LANGCODE; -import com.jpexs.decompiler.flash.types.RECT; -import com.jpexs.decompiler.flash.types.SHAPE; -import com.jpexs.decompiler.flash.types.gfx.FontType; -import com.jpexs.decompiler.flash.types.gfx.GFxInputStream; -import com.jpexs.decompiler.flash.types.gfx.GFxOutputStream; -import com.jpexs.decompiler.flash.types.gfx.GlyphInfoType; -import com.jpexs.decompiler.flash.types.gfx.GlyphType; -import com.jpexs.decompiler.flash.types.gfx.KerningPairType; -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.helpers.ByteArrayRange; -import com.jpexs.helpers.MemoryInputStream; -import java.awt.Font; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; - -/** - * - * - * @author JPEXS - */ -public final class DefineCompactedFont extends FontTag { - - public static final int ID = 1005; - - public int fontId; - - public List fonts; - - private List shapeCache; - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(fontId); - for (FontType ft : fonts) { - ft.write(new GFxOutputStream(sos)); - } - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - - /** - * Constructor - * - * @param swf - */ - public DefineCompactedFont(SWF swf) { - super(swf, ID, "DefineCompactedFont", null); - fontId = swf.getNextCharacterId(); - - fonts = new ArrayList<>(); - FontType ft = new FontType(); - fonts.add(ft); - - rebuildShapeCache(); - } - - /** - * Constructor - * - * @param sis - * @param data - * @throws IOException - */ - public DefineCompactedFont(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DefineCompactedFont", data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - fontId = sis.readUI16("fontId"); - fonts = new ArrayList<>(); - - MemoryInputStream mis = sis.getBaseStream(); - while (mis.available() > 0) { - GFxInputStream gis = new GFxInputStream(mis); - gis.dumpInfo = sis.dumpInfo; - gis.newDumpLevel("fontType", "FontType"); - fonts.add(new FontType(gis)); - gis.endDumpLevel(); - } - rebuildShapeCache(); - } - - public void rebuildShapeCache() { - shapeCache = fonts.get(0).getGlyphShapes(); - } - - @Override - public String getFontNameIntag() { - StringBuilder ret = new StringBuilder(); - for (int i = 0; i < fonts.size(); i++) { - if (i > 0) { - ret.append(", "); - } - ret.append(fonts.get(i).fontName); - } - return ret.toString(); - } - - @Override - public int getCharacterId() { - return fontId; - } - - @Override - public void setCharacterId(int characterId) { - this.fontId = characterId; - } - - @Override - public int getFontId() { - return fontId; - } - - @Override - public List getGlyphShapeTable() { - return shapeCache; - } - - @Override - public void addCharacter(char character, Font cfont) { - int fontStyle = getFontStyle(); - FontType font = fonts.get(0); - - double d = 1; - SHAPE shp = SHAPERECORD.fontCharacterToSHAPE(cfont, (int) (font.nominalSize * d), character); - - int code = (int) character; - int pos = -1; - boolean exists = false; - for (int i = 0; i < font.glyphInfo.size(); i++) { - if (font.glyphInfo.get(i).glyphCode >= code) { - if (font.glyphInfo.get(i).glyphCode == code) { - exists = true; - } - pos = i; - break; - } - } - if (pos == -1) { - pos = font.glyphInfo.size(); - } - - if (!exists) { - shiftGlyphIndices(fontId, pos); - } - - Font fnt = cfont.deriveFont(fontStyle, Math.round(font.nominalSize * d)); - int advance = (int) Math.round(FontHelper.getFontAdvance(fnt, character)); - if (!exists) { - font.glyphInfo.add(pos, new GlyphInfoType(code, advance, 0)); - font.glyphs.add(pos, new GlyphType(shp.shapeRecords)); - shapeCache.add(pos, font.glyphs.get(pos).toSHAPE()); - } else { - font.glyphInfo.set(pos, new GlyphInfoType(code, advance, 0)); - font.glyphs.set(pos, new GlyphType(shp.shapeRecords)); - shapeCache.set(pos, font.glyphs.get(pos).toSHAPE()); - } - - setModified(true); - getSwf().clearImageCache(); - } - - @Override - public void setAdvanceValues(Font font) { - throw new UnsupportedOperationException("Setting the advance values for DefineCompactedFont is not supported."); - } - - @Override - public char glyphToChar(int glyphIndex) { - return (char) fonts.get(0).glyphInfo.get(glyphIndex).glyphCode; - } - - @Override - public int charToGlyph(char c) { - FontType ft = fonts.get(0); - for (int i = 0; i < ft.glyphInfo.size(); i++) { - if (ft.glyphInfo.get(i).glyphCode == c) { - return i; - } - } - return -1; - } - - @Override - public double getGlyphAdvance(int glyphIndex) { - return resize(fonts.get(0).glyphInfo.get(glyphIndex).advanceX); - } - - @Override - public int getGlyphKerningAdjustment(int glyphIndex, int nextGlyphIndex) { - char c1 = glyphToChar(glyphIndex); - char c2 = glyphToChar(nextGlyphIndex); - return getCharKerningAdjustment(c1, c2); - } - - @Override - public int getCharKerningAdjustment(char c1, char c2) { - for (KerningPairType kp : fonts.get(0).kerning) { - if (kp.char1 == c1 && kp.char2 == c2) { - return resize(kp.advance); - } - } - return 0; - } - - @Override - public int getGlyphWidth(int glyphIndex) { - return resize(getGlyphShapeTable().get(glyphIndex).getBounds().getWidth()); - } - - @Override - public boolean isSmall() { - return false; - } - - @Override - public boolean isBold() { - return (fonts.get(0).flags & FontType.FF_Bold) == FontType.FF_Bold; - } - - @Override - public boolean isItalic() { - return (fonts.get(0).flags & FontType.FF_Italic) == FontType.FF_Italic; - } - - @Override - public boolean isSmallEditable() { - return false; - } - - @Override - public boolean isBoldEditable() { - return true; - } - - @Override - public boolean isItalicEditable() { - return true; - } - - @Override - public void setSmall(boolean value) { - } - - @Override - public void setBold(boolean value) { - for (FontType font : fonts) { - font.flags &= FontType.FF_Bold; - if (!value) { - font.flags ^= FontType.FF_Bold; - } - } - } - - @Override - public void setItalic(boolean value) { - for (FontType font : fonts) { - font.flags &= FontType.FF_Italic; - if (!value) { - font.flags ^= FontType.FF_Italic; - } - } - } - - @Override - public double getDivider() { - return 1; - } - - @Override - public int getAscent() { - return fonts.get(0).ascent; - } - - @Override - public int getDescent() { - return fonts.get(0).descent; - } - - @Override - public int getLeading() { - return fonts.get(0).leading; - } - - @Override - public String getCharacters(List tags) { - FontType ft = fonts.get(0); - StringBuilder ret = new StringBuilder(ft.glyphInfo.size()); - for (GlyphInfoType gi : ft.glyphInfo) { - ret.append((char) gi.glyphCode); - } - return ret.toString(); - } - - @Override - public RECT getGlyphBounds(int glyphIndex) { - GlyphType gt = fonts.get(0).glyphs.get(glyphIndex); - return new RECT(resize(gt.boundingBox[0]), resize(gt.boundingBox[1]), resize(gt.boundingBox[2]), resize(gt.boundingBox[3])); - } - - public SHAPE resizeShape(SHAPE shp) { - SHAPE ret = new SHAPE(); - ret.numFillBits = 1; - ret.numLineBits = 0; - List recs = new ArrayList<>(); - for (SHAPERECORD r : shp.shapeRecords) { - SHAPERECORD c = r.clone(); - if (c instanceof StyleChangeRecord) { - StyleChangeRecord scr = (StyleChangeRecord) c; - scr.moveDeltaX = resize(scr.moveDeltaX); - scr.moveDeltaY = resize(scr.moveDeltaY); - scr.calculateBits(); - } - if (c instanceof CurvedEdgeRecord) { - CurvedEdgeRecord cer = (CurvedEdgeRecord) c; - cer.controlDeltaX = resize(cer.controlDeltaX); - cer.controlDeltaY = resize(cer.controlDeltaY); - cer.anchorDeltaX = resize(cer.anchorDeltaX); - cer.anchorDeltaY = resize(cer.anchorDeltaY); - cer.calculateBits(); - } - if (c instanceof StraightEdgeRecord) { - StraightEdgeRecord ser = (StraightEdgeRecord) c; - ser.deltaX = resize(ser.deltaX); - ser.deltaY = resize(ser.deltaY); - ser.calculateBits(); - } - recs.add(c); - } - ret.shapeRecords = recs; - return ret; - } - - protected int resize(double val) { - FontType ft = fonts.get(0); - return (int) Math.round(val * 1024.0 / ft.nominalSize); - } - - @Override - public FontTag toClassicFont() { - DefineFont2Tag ret = new DefineFont2Tag(swf); - ret.fontId = getFontId(); - ret.fontFlagsBold = isBold(); - ret.fontFlagsItalic = isItalic(); - ret.fontFlagsWideOffsets = true; - ret.fontFlagsWideCodes = true; - ret.fontFlagsHasLayout = true; - ret.fontAscent = (getAscent()); - ret.fontDescent = (getDescent()); - ret.fontLeading = (getLeading()); - ret.fontAdvanceTable = new ArrayList<>(); - ret.fontBoundsTable = new ArrayList<>(); - ret.codeTable = new ArrayList<>(); - ret.glyphShapeTable = new ArrayList<>(); - List shp = getGlyphShapeTable(); - for (int g = 0; g < shp.size(); g++) { - ret.fontAdvanceTable.add(resize(getGlyphAdvance(g))); - ret.codeTable.add((int) glyphToChar(g)); - - SHAPE shpX = resizeShape(shp.get(g)); - ret.glyphShapeTable.add(shpX); - ret.fontBoundsTable.add(getGlyphBounds(g)); - } - ret.fontName = getFontNameIntag(); - ret.languageCode = new LANGCODE(1); - ret.fontKerningTable = new ArrayList<>(); - - FontType ft = fonts.get(0); - for (int i = 0; i < ft.kerning.size(); i++) { - KERNINGRECORD kr = new KERNINGRECORD(); - kr.fontKerningAdjustment = resize(ft.kerning.get(i).advance); - kr.fontKerningCode1 = ft.kerning.get(i).char1; - kr.fontKerningCode2 = ft.kerning.get(i).char2; - ret.fontKerningTable.add(kr); - } - - return ret; - } - - @Override - public boolean hasLayout() { - return true; - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags.gfx; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.helpers.FontHelper; +import com.jpexs.decompiler.flash.tags.DefineFont2Tag; +import com.jpexs.decompiler.flash.tags.Tag; +import com.jpexs.decompiler.flash.tags.base.FontTag; +import com.jpexs.decompiler.flash.types.KERNINGRECORD; +import com.jpexs.decompiler.flash.types.LANGCODE; +import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.decompiler.flash.types.SHAPE; +import com.jpexs.decompiler.flash.types.gfx.FontType; +import com.jpexs.decompiler.flash.types.gfx.GFxInputStream; +import com.jpexs.decompiler.flash.types.gfx.GFxOutputStream; +import com.jpexs.decompiler.flash.types.gfx.GlyphInfoType; +import com.jpexs.decompiler.flash.types.gfx.GlyphType; +import com.jpexs.decompiler.flash.types.gfx.KerningPairType; +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.helpers.ByteArrayRange; +import com.jpexs.helpers.MemoryInputStream; +import java.awt.Font; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; + +/** + * + * + * @author JPEXS + */ +public final class DefineCompactedFont extends FontTag { + + public static final int ID = 1005; + + public static final String NAME = "DefineCompactedFont"; + + public int fontId; + + public List fonts; + + private List shapeCache; + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(fontId); + for (FontType ft : fonts) { + ft.write(new GFxOutputStream(sos)); + } + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + /** + * Constructor + * + * @param swf + */ + public DefineCompactedFont(SWF swf) { + super(swf, ID, NAME, null); + fontId = swf.getNextCharacterId(); + + fonts = new ArrayList<>(); + FontType ft = new FontType(); + fonts.add(ft); + + rebuildShapeCache(); + } + + /** + * Constructor + * + * @param sis + * @param data + * @throws IOException + */ + public DefineCompactedFont(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + fontId = sis.readUI16("fontId"); + fonts = new ArrayList<>(); + + MemoryInputStream mis = sis.getBaseStream(); + while (mis.available() > 0) { + GFxInputStream gis = new GFxInputStream(mis); + gis.dumpInfo = sis.dumpInfo; + gis.newDumpLevel("fontType", "FontType"); + fonts.add(new FontType(gis)); + gis.endDumpLevel(); + } + rebuildShapeCache(); + } + + public void rebuildShapeCache() { + shapeCache = fonts.get(0).getGlyphShapes(); + } + + @Override + public String getFontNameIntag() { + StringBuilder ret = new StringBuilder(); + for (int i = 0; i < fonts.size(); i++) { + if (i > 0) { + ret.append(", "); + } + ret.append(fonts.get(i).fontName); + } + return ret.toString(); + } + + @Override + public int getCharacterId() { + return fontId; + } + + @Override + public void setCharacterId(int characterId) { + this.fontId = characterId; + } + + @Override + public int getFontId() { + return fontId; + } + + @Override + public List getGlyphShapeTable() { + return shapeCache; + } + + @Override + public void addCharacter(char character, Font cfont) { + int fontStyle = getFontStyle(); + FontType font = fonts.get(0); + + double d = 1; + SHAPE shp = SHAPERECORD.fontCharacterToSHAPE(cfont, (int) (font.nominalSize * d), character); + + int code = (int) character; + int pos = -1; + boolean exists = false; + for (int i = 0; i < font.glyphInfo.size(); i++) { + if (font.glyphInfo.get(i).glyphCode >= code) { + if (font.glyphInfo.get(i).glyphCode == code) { + exists = true; + } + pos = i; + break; + } + } + if (pos == -1) { + pos = font.glyphInfo.size(); + } + + if (!exists) { + shiftGlyphIndices(fontId, pos); + } + + Font fnt = cfont.deriveFont(fontStyle, Math.round(font.nominalSize * d)); + int advance = (int) Math.round(FontHelper.getFontAdvance(fnt, character)); + if (!exists) { + font.glyphInfo.add(pos, new GlyphInfoType(code, advance, 0)); + font.glyphs.add(pos, new GlyphType(shp.shapeRecords)); + shapeCache.add(pos, font.glyphs.get(pos).toSHAPE()); + } else { + font.glyphInfo.set(pos, new GlyphInfoType(code, advance, 0)); + font.glyphs.set(pos, new GlyphType(shp.shapeRecords)); + shapeCache.set(pos, font.glyphs.get(pos).toSHAPE()); + } + + setModified(true); + getSwf().clearImageCache(); + } + + @Override + public void setAdvanceValues(Font font) { + throw new UnsupportedOperationException("Setting the advance values for DefineCompactedFont is not supported."); + } + + @Override + public char glyphToChar(int glyphIndex) { + return (char) fonts.get(0).glyphInfo.get(glyphIndex).glyphCode; + } + + @Override + public int charToGlyph(char c) { + FontType ft = fonts.get(0); + for (int i = 0; i < ft.glyphInfo.size(); i++) { + if (ft.glyphInfo.get(i).glyphCode == c) { + return i; + } + } + return -1; + } + + @Override + public double getGlyphAdvance(int glyphIndex) { + return resize(fonts.get(0).glyphInfo.get(glyphIndex).advanceX); + } + + @Override + public int getGlyphKerningAdjustment(int glyphIndex, int nextGlyphIndex) { + char c1 = glyphToChar(glyphIndex); + char c2 = glyphToChar(nextGlyphIndex); + return getCharKerningAdjustment(c1, c2); + } + + @Override + public int getCharKerningAdjustment(char c1, char c2) { + for (KerningPairType kp : fonts.get(0).kerning) { + if (kp.char1 == c1 && kp.char2 == c2) { + return resize(kp.advance); + } + } + return 0; + } + + @Override + public int getGlyphWidth(int glyphIndex) { + return resize(getGlyphShapeTable().get(glyphIndex).getBounds().getWidth()); + } + + @Override + public boolean isSmall() { + return false; + } + + @Override + public boolean isBold() { + return (fonts.get(0).flags & FontType.FF_Bold) == FontType.FF_Bold; + } + + @Override + public boolean isItalic() { + return (fonts.get(0).flags & FontType.FF_Italic) == FontType.FF_Italic; + } + + @Override + public boolean isSmallEditable() { + return false; + } + + @Override + public boolean isBoldEditable() { + return true; + } + + @Override + public boolean isItalicEditable() { + return true; + } + + @Override + public void setSmall(boolean value) { + } + + @Override + public void setBold(boolean value) { + for (FontType font : fonts) { + font.flags &= FontType.FF_Bold; + if (!value) { + font.flags ^= FontType.FF_Bold; + } + } + } + + @Override + public void setItalic(boolean value) { + for (FontType font : fonts) { + font.flags &= FontType.FF_Italic; + if (!value) { + font.flags ^= FontType.FF_Italic; + } + } + } + + @Override + public double getDivider() { + return 1; + } + + @Override + public int getAscent() { + return fonts.get(0).ascent; + } + + @Override + public int getDescent() { + return fonts.get(0).descent; + } + + @Override + public int getLeading() { + return fonts.get(0).leading; + } + + @Override + public String getCharacters(List tags) { + FontType ft = fonts.get(0); + StringBuilder ret = new StringBuilder(ft.glyphInfo.size()); + for (GlyphInfoType gi : ft.glyphInfo) { + ret.append((char) gi.glyphCode); + } + return ret.toString(); + } + + @Override + public RECT getGlyphBounds(int glyphIndex) { + GlyphType gt = fonts.get(0).glyphs.get(glyphIndex); + return new RECT(resize(gt.boundingBox[0]), resize(gt.boundingBox[1]), resize(gt.boundingBox[2]), resize(gt.boundingBox[3])); + } + + public SHAPE resizeShape(SHAPE shp) { + SHAPE ret = new SHAPE(); + ret.numFillBits = 1; + ret.numLineBits = 0; + List recs = new ArrayList<>(); + for (SHAPERECORD r : shp.shapeRecords) { + SHAPERECORD c = r.clone(); + if (c instanceof StyleChangeRecord) { + StyleChangeRecord scr = (StyleChangeRecord) c; + scr.moveDeltaX = resize(scr.moveDeltaX); + scr.moveDeltaY = resize(scr.moveDeltaY); + scr.calculateBits(); + } + if (c instanceof CurvedEdgeRecord) { + CurvedEdgeRecord cer = (CurvedEdgeRecord) c; + cer.controlDeltaX = resize(cer.controlDeltaX); + cer.controlDeltaY = resize(cer.controlDeltaY); + cer.anchorDeltaX = resize(cer.anchorDeltaX); + cer.anchorDeltaY = resize(cer.anchorDeltaY); + cer.calculateBits(); + } + if (c instanceof StraightEdgeRecord) { + StraightEdgeRecord ser = (StraightEdgeRecord) c; + ser.deltaX = resize(ser.deltaX); + ser.deltaY = resize(ser.deltaY); + ser.calculateBits(); + } + recs.add(c); + } + ret.shapeRecords = recs; + return ret; + } + + protected int resize(double val) { + FontType ft = fonts.get(0); + return (int) Math.round(val * 1024.0 / ft.nominalSize); + } + + @Override + public FontTag toClassicFont() { + DefineFont2Tag ret = new DefineFont2Tag(swf); + ret.fontId = getFontId(); + ret.fontFlagsBold = isBold(); + ret.fontFlagsItalic = isItalic(); + ret.fontFlagsWideOffsets = true; + ret.fontFlagsWideCodes = true; + ret.fontFlagsHasLayout = true; + ret.fontAscent = (getAscent()); + ret.fontDescent = (getDescent()); + ret.fontLeading = (getLeading()); + ret.fontAdvanceTable = new ArrayList<>(); + ret.fontBoundsTable = new ArrayList<>(); + ret.codeTable = new ArrayList<>(); + ret.glyphShapeTable = new ArrayList<>(); + List shp = getGlyphShapeTable(); + for (int g = 0; g < shp.size(); g++) { + ret.fontAdvanceTable.add(resize(getGlyphAdvance(g))); + ret.codeTable.add((int) glyphToChar(g)); + + SHAPE shpX = resizeShape(shp.get(g)); + ret.glyphShapeTable.add(shpX); + ret.fontBoundsTable.add(getGlyphBounds(g)); + } + ret.fontName = getFontNameIntag(); + ret.languageCode = new LANGCODE(1); + ret.fontKerningTable = new ArrayList<>(); + + FontType ft = fonts.get(0); + for (int i = 0; i < ft.kerning.size(); i++) { + KERNINGRECORD kr = new KERNINGRECORD(); + kr.fontKerningAdjustment = resize(ft.kerning.get(i).advance); + kr.fontKerningCode1 = ft.kerning.get(i).char1; + kr.fontKerningCode2 = ft.kerning.get(i).char2; + ret.fontKerningTable.add(kr); + } + + return ret; + } + + @Override + public boolean hasLayout() { + return true; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalGradient.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalGradient.java index 437f30a33..4502ec6e2 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalGradient.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalGradient.java @@ -33,6 +33,8 @@ public class DefineExternalGradient extends Tag { public static final int ID = 1003; + public static final String NAME = "DefineExternalGradient"; + public static final int BITMAP_FORMAT_DEFAULT = 0; public static final int BITMAP_FORMAT_TGA = 1; @@ -78,7 +80,7 @@ public class DefineExternalGradient extends Tag { * @throws IOException */ public DefineExternalGradient(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DefineExternalGradient", data); + super(sis.getSwf(), ID, NAME, data); readData(sis, data, 0, false, false, false); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalImage.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalImage.java index c20ba747f..73d487faf 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalImage.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalImage.java @@ -33,6 +33,8 @@ public class DefineExternalImage extends Tag { public static final int ID = 1001; + public static final String NAME = "DefineExternalImage"; + public int characterId; public int bitmapFormat; @@ -81,7 +83,7 @@ public class DefineExternalImage extends Tag { * @throws IOException */ public DefineExternalImage(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DefineExternalImage", data); + super(sis.getSwf(), ID, NAME, data); readData(sis, data, 0, false, false, false); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalImage2.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalImage2.java index 6bbc27fe6..835b8ad86 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalImage2.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalImage2.java @@ -33,6 +33,8 @@ public class DefineExternalImage2 extends Tag { public static final int ID = 1009; + public static final String NAME = "DefineExternalImage2"; + public long characterId; public int bitmapFormat; @@ -91,7 +93,7 @@ public class DefineExternalImage2 extends Tag { * @throws IOException */ public DefineExternalImage2(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DefineExternalImage2", data); + super(sis.getSwf(), ID, NAME, data); readData(sis, data, 0, false, false, false); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalSound.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalSound.java index 23992a0b6..9588c5889 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalSound.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalSound.java @@ -33,6 +33,8 @@ public class DefineExternalSound extends Tag { public static final int ID = 1006; + public static final String NAME = "DefineExternalSound"; + public int characterId; public int soundFormat; @@ -91,7 +93,7 @@ public class DefineExternalSound extends Tag { * @throws IOException */ public DefineExternalSound(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DefineExternalSound", data); + super(sis.getSwf(), ID, NAME, data); readData(sis, data, 0, false, false, false); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalStreamSound.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalStreamSound.java index 676ca8e3d..ecdaaa110 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalStreamSound.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalStreamSound.java @@ -33,6 +33,8 @@ public class DefineExternalStreamSound extends Tag { public static final int ID = 1007; + public static final String NAME = "DefineExternalStreamSound"; + public int soundFormat; public int bits; @@ -89,7 +91,7 @@ public class DefineExternalStreamSound extends Tag { * @throws IOException */ public DefineExternalStreamSound(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DefineExternalStreamSound", data); + super(sis.getSwf(), ID, NAME, data); readData(sis, data, 0, false, false, false); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineGradientMap.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineGradientMap.java index 3173763fe..90e432dec 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineGradientMap.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineGradientMap.java @@ -33,6 +33,8 @@ public class DefineGradientMap extends Tag { public static final int ID = 1004; + public static final String NAME = "DefineGradientMap"; + public int[] indices; /** @@ -64,7 +66,7 @@ public class DefineGradientMap extends Tag { * @throws IOException */ public DefineGradientMap(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DefineGradientMap", data); + super(sis.getSwf(), ID, NAME, data); readData(sis, data, 0, false, false, false); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineSubImage.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineSubImage.java index a5f4c937e..fae191670 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineSubImage.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineSubImage.java @@ -33,6 +33,8 @@ public class DefineSubImage extends Tag { public static final int ID = 1008; + public static final String NAME = "DefineSubImage"; + public int characterId; public int imageCharacterId; @@ -76,7 +78,7 @@ public class DefineSubImage extends Tag { * @throws IOException */ public DefineSubImage(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DefineSubImage", data); + super(sis.getSwf(), ID, NAME, data); readData(sis, data, 0, false, false, false); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/ExporterInfo.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/ExporterInfo.java index f7ac579e9..b1ba88fbe 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/ExporterInfo.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/ExporterInfo.java @@ -35,6 +35,8 @@ public class ExporterInfo extends Tag { public static final int ID = 1000; + public static final String NAME = "ExporterInfo"; + //Version (1.10 will be encoded as 0x10A) public int version; @@ -100,7 +102,7 @@ public class ExporterInfo extends Tag { * @throws IOException */ public ExporterInfo(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "ExporterInfo", data); + super(sis.getSwf(), ID, NAME, data); readData(sis, data, 0, false, false, false); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/FontTextureInfo.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/FontTextureInfo.java index 357c3a76b..af63f4763 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/FontTextureInfo.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/FontTextureInfo.java @@ -38,6 +38,8 @@ public class FontTextureInfo extends Tag { public static final int ID = 1002; + public static final String NAME = "FontTextureInfo"; + public long textureID; public int textureFormat; @@ -104,7 +106,7 @@ public class FontTextureInfo extends Tag { * @throws IOException */ public FontTextureInfo(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "FontTextureInfo", data); + super(sis.getSwf(), ID, NAME, data); readData(sis, data, 0, false, false, false); } diff --git a/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java b/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java index 8c61d8600..043b14fa0 100644 --- a/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java +++ b/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java @@ -1,1728 +1,1757 @@ -/* - * Copyright (C) 2010-2015 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.console; - -import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler; -import com.jpexs.decompiler.flash.ApplicationInfo; -import com.jpexs.decompiler.flash.EventListener; -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFBundle; -import com.jpexs.decompiler.flash.SWFSourceInfo; -import com.jpexs.decompiler.flash.SearchMode; -import com.jpexs.decompiler.flash.abc.ABC; -import com.jpexs.decompiler.flash.abc.RenameType; -import com.jpexs.decompiler.flash.abc.ScriptPack; -import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; -import com.jpexs.decompiler.flash.abc.avm2.parser.AVM2ParseException; -import com.jpexs.decompiler.flash.abc.avm2.parser.pcode.ASM3Parser; -import com.jpexs.decompiler.flash.abc.avm2.parser.pcode.MissingSymbolHandler; -import com.jpexs.decompiler.flash.abc.avm2.parser.script.ActionScriptParser; -import com.jpexs.decompiler.flash.abc.types.MethodBody; -import com.jpexs.decompiler.flash.abc.types.traits.Trait; -import com.jpexs.decompiler.flash.action.parser.ActionParseException; -import com.jpexs.decompiler.flash.action.parser.pcode.ASMParser; -import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.decompiler.flash.configuration.ConfigurationItem; -import com.jpexs.decompiler.flash.exporters.BinaryDataExporter; -import com.jpexs.decompiler.flash.exporters.FontExporter; -import com.jpexs.decompiler.flash.exporters.FrameExporter; -import com.jpexs.decompiler.flash.exporters.ImageExporter; -import com.jpexs.decompiler.flash.exporters.MorphShapeExporter; -import com.jpexs.decompiler.flash.exporters.MovieExporter; -import com.jpexs.decompiler.flash.exporters.ShapeExporter; -import com.jpexs.decompiler.flash.exporters.SoundExporter; -import com.jpexs.decompiler.flash.exporters.TextExporter; -import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; -import com.jpexs.decompiler.flash.exporters.modes.BinaryDataExportMode; -import com.jpexs.decompiler.flash.exporters.modes.FontExportMode; -import com.jpexs.decompiler.flash.exporters.modes.FrameExportMode; -import com.jpexs.decompiler.flash.exporters.modes.ImageExportMode; -import com.jpexs.decompiler.flash.exporters.modes.MorphShapeExportMode; -import com.jpexs.decompiler.flash.exporters.modes.MovieExportMode; -import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; -import com.jpexs.decompiler.flash.exporters.modes.ShapeExportMode; -import com.jpexs.decompiler.flash.exporters.modes.SoundExportMode; -import com.jpexs.decompiler.flash.exporters.modes.TextExportMode; -import com.jpexs.decompiler.flash.exporters.settings.BinaryDataExportSettings; -import com.jpexs.decompiler.flash.exporters.settings.FontExportSettings; -import com.jpexs.decompiler.flash.exporters.settings.FrameExportSettings; -import com.jpexs.decompiler.flash.exporters.settings.ImageExportSettings; -import com.jpexs.decompiler.flash.exporters.settings.MorphShapeExportSettings; -import com.jpexs.decompiler.flash.exporters.settings.MovieExportSettings; -import com.jpexs.decompiler.flash.exporters.settings.ScriptExportSettings; -import com.jpexs.decompiler.flash.exporters.settings.ShapeExportSettings; -import com.jpexs.decompiler.flash.exporters.settings.SoundExportSettings; -import com.jpexs.decompiler.flash.exporters.settings.TextExportSettings; -import com.jpexs.decompiler.flash.exporters.swf.SwfXmlExporter; -import com.jpexs.decompiler.flash.gui.Main; -import com.jpexs.decompiler.flash.helpers.FileTextWriter; -import com.jpexs.decompiler.flash.importers.BinaryDataImporter; -import com.jpexs.decompiler.flash.importers.ImageImporter; -import com.jpexs.decompiler.flash.importers.SwfXmlImporter; -import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag; -import com.jpexs.decompiler.flash.tags.DefineSpriteTag; -import com.jpexs.decompiler.flash.tags.Tag; -import com.jpexs.decompiler.flash.tags.base.ASMSource; -import com.jpexs.decompiler.flash.tags.base.CharacterIdTag; -import com.jpexs.decompiler.flash.tags.base.CharacterTag; -import com.jpexs.decompiler.flash.tags.base.ImageTag; -import com.jpexs.decompiler.flash.tags.base.SoundTag; -import com.jpexs.decompiler.flash.treeitems.SWFList; -import com.jpexs.decompiler.flash.types.ColorTransform; -import com.jpexs.decompiler.flash.types.RECT; -import com.jpexs.decompiler.flash.types.sound.SoundFormat; -import com.jpexs.decompiler.flash.xfl.FLAVersion; -import com.jpexs.decompiler.graph.CompilationException; -import com.jpexs.helpers.Helper; -import com.jpexs.helpers.Path; -import com.jpexs.helpers.streams.SeekableInputStream; -import com.sun.jna.Platform; -import com.sun.jna.platform.win32.Kernel32; -import gnu.jpdf.PDFJob; -import java.awt.Color; -import java.awt.Graphics; -import java.awt.image.BufferedImage; -import java.awt.print.PageFormat; -import java.awt.print.Paper; -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.FilenameFilter; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.PrintStream; -import java.io.StringReader; -import java.util.ArrayList; -import java.util.Arrays; -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; - -/** - * - * @author JPEXS - */ -public class CommandLineArgumentParser { - - private static boolean commandLineMode = false; - - private static String stdOut = null; - - private static String stdErr = null; - - @SuppressWarnings("unchecked") - private static final ConfigurationItem[] commandlineConfigBoolean = new ConfigurationItem[]{ - Configuration.decompile, - Configuration.parallelSpeedUp, - Configuration.internalFlashViewer, - //Configuration.autoDeobfuscate, - Configuration.cacheOnDisk - }; - - public static boolean isCommandLineMode() { - return commandLineMode; - } - - public static void printCmdLineUsage() { - printCmdLineUsage(System.out, true); - } - - public static void printCmdLineUsage(PrintStream out, boolean printConfigs) { - int cnt = 1; - out.println("Commandline arguments:"); - out.println(" " + (cnt++) + ") -help | --help | /?"); - out.println(" ...shows commandline arguments (this help)"); - out.println(" " + (cnt++) + ") [ ...]"); - out.println(" ...opens SWF file(s) with the decompiler GUI"); - out.println(" " + (cnt++) + ") -proxy [-P]"); - out.println(" ...auto start proxy in the tray. Optional parameter -P specifies port for proxy. Defaults to 55555. "); - out.println(" " + (cnt++) + ") -export [-selectas3class ...]"); - out.println(" ...export sources to ."); - out.println(" Exports all files from when it is a folder."); - out.println(" Values for parameter:"); - out.println(" script - Scripts (Default format: ActionScript source)"); - out.println(" - Optional DEPRECATED \"-selectas3class\" parameter can be passed in same way as -selectclass"); - out.println(" image - Images (Default format: PNG/JPEG)"); - out.println(" shape - Shapes (Default format: SVG)"); - out.println(" morphshape - MorphShapes (Default format: SVG)"); - out.println(" movie - Movies (Default format: FLV without sound)"); - out.println(" font - Fonts (Default format: TTF)"); - out.println(" frame - Frames (Default format: PNG)"); - out.println(" sound - Sounds (Default format: MP3/WAV/FLV only sound)"); - out.println(" binaryData - Binary data (Default format: Raw data)"); - out.println(" text - Texts (Default format: Plain text)"); - out.println(" all - Every resource (but not FLA and XFL)"); - out.println(" fla - Everything to FLA compressed format"); - out.println(" xfl - Everything to uncompressed FLA format (XFL)"); - out.println(" You can export multiple types of items by using colon \",\""); - out.println(" DO NOT PUT space between comma (,) and next value."); - out.println(); - out.println(" Old DEPRECATED aliases include: (please use basic itemtypes and -format parameter instead)"); - out.println(" as, pcode, pcodehex, hex, all_as, all_pcode, all_pcodehex, textplain"); - out.println(); - out.println(" " + (cnt++) + ") -format "); - out.println(" ...sets output formats for export"); - out.println(" Values for parameter:"); - out.println(" script:as - ActionScript source"); - out.println(" script:pcode - ActionScript P-code"); - out.println(" script:pcodehex - ActionScript P-code with hex"); - out.println(" script:hex - ActionScript Hex only"); - out.println(" shape:svg - SVG format for Shapes"); - out.println(" shape:png - PNG format for Shapes"); - out.println(" shape:canvas - HTML5 Canvas format for Shapes"); - out.println(" shape:bmp - BMP format for Shapes"); - out.println(" morphshape:svg - SVG format for MorphShapes"); - out.println(" morphshape:canvas - HTML5 Canvas format for MorphShapes"); - out.println(" frame:png - PNG format for Frames"); - out.println(" frame:gif - GIF format for Frames"); - out.println(" frame:avi - AVI format for Frames"); - out.println(" frame:canvas - HTML5 Canvas format for Frames"); - out.println(" frame:pdf - PDF format for Frames"); - out.println(" frame:bmp - BMP format for Frames"); - out.println(" image:png_jpeg - PNG/JPEG format for Images"); - out.println(" image:png - PNG format for Images"); - out.println(" image:jpeg - JPEG format for Images"); - out.println(" image:bmp - BMP format for Images"); - out.println(" text:plain - Plain text format for Texts"); - out.println(" text:formatted - Formatted text format for Texts"); - out.println(" text:svg - SVG format for Texts"); - out.println(" sound:mp3_wav_flv - MP3/WAV/FLV format for Sounds"); - out.println(" sound:mp3_wav - MP3/WAV format for Sounds"); - out.println(" sound:wav - WAV format for Sounds"); - out.println(" sound:flv - FLV format for Sounds"); - out.println(" font:ttf - TTF format for Fonts"); - out.println(" font:woff - WOFF format for Fonts"); - out.println(" fla: or xfl: - Specify FLA format version"); - out.println(" - values for : cs5,cs5.5,cs6,cc"); - - out.println(" You can set multiple formats at once using comma (,)"); - out.println(" DO NOT PUT space between comma (,) and next value."); - out.println(" The prefix with colon (:) is neccessary."); - out.println(" " + (cnt++) + ") -select "); - out.println(" ...selects frames/pages for export"); - out.println(" Example formats:"); - out.println(" 1-5"); - out.println(" 2,3"); - out.println(" 2-5,7,9-"); - out.println(" DO NOT PUT space between comma (,) and next ramge."); - out.println(" " + (cnt++) + ") -selectid "); - out.println(" ...selects characters for export by character id"); - out.println(" format is same as in -select"); - out.println(" " + (cnt++) + ") -selectclass "); - out.println(" ...selects scripts to export by class name (ActionScript 3 ONLY)"); - out.println(" format:"); - out.println(" com.example.MyClass"); - out.println(" com.example.+ (all classes in package \"com.example\")"); - out.println(" com.++,net.company.MyClass (all classes in package \"com\" and all subpackages, class net.company.MyClass)"); - out.println(" DO NOT PUT space between comma (,) and next class."); - out.println(" " + (cnt++) + ") -dumpSWF "); - out.println(" ...dumps list of SWF tags to console"); - out.println(" " + (cnt++) + ") -dumpAS2 "); - out.println(" ...dumps list of AS1/2 sctipts to console"); - out.println(" " + (cnt++) + ") -dumpAS3 "); - out.println(" ...dumps list of AS3 sctipts to console"); - out.println(" " + (cnt++) + ") -compress "); - out.println(" ...Compress SWF and save it to "); - out.println(" " + (cnt++) + ") -decompress "); - out.println(" ...Decompress and save it to "); - out.println(" " + (cnt++) + ") -swf2xml "); - out.println(" ...Converts the SWF to XML file"); - out.println(" " + (cnt++) + ") -xml2swf "); - out.println(" ...Converts the XML to SWF file"); - out.println(" " + (cnt++) + ") -extract [-o |] [nocheck] [(all|biggest|smallest|first|last)]"); - out.println(" ...Extracts SWF files from ZIP or other binary files"); - out.println(" ...-o parameter should contain a file path when \"biggest\" or \"first\" parameter is specified"); - out.println(" ...-o parameter should contain a folder path when no exctaction mode or \"all\" parameter is specified"); - out.println(" " + (cnt++) + ") -renameInvalidIdentifiers (typeNumber|randomWord) "); - out.println(" ...Renames the invalid identifiers in and save it to "); - out.println(" " + (cnt++) + ") -config key=value[,key2=value2][,key3=value3...] [other parameters]"); - out.print(" ...Sets configuration values. "); - if (printConfigs) { - out.print("Available keys[current setting]:"); - for (ConfigurationItem item : commandlineConfigBoolean) { - out.print(" " + item + "[" + item.get() + "]"); - } - } - out.println(""); - out.println(" Values are boolean, you can use 0/1, true/false, on/off or yes/no."); - out.println(" If no other parameters passed, configuration is saved. Otherwise it is used only once."); - out.println(" DO NOT PUT space between comma (,) and next value."); - out.println(" " + (cnt++) + ") -onerror (abort|retryN|ignore)"); - out.println(" ...error handling mode. \"abort\" stops the exporting, \"retry\" tries the exporting N times, \"ignore\" ignores the current file"); - out.println(" " + (cnt++) + ") -timeout "); - out.println(" ...decompilation timeout for a single method in AS3 or single action in AS1/2 in seconds"); - out.println(" " + (cnt++) + ") -exportTimeout "); - out.println(" ...total export timeout in seconds"); - out.println(" " + (cnt++) + ") -exportFileTimeout "); - out.println(" ...export timeout for a single AS3 class in seconds"); - out.println(" " + (cnt++) + ") -flashpaper2pdf "); - out.println(" ...converts FlashPaper SWF file to PDF . Use -zoom parameter to specify image quality."); - out.println(" " + (cnt++) + ") -zoom "); - out.println(" ...apply zoom during export (currently for FlashPaper conversion only)"); - out.println(" " + (cnt++) + ") -replace (|) [methodBodyIndex1] [(|) [methodBodyIndex2]]..."); - out.println(" ...replaces the data of the specified BinaryData, Image, DefineSound tag or Script"); - out.println(" ...methodBodyIndexN parameter should be specified if and only if the imported entity is an AS3 P-Code"); - printCmdLineUsageExamples(out); - } - - private static void printCmdLineUsageExamples(PrintStream out) { - out.println(); - out.println("Examples:"); - out.println("java -jar ffdec.jar myfile.swf"); - out.println("java -jar ffdec.jar -proxy"); - out.println("java -jar ffdec.jar -proxy -P1234"); - out.println("java -jar ffdec.jar -export script \"C:\\decompiled\" myfile.swf"); - out.println("java -jar ffdec.jar -selectclass com.example.MyClass,com.example.SecondClass -export script \"C:\\decompiled\" myfile.swf"); - out.println("java -jar ffdec.jar -format script:pcode -export script \"C:\\decompiled\" myfile.swf"); - out.println("java -jar ffdec.jar -format script:pcode,text:plain -export script,text,image \"C:\\decompiled\" myfile.swf"); - out.println("java -jar ffdec.jar -format fla:cs5.5 -export fla \"C:\\sources\\myfile.fla\" myfile.swf"); - out.println("java -jar ffdec.jar -dumpSWF myfile.swf"); - out.println("java -jar ffdec.jar -compress myfile.swf myfiledec.swf"); - out.println("java -jar ffdec.jar -decompress myfiledec.swf myfile.swf"); - out.println("java -jar ffdec.jar -onerror ignore -export script \"C:\\decompiled\" myfile.swf"); - out.println("java -jar ffdec.jar -onerror retry 5 -export script \"C:\\decompiled\" myfile.swf"); - out.println("java -jar ffdec.jar -config autoDeobfuscate=1,parallelSpeedUp=0 -export script \"C:\\decompiled\" myfile.swf"); - out.println(""); - out.println("Instead of \"java -jar ffdec.jar\" you can use ffdec.bat on Windows, ffdec.sh on Linux/MacOs"); - } - - /** - * Parses the console arguments - * - * @param arguments Arguments - * @return paths to the file which should be opened or null - * @throws java.io.IOException On error - */ - public static String[] parseArguments(String[] arguments) throws IOException { - Level traceLevel = Level.WARNING; - Stack args = new Stack<>(); - for (int i = arguments.length - 1; i >= 0; i--) { - String arg = arguments[i]; - if (arg.length() > 0) { - args.add(arg); - } - } - - AbortRetryIgnoreHandler handler = null; - Map format = new HashMap<>(); - double zoom = 1; - Selection selection = new Selection(); - Selection selectionIds = new Selection(); - List selectionClasses = null; - String nextParam = null, nextParamOriginal = null; - OUTER: - while (true) { - nextParamOriginal = args.pop(); - if (nextParamOriginal != null) { - nextParam = nextParamOriginal.toLowerCase(); - } - switch (nextParam) { - case "-selectid": - selectionIds = parseSelect(args); - break; - case "-select": - selection = parseSelect(args); - break; - case "-selectclass": - selectionClasses = parseSelectClass(args); - break; - case "-zoom": - zoom = parseZoom(args); - break; - case "-format": - format = parseFormat(args); - break; - case "-config": - parseConfig(args); - if (args.isEmpty()) { - Configuration.saveConfig(); - System.out.println("Configuration saved"); - return null; - } - break; - case "-onerror": - handler = parseOnError(args); - break; - case "-timeout": - parseTimeout(args); - break; - case "-exporttimeout": - parseExportTimeout(args); - break; - case "-exportfiletimeout": - parseExportFileTimeout(args); - break; - case "-stdout": - parseStdOut(args); - break; - case "-stderr": - parseStdErr(args); - break; - case "-affinity": - parseAffinity(args); - break; - case "-priority": - parsePriority(args); - break; - case "-verbose": - traceLevel = Level.FINE; - break; - case "-debug": - for (int i = 0; i < arguments.length; i++) { - System.out.println(i + ".:" + arguments[i]); - } - Configuration.debugMode.set(true); - break; - default: - break OUTER; - } - if (args.isEmpty()) { - return null; - } - } - - String command = ""; - if (nextParam.startsWith("-")) { - command = nextParam.substring(1); - } - - if (command.equals("removefromcontextmenu")) { - if (!args.isEmpty()) { - badArguments(command); - } - ContextMenuTools.addToContextMenu(false, true); - System.exit(0); - } else if (command.equals("addtocontextmenu")) { - if (!args.isEmpty()) { - badArguments(command); - } - ContextMenuTools.addToContextMenu(true, true); - System.exit(0); - } else if (command.equals("proxy")) { - parseProxy(args); - } else if (command.equals("export")) { - parseExport(selectionClasses, selection, selectionIds, args, handler, traceLevel, format, zoom); - } else if (command.equals("compress")) { - parseCompress(args); - } else if (command.equals("decompress")) { - parseDecompress(args); - } else if (command.equals("swf2xml")) { - parseSwf2Xml(args); - } else if (command.equals("xml2swf")) { - parseXml2Swf(args); - } else if (command.equals("extract")) { - parseExtract(args); - } else if (command.equals("renameinvalididentifiers")) { - parseRenameInvalidIdentifiers(args); - } else if (command.equals("dumpswf")) { - parseDumpSwf(args); - } else if (command.equals("dumpas2")) { - parseDumpAS2(args); - } else if (command.equals("dumpas3")) { - parseDumpAS3(args); - } else if (command.equals("flashpaper2pdf")) { - parseFlashPaperToPdf(selection, zoom, args); - } else if (command.equals("replace")) { - parseReplace(args); - } else if (command.equals("as3compiler")) { - ActionScriptParser.compile(null /*?*/, args.pop(), args.pop(), 0); - } else if (nextParam.equals("-help") || nextParam.equals("--help") || nextParam.equals("/?") || nextParam.equals("\\_") /* /? translates as this on windows */) { - printHeader(); - printCmdLineUsage(); - System.exit(0); - } else if (nextParam.equals("--webhelp")) { //for generating commandline usage on webpages - ByteArrayOutputStream whbaos = new ByteArrayOutputStream(); - printCmdLineUsage(new PrintStream(whbaos, true), false); - String wh = new String(whbaos.toByteArray()); - wh = wh.replace("<", "<").replace(">", ">"); - System.out.println(wh); - } else { - args.push(nextParamOriginal); // file names should be the original one - String[] fileNames = args.toArray(new String[args.size()]); - boolean allParamIsAFile = true; - for (String fileName : fileNames) { - File file = new File(fileName); - if (!file.exists() || !file.isFile()) { - allParamIsAFile = false; - } - } - - if (allParamIsAFile) { - return fileNames; - } else { - badArguments(); - } - } - - return null; - } - - public static void printHeader() { - System.out.println(ApplicationInfo.applicationVerName); - for (int i = 0; i < ApplicationInfo.applicationVerName.length(); i++) { - System.out.print("-"); - } - System.out.println(); - } - - public static void badArguments() { - badArguments(null); - } - - public static void badArguments(String command) { - System.err.println("Error: Bad Commandline Arguments!"); - printCmdLineUsage(); - System.exit(1); - } - - private static void setConfigurations(String cfgStr) { - String[] cfgs; - if (cfgStr.contains(",")) { - cfgs = cfgStr.split(","); - } else { - cfgs = new String[]{cfgStr}; - } - - for (String c : cfgs) { - String[] cp; - if (c.contains("=")) { - cp = c.split("="); - } else { - cp = new String[]{c, "1"}; - } - String key = cp[0]; - String value = cp[1]; - if (key.toLowerCase().equals("paralelSpeedUp".toLowerCase())) { - key = "parallelSpeedUp"; - } - for (ConfigurationItem item : commandlineConfigBoolean) { - if (key.toLowerCase().equals(item.getName().toLowerCase())) { - Boolean bValue = parseBooleanConfigValue(value); - if (bValue != null) { - System.out.println("Config " + item.getName() + " set to " + bValue); - item.set(bValue); - } - } - } - } - } - - private static Boolean parseBooleanConfigValue(String value) { - if (value == null) { - return null; - } - - Boolean bValue = null; - value = value.toLowerCase(); - if (value.equals("0") || value.equals("false") || value.equals("no") || value.equals("off")) { - bValue = false; - } - if (value.equals("1") || value.equals("true") || value.equals("yes") || value.equals("on")) { - bValue = true; - } - return bValue; - } - - private static void parseConfig(Stack args) { - if (args.isEmpty()) { - System.err.println("Config values expected"); - badArguments(); - } - setConfigurations(args.pop()); - } - - private static class Range { - - public Integer min; - - public Integer max; - - public Range(Integer min, Integer max) { - this.min = min; - this.max = max; - } - - public boolean contains(int index) { - int minimum = min == null ? Integer.MIN_VALUE : min; - int maximum = max == null ? Integer.MAX_VALUE : max; - - return index >= minimum && index <= maximum; - } - } - - private static class Selection { - - public List ranges; - - public Selection() { - this.ranges = new ArrayList<>(); - this.ranges.add(new Range(null, null)); - } - - public Selection(List ranges) { - this.ranges = ranges; - } - - public boolean contains(int index) { - for (Range r : ranges) { - if (r.contains(index)) { - return true; - } - } - return false; - } - } - - private static Selection parseSelect(Stack args) { - List ret = new ArrayList<>(); - if (args.isEmpty()) { - System.err.println("range parameter expected"); - badArguments(); - } - String range = args.pop(); - String[] ranges; - if (range.contains(",")) { - ranges = range.split(","); - } else { - ranges = new String[]{range}; - } - for (String r : ranges) { - Integer min = null; - Integer max = null; - if (r.contains("-")) { - String ps[] = r.split("\\-"); - if (ps.length != 2) { - System.err.println("invalid range"); - badArguments(); - } - try { - if (!"".equals(ps[0])) { - min = Integer.parseInt(ps[0]); - } - if (!"".equals(ps[1])) { - max = Integer.parseInt(ps[1]); - } - } catch (NumberFormatException nfe) { - System.err.println("invalid range"); - badArguments(); - } - } else { - try { - min = Integer.parseInt(r); - max = min; - } catch (NumberFormatException nfe) { - System.err.println("invalid range"); - badArguments(); - } - } - ret.add(new Range(min, max)); - } - return new Selection(ret); - } - - private static double parseZoom(Stack args) { - if (args.isEmpty()) { - System.err.println("zoom parameter expected"); - badArguments(); - } - try { - return Double.parseDouble(args.pop()); - } catch (NumberFormatException nfe) { - System.err.println("invalid zoom"); - badArguments(); - } - return 1; - } - - private static AbortRetryIgnoreHandler parseOnError(Stack args) { - int errorMode = AbortRetryIgnoreHandler.UNDEFINED; - int retryCount = 0; - - if (args.isEmpty()) { - System.err.println("onerror parameter expected"); - badArguments(); - } - String errorModeParameter = args.pop(); - switch (errorModeParameter) { - case "abort": - errorMode = AbortRetryIgnoreHandler.ABORT; - break; - case "retry": - errorMode = AbortRetryIgnoreHandler.RETRY; - if (args.isEmpty()) { - System.err.println("onerror retry count parameter expected"); - badArguments(); - } - - try { - retryCount = Integer.parseInt(args.pop()); - } catch (NumberFormatException nex) { - System.err.println("Bad retry count number"); - } - break; - case "ignore": - errorMode = AbortRetryIgnoreHandler.IGNORE; - break; - } - - return new ConsoleAbortRetryIgnoreHandler(errorMode, retryCount); - } - - private static void parseTimeout(Stack args) { - if (args.isEmpty()) { - System.err.println("timeout parameter expected"); - badArguments(); - } - try { - int timeout = Integer.parseInt(args.pop()); - Configuration.decompilationTimeoutSingleMethod.set(timeout); - } catch (NumberFormatException nex) { - System.err.println("Bad timeout value"); - } - } - - private static void parseExportTimeout(Stack args) { - if (args.isEmpty()) { - System.err.println("timeout parameter expected"); - badArguments(); - } - try { - int timeout = Integer.parseInt(args.pop()); - Configuration.exportTimeout.set(timeout); - } catch (NumberFormatException nex) { - System.err.println("Bad timeout value"); - } - } - - private static void parseExportFileTimeout(Stack args) { - if (args.isEmpty()) { - System.err.println("timeout parameter expected"); - badArguments(); - } - try { - int timeout = Integer.parseInt(args.pop()); - Configuration.decompilationTimeoutFile.set(timeout); - } catch (NumberFormatException nex) { - System.err.println("Bad timeout value"); - } - } - - private static void parseStdOut(Stack args) { - if (args.isEmpty()) { - System.err.println("stdOut parameter expected"); - badArguments(); - } - - stdOut = args.pop(); - } - - private static void parseStdErr(Stack args) { - if (args.isEmpty()) { - System.err.println("stdErr parameter expected"); - badArguments(); - } - - stdErr = args.pop(); - } - - private static void parseAffinity(Stack args) { - if (Platform.isWindows()) { - if (args.isEmpty()) { - System.err.println("affinity parameter expected"); - badArguments(); - } - try { - int affinityMask = Integer.parseInt(args.pop()); - Kernel32.INSTANCE.SetProcessAffinityMask(Kernel32.INSTANCE.GetCurrentProcess(), affinityMask); - } catch (NumberFormatException nex) { - System.err.println("Bad affinityMask value"); - } - } else { - System.err.println("Process affinity setting is only available on Windows platform."); - } - } - - private static void parsePriority(Stack args) { - if (Platform.isWindows()) { - if (args.isEmpty()) { - System.err.println("priority parameter expected"); - badArguments(); - } - String priority = args.pop(); - int priorityClass = 0; - switch (priority) { - case "low": - priorityClass = Kernel32.IDLE_PRIORITY_CLASS; - break; - case "belownormal": - priorityClass = Kernel32.BELOW_NORMAL_PRIORITY_CLASS; - break; - case "normal": - priorityClass = Kernel32.NORMAL_PRIORITY_CLASS; - break; - case "abovenormal": - priorityClass = Kernel32.ABOVE_NORMAL_PRIORITY_CLASS; - break; - case "high": - priorityClass = Kernel32.HIGH_PRIORITY_CLASS; - break; - case "realtime": - priorityClass = Kernel32.REALTIME_PRIORITY_CLASS; - break; - default: - System.err.println("Bad affinityMask value"); - } - if (priorityClass != 0) { - Kernel32.INSTANCE.SetPriorityClass(Kernel32.INSTANCE.GetCurrentProcess(), priorityClass); - } - } else { - System.err.println("Process priority setting is only available on Windows platform."); - } - } - - private static void parseProxy(Stack args) { - int port = 55555; - String portStr = args.peek(); - if (portStr != null && portStr.startsWith("-P")) { - args.pop(); - try { - port = Integer.parseInt(portStr.substring(2)); - } catch (NumberFormatException nex) { - System.err.println("Bad port number"); - } - } - Main.startProxy(port); - } - - private static List parseSelectClassOld(Stack args) { - List ret = new ArrayList<>(); - if (!args.isEmpty() && args.peek().equals("-selectas3class")) { - args.pop(); - while (!args.isEmpty()) { - ret.add(args.pop()); - } - System.err.println("WARNING: Using deprecated -selectas3class parameter. Please use -selectclass instead. See --help for usage."); - } - return ret; - - } - - private static List parseSelectClass(Stack args) { - if (args.size() < 1) { - badArguments(); - } - List ret = new ArrayList<>(); - String classesStr = args.pop(); - String classes[]; - if (classesStr.contains(",")) { - classes = classesStr.split(","); - } else { - classes = new String[]{classesStr}; - } - ret.addAll(Arrays.asList(classes)); - return ret; - - } - - private static void parseExport(List selectionClasses, Selection selection, Selection selectionIds, Stack args, AbortRetryIgnoreHandler handler, Level traceLevel, Map formats, double zoom) { - if (args.size() < 3) { - badArguments(); - } - String[] validExportItems = new String[]{ - "script", - "image", - "shape", - "morphshape", - "movie", - "font", - "frame", - "sound", - "binarydata", - "text", - "all", - "fla", - "xfl" - }; - - String[] removedExportFormats = new String[]{ - "as", - "pcode", - "hex", - "pcodehex", - "all_as", - "all_pcode", - "all_pcodehex", - "all_hex", - "textplain" - }; - - if (handler == null) { - handler = new ConsoleAbortRetryIgnoreHandler(AbortRetryIgnoreHandler.UNDEFINED, 0); - } - String exportFormatString = args.pop().toLowerCase(); - List exportFormats = Arrays.asList(exportFormatString.split(",")); - long startTime = System.currentTimeMillis(); - - File outDirBase = new File(args.pop()); - File inFileOrFolder = new File(args.pop()); - if (!inFileOrFolder.exists()) { - System.err.println("Input SWF file does not exist!"); - badArguments(); - } - printHeader(); - boolean exportOK = true; - - List as3classes = new ArrayList<>(); - if (selectionClasses != null) { - as3classes.addAll(selectionClasses); - } - - try { - File[] inFiles; - boolean singleFile = true; - if (inFileOrFolder.isDirectory()) { - singleFile = false; - inFiles = inFileOrFolder.listFiles(new FilenameFilter() { - - @Override - public boolean accept(File dir, String name) { - return name.toLowerCase().endsWith(".swf"); - } - }); - } else { - inFiles = new File[]{inFileOrFolder}; - } - - for (File inFile : inFiles) { - String inFileName = Path.getFileNameWithoutExtension(inFile); - if (stdOut != null) { - System.setOut(new PrintStream(new FileOutputStream(stdOut.replace("{swfFile}", inFileName), true))); - } - - if (stdErr != null) { - System.setErr(new PrintStream(new FileOutputStream(stdErr.replace("{swfFile}", inFileName), true))); - Main.initLogging(Configuration.debugMode.get()); - } - - long startTimeSwf = 0; - if (!singleFile) { - startTimeSwf = System.currentTimeMillis(); - System.out.println("Start exporting " + inFile.getName()); - } - - SWFSourceInfo sourceInfo = new SWFSourceInfo(null, inFile.getAbsolutePath(), inFile.getName()); - SWF swf = new SWF(new FileInputStream(inFile), sourceInfo.getFile(), sourceInfo.getFileTitle(), Configuration.parallelSpeedUp.get()); - swf.swfList = new SWFList(); - swf.swfList.sourceInfo = sourceInfo; - String outDir = outDirBase.getAbsolutePath(); - if (!singleFile) { - outDir = Path.combine(outDir, inFile.getName()); - } - - List extags = new ArrayList<>(); - for (Tag t : swf.tags) { - if (t instanceof CharacterIdTag) { - CharacterIdTag c = (CharacterIdTag) t; - if (selectionIds.contains(c.getCharacterId())) { - extags.add(t); - } - } else { - if (selectionIds.contains(0)) { - extags.add(t); - } - } - } - - final Level level = traceLevel; - swf.addEventListener(new EventListener() { - @Override - public void handleExportingEvent(String type, int index, int count, Object data) { - if (level.intValue() <= Level.FINE.intValue()) { - String text = "Exporting "; - if (type != null && type.length() > 0) { - text += type + " "; - } - System.out.println(text + index + "/" + count + " " + data); - } - } - - @Override - public void handleExportedEvent(String type, int index, int count, Object data) { - String text = "Exported "; - if (type != null && type.length() > 0) { - text += type + " "; - } - System.out.println(text + index + "/" + count + " " + data); - } - - @Override - public void handleEvent(String event, Object data) { - } - }); - - // First check all the specified export formats - for (String exportFormat : exportFormats) { - if (Arrays.asList(removedExportFormats).contains(exportFormat)) { - System.err.println("Error: Export format : " + exportFormat + " was REMOVED. Run application with --help parameter to see available formats."); - System.exit(1); - } else if (!Arrays.asList(validExportItems).contains(exportFormat)) { - System.err.println("Invalid export item:" + exportFormat); - badArguments(); - } - } - - // Here the exportFormats array should contain only validitems - commandLineMode = true; - boolean exportAll = exportFormats.contains("all"); - boolean multipleExportTypes = exportAll || exportFormats.size() > 1; - EventListener evl = swf.getExportEventListener(); - - if (exportAll || exportFormats.contains("image")) { - System.out.println("Exporting images..."); - new ImageExporter().exportImages(handler, outDir + (multipleExportTypes ? File.separator + ImageExportSettings.EXPORT_FOLDER_NAME : ""), extags, new ImageExportSettings(enumFromStr(formats.get("image"), ImageExportMode.class)), evl); - } - - if (exportAll || exportFormats.contains("shape")) { - System.out.println("Exporting shapes..."); - new ShapeExporter().exportShapes(handler, outDir + (multipleExportTypes ? File.separator + ShapeExportSettings.EXPORT_FOLDER_NAME : ""), extags, new ShapeExportSettings(enumFromStr(formats.get("shape"), ShapeExportMode.class), zoom), evl); - } - - if (exportAll || exportFormats.contains("morphshape")) { - System.out.println("Exporting morphshapes..."); - new MorphShapeExporter().exportMorphShapes(handler, outDir + (multipleExportTypes ? File.separator + MorphShapeExportSettings.EXPORT_FOLDER_NAME : ""), extags, new MorphShapeExportSettings(enumFromStr(formats.get("morphshape"), MorphShapeExportMode.class), zoom), evl); - } - - if (exportAll || exportFormats.contains("movie")) { - System.out.println("Exporting movies..."); - new MovieExporter().exportMovies(handler, outDir + (multipleExportTypes ? File.separator + MovieExportSettings.EXPORT_FOLDER_NAME : ""), extags, new MovieExportSettings(enumFromStr(formats.get("movie"), MovieExportMode.class)), evl); - } - - if (exportAll || exportFormats.contains("font")) { - System.out.println("Exporting fonts..."); - new FontExporter().exportFonts(handler, outDir + (multipleExportTypes ? File.separator + FontExportSettings.EXPORT_FOLDER_NAME : ""), extags, new FontExportSettings(enumFromStr(formats.get("font"), FontExportMode.class)), evl); - } - - if (exportAll || exportFormats.contains("sound")) { - System.out.println("Exporting sounds..."); - new SoundExporter().exportSounds(handler, outDir + (multipleExportTypes ? File.separator + SoundExportSettings.EXPORT_FOLDER_NAME : ""), extags, new SoundExportSettings(enumFromStr(formats.get("sound"), SoundExportMode.class)), evl); - } - - if (exportAll || exportFormats.contains("binarydata")) { - System.out.println("Exporting binaryData..."); - new BinaryDataExporter().exportBinaryData(handler, outDir + (multipleExportTypes ? File.separator + BinaryDataExportSettings.EXPORT_FOLDER_NAME : ""), extags, new BinaryDataExportSettings(enumFromStr(formats.get("binarydata"), BinaryDataExportMode.class)), evl); - } - - if (exportAll || exportFormats.contains("text")) { - System.out.println("Exporting texts..."); - Boolean singleTextFile = parseBooleanConfigValue(formats.get("singletext")); - if (singleTextFile == null) { - singleTextFile = Configuration.textExportSingleFile.get(); - } - new TextExporter().exportTexts(handler, outDir + (multipleExportTypes ? File.separator + TextExportSettings.EXPORT_FOLDER_NAME : ""), extags, new TextExportSettings(enumFromStr(formats.get("text"), TextExportMode.class), singleTextFile, zoom), evl); - } - - if (exportAll || exportFormats.contains("frame")) { - System.out.println("Exporting frames..."); - List frames = new ArrayList<>(); - for (int i = 0; i < swf.frameCount; i++) { - if (selection.contains(i + 1)) { - frames.add(i); - } - } - new FrameExporter().exportFrames(handler, outDir + (multipleExportTypes ? File.separator + FrameExportSettings.EXPORT_FOLDER_NAME : ""), swf, 0, frames, new FrameExportSettings(enumFromStr(formats.get("frame"), FrameExportMode.class), zoom), evl); - } - - boolean parallel = Configuration.parallelSpeedUp.get(); - String scriptsFolder = Path.combine(outDir, ScriptExportSettings.EXPORT_FOLDER_NAME); - Path.createDirectorySafe(new File(scriptsFolder)); - Boolean singleScriptFile = parseBooleanConfigValue(formats.get("singlescript")); - if (singleScriptFile == null) { - singleScriptFile = Configuration.scriptExportSingleFile.get(); - } - - if (parallel && singleScriptFile) { - System.out.println("Single file script export is not supported with enabled parallel speedup"); - singleScriptFile = false; - } - - ScriptExportSettings scriptExportSettings = new ScriptExportSettings(enumFromStr(formats.get("script"), ScriptExportMode.class), singleScriptFile); - if (exportAll || exportFormats.contains("script")) { - System.out.println("Exporting scripts..."); - if (as3classes.isEmpty()) { - as3classes = parseSelectClassOld(args); - } - - String singleFileName = Path.combine(scriptsFolder, swf.getShortFileName() + scriptExportSettings.getFileExtension()); - try (FileTextWriter writer = scriptExportSettings.singleFile ? new FileTextWriter(Configuration.getCodeFormatting(), new FileOutputStream(singleFileName)) : null) { - scriptExportSettings.singleFileWriter = writer; - if (!as3classes.isEmpty()) { - for (String as3class : as3classes) { - exportOK = exportOK && swf.exportAS3Class(as3class, scriptsFolder, scriptExportSettings, parallel, evl); - } - } else { - exportOK = exportOK && swf.exportActionScript(handler, scriptsFolder, scriptExportSettings, parallel, evl) != null; - } - } - } - - if (exportFormats.contains("fla")) { - System.out.println("Exporting FLA..."); - FLAVersion flaVersion = FLAVersion.fromString(formats.get("fla")); - if (flaVersion == null) { - flaVersion = FLAVersion.CS6; //Defaults to CS6 - } - swf.exportFla(handler, outDir + (multipleExportTypes ? File.separator + "fla" : ""), inFile.getName(), ApplicationInfo.APPLICATION_NAME, ApplicationInfo.applicationVerName, ApplicationInfo.version, Configuration.parallelSpeedUp.get(), flaVersion); - } - - if (exportFormats.contains("xfl")) { - System.out.println("Exporting XFL..."); - FLAVersion xflVersion = FLAVersion.fromString(formats.get("xfl")); - if (xflVersion == null) { - xflVersion = FLAVersion.CS6; //Defaults to CS6 - } - swf.exportXfl(handler, outDir + (multipleExportTypes ? File.separator + "xfl" : ""), inFile.getName(), ApplicationInfo.APPLICATION_NAME, ApplicationInfo.applicationVerName, ApplicationInfo.version, Configuration.parallelSpeedUp.get(), xflVersion); - } - - if (!singleFile) { - long stopTimeSwf = System.currentTimeMillis(); - long time = stopTimeSwf - startTimeSwf; - System.out.println("Export finished: " + inFile.getName() + " Export time: " + Helper.formatTimeSec(time)); - } - - swf.clearAllCache(); - } - } catch (OutOfMemoryError | Exception ex) { - System.err.print("FAIL: Exporting Failed on Exception - "); - Logger.getLogger(CommandLineArgumentParser.class.getName()).log(Level.SEVERE, null, ex); - System.exit(1); - } - - long stopTime = System.currentTimeMillis(); - long time = stopTime - startTime; - System.out.println("Export finished. Total export time: " + Helper.formatTimeSec(time)); - if (exportOK) { - System.out.println("OK"); - System.exit(0); - } else { - System.err.println("FAIL"); - System.exit(1); - } - } - - private static void parseCompress(Stack args) { - if (args.size() < 2) { - badArguments(); - } - - try { - try (InputStream fis = new BufferedInputStream(new FileInputStream(args.pop())); - OutputStream fos = new BufferedOutputStream(new FileOutputStream(args.pop()))) { - if (SWF.fws2cws(fis, fos)) { - System.out.println("OK"); - } else { - System.err.println("FAIL"); - } - } catch (FileNotFoundException ex) { - System.err.println("File not found."); - } - } catch (IOException ex) { - Logger.getLogger(CommandLineArgumentParser.class.getName()).log(Level.SEVERE, null, ex); - } - - System.exit(0); - } - - private static void parseDecompress(Stack args) { - if (args.size() < 2) { - badArguments(); - } - - try { - try (InputStream fis = new BufferedInputStream(new FileInputStream(args.pop())); - OutputStream fos = new BufferedOutputStream(new FileOutputStream(args.pop()))) { - if (SWF.decompress(fis, fos)) { - System.out.println("OK"); - System.exit(0); - } else { - System.err.println("FAIL"); - System.exit(1); - } - } catch (FileNotFoundException ex) { - System.err.println("File not found."); - } - } catch (IOException ex) { - Logger.getLogger(CommandLineArgumentParser.class.getName()).log(Level.SEVERE, null, ex); - } - - System.exit(0); - } - - private static void parseSwf2Xml(Stack args) { - if (args.size() < 2) { - badArguments(); - } - - try { - try (FileInputStream is = new FileInputStream(args.pop())) { - SWF swf = new SWF(is, Configuration.parallelSpeedUp.get()); - new SwfXmlExporter().exportXml(swf, new File(args.pop())); - } catch (FileNotFoundException ex) { - System.err.println("File not found."); - } catch (InterruptedException ex) { - Logger.getLogger(CommandLineArgumentParser.class.getName()).log(Level.SEVERE, null, ex); - } - } catch (IOException ex) { - Logger.getLogger(CommandLineArgumentParser.class.getName()).log(Level.SEVERE, null, ex); - } - - System.exit(0); - } - - private static void parseXml2Swf(Stack args) { - if (args.size() < 2) { - badArguments(); - } - - try { - String xml = Helper.readTextFile(args.pop()); - SWF swf = new SWF(); - new SwfXmlImporter().importSwf(swf, xml); - try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(new File(args.pop())))) { - swf.saveTo(new BufferedOutputStream(fos)); - } - } catch (IOException ex) { - Logger.getLogger(CommandLineArgumentParser.class.getName()).log(Level.SEVERE, null, ex); - } - - System.exit(0); - } - - private static void parseExtract(Stack args) { - if (args.size() < 1) { - badArguments(); - } - - String fileName = args.pop(); - SearchMode mode = SearchMode.ALL; - - boolean noCheck = false; - String output = null; - - if (args.size() > 0 && args.peek().toLowerCase().equals("-o")) { - args.pop(); - if (args.size() < 1) { - badArguments(); - } - output = args.pop(); - } - - if (args.size() > 0 && args.peek().toLowerCase().equals("nocheck")) { - noCheck = true; - args.pop(); - } - - if (args.size() > 0) { - String modeStr = args.pop().toLowerCase(); - switch (modeStr) { - case "biggest": - mode = SearchMode.BIGGEST; - break; - case "smallest": - mode = SearchMode.SMALLEST; - break; - case "first": - mode = SearchMode.FIRST; - break; - case "last": - mode = SearchMode.LAST; - break; - } - } - - try { - SWFSourceInfo sourceInfo = new SWFSourceInfo(null, fileName, null); - if (!sourceInfo.isBundle()) { - System.err.println("Error: should be a bundle. (ZIP or non SWF binary file)"); - System.exit(1); - } - SWFBundle bundle = sourceInfo.getBundle(noCheck, mode); - List> streamsToExtract = new ArrayList<>(); - for (Map.Entry streamEntry : bundle.getAll().entrySet()) { - InputStream stream = streamEntry.getValue(); - stream.reset(); - streamsToExtract.add(streamEntry); - } - - for (Map.Entry streamEntry : streamsToExtract) { - InputStream stream = streamEntry.getValue(); - stream.reset(); - String fileNameOut; - if (mode != SearchMode.ALL) { - if (output == null) { - fileNameOut = Path.getFileNameWithoutExtension(new File(fileName)) + ".swf"; - } else { - fileNameOut = output; - } - } else { - fileNameOut = streamEntry.getKey() + ".swf"; - if (output != null) { - fileNameOut = Path.combine(output, fileNameOut); - } - } - - try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(fileNameOut))) { - byte[] swfData = new byte[stream.available()]; - int cnt = stream.read(swfData); - fos.write(swfData, 0, cnt); - } - } - } catch (IOException ex) { - Logger.getLogger(CommandLineArgumentParser.class.getName()).log(Level.SEVERE, null, ex); - } - - System.exit(0); - } - - private static void parseRenameInvalidIdentifiers(Stack args) { - if (args.size() < 3) { - badArguments(); - } - - String renameTypeStr = args.pop(); - RenameType renameType; - switch (renameTypeStr.toLowerCase()) { - case "typenumber": - renameType = RenameType.TYPENUMBER; - break; - case "randomword": - renameType = RenameType.RANDOMWORD; - break; - default: - System.err.println("Invalid rename type:" + renameTypeStr); - badArguments(); - return; - } - - try { - try (InputStream fis = new BufferedInputStream(new FileInputStream(args.pop())); - OutputStream fos = new BufferedOutputStream(new FileOutputStream(args.pop()))) { - if (SWF.renameInvalidIdentifiers(renameType, fis, fos)) { - System.out.println("OK"); - System.exit(0); - } else { - System.err.println("FAIL"); - System.exit(1); - } - } catch (FileNotFoundException ex) { - System.err.println("File not found."); - } - } catch (IOException ex) { - Logger.getLogger(CommandLineArgumentParser.class.getName()).log(Level.SEVERE, null, ex); - } - - System.exit(0); - } - - private static Map parseFormat(Stack args) { - if (args.size() < 1) { - badArguments(); - } - String fmtStr = args.pop(); - String[] fmts; - if (fmtStr.contains(",")) { - fmts = fmtStr.split(","); - } else { - fmts = new String[]{fmtStr}; - } - Map ret = new HashMap<>(); - for (String fmt : fmts) { - String[] parts = fmt.split(":"); - ret.put(parts[0].toLowerCase(), parts[1].toLowerCase()); - } - return ret; - } - - private static void parseFlashPaperToPdf(Selection selection, double zoom, Stack args) { - if (args.size() < 2) { - badArguments(); - } - File inFile = new File(args.pop()); - File outFile = new File(args.pop()); - printHeader(); - - try (FileInputStream is = new FileInputStream(inFile)) { - - PDFJob job = null; - - SWF swf = new SWF(is, Configuration.parallelSpeedUp.get()); - int totalPages = 0; - - for (Tag t : swf.tags) { - if (t instanceof DefineSpriteTag) { - DefineSpriteTag ds = (DefineSpriteTag) t; - if ("page1".equals(ds.getExportName())) { - totalPages = 1; - } else { - if (totalPages > 0) { - totalPages++; - } - } - } - } - - int page = 0; - - for (Tag t : swf.tags) { - if (t instanceof DefineSpriteTag) { - DefineSpriteTag ds = (DefineSpriteTag) t; - if ("page1".equals(ds.getExportName())) { - page = 1; - job = new PDFJob(new BufferedOutputStream(new FileOutputStream(outFile))); - } else { - if (page > 0) { - page++; - } - } - if (("page" + page).equals(ds.getExportName())) { - if (!selection.contains(page)) { - continue; - } - System.out.print("Page " + page + "/" + totalPages + "..."); - RECT displayRect = new RECT(ds.getTimeline().displayRect); - //displayRect.Xmax *= zoom; - //displayRect.Ymax *= zoom; - Matrix m = new Matrix(); - //m.scale(zoom); - BufferedImage img = SWF.frameToImageGet(ds.getTimeline(), 0, 0, null, 0, displayRect, m, new ColorTransform(), Color.white, false, zoom).getBufferedImage(); - PageFormat pf = new PageFormat(); - pf.setOrientation(PageFormat.PORTRAIT); - Paper p = new Paper(); - p.setSize(img.getWidth(), img.getHeight()); - pf.setPaper(p); - Graphics g = job.getGraphics(pf); - g.drawImage(img, 0, 0, img.getWidth(), img.getHeight(), null); - g.dispose(); - System.out.println("OK"); - - } - } - } - - if (job == null) { - System.err.println("No pages found. Maybe it is not a FlashPaper file"); - System.exit(2); - } - job.end(); - - } catch (FileNotFoundException ex) { - System.err.println("File not found"); - System.exit(1); - } catch (IOException | InterruptedException ex) { - System.err.println("I/O error during reading"); - System.exit(2); - } - System.exit(0); - } - - private static void parseReplace(Stack args) { - if (args.size() < 4) { - badArguments(); - } - - File inFile = new File(args.pop()); - File outFile = new File(args.pop()); - try { - try (FileInputStream is = new FileInputStream(inFile)) { - SWF swf = new SWF(is, Configuration.parallelSpeedUp.get()); - while (true) { - String objectToReplace = args.pop(); - - if (objectToReplace.matches("\\d+")) { - // replace character tag - int characterId = 0; - try { - characterId = Integer.parseInt(objectToReplace); - } catch (NumberFormatException nfe) { - System.err.println("CharacterId should be integer"); - System.exit(1); - } - if (!swf.getCharacters().containsKey(characterId)) { - System.err.println("CharacterId does not exist"); - System.exit(1); - } - - CharacterTag characterTag = swf.getCharacter(characterId); - String repFile = args.pop(); - byte[] data = Helper.readFile(repFile); - if (characterTag instanceof DefineBinaryDataTag) { - DefineBinaryDataTag defineBinaryData = (DefineBinaryDataTag) characterTag; - new BinaryDataImporter().importData(defineBinaryData, data); - } else if (characterTag instanceof ImageTag) { - ImageTag imageTag = (ImageTag) characterTag; - new ImageImporter().importImage(imageTag, data); - } else if (characterTag instanceof SoundTag) { - SoundTag st = (SoundTag) characterTag; - int soundFormat = SoundFormat.FORMAT_UNCOMPRESSED_LITTLE_ENDIAN; - if (repFile.toLowerCase().endsWith(".mp3")) { - soundFormat = SoundFormat.FORMAT_MP3; - } - boolean ok = st.setSound(new ByteArrayInputStream(data), soundFormat); - if (!ok) { - System.err.println("Import FAILED. Maybe unsuppoted media type? Only MP3 and uncompressed WAV are available."); - System.exit(1); - } - } else { - System.err.println("The specified tag type it not supported for import"); - System.exit(1); - } - } else { - Map asms = swf.getASMs(false); - boolean found = false; - if (asms.containsKey(objectToReplace)) { - found = true; - // replace AS1/2 - String repFile = args.pop(); - String repText = Helper.readTextFile(repFile); - ASMSource src = asms.get(objectToReplace); - if (Path.getExtension(repFile).equals(".as")) { - replaceAS2(repText, src); - } else { - replaceAS2PCode(repText, src); - } - } else { - List packs = swf.getAS3Packs(); - for (ScriptPack entry : packs) { - if (entry.getClassPath().toString().equals(objectToReplace)) { - found = true; - // replace AS3 - String repFile = args.pop(); - String repText = Helper.readTextFile(repFile); - ScriptPack pack = entry; - if (Path.getExtension(repFile).equals(".as")) { - replaceAS3(repText, pack); - } else { - // todo: get traits - if (args.isEmpty()) { - badArguments(); - } - int bodyIndex = Integer.parseInt(args.pop()); - //int classIndex = 0; - //int traitId = 0; - Trait trait = null; //abc.findTraitByTraitId(classIndex, traitId); - replaceAS3PCode(repText, pack.abc, bodyIndex, trait); - } - } - } - } - - if (!found) { - System.err.println(objectToReplace + " is not reocginized as a CharacterId or a script name."); - System.exit(1); - } - } - - if (args.isEmpty() || args.peek().startsWith("-")) { - break; - } - } - - try { - try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(outFile))) { - swf.saveTo(fos); - } - } catch (IOException e) { - System.err.println("I/O error during writing"); - System.exit(2); - } - } - } catch (IOException | InterruptedException e) { - System.err.println("I/O error during reading"); - System.exit(2); - } - } - - private static void replaceAS2PCode(String text, ASMSource src) throws IOException, InterruptedException { - System.out.println("Replace AS1/2 PCode"); - if (text.trim().startsWith(Helper.hexData)) { - src.setActionBytes(Helper.getBytesFromHexaText(text)); - } else { - try { - src.setActions(ASMParser.parse(0, true, text, src.getSwf().version, false)); - } catch (ActionParseException ex) { - System.err.println("%error% on line %line%".replace("%error%", ex.text).replace("%line%", Long.toString(ex.line))); - System.exit(1); - } - } - src.setModified(); - } - - private static void replaceAS2(String as, ASMSource src) throws IOException, InterruptedException { - System.out.println("Replace AS1/2"); - System.out.println("Warning: This feature is EXPERIMENTAL"); - com.jpexs.decompiler.flash.action.parser.script.ActionScriptParser par = new com.jpexs.decompiler.flash.action.parser.script.ActionScriptParser(src.getSwf().version); - try { - src.setActions(par.actionsFromString(as)); - } catch (ActionParseException ex) { - System.err.println("%error% on line %line%".replace("%error%", ex.text).replace("%line%", Long.toString(ex.line))); - System.exit(1); - } catch (CompilationException ex) { - System.err.println("%error% on line %line%".replace("%error%", ex.text).replace("%line%", Long.toString(ex.line))); - System.exit(1); - } - src.setModified(); - } - - private static void replaceAS3PCode(String text, ABC abc, int bodyIndex, Trait trait) throws IOException, InterruptedException { - System.out.println("Replace AS3 PCode"); - if (text.trim().startsWith(Helper.hexData)) { - byte[] data = Helper.getBytesFromHexaText(text); - MethodBody mb = abc.bodies.get(bodyIndex); - mb.setCodeBytes(data); - } else { - try { - AVM2Code acode = ASM3Parser.parse(new StringReader(text), abc.constants, trait, new MissingSymbolHandler() { - //no longer ask for adding new constants - @Override - public boolean missingString(String value) { - return true; - } - - @Override - public boolean missingInt(long value) { - return true; - } - - @Override - public boolean missingUInt(long value) { - return true; - } - - @Override - public boolean missingDouble(double value) { - return true; - } - }, abc.bodies.get(bodyIndex), abc.method_info.get(abc.bodies.get(bodyIndex).method_info)); - //acode.getBytes(abc.bodies.get(bodyIndex).getCodeBytes()); - abc.bodies.get(bodyIndex).setCode(acode); - } catch (AVM2ParseException ex) { - System.err.println("%error% on line %line%".replace("%error%", ex.text).replace("%line%", Long.toString(ex.line))); - System.exit(1); - } - } - ((Tag) abc.parentTag).setModified(true); - } - - private static void replaceAS3(String as, ScriptPack pack) throws IOException, InterruptedException { - System.out.println("Replace AS3"); - System.out.println("Warning: This feature is EXPERIMENTAL"); - File swc = Configuration.getPlayerSWC(); - if (swc == null) { - final String adobePage = "http://www.adobe.com/support/flashplayer/downloads.html"; - System.err.println("For ActionScript 3 direct editation, a library called \"PlayerGlobal.swc\" needs to be downloaded from Adobe homepage:"); - System.err.println(adobePage); - System.err.println("Download the library called PlayerGlobal(.swc), and place it to directory"); - System.err.println(Configuration.getFlashLibPath().getAbsolutePath()); - System.exit(1); - } - - try { - pack.abc.replaceScriptPack(pack, as); - } catch (AVM2ParseException ex) { - System.err.println("%error% on line %line%".replace("%error%", ex.text).replace("%line%", Long.toString(ex.line))); - System.exit(1); - } catch (CompilationException ex) { - System.err.println("%error% on line %line%".replace("%error%", ex.text).replace("%line%", Long.toString(ex.line))); - System.exit(1); - } - } - - private static void parseDumpSwf(Stack args) { - if (args.isEmpty()) { - badArguments(); - } - try { - Configuration.dumpTags.set(true); - Configuration.parallelSpeedUp.set(false); - SWFSourceInfo sourceInfo = new SWFSourceInfo(null, args.pop(), null); - Main.parseSWF(sourceInfo); - } catch (Exception ex) { - Logger.getLogger(CommandLineArgumentParser.class.getName()).log(Level.SEVERE, null, ex); - System.exit(1); - } - System.exit(0); - } - - private static void parseDumpAS2(Stack args) { - if (args.isEmpty()) { - badArguments(); - } - File file = new File(args.pop()); - try { - try (FileInputStream is = new FileInputStream(file)) { - SWF swf = new SWF(is, Configuration.parallelSpeedUp.get()); - Map asms = swf.getASMs(false); - for (String as2 : asms.keySet()) { - System.out.println(as2); - } - } - } catch (IOException | InterruptedException e) { - System.err.println("I/O error during reading"); - System.exit(2); - } - } - - private static void parseDumpAS3(Stack args) { - if (args.isEmpty()) { - badArguments(); - } - File file = new File(args.pop()); - try { - try (FileInputStream is = new FileInputStream(file)) { - SWF swf = new SWF(is, Configuration.parallelSpeedUp.get()); - List packs = swf.getAS3Packs(); - for (ScriptPack entry : packs) { - System.out.println(entry.getClassPath().toString() + " " + entry.scriptIndex); - } - } - } catch (IOException | InterruptedException e) { - System.err.println("I/O error during reading"); - System.exit(2); - } - } - - private static E enumFromStr(String str, Class cls) { - E[] vals = cls.getEnumConstants(); - if (str == null) { - return vals[0]; - } - for (E e : vals) { - if (e.toString().toLowerCase().replace("_", "").equals(str.toLowerCase().replace("_", ""))) { - return e; - } - } - return vals[0]; - } -} +/* + * Copyright (C) 2010-2015 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.console; + +import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler; +import com.jpexs.decompiler.flash.ApplicationInfo; +import com.jpexs.decompiler.flash.EventListener; +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFBundle; +import com.jpexs.decompiler.flash.SWFSourceInfo; +import com.jpexs.decompiler.flash.SearchMode; +import com.jpexs.decompiler.flash.abc.ABC; +import com.jpexs.decompiler.flash.abc.RenameType; +import com.jpexs.decompiler.flash.abc.ScriptPack; +import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; +import com.jpexs.decompiler.flash.abc.avm2.parser.AVM2ParseException; +import com.jpexs.decompiler.flash.abc.avm2.parser.pcode.ASM3Parser; +import com.jpexs.decompiler.flash.abc.avm2.parser.pcode.MissingSymbolHandler; +import com.jpexs.decompiler.flash.abc.avm2.parser.script.ActionScriptParser; +import com.jpexs.decompiler.flash.abc.types.MethodBody; +import com.jpexs.decompiler.flash.abc.types.traits.Trait; +import com.jpexs.decompiler.flash.action.parser.ActionParseException; +import com.jpexs.decompiler.flash.action.parser.pcode.ASMParser; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.configuration.ConfigurationItem; +import com.jpexs.decompiler.flash.exporters.BinaryDataExporter; +import com.jpexs.decompiler.flash.exporters.FontExporter; +import com.jpexs.decompiler.flash.exporters.FrameExporter; +import com.jpexs.decompiler.flash.exporters.ImageExporter; +import com.jpexs.decompiler.flash.exporters.MorphShapeExporter; +import com.jpexs.decompiler.flash.exporters.MovieExporter; +import com.jpexs.decompiler.flash.exporters.ShapeExporter; +import com.jpexs.decompiler.flash.exporters.SoundExporter; +import com.jpexs.decompiler.flash.exporters.TextExporter; +import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; +import com.jpexs.decompiler.flash.exporters.modes.BinaryDataExportMode; +import com.jpexs.decompiler.flash.exporters.modes.FontExportMode; +import com.jpexs.decompiler.flash.exporters.modes.FrameExportMode; +import com.jpexs.decompiler.flash.exporters.modes.ImageExportMode; +import com.jpexs.decompiler.flash.exporters.modes.MorphShapeExportMode; +import com.jpexs.decompiler.flash.exporters.modes.MovieExportMode; +import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; +import com.jpexs.decompiler.flash.exporters.modes.ShapeExportMode; +import com.jpexs.decompiler.flash.exporters.modes.SoundExportMode; +import com.jpexs.decompiler.flash.exporters.modes.TextExportMode; +import com.jpexs.decompiler.flash.exporters.settings.BinaryDataExportSettings; +import com.jpexs.decompiler.flash.exporters.settings.FontExportSettings; +import com.jpexs.decompiler.flash.exporters.settings.FrameExportSettings; +import com.jpexs.decompiler.flash.exporters.settings.ImageExportSettings; +import com.jpexs.decompiler.flash.exporters.settings.MorphShapeExportSettings; +import com.jpexs.decompiler.flash.exporters.settings.MovieExportSettings; +import com.jpexs.decompiler.flash.exporters.settings.ScriptExportSettings; +import com.jpexs.decompiler.flash.exporters.settings.ShapeExportSettings; +import com.jpexs.decompiler.flash.exporters.settings.SoundExportSettings; +import com.jpexs.decompiler.flash.exporters.settings.TextExportSettings; +import com.jpexs.decompiler.flash.exporters.swf.SwfXmlExporter; +import com.jpexs.decompiler.flash.gui.Main; +import com.jpexs.decompiler.flash.helpers.FileTextWriter; +import com.jpexs.decompiler.flash.importers.BinaryDataImporter; +import com.jpexs.decompiler.flash.importers.ImageImporter; +import com.jpexs.decompiler.flash.importers.SwfXmlImporter; +import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag; +import com.jpexs.decompiler.flash.tags.DefineSpriteTag; +import com.jpexs.decompiler.flash.tags.Tag; +import com.jpexs.decompiler.flash.tags.base.ASMSource; +import com.jpexs.decompiler.flash.tags.base.CharacterIdTag; +import com.jpexs.decompiler.flash.tags.base.CharacterTag; +import com.jpexs.decompiler.flash.tags.base.ImageTag; +import com.jpexs.decompiler.flash.tags.base.SoundTag; +import com.jpexs.decompiler.flash.treeitems.SWFList; +import com.jpexs.decompiler.flash.types.ColorTransform; +import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.decompiler.flash.types.sound.SoundFormat; +import com.jpexs.decompiler.flash.xfl.FLAVersion; +import com.jpexs.decompiler.graph.CompilationException; +import com.jpexs.helpers.Helper; +import com.jpexs.helpers.Path; +import com.jpexs.helpers.streams.SeekableInputStream; +import com.sun.jna.Platform; +import com.sun.jna.platform.win32.Kernel32; +import gnu.jpdf.PDFJob; +import java.awt.Color; +import java.awt.Graphics; +import java.awt.image.BufferedImage; +import java.awt.print.PageFormat; +import java.awt.print.Paper; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.Arrays; +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; + +/** + * + * @author JPEXS + */ +public class CommandLineArgumentParser { + + private static boolean commandLineMode = false; + + private static String stdOut = null; + + private static String stdErr = null; + + @SuppressWarnings("unchecked") + private static final ConfigurationItem[] commandlineConfigBoolean = new ConfigurationItem[]{ + Configuration.decompile, + Configuration.parallelSpeedUp, + Configuration.internalFlashViewer, + //Configuration.autoDeobfuscate, + Configuration.cacheOnDisk + }; + + public static boolean isCommandLineMode() { + return commandLineMode; + } + + public static void printCmdLineUsage() { + printCmdLineUsage(System.out, true); + } + + public static void printCmdLineUsage(PrintStream out, boolean printConfigs) { + int cnt = 1; + out.println("Commandline arguments:"); + out.println(" " + (cnt++) + ") -help | --help | /?"); + out.println(" ...shows commandline arguments (this help)"); + out.println(" " + (cnt++) + ") [ ...]"); + out.println(" ...opens SWF file(s) with the decompiler GUI"); + out.println(" " + (cnt++) + ") -proxy [-P]"); + out.println(" ...auto start proxy in the tray. Optional parameter -P specifies port for proxy. Defaults to 55555. "); + out.println(" " + (cnt++) + ") -export [-selectas3class ...]"); + out.println(" ...export sources to ."); + out.println(" Exports all files from when it is a folder."); + out.println(" Values for parameter:"); + out.println(" script - Scripts (Default format: ActionScript source)"); + out.println(" - Optional DEPRECATED \"-selectas3class\" parameter can be passed in same way as -selectclass"); + out.println(" image - Images (Default format: PNG/JPEG)"); + out.println(" shape - Shapes (Default format: SVG)"); + out.println(" morphshape - MorphShapes (Default format: SVG)"); + out.println(" movie - Movies (Default format: FLV without sound)"); + out.println(" font - Fonts (Default format: TTF)"); + out.println(" frame - Frames (Default format: PNG)"); + out.println(" sound - Sounds (Default format: MP3/WAV/FLV only sound)"); + out.println(" binaryData - Binary data (Default format: Raw data)"); + out.println(" text - Texts (Default format: Plain text)"); + out.println(" all - Every resource (but not FLA and XFL)"); + out.println(" fla - Everything to FLA compressed format"); + out.println(" xfl - Everything to uncompressed FLA format (XFL)"); + out.println(" You can export multiple types of items by using colon \",\""); + out.println(" DO NOT PUT space between comma (,) and next value."); + out.println(); + out.println(" Old DEPRECATED aliases include: (please use basic itemtypes and -format parameter instead)"); + out.println(" as, pcode, pcodehex, hex, all_as, all_pcode, all_pcodehex, textplain"); + out.println(); + out.println(" " + (cnt++) + ") -format "); + out.println(" ...sets output formats for export"); + out.println(" Values for parameter:"); + out.println(" script:as - ActionScript source"); + out.println(" script:pcode - ActionScript P-code"); + out.println(" script:pcodehex - ActionScript P-code with hex"); + out.println(" script:hex - ActionScript Hex only"); + out.println(" shape:svg - SVG format for Shapes"); + out.println(" shape:png - PNG format for Shapes"); + out.println(" shape:canvas - HTML5 Canvas format for Shapes"); + out.println(" shape:bmp - BMP format for Shapes"); + out.println(" morphshape:svg - SVG format for MorphShapes"); + out.println(" morphshape:canvas - HTML5 Canvas format for MorphShapes"); + out.println(" frame:png - PNG format for Frames"); + out.println(" frame:gif - GIF format for Frames"); + out.println(" frame:avi - AVI format for Frames"); + out.println(" frame:canvas - HTML5 Canvas format for Frames"); + out.println(" frame:pdf - PDF format for Frames"); + out.println(" frame:bmp - BMP format for Frames"); + out.println(" image:png_jpeg - PNG/JPEG format for Images"); + out.println(" image:png - PNG format for Images"); + out.println(" image:jpeg - JPEG format for Images"); + out.println(" image:bmp - BMP format for Images"); + out.println(" text:plain - Plain text format for Texts"); + out.println(" text:formatted - Formatted text format for Texts"); + out.println(" text:svg - SVG format for Texts"); + out.println(" sound:mp3_wav_flv - MP3/WAV/FLV format for Sounds"); + out.println(" sound:mp3_wav - MP3/WAV format for Sounds"); + out.println(" sound:wav - WAV format for Sounds"); + out.println(" sound:flv - FLV format for Sounds"); + out.println(" font:ttf - TTF format for Fonts"); + out.println(" font:woff - WOFF format for Fonts"); + out.println(" fla: or xfl: - Specify FLA format version"); + out.println(" - values for : cs5,cs5.5,cs6,cc"); + + out.println(" You can set multiple formats at once using comma (,)"); + out.println(" DO NOT PUT space between comma (,) and next value."); + out.println(" The prefix with colon (:) is neccessary."); + out.println(" " + (cnt++) + ") -select "); + out.println(" ...selects frames/pages for export"); + out.println(" Example formats:"); + out.println(" 1-5"); + out.println(" 2,3"); + out.println(" 2-5,7,9-"); + out.println(" DO NOT PUT space between comma (,) and next ramge."); + out.println(" " + (cnt++) + ") -selectid "); + out.println(" ...selects characters for export by character id"); + out.println(" format is same as in -select"); + out.println(" " + (cnt++) + ") -selectclass "); + out.println(" ...selects scripts to export by class name (ActionScript 3 ONLY)"); + out.println(" format:"); + out.println(" com.example.MyClass"); + out.println(" com.example.+ (all classes in package \"com.example\")"); + out.println(" com.++,net.company.MyClass (all classes in package \"com\" and all subpackages, class net.company.MyClass)"); + out.println(" DO NOT PUT space between comma (,) and next class."); + out.println(" " + (cnt++) + ") -dumpSWF "); + out.println(" ...dumps list of SWF tags to console"); + out.println(" " + (cnt++) + ") -dumpAS2 "); + out.println(" ...dumps list of AS1/2 sctipts to console"); + out.println(" " + (cnt++) + ") -dumpAS3 "); + out.println(" ...dumps list of AS3 sctipts to console"); + out.println(" " + (cnt++) + ") -compress "); + out.println(" ...Compress SWF and save it to "); + out.println(" " + (cnt++) + ") -decompress "); + out.println(" ...Decompress and save it to "); + out.println(" " + (cnt++) + ") -swf2xml "); + out.println(" ...Converts the SWF to XML file"); + out.println(" " + (cnt++) + ") -xml2swf "); + out.println(" ...Converts the XML to SWF file"); + out.println(" " + (cnt++) + ") -extract [-o |] [nocheck] [(all|biggest|smallest|first|last)]"); + out.println(" ...Extracts SWF files from ZIP or other binary files"); + out.println(" ...-o parameter should contain a file path when \"biggest\" or \"first\" parameter is specified"); + out.println(" ...-o parameter should contain a folder path when no exctaction mode or \"all\" parameter is specified"); + out.println(" " + (cnt++) + ") -renameInvalidIdentifiers (typeNumber|randomWord) "); + out.println(" ...Renames the invalid identifiers in and save it to "); + out.println(" " + (cnt++) + ") -config key=value[,key2=value2][,key3=value3...] [other parameters]"); + out.print(" ...Sets configuration values. "); + if (printConfigs) { + out.print("Available keys[current setting]:"); + for (ConfigurationItem item : commandlineConfigBoolean) { + out.print(" " + item + "[" + item.get() + "]"); + } + } + out.println(""); + out.println(" Values are boolean, you can use 0/1, true/false, on/off or yes/no."); + out.println(" If no other parameters passed, configuration is saved. Otherwise it is used only once."); + out.println(" DO NOT PUT space between comma (,) and next value."); + out.println(" " + (cnt++) + ") -onerror (abort|retryN|ignore)"); + out.println(" ...error handling mode. \"abort\" stops the exporting, \"retry\" tries the exporting N times, \"ignore\" ignores the current file"); + out.println(" " + (cnt++) + ") -timeout "); + out.println(" ...decompilation timeout for a single method in AS3 or single action in AS1/2 in seconds"); + out.println(" " + (cnt++) + ") -exportTimeout "); + out.println(" ...total export timeout in seconds"); + out.println(" " + (cnt++) + ") -exportFileTimeout "); + out.println(" ...export timeout for a single AS3 class in seconds"); + out.println(" " + (cnt++) + ") -flashpaper2pdf "); + out.println(" ...converts FlashPaper SWF file to PDF . Use -zoom parameter to specify image quality."); + out.println(" " + (cnt++) + ") -zoom "); + out.println(" ...apply zoom during export (currently for FlashPaper conversion only)"); + out.println(" " + (cnt++) + ") -replace (|) [methodBodyIndex1] [(|) [methodBodyIndex2]]..."); + out.println(" ...replaces the data of the specified BinaryData, Image, DefineSound tag or Script"); + out.println(" ...methodBodyIndexN parameter should be specified if and only if the imported entity is an AS3 P-Code"); + printCmdLineUsageExamples(out); + } + + private static void printCmdLineUsageExamples(PrintStream out) { + out.println(); + out.println("Examples:"); + out.println("java -jar ffdec.jar myfile.swf"); + out.println("java -jar ffdec.jar -proxy"); + out.println("java -jar ffdec.jar -proxy -P1234"); + out.println("java -jar ffdec.jar -export script \"C:\\decompiled\" myfile.swf"); + out.println("java -jar ffdec.jar -selectclass com.example.MyClass,com.example.SecondClass -export script \"C:\\decompiled\" myfile.swf"); + out.println("java -jar ffdec.jar -format script:pcode -export script \"C:\\decompiled\" myfile.swf"); + out.println("java -jar ffdec.jar -format script:pcode,text:plain -export script,text,image \"C:\\decompiled\" myfile.swf"); + out.println("java -jar ffdec.jar -format fla:cs5.5 -export fla \"C:\\sources\\myfile.fla\" myfile.swf"); + out.println("java -jar ffdec.jar -dumpSWF myfile.swf"); + out.println("java -jar ffdec.jar -compress myfile.swf myfiledec.swf"); + out.println("java -jar ffdec.jar -decompress myfiledec.swf myfile.swf"); + out.println("java -jar ffdec.jar -onerror ignore -export script \"C:\\decompiled\" myfile.swf"); + out.println("java -jar ffdec.jar -onerror retry 5 -export script \"C:\\decompiled\" myfile.swf"); + out.println("java -jar ffdec.jar -config autoDeobfuscate=1,parallelSpeedUp=0 -export script \"C:\\decompiled\" myfile.swf"); + out.println(""); + out.println("Instead of \"java -jar ffdec.jar\" you can use ffdec.bat on Windows, ffdec.sh on Linux/MacOs"); + } + + /** + * Parses the console arguments + * + * @param arguments Arguments + * @return paths to the file which should be opened or null + * @throws java.io.IOException On error + */ + public static String[] parseArguments(String[] arguments) throws IOException { + Level traceLevel = Level.WARNING; + Stack args = new Stack<>(); + for (int i = arguments.length - 1; i >= 0; i--) { + String arg = arguments[i]; + if (arg.length() > 0) { + args.add(arg); + } + } + + AbortRetryIgnoreHandler handler = null; + Map format = new HashMap<>(); + double zoom = 1; + Selection selection = new Selection(); + Selection selectionIds = new Selection(); + List selectionClasses = null; + String nextParam = null, nextParamOriginal = null; + OUTER: + while (true) { + nextParamOriginal = args.pop(); + if (nextParamOriginal != null) { + nextParam = nextParamOriginal.toLowerCase(); + } + switch (nextParam) { + case "-selectid": + selectionIds = parseSelect(args); + break; + case "-select": + selection = parseSelect(args); + break; + case "-selectclass": + selectionClasses = parseSelectClass(args); + break; + case "-zoom": + zoom = parseZoom(args); + break; + case "-format": + format = parseFormat(args); + break; + case "-config": + parseConfig(args); + if (args.isEmpty()) { + Configuration.saveConfig(); + System.out.println("Configuration saved"); + return null; + } + break; + case "-onerror": + handler = parseOnError(args); + break; + case "-timeout": + parseTimeout(args); + break; + case "-exporttimeout": + parseExportTimeout(args); + break; + case "-exportfiletimeout": + parseExportFileTimeout(args); + break; + case "-stdout": + parseStdOut(args); + break; + case "-stderr": + parseStdErr(args); + break; + case "-affinity": + parseAffinity(args); + break; + case "-priority": + parsePriority(args); + break; + case "-verbose": + traceLevel = Level.FINE; + break; + case "-debug": + for (int i = 0; i < arguments.length; i++) { + System.out.println(i + ".:" + arguments[i]); + } + Configuration.debugMode.set(true); + break; + case "-debugtool": + parseDebugTool(args); + break; + default: + break OUTER; + } + if (args.isEmpty()) { + return null; + } + } + + String command = ""; + if (nextParam.startsWith("-")) { + command = nextParam.substring(1); + } + + if (command.equals("removefromcontextmenu")) { + if (!args.isEmpty()) { + badArguments(command); + } + ContextMenuTools.addToContextMenu(false, true); + System.exit(0); + } else if (command.equals("addtocontextmenu")) { + if (!args.isEmpty()) { + badArguments(command); + } + ContextMenuTools.addToContextMenu(true, true); + System.exit(0); + } else if (command.equals("proxy")) { + parseProxy(args); + } else if (command.equals("export")) { + parseExport(selectionClasses, selection, selectionIds, args, handler, traceLevel, format, zoom); + } else if (command.equals("compress")) { + parseCompress(args); + } else if (command.equals("decompress")) { + parseDecompress(args); + } else if (command.equals("swf2xml")) { + parseSwf2Xml(args); + } else if (command.equals("xml2swf")) { + parseXml2Swf(args); + } else if (command.equals("extract")) { + parseExtract(args); + } else if (command.equals("renameinvalididentifiers")) { + parseRenameInvalidIdentifiers(args); + } else if (command.equals("dumpswf")) { + parseDumpSwf(args); + } else if (command.equals("dumpas2")) { + parseDumpAS2(args); + } else if (command.equals("dumpas3")) { + parseDumpAS3(args); + } else if (command.equals("flashpaper2pdf")) { + parseFlashPaperToPdf(selection, zoom, args); + } else if (command.equals("replace")) { + parseReplace(args); + } else if (command.equals("as3compiler")) { + ActionScriptParser.compile(null /*?*/, args.pop(), args.pop(), 0); + } else if (nextParam.equals("-help") || nextParam.equals("--help") || nextParam.equals("/?") || nextParam.equals("\\_") /* /? translates as this on windows */) { + printHeader(); + printCmdLineUsage(); + System.exit(0); + } else if (nextParam.equals("--webhelp")) { //for generating commandline usage on webpages + ByteArrayOutputStream whbaos = new ByteArrayOutputStream(); + printCmdLineUsage(new PrintStream(whbaos, true), false); + String wh = new String(whbaos.toByteArray()); + wh = wh.replace("<", "<").replace(">", ">"); + System.out.println(wh); + } else { + args.push(nextParamOriginal); // file names should be the original one + String[] fileNames = args.toArray(new String[args.size()]); + boolean allParamIsAFile = true; + for (String fileName : fileNames) { + File file = new File(fileName); + if (!file.exists() || !file.isFile()) { + allParamIsAFile = false; + } + } + + if (allParamIsAFile) { + return fileNames; + } else { + badArguments(); + } + } + + return null; + } + + public static void printHeader() { + System.out.println(ApplicationInfo.applicationVerName); + for (int i = 0; i < ApplicationInfo.applicationVerName.length(); i++) { + System.out.print("-"); + } + System.out.println(); + } + + public static void badArguments() { + badArguments(null); + } + + public static void badArguments(String command) { + System.err.println("Error: Bad Commandline Arguments!"); + printCmdLineUsage(); + System.exit(1); + } + + private static void setConfigurations(String cfgStr) { + String[] cfgs; + if (cfgStr.contains(",")) { + cfgs = cfgStr.split(","); + } else { + cfgs = new String[]{cfgStr}; + } + + for (String c : cfgs) { + String[] cp; + if (c.contains("=")) { + cp = c.split("="); + } else { + cp = new String[]{c, "1"}; + } + String key = cp[0]; + String value = cp[1]; + if (key.toLowerCase().equals("paralelSpeedUp".toLowerCase())) { + key = "parallelSpeedUp"; + } + for (ConfigurationItem item : commandlineConfigBoolean) { + if (key.toLowerCase().equals(item.getName().toLowerCase())) { + Boolean bValue = parseBooleanConfigValue(value); + if (bValue != null) { + System.out.println("Config " + item.getName() + " set to " + bValue); + item.set(bValue); + } + } + } + } + } + + private static Boolean parseBooleanConfigValue(String value) { + if (value == null) { + return null; + } + + Boolean bValue = null; + value = value.toLowerCase(); + if (value.equals("0") || value.equals("false") || value.equals("no") || value.equals("off")) { + bValue = false; + } + if (value.equals("1") || value.equals("true") || value.equals("yes") || value.equals("on")) { + bValue = true; + } + return bValue; + } + + private static void parseConfig(Stack args) { + if (args.isEmpty()) { + System.err.println("Config values expected"); + badArguments(); + } + setConfigurations(args.pop()); + } + + private static class Range { + + public Integer min; + + public Integer max; + + public Range(Integer min, Integer max) { + this.min = min; + this.max = max; + } + + public boolean contains(int index) { + int minimum = min == null ? Integer.MIN_VALUE : min; + int maximum = max == null ? Integer.MAX_VALUE : max; + + return index >= minimum && index <= maximum; + } + } + + private static class Selection { + + public List ranges; + + public Selection() { + this.ranges = new ArrayList<>(); + this.ranges.add(new Range(null, null)); + } + + public Selection(List ranges) { + this.ranges = ranges; + } + + public boolean contains(int index) { + for (Range r : ranges) { + if (r.contains(index)) { + return true; + } + } + return false; + } + } + + private static Selection parseSelect(Stack args) { + List ret = new ArrayList<>(); + if (args.isEmpty()) { + System.err.println("range parameter expected"); + badArguments(); + } + String range = args.pop(); + String[] ranges; + if (range.contains(",")) { + ranges = range.split(","); + } else { + ranges = new String[]{range}; + } + for (String r : ranges) { + Integer min = null; + Integer max = null; + if (r.contains("-")) { + String ps[] = r.split("\\-"); + if (ps.length != 2) { + System.err.println("invalid range"); + badArguments(); + } + try { + if (!"".equals(ps[0])) { + min = Integer.parseInt(ps[0]); + } + if (!"".equals(ps[1])) { + max = Integer.parseInt(ps[1]); + } + } catch (NumberFormatException nfe) { + System.err.println("invalid range"); + badArguments(); + } + } else { + try { + min = Integer.parseInt(r); + max = min; + } catch (NumberFormatException nfe) { + System.err.println("invalid range"); + badArguments(); + } + } + ret.add(new Range(min, max)); + } + return new Selection(ret); + } + + private static double parseZoom(Stack args) { + if (args.isEmpty()) { + System.err.println("zoom parameter expected"); + badArguments(); + } + try { + return Double.parseDouble(args.pop()); + } catch (NumberFormatException nfe) { + System.err.println("invalid zoom"); + badArguments(); + } + return 1; + } + + private static AbortRetryIgnoreHandler parseOnError(Stack args) { + int errorMode = AbortRetryIgnoreHandler.UNDEFINED; + int retryCount = 0; + + if (args.isEmpty()) { + System.err.println("onerror parameter expected"); + badArguments(); + } + String errorModeParameter = args.pop(); + switch (errorModeParameter) { + case "abort": + errorMode = AbortRetryIgnoreHandler.ABORT; + break; + case "retry": + errorMode = AbortRetryIgnoreHandler.RETRY; + if (args.isEmpty()) { + System.err.println("onerror retry count parameter expected"); + badArguments(); + } + + try { + retryCount = Integer.parseInt(args.pop()); + } catch (NumberFormatException nex) { + System.err.println("Bad retry count number"); + } + break; + case "ignore": + errorMode = AbortRetryIgnoreHandler.IGNORE; + break; + } + + return new ConsoleAbortRetryIgnoreHandler(errorMode, retryCount); + } + + private static void parseTimeout(Stack args) { + if (args.isEmpty()) { + System.err.println("timeout parameter expected"); + badArguments(); + } + try { + int timeout = Integer.parseInt(args.pop()); + Configuration.decompilationTimeoutSingleMethod.set(timeout); + } catch (NumberFormatException nex) { + System.err.println("Bad timeout value"); + } + } + + private static void parseExportTimeout(Stack args) { + if (args.isEmpty()) { + System.err.println("timeout parameter expected"); + badArguments(); + } + try { + int timeout = Integer.parseInt(args.pop()); + Configuration.exportTimeout.set(timeout); + } catch (NumberFormatException nex) { + System.err.println("Bad timeout value"); + } + } + + private static void parseExportFileTimeout(Stack args) { + if (args.isEmpty()) { + System.err.println("timeout parameter expected"); + badArguments(); + } + try { + int timeout = Integer.parseInt(args.pop()); + Configuration.decompilationTimeoutFile.set(timeout); + } catch (NumberFormatException nex) { + System.err.println("Bad timeout value"); + } + } + + private static void parseStdOut(Stack args) { + if (args.isEmpty()) { + System.err.println("stdOut parameter expected"); + badArguments(); + } + + stdOut = args.pop(); + } + + private static void parseStdErr(Stack args) { + if (args.isEmpty()) { + System.err.println("stdErr parameter expected"); + badArguments(); + } + + stdErr = args.pop(); + } + + private static void parseAffinity(Stack args) { + if (Platform.isWindows()) { + if (args.isEmpty()) { + System.err.println("affinity parameter expected"); + badArguments(); + } + try { + int affinityMask = Integer.parseInt(args.pop()); + Kernel32.INSTANCE.SetProcessAffinityMask(Kernel32.INSTANCE.GetCurrentProcess(), affinityMask); + } catch (NumberFormatException nex) { + System.err.println("Bad affinityMask value"); + } + } else { + System.err.println("Process affinity setting is only available on Windows platform."); + } + } + + private static void parsePriority(Stack args) { + if (Platform.isWindows()) { + if (args.isEmpty()) { + System.err.println("priority parameter expected"); + badArguments(); + } + String priority = args.pop(); + int priorityClass = 0; + switch (priority) { + case "low": + priorityClass = Kernel32.IDLE_PRIORITY_CLASS; + break; + case "belownormal": + priorityClass = Kernel32.BELOW_NORMAL_PRIORITY_CLASS; + break; + case "normal": + priorityClass = Kernel32.NORMAL_PRIORITY_CLASS; + break; + case "abovenormal": + priorityClass = Kernel32.ABOVE_NORMAL_PRIORITY_CLASS; + break; + case "high": + priorityClass = Kernel32.HIGH_PRIORITY_CLASS; + break; + case "realtime": + priorityClass = Kernel32.REALTIME_PRIORITY_CLASS; + break; + default: + System.err.println("Bad affinityMask value"); + } + if (priorityClass != 0) { + Kernel32.INSTANCE.SetPriorityClass(Kernel32.INSTANCE.GetCurrentProcess(), priorityClass); + } + } else { + System.err.println("Process priority setting is only available on Windows platform."); + } + } + + private static void parseDebugTool(Stack args) { + String cmd = args.pop().toLowerCase(); + switch (cmd) { + case "findtag": + String folder = args.pop(); + String tagIdOrName = args.pop(); + int tagId; + try { + tagId = Integer.parseInt(tagIdOrName); + } catch (NumberFormatException e) { + tagId = Tag.getKnownClassesByName().get(tagIdOrName).id; + } + + File[] files = new File(folder).listFiles(getSwfFilter()); + for (File file : files) { + SWFSourceInfo sourceInfo = new SWFSourceInfo(null, file.getAbsolutePath(), file.getName()); + try { + SWF swf = new SWF(new FileInputStream(file), sourceInfo.getFile(), sourceInfo.getFileTitle(), Configuration.parallelSpeedUp.get()); + swf.swfList = new SWFList(); + swf.swfList.sourceInfo = sourceInfo; + } catch (IOException | InterruptedException ex) { + Logger.getLogger(CommandLineArgumentParser.class.getName()).log(Level.SEVERE, null, ex); + } + } + break; + } + } + + private static void parseProxy(Stack args) { + int port = 55555; + String portStr = args.peek(); + if (portStr != null && portStr.startsWith("-P")) { + args.pop(); + try { + port = Integer.parseInt(portStr.substring(2)); + } catch (NumberFormatException nex) { + System.err.println("Bad port number"); + } + } + Main.startProxy(port); + } + + private static List parseSelectClassOld(Stack args) { + List ret = new ArrayList<>(); + if (!args.isEmpty() && args.peek().equals("-selectas3class")) { + args.pop(); + while (!args.isEmpty()) { + ret.add(args.pop()); + } + System.err.println("WARNING: Using deprecated -selectas3class parameter. Please use -selectclass instead. See --help for usage."); + } + return ret; + + } + + private static List parseSelectClass(Stack args) { + if (args.size() < 1) { + badArguments(); + } + List ret = new ArrayList<>(); + String classesStr = args.pop(); + String classes[]; + if (classesStr.contains(",")) { + classes = classesStr.split(","); + } else { + classes = new String[]{classesStr}; + } + ret.addAll(Arrays.asList(classes)); + return ret; + + } + + private static void parseExport(List selectionClasses, Selection selection, Selection selectionIds, Stack args, AbortRetryIgnoreHandler handler, Level traceLevel, Map formats, double zoom) { + if (args.size() < 3) { + badArguments(); + } + String[] validExportItems = new String[]{ + "script", + "image", + "shape", + "morphshape", + "movie", + "font", + "frame", + "sound", + "binarydata", + "text", + "all", + "fla", + "xfl" + }; + + String[] removedExportFormats = new String[]{ + "as", + "pcode", + "hex", + "pcodehex", + "all_as", + "all_pcode", + "all_pcodehex", + "all_hex", + "textplain" + }; + + if (handler == null) { + handler = new ConsoleAbortRetryIgnoreHandler(AbortRetryIgnoreHandler.UNDEFINED, 0); + } + String exportFormatString = args.pop().toLowerCase(); + List exportFormats = Arrays.asList(exportFormatString.split(",")); + long startTime = System.currentTimeMillis(); + + File outDirBase = new File(args.pop()); + File inFileOrFolder = new File(args.pop()); + if (!inFileOrFolder.exists()) { + System.err.println("Input SWF file does not exist!"); + badArguments(); + } + printHeader(); + boolean exportOK = true; + + List as3classes = new ArrayList<>(); + if (selectionClasses != null) { + as3classes.addAll(selectionClasses); + } + + try { + File[] inFiles; + boolean singleFile = true; + if (inFileOrFolder.isDirectory()) { + singleFile = false; + inFiles = inFileOrFolder.listFiles(getSwfFilter()); + } else { + inFiles = new File[]{inFileOrFolder}; + } + + for (File inFile : inFiles) { + String inFileName = Path.getFileNameWithoutExtension(inFile); + if (stdOut != null) { + System.setOut(new PrintStream(new FileOutputStream(stdOut.replace("{swfFile}", inFileName), true))); + } + + if (stdErr != null) { + System.setErr(new PrintStream(new FileOutputStream(stdErr.replace("{swfFile}", inFileName), true))); + Main.initLogging(Configuration.debugMode.get()); + } + + long startTimeSwf = 0; + if (!singleFile) { + startTimeSwf = System.currentTimeMillis(); + System.out.println("Start exporting " + inFile.getName()); + } + + SWFSourceInfo sourceInfo = new SWFSourceInfo(null, inFile.getAbsolutePath(), inFile.getName()); + SWF swf = new SWF(new FileInputStream(inFile), sourceInfo.getFile(), sourceInfo.getFileTitle(), Configuration.parallelSpeedUp.get()); + swf.swfList = new SWFList(); + swf.swfList.sourceInfo = sourceInfo; + String outDir = outDirBase.getAbsolutePath(); + if (!singleFile) { + outDir = Path.combine(outDir, inFile.getName()); + } + + List extags = new ArrayList<>(); + for (Tag t : swf.tags) { + if (t instanceof CharacterIdTag) { + CharacterIdTag c = (CharacterIdTag) t; + if (selectionIds.contains(c.getCharacterId())) { + extags.add(t); + } + } else { + if (selectionIds.contains(0)) { + extags.add(t); + } + } + } + + final Level level = traceLevel; + swf.addEventListener(new EventListener() { + @Override + public void handleExportingEvent(String type, int index, int count, Object data) { + if (level.intValue() <= Level.FINE.intValue()) { + String text = "Exporting "; + if (type != null && type.length() > 0) { + text += type + " "; + } + System.out.println(text + index + "/" + count + " " + data); + } + } + + @Override + public void handleExportedEvent(String type, int index, int count, Object data) { + String text = "Exported "; + if (type != null && type.length() > 0) { + text += type + " "; + } + System.out.println(text + index + "/" + count + " " + data); + } + + @Override + public void handleEvent(String event, Object data) { + } + }); + + // First check all the specified export formats + for (String exportFormat : exportFormats) { + if (Arrays.asList(removedExportFormats).contains(exportFormat)) { + System.err.println("Error: Export format : " + exportFormat + " was REMOVED. Run application with --help parameter to see available formats."); + System.exit(1); + } else if (!Arrays.asList(validExportItems).contains(exportFormat)) { + System.err.println("Invalid export item:" + exportFormat); + badArguments(); + } + } + + // Here the exportFormats array should contain only validitems + commandLineMode = true; + boolean exportAll = exportFormats.contains("all"); + boolean multipleExportTypes = exportAll || exportFormats.size() > 1; + EventListener evl = swf.getExportEventListener(); + + if (exportAll || exportFormats.contains("image")) { + System.out.println("Exporting images..."); + new ImageExporter().exportImages(handler, outDir + (multipleExportTypes ? File.separator + ImageExportSettings.EXPORT_FOLDER_NAME : ""), extags, new ImageExportSettings(enumFromStr(formats.get("image"), ImageExportMode.class)), evl); + } + + if (exportAll || exportFormats.contains("shape")) { + System.out.println("Exporting shapes..."); + new ShapeExporter().exportShapes(handler, outDir + (multipleExportTypes ? File.separator + ShapeExportSettings.EXPORT_FOLDER_NAME : ""), extags, new ShapeExportSettings(enumFromStr(formats.get("shape"), ShapeExportMode.class), zoom), evl); + } + + if (exportAll || exportFormats.contains("morphshape")) { + System.out.println("Exporting morphshapes..."); + new MorphShapeExporter().exportMorphShapes(handler, outDir + (multipleExportTypes ? File.separator + MorphShapeExportSettings.EXPORT_FOLDER_NAME : ""), extags, new MorphShapeExportSettings(enumFromStr(formats.get("morphshape"), MorphShapeExportMode.class), zoom), evl); + } + + if (exportAll || exportFormats.contains("movie")) { + System.out.println("Exporting movies..."); + new MovieExporter().exportMovies(handler, outDir + (multipleExportTypes ? File.separator + MovieExportSettings.EXPORT_FOLDER_NAME : ""), extags, new MovieExportSettings(enumFromStr(formats.get("movie"), MovieExportMode.class)), evl); + } + + if (exportAll || exportFormats.contains("font")) { + System.out.println("Exporting fonts..."); + new FontExporter().exportFonts(handler, outDir + (multipleExportTypes ? File.separator + FontExportSettings.EXPORT_FOLDER_NAME : ""), extags, new FontExportSettings(enumFromStr(formats.get("font"), FontExportMode.class)), evl); + } + + if (exportAll || exportFormats.contains("sound")) { + System.out.println("Exporting sounds..."); + new SoundExporter().exportSounds(handler, outDir + (multipleExportTypes ? File.separator + SoundExportSettings.EXPORT_FOLDER_NAME : ""), extags, new SoundExportSettings(enumFromStr(formats.get("sound"), SoundExportMode.class)), evl); + } + + if (exportAll || exportFormats.contains("binarydata")) { + System.out.println("Exporting binaryData..."); + new BinaryDataExporter().exportBinaryData(handler, outDir + (multipleExportTypes ? File.separator + BinaryDataExportSettings.EXPORT_FOLDER_NAME : ""), extags, new BinaryDataExportSettings(enumFromStr(formats.get("binarydata"), BinaryDataExportMode.class)), evl); + } + + if (exportAll || exportFormats.contains("text")) { + System.out.println("Exporting texts..."); + Boolean singleTextFile = parseBooleanConfigValue(formats.get("singletext")); + if (singleTextFile == null) { + singleTextFile = Configuration.textExportSingleFile.get(); + } + new TextExporter().exportTexts(handler, outDir + (multipleExportTypes ? File.separator + TextExportSettings.EXPORT_FOLDER_NAME : ""), extags, new TextExportSettings(enumFromStr(formats.get("text"), TextExportMode.class), singleTextFile, zoom), evl); + } + + if (exportAll || exportFormats.contains("frame")) { + System.out.println("Exporting frames..."); + List frames = new ArrayList<>(); + for (int i = 0; i < swf.frameCount; i++) { + if (selection.contains(i + 1)) { + frames.add(i); + } + } + new FrameExporter().exportFrames(handler, outDir + (multipleExportTypes ? File.separator + FrameExportSettings.EXPORT_FOLDER_NAME : ""), swf, 0, frames, new FrameExportSettings(enumFromStr(formats.get("frame"), FrameExportMode.class), zoom), evl); + } + + boolean parallel = Configuration.parallelSpeedUp.get(); + String scriptsFolder = Path.combine(outDir, ScriptExportSettings.EXPORT_FOLDER_NAME); + Path.createDirectorySafe(new File(scriptsFolder)); + Boolean singleScriptFile = parseBooleanConfigValue(formats.get("singlescript")); + if (singleScriptFile == null) { + singleScriptFile = Configuration.scriptExportSingleFile.get(); + } + + if (parallel && singleScriptFile) { + System.out.println("Single file script export is not supported with enabled parallel speedup"); + singleScriptFile = false; + } + + ScriptExportSettings scriptExportSettings = new ScriptExportSettings(enumFromStr(formats.get("script"), ScriptExportMode.class), singleScriptFile); + if (exportAll || exportFormats.contains("script")) { + System.out.println("Exporting scripts..."); + if (as3classes.isEmpty()) { + as3classes = parseSelectClassOld(args); + } + + String singleFileName = Path.combine(scriptsFolder, swf.getShortFileName() + scriptExportSettings.getFileExtension()); + try (FileTextWriter writer = scriptExportSettings.singleFile ? new FileTextWriter(Configuration.getCodeFormatting(), new FileOutputStream(singleFileName)) : null) { + scriptExportSettings.singleFileWriter = writer; + if (!as3classes.isEmpty()) { + for (String as3class : as3classes) { + exportOK = exportOK && swf.exportAS3Class(as3class, scriptsFolder, scriptExportSettings, parallel, evl); + } + } else { + exportOK = exportOK && swf.exportActionScript(handler, scriptsFolder, scriptExportSettings, parallel, evl) != null; + } + } + } + + if (exportFormats.contains("fla")) { + System.out.println("Exporting FLA..."); + FLAVersion flaVersion = FLAVersion.fromString(formats.get("fla")); + if (flaVersion == null) { + flaVersion = FLAVersion.CS6; //Defaults to CS6 + } + swf.exportFla(handler, outDir + (multipleExportTypes ? File.separator + "fla" : ""), inFile.getName(), ApplicationInfo.APPLICATION_NAME, ApplicationInfo.applicationVerName, ApplicationInfo.version, Configuration.parallelSpeedUp.get(), flaVersion); + } + + if (exportFormats.contains("xfl")) { + System.out.println("Exporting XFL..."); + FLAVersion xflVersion = FLAVersion.fromString(formats.get("xfl")); + if (xflVersion == null) { + xflVersion = FLAVersion.CS6; //Defaults to CS6 + } + swf.exportXfl(handler, outDir + (multipleExportTypes ? File.separator + "xfl" : ""), inFile.getName(), ApplicationInfo.APPLICATION_NAME, ApplicationInfo.applicationVerName, ApplicationInfo.version, Configuration.parallelSpeedUp.get(), xflVersion); + } + + if (!singleFile) { + long stopTimeSwf = System.currentTimeMillis(); + long time = stopTimeSwf - startTimeSwf; + System.out.println("Export finished: " + inFile.getName() + " Export time: " + Helper.formatTimeSec(time)); + } + + swf.clearAllCache(); + } + } catch (OutOfMemoryError | Exception ex) { + System.err.print("FAIL: Exporting Failed on Exception - "); + Logger.getLogger(CommandLineArgumentParser.class.getName()).log(Level.SEVERE, null, ex); + System.exit(1); + } + + long stopTime = System.currentTimeMillis(); + long time = stopTime - startTime; + System.out.println("Export finished. Total export time: " + Helper.formatTimeSec(time)); + if (exportOK) { + System.out.println("OK"); + System.exit(0); + } else { + System.err.println("FAIL"); + System.exit(1); + } + } + + private static void parseCompress(Stack args) { + if (args.size() < 2) { + badArguments(); + } + + try { + try (InputStream fis = new BufferedInputStream(new FileInputStream(args.pop())); + OutputStream fos = new BufferedOutputStream(new FileOutputStream(args.pop()))) { + if (SWF.fws2cws(fis, fos)) { + System.out.println("OK"); + } else { + System.err.println("FAIL"); + } + } catch (FileNotFoundException ex) { + System.err.println("File not found."); + } + } catch (IOException ex) { + Logger.getLogger(CommandLineArgumentParser.class.getName()).log(Level.SEVERE, null, ex); + } + + System.exit(0); + } + + private static void parseDecompress(Stack args) { + if (args.size() < 2) { + badArguments(); + } + + try { + try (InputStream fis = new BufferedInputStream(new FileInputStream(args.pop())); + OutputStream fos = new BufferedOutputStream(new FileOutputStream(args.pop()))) { + if (SWF.decompress(fis, fos)) { + System.out.println("OK"); + System.exit(0); + } else { + System.err.println("FAIL"); + System.exit(1); + } + } catch (FileNotFoundException ex) { + System.err.println("File not found."); + } + } catch (IOException ex) { + Logger.getLogger(CommandLineArgumentParser.class.getName()).log(Level.SEVERE, null, ex); + } + + System.exit(0); + } + + private static void parseSwf2Xml(Stack args) { + if (args.size() < 2) { + badArguments(); + } + + try { + try (FileInputStream is = new FileInputStream(args.pop())) { + SWF swf = new SWF(is, Configuration.parallelSpeedUp.get()); + new SwfXmlExporter().exportXml(swf, new File(args.pop())); + } catch (FileNotFoundException ex) { + System.err.println("File not found."); + } catch (InterruptedException ex) { + Logger.getLogger(CommandLineArgumentParser.class.getName()).log(Level.SEVERE, null, ex); + } + } catch (IOException ex) { + Logger.getLogger(CommandLineArgumentParser.class.getName()).log(Level.SEVERE, null, ex); + } + + System.exit(0); + } + + private static void parseXml2Swf(Stack args) { + if (args.size() < 2) { + badArguments(); + } + + try { + String xml = Helper.readTextFile(args.pop()); + SWF swf = new SWF(); + new SwfXmlImporter().importSwf(swf, xml); + try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(new File(args.pop())))) { + swf.saveTo(new BufferedOutputStream(fos)); + } + } catch (IOException ex) { + Logger.getLogger(CommandLineArgumentParser.class.getName()).log(Level.SEVERE, null, ex); + } + + System.exit(0); + } + + private static void parseExtract(Stack args) { + if (args.size() < 1) { + badArguments(); + } + + String fileName = args.pop(); + SearchMode mode = SearchMode.ALL; + + boolean noCheck = false; + String output = null; + + if (args.size() > 0 && args.peek().toLowerCase().equals("-o")) { + args.pop(); + if (args.size() < 1) { + badArguments(); + } + output = args.pop(); + } + + if (args.size() > 0 && args.peek().toLowerCase().equals("nocheck")) { + noCheck = true; + args.pop(); + } + + if (args.size() > 0) { + String modeStr = args.pop().toLowerCase(); + switch (modeStr) { + case "biggest": + mode = SearchMode.BIGGEST; + break; + case "smallest": + mode = SearchMode.SMALLEST; + break; + case "first": + mode = SearchMode.FIRST; + break; + case "last": + mode = SearchMode.LAST; + break; + } + } + + try { + SWFSourceInfo sourceInfo = new SWFSourceInfo(null, fileName, null); + if (!sourceInfo.isBundle()) { + System.err.println("Error: should be a bundle. (ZIP or non SWF binary file)"); + System.exit(1); + } + SWFBundle bundle = sourceInfo.getBundle(noCheck, mode); + List> streamsToExtract = new ArrayList<>(); + for (Map.Entry streamEntry : bundle.getAll().entrySet()) { + InputStream stream = streamEntry.getValue(); + stream.reset(); + streamsToExtract.add(streamEntry); + } + + for (Map.Entry streamEntry : streamsToExtract) { + InputStream stream = streamEntry.getValue(); + stream.reset(); + String fileNameOut; + if (mode != SearchMode.ALL) { + if (output == null) { + fileNameOut = Path.getFileNameWithoutExtension(new File(fileName)) + ".swf"; + } else { + fileNameOut = output; + } + } else { + fileNameOut = streamEntry.getKey() + ".swf"; + if (output != null) { + fileNameOut = Path.combine(output, fileNameOut); + } + } + + try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(fileNameOut))) { + byte[] swfData = new byte[stream.available()]; + int cnt = stream.read(swfData); + fos.write(swfData, 0, cnt); + } + } + } catch (IOException ex) { + Logger.getLogger(CommandLineArgumentParser.class.getName()).log(Level.SEVERE, null, ex); + } + + System.exit(0); + } + + private static void parseRenameInvalidIdentifiers(Stack args) { + if (args.size() < 3) { + badArguments(); + } + + String renameTypeStr = args.pop(); + RenameType renameType; + switch (renameTypeStr.toLowerCase()) { + case "typenumber": + renameType = RenameType.TYPENUMBER; + break; + case "randomword": + renameType = RenameType.RANDOMWORD; + break; + default: + System.err.println("Invalid rename type:" + renameTypeStr); + badArguments(); + return; + } + + try { + try (InputStream fis = new BufferedInputStream(new FileInputStream(args.pop())); + OutputStream fos = new BufferedOutputStream(new FileOutputStream(args.pop()))) { + if (SWF.renameInvalidIdentifiers(renameType, fis, fos)) { + System.out.println("OK"); + System.exit(0); + } else { + System.err.println("FAIL"); + System.exit(1); + } + } catch (FileNotFoundException ex) { + System.err.println("File not found."); + } + } catch (IOException ex) { + Logger.getLogger(CommandLineArgumentParser.class.getName()).log(Level.SEVERE, null, ex); + } + + System.exit(0); + } + + private static Map parseFormat(Stack args) { + if (args.size() < 1) { + badArguments(); + } + String fmtStr = args.pop(); + String[] fmts; + if (fmtStr.contains(",")) { + fmts = fmtStr.split(","); + } else { + fmts = new String[]{fmtStr}; + } + Map ret = new HashMap<>(); + for (String fmt : fmts) { + String[] parts = fmt.split(":"); + ret.put(parts[0].toLowerCase(), parts[1].toLowerCase()); + } + return ret; + } + + private static void parseFlashPaperToPdf(Selection selection, double zoom, Stack args) { + if (args.size() < 2) { + badArguments(); + } + File inFile = new File(args.pop()); + File outFile = new File(args.pop()); + printHeader(); + + try (FileInputStream is = new FileInputStream(inFile)) { + + PDFJob job = null; + + SWF swf = new SWF(is, Configuration.parallelSpeedUp.get()); + int totalPages = 0; + + for (Tag t : swf.tags) { + if (t instanceof DefineSpriteTag) { + DefineSpriteTag ds = (DefineSpriteTag) t; + if ("page1".equals(ds.getExportName())) { + totalPages = 1; + } else { + if (totalPages > 0) { + totalPages++; + } + } + } + } + + int page = 0; + + for (Tag t : swf.tags) { + if (t instanceof DefineSpriteTag) { + DefineSpriteTag ds = (DefineSpriteTag) t; + if ("page1".equals(ds.getExportName())) { + page = 1; + job = new PDFJob(new BufferedOutputStream(new FileOutputStream(outFile))); + } else { + if (page > 0) { + page++; + } + } + if (("page" + page).equals(ds.getExportName())) { + if (!selection.contains(page)) { + continue; + } + System.out.print("Page " + page + "/" + totalPages + "..."); + RECT displayRect = new RECT(ds.getTimeline().displayRect); + //displayRect.Xmax *= zoom; + //displayRect.Ymax *= zoom; + Matrix m = new Matrix(); + //m.scale(zoom); + BufferedImage img = SWF.frameToImageGet(ds.getTimeline(), 0, 0, null, 0, displayRect, m, new ColorTransform(), Color.white, false, zoom).getBufferedImage(); + PageFormat pf = new PageFormat(); + pf.setOrientation(PageFormat.PORTRAIT); + Paper p = new Paper(); + p.setSize(img.getWidth(), img.getHeight()); + pf.setPaper(p); + Graphics g = job.getGraphics(pf); + g.drawImage(img, 0, 0, img.getWidth(), img.getHeight(), null); + g.dispose(); + System.out.println("OK"); + + } + } + } + + if (job == null) { + System.err.println("No pages found. Maybe it is not a FlashPaper file"); + System.exit(2); + } + job.end(); + + } catch (FileNotFoundException ex) { + System.err.println("File not found"); + System.exit(1); + } catch (IOException | InterruptedException ex) { + System.err.println("I/O error during reading"); + System.exit(2); + } + System.exit(0); + } + + private static void parseReplace(Stack args) { + if (args.size() < 4) { + badArguments(); + } + + File inFile = new File(args.pop()); + File outFile = new File(args.pop()); + try { + try (FileInputStream is = new FileInputStream(inFile)) { + SWF swf = new SWF(is, Configuration.parallelSpeedUp.get()); + while (true) { + String objectToReplace = args.pop(); + + if (objectToReplace.matches("\\d+")) { + // replace character tag + int characterId = 0; + try { + characterId = Integer.parseInt(objectToReplace); + } catch (NumberFormatException nfe) { + System.err.println("CharacterId should be integer"); + System.exit(1); + } + if (!swf.getCharacters().containsKey(characterId)) { + System.err.println("CharacterId does not exist"); + System.exit(1); + } + + CharacterTag characterTag = swf.getCharacter(characterId); + String repFile = args.pop(); + byte[] data = Helper.readFile(repFile); + if (characterTag instanceof DefineBinaryDataTag) { + DefineBinaryDataTag defineBinaryData = (DefineBinaryDataTag) characterTag; + new BinaryDataImporter().importData(defineBinaryData, data); + } else if (characterTag instanceof ImageTag) { + ImageTag imageTag = (ImageTag) characterTag; + new ImageImporter().importImage(imageTag, data); + } else if (characterTag instanceof SoundTag) { + SoundTag st = (SoundTag) characterTag; + int soundFormat = SoundFormat.FORMAT_UNCOMPRESSED_LITTLE_ENDIAN; + if (repFile.toLowerCase().endsWith(".mp3")) { + soundFormat = SoundFormat.FORMAT_MP3; + } + boolean ok = st.setSound(new ByteArrayInputStream(data), soundFormat); + if (!ok) { + System.err.println("Import FAILED. Maybe unsuppoted media type? Only MP3 and uncompressed WAV are available."); + System.exit(1); + } + } else { + System.err.println("The specified tag type it not supported for import"); + System.exit(1); + } + } else { + Map asms = swf.getASMs(false); + boolean found = false; + if (asms.containsKey(objectToReplace)) { + found = true; + // replace AS1/2 + String repFile = args.pop(); + String repText = Helper.readTextFile(repFile); + ASMSource src = asms.get(objectToReplace); + if (Path.getExtension(repFile).equals(".as")) { + replaceAS2(repText, src); + } else { + replaceAS2PCode(repText, src); + } + } else { + List packs = swf.getAS3Packs(); + for (ScriptPack entry : packs) { + if (entry.getClassPath().toString().equals(objectToReplace)) { + found = true; + // replace AS3 + String repFile = args.pop(); + String repText = Helper.readTextFile(repFile); + ScriptPack pack = entry; + if (Path.getExtension(repFile).equals(".as")) { + replaceAS3(repText, pack); + } else { + // todo: get traits + if (args.isEmpty()) { + badArguments(); + } + int bodyIndex = Integer.parseInt(args.pop()); + //int classIndex = 0; + //int traitId = 0; + Trait trait = null; //abc.findTraitByTraitId(classIndex, traitId); + replaceAS3PCode(repText, pack.abc, bodyIndex, trait); + } + } + } + } + + if (!found) { + System.err.println(objectToReplace + " is not reocginized as a CharacterId or a script name."); + System.exit(1); + } + } + + if (args.isEmpty() || args.peek().startsWith("-")) { + break; + } + } + + try { + try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(outFile))) { + swf.saveTo(fos); + } + } catch (IOException e) { + System.err.println("I/O error during writing"); + System.exit(2); + } + } + } catch (IOException | InterruptedException e) { + System.err.println("I/O error during reading"); + System.exit(2); + } + } + + private static void replaceAS2PCode(String text, ASMSource src) throws IOException, InterruptedException { + System.out.println("Replace AS1/2 PCode"); + if (text.trim().startsWith(Helper.hexData)) { + src.setActionBytes(Helper.getBytesFromHexaText(text)); + } else { + try { + src.setActions(ASMParser.parse(0, true, text, src.getSwf().version, false)); + } catch (ActionParseException ex) { + System.err.println("%error% on line %line%".replace("%error%", ex.text).replace("%line%", Long.toString(ex.line))); + System.exit(1); + } + } + src.setModified(); + } + + private static void replaceAS2(String as, ASMSource src) throws IOException, InterruptedException { + System.out.println("Replace AS1/2"); + System.out.println("Warning: This feature is EXPERIMENTAL"); + com.jpexs.decompiler.flash.action.parser.script.ActionScriptParser par = new com.jpexs.decompiler.flash.action.parser.script.ActionScriptParser(src.getSwf().version); + try { + src.setActions(par.actionsFromString(as)); + } catch (ActionParseException ex) { + System.err.println("%error% on line %line%".replace("%error%", ex.text).replace("%line%", Long.toString(ex.line))); + System.exit(1); + } catch (CompilationException ex) { + System.err.println("%error% on line %line%".replace("%error%", ex.text).replace("%line%", Long.toString(ex.line))); + System.exit(1); + } + src.setModified(); + } + + private static void replaceAS3PCode(String text, ABC abc, int bodyIndex, Trait trait) throws IOException, InterruptedException { + System.out.println("Replace AS3 PCode"); + if (text.trim().startsWith(Helper.hexData)) { + byte[] data = Helper.getBytesFromHexaText(text); + MethodBody mb = abc.bodies.get(bodyIndex); + mb.setCodeBytes(data); + } else { + try { + AVM2Code acode = ASM3Parser.parse(new StringReader(text), abc.constants, trait, new MissingSymbolHandler() { + //no longer ask for adding new constants + @Override + public boolean missingString(String value) { + return true; + } + + @Override + public boolean missingInt(long value) { + return true; + } + + @Override + public boolean missingUInt(long value) { + return true; + } + + @Override + public boolean missingDouble(double value) { + return true; + } + }, abc.bodies.get(bodyIndex), abc.method_info.get(abc.bodies.get(bodyIndex).method_info)); + //acode.getBytes(abc.bodies.get(bodyIndex).getCodeBytes()); + abc.bodies.get(bodyIndex).setCode(acode); + } catch (AVM2ParseException ex) { + System.err.println("%error% on line %line%".replace("%error%", ex.text).replace("%line%", Long.toString(ex.line))); + System.exit(1); + } + } + ((Tag) abc.parentTag).setModified(true); + } + + private static void replaceAS3(String as, ScriptPack pack) throws IOException, InterruptedException { + System.out.println("Replace AS3"); + System.out.println("Warning: This feature is EXPERIMENTAL"); + File swc = Configuration.getPlayerSWC(); + if (swc == null) { + final String adobePage = "http://www.adobe.com/support/flashplayer/downloads.html"; + System.err.println("For ActionScript 3 direct editation, a library called \"PlayerGlobal.swc\" needs to be downloaded from Adobe homepage:"); + System.err.println(adobePage); + System.err.println("Download the library called PlayerGlobal(.swc), and place it to directory"); + System.err.println(Configuration.getFlashLibPath().getAbsolutePath()); + System.exit(1); + } + + try { + pack.abc.replaceScriptPack(pack, as); + } catch (AVM2ParseException ex) { + System.err.println("%error% on line %line%".replace("%error%", ex.text).replace("%line%", Long.toString(ex.line))); + System.exit(1); + } catch (CompilationException ex) { + System.err.println("%error% on line %line%".replace("%error%", ex.text).replace("%line%", Long.toString(ex.line))); + System.exit(1); + } + } + + private static void parseDumpSwf(Stack args) { + if (args.isEmpty()) { + badArguments(); + } + try { + Configuration.dumpTags.set(true); + Configuration.parallelSpeedUp.set(false); + SWFSourceInfo sourceInfo = new SWFSourceInfo(null, args.pop(), null); + Main.parseSWF(sourceInfo); + } catch (Exception ex) { + Logger.getLogger(CommandLineArgumentParser.class.getName()).log(Level.SEVERE, null, ex); + System.exit(1); + } + System.exit(0); + } + + private static void parseDumpAS2(Stack args) { + if (args.isEmpty()) { + badArguments(); + } + File file = new File(args.pop()); + try { + try (FileInputStream is = new FileInputStream(file)) { + SWF swf = new SWF(is, Configuration.parallelSpeedUp.get()); + Map asms = swf.getASMs(false); + for (String as2 : asms.keySet()) { + System.out.println(as2); + } + } + } catch (IOException | InterruptedException e) { + System.err.println("I/O error during reading"); + System.exit(2); + } + } + + private static void parseDumpAS3(Stack args) { + if (args.isEmpty()) { + badArguments(); + } + File file = new File(args.pop()); + try { + try (FileInputStream is = new FileInputStream(file)) { + SWF swf = new SWF(is, Configuration.parallelSpeedUp.get()); + List packs = swf.getAS3Packs(); + for (ScriptPack entry : packs) { + System.out.println(entry.getClassPath().toString() + " " + entry.scriptIndex); + } + } + } catch (IOException | InterruptedException e) { + System.err.println("I/O error during reading"); + System.exit(2); + } + } + + private static FilenameFilter getSwfFilter() { + return (File dir, String name) -> name.toLowerCase().endsWith(".swf"); + } + + private static E enumFromStr(String str, Class cls) { + E[] vals = cls.getEnumConstants(); + if (str == null) { + return vals[0]; + } + for (E e : vals) { + if (e.toString().toLowerCase().replace("_", "").equals(str.toLowerCase().replace("_", ""))) { + return e; + } + } + return vals[0]; + } +} diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index 6998dd253..03c7561ef 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -1227,7 +1227,8 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } public void exportAll(SWF swf, AbortRetryIgnoreHandler handler, String selFile, ExportDialog export) throws IOException { - if (Configuration.debugMode.get()) { + boolean exportAll = false; + if (exportAll) { exportAllDebug(swf, handler, selFile, export); return; }