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 a19bee961..2b630492a 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
@@ -45,20 +45,50 @@ public class DefineBitsJPEG2Tag extends ImageTag implements AloneTag {
public static final String NAME = "DefineBitsJPEG2";
- @SWFType(BasicType.UI16)
- public int characterID;
-
@SWFType(BasicType.UI8)
public ByteArrayRange imageData;
- @Override
- public int getCharacterId() {
- return characterID;
+ /**
+ * Constructor
+ *
+ * @param swf
+ */
+ public DefineBitsJPEG2Tag(SWF swf) {
+ super(swf, ID, NAME, null);
+ characterID = swf.getNextCharacterId();
+ imageData = ByteArrayRange.EMPTY;
+ forceWriteAsLong = true;
+ }
+
+ 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);
+ }
+
+ public DefineBitsJPEG2Tag(SWFInputStream sis, ByteArrayRange data) throws IOException {
+ super(sis.getSwf(), ID, NAME, data);
+ readData(sis, data, 0, false, false, false);
}
@Override
- public void setCharacterId(int characterId) {
- this.characterID = characterId;
+ 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");
+ }
+
+ @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();
}
@Override
@@ -93,52 +123,10 @@ public class DefineBitsJPEG2Tag extends ImageTag implements AloneTag {
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 1e91a1541..f1dcdc372 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
@@ -46,23 +46,64 @@ public class DefineBitsJPEG3Tag extends ImageTag implements AloneTag {
public static final String NAME = "DefineBitsJPEG3";
- @SWFType(BasicType.UI16)
- public int characterID;
-
@SWFType(BasicType.UI8)
public ByteArrayRange imageData;
@SWFType(BasicType.UI8)
- public byte[] bitmapAlphaData;
+ public ByteArrayRange bitmapAlphaData;
- @Override
- public int getCharacterId() {
- return characterID;
+ /**
+ * Constructor
+ *
+ * @param swf
+ */
+ public DefineBitsJPEG3Tag(SWF swf) {
+ super(swf, ID, NAME, null);
+ characterID = swf.getNextCharacterId();
+ imageData = new ByteArrayRange(createEmptyImage());
+ bitmapAlphaData = ByteArrayRange.EMPTY;
+ forceWriteAsLong = true;
+ }
+
+ /**
+ * Constructor
+ *
+ * @param sis
+ * @param data
+ * @throws IOException
+ */
+ public DefineBitsJPEG3Tag(SWFInputStream sis, ByteArrayRange data) throws IOException {
+ super(sis.getSwf(), ID, NAME, data);
+ readData(sis, data, 0, false, false, false);
}
@Override
- public void setCharacterId(int characterId) {
- this.characterID = characterId;
+ 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.readByteRangeEx(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.write(bitmapAlphaData);
+ } catch (IOException e) {
+ throw new Error("This should never happen.", e);
+ }
+ return baos.toByteArray();
}
private byte[] createEmptyImage() {
@@ -80,10 +121,12 @@ public class DefineBitsJPEG3Tag extends ImageTag implements AloneTag {
for (int i = 0; i < ba.length; i++) {
ba[i] = (byte) 255;
}
- bitmapAlphaData = ba;
+
+ bitmapAlphaData = new ByteArrayRange(SWFOutputStream.compressByteArray(ba));
} else {
- bitmapAlphaData = new byte[0];
+ bitmapAlphaData = ByteArrayRange.EMPTY;
}
+
imageData = new ByteArrayRange(data);
clearCache();
setModified(true);
@@ -117,14 +160,15 @@ public class DefineBitsJPEG3Tag extends ImageTag implements AloneTag {
}
SerializableImage img = new SerializableImage(image);
- if (bitmapAlphaData.length == 0) {
+ if (bitmapAlphaData.getLength() == 0) {
cachedImage = img;
return img;
}
+ byte[] alphaData = SWFInputStream.uncompressByteArray(bitmapAlphaData.getRangeData());
int[] pixels = ((DataBufferInt) img.getRaster().getDataBuffer()).getData();
for (int i = 0; i < pixels.length; i++) {
- int a = bitmapAlphaData[i] & 0xff;
+ int a = alphaData[i] & 0xff;
pixels[i] = multiplyAlpha((pixels[i] & 0xffffff) | (a << 24));
}
@@ -135,50 +179,4 @@ public class DefineBitsJPEG3Tag extends ImageTag implements AloneTag {
}
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 6adcb3f80..3b6aeb4f2 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
@@ -46,9 +46,6 @@ public class DefineBitsJPEG4Tag extends ImageTag implements AloneTag {
public static final String NAME = "DefineBitsJPEG4";
- @SWFType(BasicType.UI16)
- public int characterID;
-
@SWFType(BasicType.UI16)
public int deblockParam;
@@ -58,86 +55,6 @@ public class DefineBitsJPEG4Tag extends ImageTag implements AloneTag {
@SWFType(BasicType.UI8)
public ByteArrayRange bitmapAlphaData;
- @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;
- }
-
- private byte[] createEmptyImage() {
- BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
- ByteArrayOutputStream bitmapDataOS = new ByteArrayOutputStream();
- ImageHelper.write(img, "JPG", bitmapDataOS);
- return bitmapDataOS.toByteArray();
- }
-
- @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;
- }
-
/**
* Constructor
*
@@ -148,6 +65,7 @@ public class DefineBitsJPEG4Tag extends ImageTag implements AloneTag {
characterID = swf.getNextCharacterId();
imageData = new ByteArrayRange(createEmptyImage());
bitmapAlphaData = ByteArrayRange.EMPTY;
+ forceWriteAsLong = true;
}
/**
@@ -192,4 +110,77 @@ public class DefineBitsJPEG4Tag extends ImageTag implements AloneTag {
}
return baos.toByteArray();
}
+
+ private byte[] createEmptyImage() {
+ BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
+ ByteArrayOutputStream bitmapDataOS = new ByteArrayOutputStream();
+ ImageHelper.write(img, "JPG", bitmapDataOS);
+ return bitmapDataOS.toByteArray();
+ }
+
+ @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 = new ByteArrayRange(SWFOutputStream.compressByteArray(ba));
+ } else {
+ bitmapAlphaData = ByteArrayRange.EMPTY;
+ }
+
+ 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() {
+ 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;
+ }
+
+ byte[] alphaData = SWFInputStream.uncompressByteArray(bitmapAlphaData.getRangeData());
+ int[] pixels = ((DataBufferInt) img.getRaster().getDataBuffer()).getData();
+ for (int i = 0; i < pixels.length; i++) {
+ int a = alphaData[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;
+ }
}
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 0a4fa9302..e54430950 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
@@ -52,9 +52,6 @@ public class DefineBitsLossless2Tag extends ImageTag implements AloneTag {
public static final String NAME = "DefineBitsLossless2";
- @SWFType(BasicType.UI16)
- public int characterID;
-
@SWFType(BasicType.UI8)
public int bitmapFormat;
@@ -83,14 +80,61 @@ public class DefineBitsLossless2Tag extends ImageTag implements AloneTag {
@Internal
private boolean decompressed = false;
- @Override
- public int getCharacterId() {
- return characterID;
+ /**
+ * Constructor
+ *
+ * @param swf
+ */
+ public DefineBitsLossless2Tag(SWF swf) {
+ super(swf, ID, NAME, null);
+ characterID = swf.getNextCharacterId();
+ bitmapFormat = DefineBitsLossless2Tag.FORMAT_32BIT_ARGB;
+ bitmapWidth = 1;
+ bitmapHeight = 1;
+ zlibBitmapData = new ByteArrayRange(createEmptyImage());
+ forceWriteAsLong = true;
+ }
+
+ public DefineBitsLossless2Tag(SWFInputStream sis, ByteArrayRange data) throws IOException {
+ super(sis.getSwf(), ID, NAME, data);
+ readData(sis, data, 0, false, false, false);
}
@Override
- public void setCharacterId(int characterId) {
- this.characterID = characterId;
+ public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException {
+ characterID = sis.readUI16("characterID");
+ bitmapFormat = sis.readUI8("bitmapFormat");
+ bitmapWidth = sis.readUI16("bitmapWidth");
+ bitmapHeight = sis.readUI16("bitmapHeight");
+ if (bitmapFormat == FORMAT_8BIT_COLORMAPPED) {
+ bitmapColorTableSize = sis.readUI8("bitmapColorTableSize");
+ }
+ zlibBitmapData = sis.readByteRangeEx(sis.available(), "zlibBitmapData");
+ }
+
+ /**
+ * 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.writeUI8(bitmapFormat);
+ sos.writeUI16(bitmapWidth);
+ sos.writeUI16(bitmapHeight);
+ if (bitmapFormat == FORMAT_8BIT_COLORMAPPED) {
+ sos.writeUI8(bitmapColorTableSize);
+ }
+ sos.write(zlibBitmapData);
+ } catch (IOException e) {
+ throw new Error("This should never happen.", e);
+ }
+ return baos.toByteArray();
}
private byte[] createEmptyImage() {
@@ -148,37 +192,6 @@ public class DefineBitsLossless2Tag extends ImageTag implements AloneTag {
setModified(true);
}
- /**
- * Constructor
- *
- * @param swf
- */
- public DefineBitsLossless2Tag(SWF swf) {
- super(swf, ID, NAME, null);
- characterID = swf.getNextCharacterId();
- bitmapFormat = DefineBitsLossless2Tag.FORMAT_32BIT_ARGB;
- bitmapWidth = 1;
- bitmapHeight = 1;
- zlibBitmapData = new ByteArrayRange(createEmptyImage());
- }
-
- public DefineBitsLossless2Tag(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");
- bitmapFormat = sis.readUI8("bitmapFormat");
- bitmapWidth = sis.readUI16("bitmapWidth");
- bitmapHeight = sis.readUI16("bitmapHeight");
- if (bitmapFormat == FORMAT_8BIT_COLORMAPPED) {
- bitmapColorTableSize = sis.readUI8("bitmapColorTableSize");
- }
- zlibBitmapData = sis.readByteRangeEx(sis.available(), "zlibBitmapData");
- }
-
public ALPHACOLORMAPDATA getColorMapData() {
if (!decompressed) {
uncompressData();
@@ -207,31 +220,6 @@ public class DefineBitsLossless2Tag extends ImageTag implements AloneTag {
decompressed = true;
}
- /**
- * 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.writeUI8(bitmapFormat);
- sos.writeUI16(bitmapWidth);
- sos.writeUI16(bitmapHeight);
- if (bitmapFormat == FORMAT_8BIT_COLORMAPPED) {
- sos.writeUI8(bitmapColorTableSize);
- }
- sos.write(zlibBitmapData);
- } catch (IOException e) {
- throw new Error("This should never happen.", e);
- }
- return baos.toByteArray();
- }
-
@Override
public String getImageFormat() {
return "png";
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 b1df0f32a..05549c9db 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
@@ -52,9 +52,6 @@ public class DefineBitsLosslessTag extends ImageTag implements AloneTag {
public static final String NAME = "DefineBitsLossless";
- @SWFType(BasicType.UI16)
- public int characterID;
-
@SWFType(BasicType.UI8)
public int bitmapFormat;
@@ -85,6 +82,63 @@ public class DefineBitsLosslessTag extends ImageTag implements AloneTag {
@Internal
private boolean decompressed = false;
+ /**
+ * Constructor
+ *
+ * @param swf
+ */
+ public DefineBitsLosslessTag(SWF swf) {
+ super(swf, ID, NAME, null);
+ characterID = swf.getNextCharacterId();
+ bitmapFormat = DefineBitsLosslessTag.FORMAT_24BIT_RGB;
+ bitmapWidth = 1;
+ bitmapHeight = 1;
+ zlibBitmapData = new ByteArrayRange(createEmptyImage());
+ forceWriteAsLong = true;
+ }
+
+ public DefineBitsLosslessTag(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");
+ bitmapFormat = sis.readUI8("bitmapFormat");
+ bitmapWidth = sis.readUI16("bitmapWidth");
+ bitmapHeight = sis.readUI16("bitmapHeight");
+ if (bitmapFormat == FORMAT_8BIT_COLORMAPPED) {
+ bitmapColorTableSize = sis.readUI8("bitmapColorTableSize");
+ }
+ zlibBitmapData = sis.readByteRangeEx(sis.available(), "zlibBitmapData");
+ }
+
+ /**
+ * 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.writeUI8(bitmapFormat);
+ sos.writeUI16(bitmapWidth);
+ sos.writeUI16(bitmapHeight);
+ if (bitmapFormat == FORMAT_8BIT_COLORMAPPED) {
+ sos.writeUI8(bitmapColorTableSize);
+ }
+ sos.write(zlibBitmapData);
+ } catch (IOException e) {
+ throw new Error("This should never happen.", e);
+ }
+ return baos.toByteArray();
+ }
+
private byte[] createEmptyImage() {
try {
BITMAPDATA bitmapData = new BITMAPDATA();
@@ -188,16 +242,6 @@ public class DefineBitsLosslessTag extends ImageTag implements AloneTag {
return bi;
}
- @Override
- public int getCharacterId() {
- return characterID;
- }
-
- @Override
- public void setCharacterId(int characterId) {
- this.characterID = characterId;
- }
-
public COLORMAPDATA getColorMapData() {
if (!decompressed) {
uncompressData();
@@ -226,62 +270,6 @@ public class DefineBitsLosslessTag extends ImageTag implements AloneTag {
decompressed = true;
}
- /**
- * Constructor
- *
- * @param swf
- */
- public DefineBitsLosslessTag(SWF swf) {
- super(swf, ID, NAME, null);
- characterID = swf.getNextCharacterId();
- bitmapFormat = DefineBitsLosslessTag.FORMAT_24BIT_RGB;
- bitmapWidth = 1;
- bitmapHeight = 1;
- zlibBitmapData = new ByteArrayRange(createEmptyImage());
- }
-
- public DefineBitsLosslessTag(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");
- bitmapFormat = sis.readUI8("bitmapFormat");
- bitmapWidth = sis.readUI16("bitmapWidth");
- bitmapHeight = sis.readUI16("bitmapHeight");
- if (bitmapFormat == FORMAT_8BIT_COLORMAPPED) {
- bitmapColorTableSize = sis.readUI8("bitmapColorTableSize");
- }
- zlibBitmapData = sis.readByteRangeEx(sis.available(), "zlibBitmapData");
- }
-
- /**
- * 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.writeUI8(bitmapFormat);
- sos.writeUI16(bitmapWidth);
- sos.writeUI16(bitmapHeight);
- if (bitmapFormat == FORMAT_8BIT_COLORMAPPED) {
- sos.writeUI8(bitmapColorTableSize);
- }
- sos.write(zlibBitmapData);
- } catch (IOException e) {
- throw new Error("This should never happen.", e);
- }
- return baos.toByteArray();
- }
-
@Override
public String getImageFormat() {
return "png";
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 a75c4ef5a..ed9d8159e 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
@@ -43,9 +43,6 @@ public class DefineBitsTag extends ImageTag implements TagChangedListener {
public static final String NAME = "DefineBits";
- @SWFType(BasicType.UI16)
- public int characterID;
-
@SWFType(BasicType.UI8)
public ByteArrayRange jpegData;
@@ -69,6 +66,7 @@ public class DefineBitsTag extends ImageTag implements TagChangedListener {
super(swf, ID, NAME, null);
characterID = swf.getNextCharacterId();
jpegData = ByteArrayRange.EMPTY;
+ forceWriteAsLong = true;
}
public DefineBitsTag(SWFInputStream sis, ByteArrayRange data) throws IOException {
@@ -82,6 +80,25 @@ public class DefineBitsTag extends ImageTag implements TagChangedListener {
jpegData = sis.readByteRangeEx(sis.available(), "jpegData");
}
+ /**
+ * 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 InputStream getImageData() {
return null;
@@ -119,35 +136,6 @@ public class DefineBitsTag extends ImageTag implements TagChangedListener {
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";
@@ -155,6 +143,7 @@ public class DefineBitsTag extends ImageTag implements TagChangedListener {
@Override
public void handleEvent(Tag tag) {
+ // cache should be cleared when Jtt tag changes
clearCache();
}
}
diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ImageTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ImageTag.java
index 26085fde1..487038dbd 100644
--- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ImageTag.java
+++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ImageTag.java
@@ -22,6 +22,7 @@ import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
import com.jpexs.decompiler.flash.exporters.shape.BitmapExporter;
import com.jpexs.decompiler.flash.exporters.shape.CanvasShapeExporter;
import com.jpexs.decompiler.flash.exporters.shape.SVGShapeExporter;
+import com.jpexs.decompiler.flash.types.BasicType;
import com.jpexs.decompiler.flash.types.ColorTransform;
import com.jpexs.decompiler.flash.types.FILLSTYLE;
import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY;
@@ -31,6 +32,7 @@ import com.jpexs.decompiler.flash.types.MATRIX;
import com.jpexs.decompiler.flash.types.RECT;
import com.jpexs.decompiler.flash.types.RGBA;
import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE;
+import com.jpexs.decompiler.flash.types.annotations.SWFType;
import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord;
import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord;
import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord;
@@ -48,6 +50,9 @@ import java.util.Set;
*/
public abstract class ImageTag extends CharacterTag implements DrawableTag {
+ @SWFType(BasicType.UI16)
+ public int characterID;
+
protected SerializableImage cachedImage;
public ImageTag(SWF swf, int id, String name, ByteArrayRange data) {
@@ -239,4 +244,14 @@ public abstract class ImageTag extends CharacterTag implements DrawableTag {
public void clearCache() {
cachedImage = null;
}
+
+ @Override
+ public int getCharacterId() {
+ return characterID;
+ }
+
+ @Override
+ public void setCharacterId(int characterId) {
+ this.characterID = characterId;
+ }
}
diff --git a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java
index 428230a99..e660f8f66 100644
--- a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java
+++ b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java
@@ -1,743 +1,755 @@
-/*
- * 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.gui.tagtree;
-
-import com.jpexs.decompiler.flash.SWF;
-import com.jpexs.decompiler.flash.gui.AppDialog;
-import com.jpexs.decompiler.flash.gui.Main;
-import com.jpexs.decompiler.flash.gui.MainPanel;
-import com.jpexs.decompiler.flash.gui.ReplaceCharacterDialog;
-import com.jpexs.decompiler.flash.gui.View;
-import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag;
-import com.jpexs.decompiler.flash.tags.DefineSoundTag;
-import com.jpexs.decompiler.flash.tags.DefineSpriteTag;
-import com.jpexs.decompiler.flash.tags.DoActionTag;
-import com.jpexs.decompiler.flash.tags.DoInitActionTag;
-import com.jpexs.decompiler.flash.tags.Tag;
-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.ShapeTag;
-import com.jpexs.decompiler.flash.timeline.Frame;
-import com.jpexs.decompiler.flash.timeline.TagScript;
-import com.jpexs.decompiler.flash.timeline.Timelined;
-import com.jpexs.decompiler.flash.treeitems.FolderItem;
-import com.jpexs.decompiler.flash.treeitems.SWFList;
-import com.jpexs.decompiler.flash.treeitems.TreeItem;
-import com.jpexs.helpers.Helper;
-import java.awt.event.ActionEvent;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-import java.io.IOException;
-import java.lang.reflect.InvocationTargetException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-import javax.swing.JMenu;
-import javax.swing.JMenuItem;
-import javax.swing.JOptionPane;
-import javax.swing.JPopupMenu;
-import javax.swing.SwingUtilities;
-import javax.swing.tree.TreePath;
-
-/**
- *
- * @author JPEXS
- */
-public class TagTreeContextMenu extends JPopupMenu {
-
- private static final Logger logger = Logger.getLogger(TagTreeContextMenu.class.getName());
-
- private final MainPanel mainPanel;
-
- private final TagTree tagTree;
-
- private JMenuItem expandRecursiveMenuItem;
-
- private JMenuItem removeMenuItem;
-
- private JMenuItem removeWithDependenciesMenuItem;
-
- private JMenuItem undoTagMenuItem;
-
- private JMenuItem exportSelectionMenuItem;
-
- private JMenuItem replaceMenuItem;
-
- private JMenuItem replaceWithTagMenuItem;
-
- private JMenuItem rawEditMenuItem;
-
- private JMenuItem jumpToCharacterMenuItem;
-
- private JMenuItem exportJavaSourceMenuItem;
-
- private JMenuItem exportSwfXmlMenuItem;
-
- private JMenuItem importSwfXmlMenuItem;
-
- private JMenuItem closeMenuItem;
-
- private JMenu addTagMenu;
-
- private JMenu moveTagMenu;
-
- private JMenu copyTagMenu;
-
- private JMenu copyTagWithDependenciesMenu;
-
- private JMenuItem openSWFInsideTagMenuItem;
-
- public TagTreeContextMenu(final TagTree tagTree, MainPanel mainPanel) {
- this.mainPanel = mainPanel;
- this.tagTree = tagTree;
- expandRecursiveMenuItem = new JMenuItem(mainPanel.translate("contextmenu.expandAll"));
- expandRecursiveMenuItem.addActionListener(this::expandRecursiveActionPerformed);
- add(expandRecursiveMenuItem);
-
- removeMenuItem = new JMenuItem(mainPanel.translate("contextmenu.remove"));
- removeMenuItem.addActionListener((ActionEvent e) -> {
- removeItemActionPerformed(e, false);
- });
- add(removeMenuItem);
-
- removeWithDependenciesMenuItem = new JMenuItem(mainPanel.translate("contextmenu.removeWithDependencies"));
- removeWithDependenciesMenuItem.addActionListener((ActionEvent e) -> {
- removeItemActionPerformed(e, true);
- });
- add(removeWithDependenciesMenuItem);
-
- undoTagMenuItem = new JMenuItem(mainPanel.translate("contextmenu.undo"));
- undoTagMenuItem.addActionListener(this::undoTagActionPerformed);
- add(undoTagMenuItem);
-
- exportSelectionMenuItem = new JMenuItem(mainPanel.translate("menu.file.export.selection"));
- exportSelectionMenuItem.addActionListener(mainPanel::exportSelectionActionPerformed);
- add(exportSelectionMenuItem);
-
- replaceMenuItem = new JMenuItem(mainPanel.translate("button.replace"));
- replaceMenuItem.addActionListener(mainPanel::replaceButtonActionPerformed);
- add(replaceMenuItem);
-
- replaceWithTagMenuItem = new JMenuItem(mainPanel.translate("button.replaceWithTag"));
- replaceWithTagMenuItem.addActionListener(this::replaceWithTagActionPerformed);
- add(replaceWithTagMenuItem);
-
- rawEditMenuItem = new JMenuItem(mainPanel.translate("contextmenu.rawEdit"));
- rawEditMenuItem.addActionListener(this::rawEditActionPerformed);
- add(rawEditMenuItem);
-
- jumpToCharacterMenuItem = new JMenuItem(mainPanel.translate("contextmenu.jumpToCharacter"));
- jumpToCharacterMenuItem.addActionListener(this::jumpToCharacterActionPerformed);
- add(jumpToCharacterMenuItem);
-
- exportJavaSourceMenuItem = new JMenuItem(mainPanel.translate("contextmenu.exportJavaSource"));
- exportJavaSourceMenuItem.addActionListener(mainPanel::exportJavaSourceActionPerformed);
- add(exportJavaSourceMenuItem);
-
- exportSwfXmlMenuItem = new JMenuItem(mainPanel.translate("contextmenu.exportSwfXml"));
- exportSwfXmlMenuItem.addActionListener(mainPanel::exportSwfXmlActionPerformed);
- add(exportSwfXmlMenuItem);
-
- importSwfXmlMenuItem = new JMenuItem(mainPanel.translate("contextmenu.importSwfXml"));
- importSwfXmlMenuItem.addActionListener(mainPanel::importSwfXmlActionPerformed);
- add(importSwfXmlMenuItem);
-
- closeMenuItem = new JMenuItem(mainPanel.translate("contextmenu.closeSwf"));
- closeMenuItem.addActionListener(this::closeSwfActionPerformed);
- add(closeMenuItem);
-
- addTagMenu = new JMenu(mainPanel.translate("contextmenu.addTag"));
- add(addTagMenu);
-
- moveTagMenu = new JMenu(mainPanel.translate("contextmenu.moveTag"));
- add(moveTagMenu);
-
- copyTagMenu = new JMenu(mainPanel.translate("contextmenu.copyTag"));
- add(copyTagMenu);
-
- copyTagWithDependenciesMenu = new JMenu(mainPanel.translate("contextmenu.copyTagWithDependencies"));
- add(copyTagWithDependenciesMenu);
-
- openSWFInsideTagMenuItem = new JMenuItem(mainPanel.translate("contextmenu.openswfinside"));
- add(openSWFInsideTagMenuItem);
- openSWFInsideTagMenuItem.addActionListener(this::openSwfInsideActionPerformed);
-
- tagTree.addMouseListener(new MouseAdapter() {
- @Override
- public void mouseClicked(MouseEvent e) {
- if (SwingUtilities.isRightMouseButton(e)) {
-
- int row = tagTree.getClosestRowForLocation(e.getX(), e.getY());
- int[] selectionRows = tagTree.getSelectionRows();
- if (!Helper.contains(selectionRows, row)) {
- tagTree.setSelectionRow(row);
- }
-
- TreePath[] paths = tagTree.getSelectionPaths();
- if (paths == null || paths.length == 0) {
- return;
- }
-
- List li = new ArrayList<>();
- for (TreePath treePath : paths) {
- TreeItem item = (TreeItem) treePath.getLastPathComponent();
- li.add(item);
- }
-
- update(li);
- show(e.getComponent(), e.getX(), e.getY());
- }
- }
- });
- }
-
- public void update(final List items) {
-
- if (items.isEmpty()) {
- return;
- }
-
- final List swfs = mainPanel.getSwfs();
-
- boolean allSelectedIsTagOrFrame = true;
- for (TreeItem item : items) {
- if (!(item instanceof Tag) && !(item instanceof Frame)) {
- if (item instanceof TagScript) {
- Tag tag = ((TagScript) item).getTag();
- if (tag instanceof DoActionTag || tag instanceof DoInitActionTag) {
- continue;
- }
- }
-
- allSelectedIsTagOrFrame = false;
- break;
- }
- }
-
- boolean allSelectedIsTag = true;
- for (TreeItem item : items) {
- if (!(item instanceof Tag)) {
- if (item instanceof TagScript) {
- Tag tag = ((TagScript) item).getTag();
- if (tag instanceof DoActionTag || tag instanceof DoInitActionTag) {
- continue;
- }
- }
-
- allSelectedIsTag = false;
- break;
- }
- }
-
- boolean allSelectedIsBinaryData = true;
- for (TreeItem item : items) {
- if (!(item instanceof DefineBinaryDataTag)) {
- allSelectedIsBinaryData = false;
- break;
- }
- }
-
- boolean allSelectedIsSwf = true;
- for (TreeItem item : items) {
- if (!(item instanceof SWF) && !(item instanceof SWFList)) {
- allSelectedIsSwf = false;
- break;
- } else if (item instanceof SWF) {
- SWF swf = (SWF) item;
- // Do not allow to close SWF in bundle
- if (swf.swfList != null && swf.swfList.isBundle()) {
- allSelectedIsSwf = false;
- }
- }
- }
-
- boolean allSelectedIsInTheSameSwf = true;
- SWF singleSwf = null;
- for (TreeItem item : items) {
- if (item instanceof SWFList) {
- allSelectedIsInTheSameSwf = false;
- break;
- }
- if (singleSwf == null) {
- singleSwf = item.getSwf();
- } else {
- if (singleSwf != item.getSwf()) {
- allSelectedIsInTheSameSwf = false;
- break;
- }
- }
- }
-
- expandRecursiveMenuItem.setVisible(false);
- removeMenuItem.setVisible(allSelectedIsTagOrFrame);
- removeWithDependenciesMenuItem.setVisible(allSelectedIsTagOrFrame);
- undoTagMenuItem.setVisible(allSelectedIsTag);
- exportSelectionMenuItem.setEnabled(tagTree.hasExportableNodes());
- replaceMenuItem.setVisible(false);
- replaceWithTagMenuItem.setVisible(false);
- rawEditMenuItem.setVisible(false);
- jumpToCharacterMenuItem.setVisible(false);
- exportJavaSourceMenuItem.setVisible(allSelectedIsSwf);
- exportSwfXmlMenuItem.setVisible(allSelectedIsSwf);
- importSwfXmlMenuItem.setVisible(allSelectedIsSwf);
- closeMenuItem.setVisible(allSelectedIsSwf);
- addTagMenu.setVisible(false);
- moveTagMenu.setVisible(false);
- copyTagMenu.setVisible(false);
- copyTagWithDependenciesMenu.setVisible(false);
- openSWFInsideTagMenuItem.setVisible(false);
-
- boolean singleSelect = items.size() == 1;
-
- if (singleSelect) {
- final TreeItem firstItem = items.get(0);
-
- if (firstItem instanceof CharacterTag) {
- replaceWithTagMenuItem.setVisible(true);
- }
-
- // replace
- if (firstItem instanceof ImageTag && ((ImageTag) firstItem).importSupported()) {
- replaceMenuItem.setVisible(true);
- }
-
- if (firstItem instanceof ShapeTag) {
- replaceMenuItem.setVisible(true);
- }
-
- if (firstItem instanceof DefineBinaryDataTag) {
- replaceMenuItem.setVisible(true);
- }
-
- if (firstItem instanceof DefineSoundTag) {
- replaceMenuItem.setVisible(true);
- }
-
- List allowedTagTypes = null;
- if (firstItem instanceof FolderItem) {
- allowedTagTypes = tagTree.getSwfFolderItemNestedTagIds(((FolderItem) firstItem).getName(), firstItem.getSwf().gfx);
- } else if (firstItem instanceof Tag) {
- allowedTagTypes = tagTree.getNestedTagIds((Tag) firstItem);
- }
-
- addTagMenu.removeAll();
- if (allowedTagTypes != null) {
- for (Integer tagId : allowedTagTypes) {
- final Class> cl = TagIdClassMap.getClassByTagId(tagId);
- JMenuItem tagItem = new JMenuItem(cl.getSimpleName());
- tagItem.addActionListener((ActionEvent ae) -> {
- addTagActionPerformed(ae, firstItem, cl);
- });
- addTagMenu.add(tagItem);
- }
- addTagMenu.setVisible(true);
- }
-
- if (tagTree.getModel().getChildCount(firstItem) > 0) {
- expandRecursiveMenuItem.setVisible(true);
- }
-
- if (firstItem instanceof CharacterIdTag && !(firstItem instanceof CharacterTag)) {
- jumpToCharacterMenuItem.setVisible(true);
- }
-
- if (firstItem instanceof Tag) {
- rawEditMenuItem.setVisible(firstItem instanceof Tag);
- }
- }
-
- if (allSelectedIsInTheSameSwf && allSelectedIsTag && swfs.size() > 1) {
- moveTagMenu.removeAll();
- copyTagMenu.removeAll();
- copyTagWithDependenciesMenu.removeAll();
- for (SWFList targetSwfList : swfs) {
- for (final SWF targetSwf : targetSwfList) {
- if (targetSwf != singleSwf) {
- JMenuItem swfItem = new JMenuItem(targetSwf.getShortFileName());
- swfItem.addActionListener((ActionEvent ae) -> {
- moveTagActionPerformed(ae, items, targetSwf);
- });
- moveTagMenu.add(swfItem);
-
- swfItem = new JMenuItem(targetSwf.getShortFileName());
- swfItem.addActionListener((ActionEvent ae) -> {
- copyTagActionPerformed(ae, items, targetSwf);
- });
- copyTagMenu.add(swfItem);
-
- swfItem = new JMenuItem(targetSwf.getShortFileName());
- swfItem.addActionListener((ActionEvent ae) -> {
- copyTagWithDependenciesActionPerformed(ae, items, targetSwf);
- });
- copyTagWithDependenciesMenu.add(swfItem);
- }
- }
- }
- moveTagMenu.setVisible(true);
- copyTagMenu.setVisible(true);
- copyTagWithDependenciesMenu.setVisible(true);
- }
-
- if (allSelectedIsBinaryData) {
- boolean anyInnerSwf = false;
- for (TreeItem item : items) {
- DefineBinaryDataTag binary = (DefineBinaryDataTag) item;
-
- // inner swf is not loaded yet
- if (binary.innerSwf == null && binary.isSwfData()) {
- anyInnerSwf = true;
- }
- }
-
- openSWFInsideTagMenuItem.setVisible(anyInnerSwf);
- }
- }
-
- private void addTagActionPerformed(ActionEvent evt, TreeItem firstItem, Class> cl) {
- try {
- SWF swf = firstItem.getSwf();
- Tag t = (Tag) cl.getDeclaredConstructor(SWF.class).newInstance(new Object[]{swf});
- boolean isDefineSprite = firstItem instanceof DefineSpriteTag;
- Timelined timelined = isDefineSprite ? (DefineSpriteTag) firstItem : swf;
- t.setTimelined(timelined);
- if (isDefineSprite) {
- ((DefineSpriteTag) firstItem).subTags.add(t);
- } else {
- if (firstItem instanceof Tag) {
- if ((t instanceof CharacterIdTag) && (firstItem instanceof CharacterTag)) {
- ((CharacterIdTag) t).setCharacterId(((CharacterTag) firstItem).getCharacterId());
- }
- int index = swf.tags.indexOf(firstItem);
- if (index > -1) {
- swf.tags.add(index, t);
- } else {
- swf.tags.add(t);
- }
- } else {
- swf.tags.add(t);
- }
- }
- timelined.resetTimeline();
- swf.updateCharacters();
- mainPanel.refreshTree(swf);
- } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException ex) {
- logger.log(Level.SEVERE, null, ex);
- }
- }
-
- private int chechUniqueCharacterId(Tag tag) {
- if (tag instanceof CharacterTag) {
- CharacterTag characterTag = (CharacterTag) tag;
- int characterId = characterTag.getCharacterId();
- SWF swf = tag.getSwf();
- if (swf.getCharacter(characterId) != null) {
- int newCharacterId = swf.getNextCharacterId();
- characterTag.setCharacterId(newCharacterId);
- logger.log(Level.WARNING, "Target SWF already contained chatacter tag with id = {0} => id changed to {1}", new Object[]{characterId, newCharacterId});
- return newCharacterId;
- }
-
- return characterId;
- }
-
- return -1;
- }
-
- private void moveTagActionPerformed(ActionEvent evt, List items, SWF targetSwf) {
- SWF sourceSwf = items.get(0).getSwf();
- for (TreeItem item : items) {
- Tag tag = (Tag) item;
- sourceSwf.tags.remove(tag);
- tag.setSwf(targetSwf, true);
- targetSwf.tags.add(tag);
- chechUniqueCharacterId(tag);
- targetSwf.updateCharacters();
- tag.setModified(true);
- }
-
- sourceSwf.assignExportNamesToSymbols();
- targetSwf.assignExportNamesToSymbols();
- sourceSwf.assignClassesToSymbols();
- targetSwf.assignClassesToSymbols();
- sourceSwf.clearImageCache();
- targetSwf.clearImageCache();
- sourceSwf.updateCharacters();
- targetSwf.updateCharacters();
- sourceSwf.resetTimelines(sourceSwf);
- targetSwf.resetTimelines(targetSwf);
- mainPanel.refreshTree(new SWF[]{sourceSwf, targetSwf});
- }
-
- private void copyTagActionPerformed(ActionEvent evt, List items, SWF targetSwf) {
- try {
- for (TreeItem item : items) {
- Tag tag = (Tag) item;
- Tag copyTag = tag.cloneTag();
- copyTag.setSwf(targetSwf, true);
- targetSwf.tags.add(copyTag);
- chechUniqueCharacterId(copyTag);
- targetSwf.updateCharacters();
- copyTag.setModified(true);
- }
-
- targetSwf.assignExportNamesToSymbols();
- targetSwf.assignClassesToSymbols();
- targetSwf.clearImageCache();
- targetSwf.updateCharacters();
- mainPanel.refreshTree(targetSwf);
- } catch (IOException | InterruptedException ex) {
- logger.log(Level.SEVERE, null, ex);
- }
- }
-
- private void copyTagWithDependenciesActionPerformed(ActionEvent evt, List items, SWF targetSwf) {
- try {
- SWF sourceSwf = items.get(0).getSwf();
- for (TreeItem item : items) {
- Set copiedTags = new HashSet<>();
- Set newTags = new HashSet<>();
- LinkedHashSet needed = new LinkedHashSet<>();
- Map changedCharacterIds = new HashMap<>();
-
- Tag tag = (Tag) item;
- tag.getNeededCharactersDeep(needed);
- Tag copyTag;
-
- List neededList = new ArrayList<>();
- for (Integer characterId : needed) {
- neededList.add(characterId);
- }
-
- // first add dependencies in reverse order
- for (int i = neededList.size() - 1; i >= 0; i--) {
- int characterId = neededList.get(i);
- Tag neededTag = (Tag) sourceSwf.getCharacter(characterId);
- if (!copiedTags.contains(neededTag)) {
- copyTag = neededTag.cloneTag();
- copyTag.setSwf(targetSwf, true);
- targetSwf.tags.add(copyTag);
- if (neededTag instanceof CharacterTag) {
- CharacterTag characterTag = (CharacterTag) copyTag;
- int oldCharacterId = characterTag.getCharacterId();
- int newCharacterId = chechUniqueCharacterId(copyTag);
- changedCharacterIds.put(oldCharacterId, newCharacterId);
- }
-
- targetSwf.updateCharacters();
- targetSwf.getCharacters(); // force rebuild character id cache
- copyTag.setModified(true);
- copiedTags.add(neededTag);
- newTags.add(copyTag);
- }
- }
-
- copyTag = tag.cloneTag();
- copyTag.setSwf(targetSwf, true);
- targetSwf.tags.add(copyTag);
- if (tag instanceof CharacterTag) {
- CharacterTag characterTag = (CharacterTag) copyTag;
- int oldCharacterId = characterTag.getCharacterId();
- int newCharacterId = chechUniqueCharacterId(copyTag);
- changedCharacterIds.put(oldCharacterId, newCharacterId);
- }
-
- targetSwf.updateCharacters();
- targetSwf.getCharacters(); // force rebuild character id cache
- copyTag.setModified(true);
- copiedTags.add(tag);
- newTags.add(copyTag);
-
- for (int oldCharacterId : changedCharacterIds.keySet()) {
- int newCharacterId = changedCharacterIds.get(oldCharacterId);
- for (Tag newTag : newTags) {
- // todo: avoid double replaces
- newTag.replaceCharacter(oldCharacterId, newCharacterId);
- }
- }
- }
-
- targetSwf.assignExportNamesToSymbols();
- targetSwf.assignClassesToSymbols();
- targetSwf.clearImageCache();
- targetSwf.updateCharacters();
- mainPanel.refreshTree(targetSwf);
- } catch (IOException | InterruptedException ex) {
- logger.log(Level.SEVERE, null, ex);
- }
- }
-
- private void openSwfInsideActionPerformed(ActionEvent evt) {
- List sel = tagTree.getSelected(tagTree);
- List binaryDatas = new ArrayList<>();
- for (TreeItem item : sel) {
- DefineBinaryDataTag binaryData = (DefineBinaryDataTag) item;
- if (binaryData.isSwfData()) {
- binaryDatas.add((DefineBinaryDataTag) item);
- }
- }
-
- mainPanel.loadFromBinaryTag(binaryDatas);
- }
-
- private void replaceWithTagActionPerformed(ActionEvent evt) {
- TreeItem itemr = tagTree.getCurrentTreeItem();
- if (itemr == null) {
- return;
- }
-
- SWF swf = itemr.getSwf();
- CharacterTag characterTag = (CharacterTag) itemr;
- int characterId = characterTag.getCharacterId();
- ReplaceCharacterDialog replaceCharacterDialog = new ReplaceCharacterDialog();
- if (replaceCharacterDialog.showDialog(swf, characterId) == AppDialog.OK_OPTION) {
- int newCharacterId = replaceCharacterDialog.getCharacterId();
- CharacterTag newCharacter = swf.getCharacter(newCharacterId);
- newCharacter.setCharacterId(characterId);
- characterTag.setCharacterId(newCharacterId);
- newCharacter.setModified(true);
- characterTag.setModified(true);
-
- swf.assignExportNamesToSymbols();
- swf.assignClassesToSymbols();
- swf.clearImageCache();
- swf.updateCharacters();
- mainPanel.refreshTree(swf);
- }
- }
-
- private void rawEditActionPerformed(ActionEvent evt) {
- TreeItem itemr = tagTree.getCurrentTreeItem();
- if (itemr == null) {
- return;
- }
-
- mainPanel.showGenericTag((Tag) itemr);
- }
-
- private void jumpToCharacterActionPerformed(ActionEvent evt) {
- TreeItem itemj = tagTree.getCurrentTreeItem();
- if (itemj == null || !(itemj instanceof CharacterIdTag)) {
- return;
- }
-
- CharacterIdTag characterIdTag = (CharacterIdTag) itemj;
- mainPanel.setTagTreeSelectedNode(itemj.getSwf().getCharacter(characterIdTag.getCharacterId()));
- }
-
- private void expandRecursiveActionPerformed(ActionEvent evt) {
- TreePath path = tagTree.getSelectionPath();
- if (path == null) {
- return;
- }
- View.expandTreeNodes(tagTree, path, true);
- }
-
- private void removeItemActionPerformed(ActionEvent evt, boolean removeDependencies) {
- List sel = tagTree.getSelected(tagTree);
-
- List tagsToRemove = new ArrayList<>();
- for (TreeItem item : sel) {
- if (item instanceof Tag) {
- tagsToRemove.add((Tag) item);
- } else if (item instanceof TagScript) {
- tagsToRemove.add(((TagScript) item).getTag());
- } else if (item instanceof Frame) {
- Frame frameNode = (Frame) item;
- Frame frame = frameNode.timeline.getFrame(frameNode.frame);
- if (frame.showFrameTag != null) {
- tagsToRemove.add(frame.showFrameTag);
- } else {
- // this should be the last frame, so remove the inner tags
- tagsToRemove.addAll(frame.innerTags);
- }
- }
- }
-
- if (tagsToRemove.size() > 0) {
- String confirmationMessage;
- if (tagsToRemove.size() == 1) {
- Tag tag = tagsToRemove.get(0);
- confirmationMessage = mainPanel.translate("message.confirm.remove").replace("%item%", tag.toString());
- } else {
- confirmationMessage = mainPanel.translate("message.confirm.removemultiple").replace("%count%", Integer.toString(tagsToRemove.size()));
- }
-
- if (View.showConfirmDialog(this, confirmationMessage, mainPanel.translate("message.confirm"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) {
- Map> tagsToRemoveBySwf = new HashMap<>();
- for (Tag tag : tagsToRemove) {
- SWF swf = tag.getSwf();
- if (!tagsToRemoveBySwf.containsKey(swf)) {
- tagsToRemoveBySwf.put(swf, new ArrayList<>());
- }
-
- tagsToRemoveBySwf.get(swf).add(tag);
- }
-
- for (SWF swf : tagsToRemoveBySwf.keySet()) {
- swf.removeTags(tagsToRemoveBySwf.get(swf), removeDependencies);
- }
-
- mainPanel.refreshTree();
- }
- }
- }
-
- private void undoTagActionPerformed(ActionEvent evt) {
- List sel = tagTree.getSelected(tagTree);
-
- for (TreeItem item : sel) {
- if (item instanceof Tag) {
- try {
- Tag tag = (Tag) item;
- tag.undo();
- tag.getSwf().clearAllCache();
- tagTree.getModel().updateNode(item);
- } catch (InterruptedException | IOException ex) {
- logger.log(Level.SEVERE, null, ex);
- }
- }
- }
-
- mainPanel.repaintTree();
- }
-
- private void closeSwfActionPerformed(ActionEvent evt) {
- List sel = tagTree.getSelected(tagTree);
- for (TreeItem item : sel) {
- if (item instanceof SWF) {
- SWF swf = (SWF) item;
- if (swf.binaryData != null) {
- // embedded swf
- swf.binaryData.innerSwf = null;
- swf.clearTagSwfs();
- mainPanel.refreshTree();
- } else {
- Main.closeFile(swf.swfList);
- }
- } else if (item instanceof SWFList) {
- Main.closeFile((SWFList) item);
- }
- }
- }
-}
+/*
+ * 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.gui.tagtree;
+
+import com.jpexs.decompiler.flash.SWF;
+import com.jpexs.decompiler.flash.gui.AppDialog;
+import com.jpexs.decompiler.flash.gui.Main;
+import com.jpexs.decompiler.flash.gui.MainPanel;
+import com.jpexs.decompiler.flash.gui.ReplaceCharacterDialog;
+import com.jpexs.decompiler.flash.gui.View;
+import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag;
+import com.jpexs.decompiler.flash.tags.DefineSoundTag;
+import com.jpexs.decompiler.flash.tags.DefineSpriteTag;
+import com.jpexs.decompiler.flash.tags.DoActionTag;
+import com.jpexs.decompiler.flash.tags.DoInitActionTag;
+import com.jpexs.decompiler.flash.tags.ShowFrameTag;
+import com.jpexs.decompiler.flash.tags.Tag;
+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.ShapeTag;
+import com.jpexs.decompiler.flash.timeline.Frame;
+import com.jpexs.decompiler.flash.timeline.TagScript;
+import com.jpexs.decompiler.flash.timeline.Timelined;
+import com.jpexs.decompiler.flash.treeitems.FolderItem;
+import com.jpexs.decompiler.flash.treeitems.SWFList;
+import com.jpexs.decompiler.flash.treeitems.TreeItem;
+import com.jpexs.helpers.Helper;
+import java.awt.event.ActionEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JPopupMenu;
+import javax.swing.SwingUtilities;
+import javax.swing.tree.TreePath;
+
+/**
+ *
+ * @author JPEXS
+ */
+public class TagTreeContextMenu extends JPopupMenu {
+
+ private static final Logger logger = Logger.getLogger(TagTreeContextMenu.class.getName());
+
+ private final MainPanel mainPanel;
+
+ private final TagTree tagTree;
+
+ private JMenuItem expandRecursiveMenuItem;
+
+ private JMenuItem removeMenuItem;
+
+ private JMenuItem removeWithDependenciesMenuItem;
+
+ private JMenuItem undoTagMenuItem;
+
+ private JMenuItem exportSelectionMenuItem;
+
+ private JMenuItem replaceMenuItem;
+
+ private JMenuItem replaceWithTagMenuItem;
+
+ private JMenuItem rawEditMenuItem;
+
+ private JMenuItem jumpToCharacterMenuItem;
+
+ private JMenuItem exportJavaSourceMenuItem;
+
+ private JMenuItem exportSwfXmlMenuItem;
+
+ private JMenuItem importSwfXmlMenuItem;
+
+ private JMenuItem closeMenuItem;
+
+ private JMenu addTagMenu;
+
+ private JMenu moveTagMenu;
+
+ private JMenu copyTagMenu;
+
+ private JMenu copyTagWithDependenciesMenu;
+
+ private JMenuItem openSWFInsideTagMenuItem;
+
+ public TagTreeContextMenu(final TagTree tagTree, MainPanel mainPanel) {
+ this.mainPanel = mainPanel;
+ this.tagTree = tagTree;
+ expandRecursiveMenuItem = new JMenuItem(mainPanel.translate("contextmenu.expandAll"));
+ expandRecursiveMenuItem.addActionListener(this::expandRecursiveActionPerformed);
+ add(expandRecursiveMenuItem);
+
+ removeMenuItem = new JMenuItem(mainPanel.translate("contextmenu.remove"));
+ removeMenuItem.addActionListener((ActionEvent e) -> {
+ removeItemActionPerformed(e, false);
+ });
+ add(removeMenuItem);
+
+ removeWithDependenciesMenuItem = new JMenuItem(mainPanel.translate("contextmenu.removeWithDependencies"));
+ removeWithDependenciesMenuItem.addActionListener((ActionEvent e) -> {
+ removeItemActionPerformed(e, true);
+ });
+ add(removeWithDependenciesMenuItem);
+
+ undoTagMenuItem = new JMenuItem(mainPanel.translate("contextmenu.undo"));
+ undoTagMenuItem.addActionListener(this::undoTagActionPerformed);
+ add(undoTagMenuItem);
+
+ exportSelectionMenuItem = new JMenuItem(mainPanel.translate("menu.file.export.selection"));
+ exportSelectionMenuItem.addActionListener(mainPanel::exportSelectionActionPerformed);
+ add(exportSelectionMenuItem);
+
+ replaceMenuItem = new JMenuItem(mainPanel.translate("button.replace"));
+ replaceMenuItem.addActionListener(mainPanel::replaceButtonActionPerformed);
+ add(replaceMenuItem);
+
+ replaceWithTagMenuItem = new JMenuItem(mainPanel.translate("button.replaceWithTag"));
+ replaceWithTagMenuItem.addActionListener(this::replaceWithTagActionPerformed);
+ add(replaceWithTagMenuItem);
+
+ rawEditMenuItem = new JMenuItem(mainPanel.translate("contextmenu.rawEdit"));
+ rawEditMenuItem.addActionListener(this::rawEditActionPerformed);
+ add(rawEditMenuItem);
+
+ jumpToCharacterMenuItem = new JMenuItem(mainPanel.translate("contextmenu.jumpToCharacter"));
+ jumpToCharacterMenuItem.addActionListener(this::jumpToCharacterActionPerformed);
+ add(jumpToCharacterMenuItem);
+
+ exportJavaSourceMenuItem = new JMenuItem(mainPanel.translate("contextmenu.exportJavaSource"));
+ exportJavaSourceMenuItem.addActionListener(mainPanel::exportJavaSourceActionPerformed);
+ add(exportJavaSourceMenuItem);
+
+ exportSwfXmlMenuItem = new JMenuItem(mainPanel.translate("contextmenu.exportSwfXml"));
+ exportSwfXmlMenuItem.addActionListener(mainPanel::exportSwfXmlActionPerformed);
+ add(exportSwfXmlMenuItem);
+
+ importSwfXmlMenuItem = new JMenuItem(mainPanel.translate("contextmenu.importSwfXml"));
+ importSwfXmlMenuItem.addActionListener(mainPanel::importSwfXmlActionPerformed);
+ add(importSwfXmlMenuItem);
+
+ closeMenuItem = new JMenuItem(mainPanel.translate("contextmenu.closeSwf"));
+ closeMenuItem.addActionListener(this::closeSwfActionPerformed);
+ add(closeMenuItem);
+
+ addTagMenu = new JMenu(mainPanel.translate("contextmenu.addTag"));
+ add(addTagMenu);
+
+ moveTagMenu = new JMenu(mainPanel.translate("contextmenu.moveTag"));
+ add(moveTagMenu);
+
+ copyTagMenu = new JMenu(mainPanel.translate("contextmenu.copyTag"));
+ add(copyTagMenu);
+
+ copyTagWithDependenciesMenu = new JMenu(mainPanel.translate("contextmenu.copyTagWithDependencies"));
+ add(copyTagWithDependenciesMenu);
+
+ openSWFInsideTagMenuItem = new JMenuItem(mainPanel.translate("contextmenu.openswfinside"));
+ add(openSWFInsideTagMenuItem);
+ openSWFInsideTagMenuItem.addActionListener(this::openSwfInsideActionPerformed);
+
+ tagTree.addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseClicked(MouseEvent e) {
+ if (SwingUtilities.isRightMouseButton(e)) {
+
+ int row = tagTree.getClosestRowForLocation(e.getX(), e.getY());
+ int[] selectionRows = tagTree.getSelectionRows();
+ if (!Helper.contains(selectionRows, row)) {
+ tagTree.setSelectionRow(row);
+ }
+
+ TreePath[] paths = tagTree.getSelectionPaths();
+ if (paths == null || paths.length == 0) {
+ return;
+ }
+
+ List li = new ArrayList<>();
+ for (TreePath treePath : paths) {
+ TreeItem item = (TreeItem) treePath.getLastPathComponent();
+ li.add(item);
+ }
+
+ update(li);
+ show(e.getComponent(), e.getX(), e.getY());
+ }
+ }
+ });
+ }
+
+ public void update(final List items) {
+
+ if (items.isEmpty()) {
+ return;
+ }
+
+ final List swfs = mainPanel.getSwfs();
+
+ boolean allSelectedIsTagOrFrame = true;
+ for (TreeItem item : items) {
+ if (!(item instanceof Tag) && !(item instanceof Frame)) {
+ if (item instanceof TagScript) {
+ Tag tag = ((TagScript) item).getTag();
+ if (tag instanceof DoActionTag || tag instanceof DoInitActionTag) {
+ continue;
+ }
+ }
+
+ allSelectedIsTagOrFrame = false;
+ break;
+ }
+ }
+
+ boolean allSelectedIsTag = true;
+ for (TreeItem item : items) {
+ if (!(item instanceof Tag)) {
+ if (item instanceof TagScript) {
+ Tag tag = ((TagScript) item).getTag();
+ if (tag instanceof DoActionTag || tag instanceof DoInitActionTag) {
+ continue;
+ }
+ }
+
+ allSelectedIsTag = false;
+ break;
+ }
+ }
+
+ boolean allSelectedIsBinaryData = true;
+ for (TreeItem item : items) {
+ if (!(item instanceof DefineBinaryDataTag)) {
+ allSelectedIsBinaryData = false;
+ break;
+ }
+ }
+
+ boolean allSelectedIsSwf = true;
+ for (TreeItem item : items) {
+ if (!(item instanceof SWF) && !(item instanceof SWFList)) {
+ allSelectedIsSwf = false;
+ break;
+ } else if (item instanceof SWF) {
+ SWF swf = (SWF) item;
+ // Do not allow to close SWF in bundle
+ if (swf.swfList != null && swf.swfList.isBundle()) {
+ allSelectedIsSwf = false;
+ }
+ }
+ }
+
+ boolean allSelectedIsInTheSameSwf = true;
+ SWF singleSwf = null;
+ for (TreeItem item : items) {
+ if (item instanceof SWFList) {
+ allSelectedIsInTheSameSwf = false;
+ break;
+ }
+ if (singleSwf == null) {
+ singleSwf = item.getSwf();
+ } else {
+ if (singleSwf != item.getSwf()) {
+ allSelectedIsInTheSameSwf = false;
+ break;
+ }
+ }
+ }
+
+ expandRecursiveMenuItem.setVisible(false);
+ removeMenuItem.setVisible(allSelectedIsTagOrFrame);
+ removeWithDependenciesMenuItem.setVisible(allSelectedIsTagOrFrame);
+ undoTagMenuItem.setVisible(allSelectedIsTag);
+ exportSelectionMenuItem.setEnabled(tagTree.hasExportableNodes());
+ replaceMenuItem.setVisible(false);
+ replaceWithTagMenuItem.setVisible(false);
+ rawEditMenuItem.setVisible(false);
+ jumpToCharacterMenuItem.setVisible(false);
+ exportJavaSourceMenuItem.setVisible(allSelectedIsSwf);
+ exportSwfXmlMenuItem.setVisible(allSelectedIsSwf);
+ importSwfXmlMenuItem.setVisible(allSelectedIsSwf);
+ closeMenuItem.setVisible(allSelectedIsSwf);
+ addTagMenu.setVisible(false);
+ moveTagMenu.setVisible(false);
+ copyTagMenu.setVisible(false);
+ copyTagWithDependenciesMenu.setVisible(false);
+ openSWFInsideTagMenuItem.setVisible(false);
+
+ boolean singleSelect = items.size() == 1;
+
+ if (singleSelect) {
+ final TreeItem firstItem = items.get(0);
+
+ if (firstItem instanceof CharacterTag) {
+ replaceWithTagMenuItem.setVisible(true);
+ }
+
+ // replace
+ if (firstItem instanceof ImageTag && ((ImageTag) firstItem).importSupported()) {
+ replaceMenuItem.setVisible(true);
+ }
+
+ if (firstItem instanceof ShapeTag) {
+ replaceMenuItem.setVisible(true);
+ }
+
+ if (firstItem instanceof DefineBinaryDataTag) {
+ replaceMenuItem.setVisible(true);
+ }
+
+ if (firstItem instanceof DefineSoundTag) {
+ replaceMenuItem.setVisible(true);
+ }
+
+ List allowedTagTypes = null;
+ if (firstItem instanceof FolderItem) {
+ allowedTagTypes = tagTree.getSwfFolderItemNestedTagIds(((FolderItem) firstItem).getName(), firstItem.getSwf().gfx);
+ } else if (firstItem instanceof Tag) {
+ allowedTagTypes = tagTree.getNestedTagIds((Tag) firstItem);
+ }
+
+ addTagMenu.removeAll();
+ if (allowedTagTypes != null) {
+ for (Integer tagId : allowedTagTypes) {
+ final Class> cl = TagIdClassMap.getClassByTagId(tagId);
+ JMenuItem tagItem = new JMenuItem(cl.getSimpleName());
+ tagItem.addActionListener((ActionEvent ae) -> {
+ addTagActionPerformed(ae, firstItem, cl);
+ });
+ addTagMenu.add(tagItem);
+ }
+ addTagMenu.setVisible(true);
+ }
+
+ if (tagTree.getModel().getChildCount(firstItem) > 0) {
+ expandRecursiveMenuItem.setVisible(true);
+ }
+
+ if (firstItem instanceof CharacterIdTag && !(firstItem instanceof CharacterTag)) {
+ jumpToCharacterMenuItem.setVisible(true);
+ }
+
+ if (firstItem instanceof Tag) {
+ rawEditMenuItem.setVisible(firstItem instanceof Tag);
+ }
+ }
+
+ if (allSelectedIsInTheSameSwf && allSelectedIsTag && swfs.size() > 1) {
+ moveTagMenu.removeAll();
+ copyTagMenu.removeAll();
+ copyTagWithDependenciesMenu.removeAll();
+ for (SWFList targetSwfList : swfs) {
+ for (final SWF targetSwf : targetSwfList) {
+ if (targetSwf != singleSwf) {
+ JMenuItem swfItem = new JMenuItem(targetSwf.getShortFileName());
+ swfItem.addActionListener((ActionEvent ae) -> {
+ moveTagActionPerformed(ae, items, targetSwf);
+ });
+ moveTagMenu.add(swfItem);
+
+ swfItem = new JMenuItem(targetSwf.getShortFileName());
+ swfItem.addActionListener((ActionEvent ae) -> {
+ copyTagActionPerformed(ae, items, targetSwf);
+ });
+ copyTagMenu.add(swfItem);
+
+ swfItem = new JMenuItem(targetSwf.getShortFileName());
+ swfItem.addActionListener((ActionEvent ae) -> {
+ copyTagWithDependenciesActionPerformed(ae, items, targetSwf);
+ });
+ copyTagWithDependenciesMenu.add(swfItem);
+ }
+ }
+ }
+ moveTagMenu.setVisible(true);
+ copyTagMenu.setVisible(true);
+ copyTagWithDependenciesMenu.setVisible(true);
+ }
+
+ if (allSelectedIsBinaryData) {
+ boolean anyInnerSwf = false;
+ for (TreeItem item : items) {
+ DefineBinaryDataTag binary = (DefineBinaryDataTag) item;
+
+ // inner swf is not loaded yet
+ if (binary.innerSwf == null && binary.isSwfData()) {
+ anyInnerSwf = true;
+ }
+ }
+
+ openSWFInsideTagMenuItem.setVisible(anyInnerSwf);
+ }
+ }
+
+ private void addTagActionPerformed(ActionEvent evt, TreeItem firstItem, Class> cl) {
+ try {
+ SWF swf = firstItem.getSwf();
+ Tag t = (Tag) cl.getDeclaredConstructor(SWF.class).newInstance(new Object[]{swf});
+ boolean isDefineSprite = firstItem instanceof DefineSpriteTag;
+ Timelined timelined = isDefineSprite ? (DefineSpriteTag) firstItem : swf;
+ t.setTimelined(timelined);
+ if (isDefineSprite) {
+ ((DefineSpriteTag) firstItem).subTags.add(t);
+ } else {
+ int index;
+ if (firstItem instanceof Tag) {
+ if ((t instanceof CharacterIdTag) && (firstItem instanceof CharacterTag)) {
+ ((CharacterIdTag) t).setCharacterId(((CharacterTag) firstItem).getCharacterId());
+ }
+ index = swf.tags.indexOf(firstItem);
+ } else {
+ index = -1;
+ if (t instanceof CharacterTag) {
+ // add before the last ShowFrame tag
+ for (int i = swf.tags.size() - 1; i >= 0; i--) {
+ if (swf.tags.get(i) instanceof ShowFrameTag) {
+ index = i;
+ break;
+ }
+ }
+ }
+ }
+
+ if (index > -1) {
+ swf.tags.add(index, t);
+ } else {
+ swf.tags.add(t);
+ }
+ }
+ timelined.resetTimeline();
+ swf.updateCharacters();
+ mainPanel.refreshTree(swf);
+ } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException ex) {
+ logger.log(Level.SEVERE, null, ex);
+ }
+ }
+
+ private int chechUniqueCharacterId(Tag tag) {
+ if (tag instanceof CharacterTag) {
+ CharacterTag characterTag = (CharacterTag) tag;
+ int characterId = characterTag.getCharacterId();
+ SWF swf = tag.getSwf();
+ if (swf.getCharacter(characterId) != null) {
+ int newCharacterId = swf.getNextCharacterId();
+ characterTag.setCharacterId(newCharacterId);
+ logger.log(Level.WARNING, "Target SWF already contained chatacter tag with id = {0} => id changed to {1}", new Object[]{characterId, newCharacterId});
+ return newCharacterId;
+ }
+
+ return characterId;
+ }
+
+ return -1;
+ }
+
+ private void moveTagActionPerformed(ActionEvent evt, List items, SWF targetSwf) {
+ SWF sourceSwf = items.get(0).getSwf();
+ for (TreeItem item : items) {
+ Tag tag = (Tag) item;
+ sourceSwf.tags.remove(tag);
+ tag.setSwf(targetSwf, true);
+ targetSwf.tags.add(tag);
+ chechUniqueCharacterId(tag);
+ targetSwf.updateCharacters();
+ tag.setModified(true);
+ }
+
+ sourceSwf.assignExportNamesToSymbols();
+ targetSwf.assignExportNamesToSymbols();
+ sourceSwf.assignClassesToSymbols();
+ targetSwf.assignClassesToSymbols();
+ sourceSwf.clearImageCache();
+ targetSwf.clearImageCache();
+ sourceSwf.updateCharacters();
+ targetSwf.updateCharacters();
+ sourceSwf.resetTimelines(sourceSwf);
+ targetSwf.resetTimelines(targetSwf);
+ mainPanel.refreshTree(new SWF[]{sourceSwf, targetSwf});
+ }
+
+ private void copyTagActionPerformed(ActionEvent evt, List items, SWF targetSwf) {
+ try {
+ for (TreeItem item : items) {
+ Tag tag = (Tag) item;
+ Tag copyTag = tag.cloneTag();
+ copyTag.setSwf(targetSwf, true);
+ targetSwf.tags.add(copyTag);
+ chechUniqueCharacterId(copyTag);
+ targetSwf.updateCharacters();
+ copyTag.setModified(true);
+ }
+
+ targetSwf.assignExportNamesToSymbols();
+ targetSwf.assignClassesToSymbols();
+ targetSwf.clearImageCache();
+ targetSwf.updateCharacters();
+ mainPanel.refreshTree(targetSwf);
+ } catch (IOException | InterruptedException ex) {
+ logger.log(Level.SEVERE, null, ex);
+ }
+ }
+
+ private void copyTagWithDependenciesActionPerformed(ActionEvent evt, List items, SWF targetSwf) {
+ try {
+ SWF sourceSwf = items.get(0).getSwf();
+ for (TreeItem item : items) {
+ Set copiedTags = new HashSet<>();
+ Set newTags = new HashSet<>();
+ LinkedHashSet needed = new LinkedHashSet<>();
+ Map changedCharacterIds = new HashMap<>();
+
+ Tag tag = (Tag) item;
+ tag.getNeededCharactersDeep(needed);
+ Tag copyTag;
+
+ List neededList = new ArrayList<>();
+ for (Integer characterId : needed) {
+ neededList.add(characterId);
+ }
+
+ // first add dependencies in reverse order
+ for (int i = neededList.size() - 1; i >= 0; i--) {
+ int characterId = neededList.get(i);
+ Tag neededTag = (Tag) sourceSwf.getCharacter(characterId);
+ if (!copiedTags.contains(neededTag)) {
+ copyTag = neededTag.cloneTag();
+ copyTag.setSwf(targetSwf, true);
+ targetSwf.tags.add(copyTag);
+ if (neededTag instanceof CharacterTag) {
+ CharacterTag characterTag = (CharacterTag) copyTag;
+ int oldCharacterId = characterTag.getCharacterId();
+ int newCharacterId = chechUniqueCharacterId(copyTag);
+ changedCharacterIds.put(oldCharacterId, newCharacterId);
+ }
+
+ targetSwf.updateCharacters();
+ targetSwf.getCharacters(); // force rebuild character id cache
+ copyTag.setModified(true);
+ copiedTags.add(neededTag);
+ newTags.add(copyTag);
+ }
+ }
+
+ copyTag = tag.cloneTag();
+ copyTag.setSwf(targetSwf, true);
+ targetSwf.tags.add(copyTag);
+ if (tag instanceof CharacterTag) {
+ CharacterTag characterTag = (CharacterTag) copyTag;
+ int oldCharacterId = characterTag.getCharacterId();
+ int newCharacterId = chechUniqueCharacterId(copyTag);
+ changedCharacterIds.put(oldCharacterId, newCharacterId);
+ }
+
+ targetSwf.updateCharacters();
+ targetSwf.getCharacters(); // force rebuild character id cache
+ copyTag.setModified(true);
+ copiedTags.add(tag);
+ newTags.add(copyTag);
+
+ for (int oldCharacterId : changedCharacterIds.keySet()) {
+ int newCharacterId = changedCharacterIds.get(oldCharacterId);
+ for (Tag newTag : newTags) {
+ // todo: avoid double replaces
+ newTag.replaceCharacter(oldCharacterId, newCharacterId);
+ }
+ }
+ }
+
+ targetSwf.assignExportNamesToSymbols();
+ targetSwf.assignClassesToSymbols();
+ targetSwf.clearImageCache();
+ targetSwf.updateCharacters();
+ mainPanel.refreshTree(targetSwf);
+ } catch (IOException | InterruptedException ex) {
+ logger.log(Level.SEVERE, null, ex);
+ }
+ }
+
+ private void openSwfInsideActionPerformed(ActionEvent evt) {
+ List sel = tagTree.getSelected(tagTree);
+ List binaryDatas = new ArrayList<>();
+ for (TreeItem item : sel) {
+ DefineBinaryDataTag binaryData = (DefineBinaryDataTag) item;
+ if (binaryData.isSwfData()) {
+ binaryDatas.add((DefineBinaryDataTag) item);
+ }
+ }
+
+ mainPanel.loadFromBinaryTag(binaryDatas);
+ }
+
+ private void replaceWithTagActionPerformed(ActionEvent evt) {
+ TreeItem itemr = tagTree.getCurrentTreeItem();
+ if (itemr == null) {
+ return;
+ }
+
+ SWF swf = itemr.getSwf();
+ CharacterTag characterTag = (CharacterTag) itemr;
+ int characterId = characterTag.getCharacterId();
+ ReplaceCharacterDialog replaceCharacterDialog = new ReplaceCharacterDialog();
+ if (replaceCharacterDialog.showDialog(swf, characterId) == AppDialog.OK_OPTION) {
+ int newCharacterId = replaceCharacterDialog.getCharacterId();
+ CharacterTag newCharacter = swf.getCharacter(newCharacterId);
+ newCharacter.setCharacterId(characterId);
+ characterTag.setCharacterId(newCharacterId);
+ newCharacter.setModified(true);
+ characterTag.setModified(true);
+
+ swf.assignExportNamesToSymbols();
+ swf.assignClassesToSymbols();
+ swf.clearImageCache();
+ swf.updateCharacters();
+ mainPanel.refreshTree(swf);
+ }
+ }
+
+ private void rawEditActionPerformed(ActionEvent evt) {
+ TreeItem itemr = tagTree.getCurrentTreeItem();
+ if (itemr == null) {
+ return;
+ }
+
+ mainPanel.showGenericTag((Tag) itemr);
+ }
+
+ private void jumpToCharacterActionPerformed(ActionEvent evt) {
+ TreeItem itemj = tagTree.getCurrentTreeItem();
+ if (itemj == null || !(itemj instanceof CharacterIdTag)) {
+ return;
+ }
+
+ CharacterIdTag characterIdTag = (CharacterIdTag) itemj;
+ mainPanel.setTagTreeSelectedNode(itemj.getSwf().getCharacter(characterIdTag.getCharacterId()));
+ }
+
+ private void expandRecursiveActionPerformed(ActionEvent evt) {
+ TreePath path = tagTree.getSelectionPath();
+ if (path == null) {
+ return;
+ }
+ View.expandTreeNodes(tagTree, path, true);
+ }
+
+ private void removeItemActionPerformed(ActionEvent evt, boolean removeDependencies) {
+ List sel = tagTree.getSelected(tagTree);
+
+ List tagsToRemove = new ArrayList<>();
+ for (TreeItem item : sel) {
+ if (item instanceof Tag) {
+ tagsToRemove.add((Tag) item);
+ } else if (item instanceof TagScript) {
+ tagsToRemove.add(((TagScript) item).getTag());
+ } else if (item instanceof Frame) {
+ Frame frameNode = (Frame) item;
+ Frame frame = frameNode.timeline.getFrame(frameNode.frame);
+ if (frame.showFrameTag != null) {
+ tagsToRemove.add(frame.showFrameTag);
+ } else {
+ // this should be the last frame, so remove the inner tags
+ tagsToRemove.addAll(frame.innerTags);
+ }
+ }
+ }
+
+ if (tagsToRemove.size() > 0) {
+ String confirmationMessage;
+ if (tagsToRemove.size() == 1) {
+ Tag tag = tagsToRemove.get(0);
+ confirmationMessage = mainPanel.translate("message.confirm.remove").replace("%item%", tag.toString());
+ } else {
+ confirmationMessage = mainPanel.translate("message.confirm.removemultiple").replace("%count%", Integer.toString(tagsToRemove.size()));
+ }
+
+ if (View.showConfirmDialog(this, confirmationMessage, mainPanel.translate("message.confirm"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) {
+ Map> tagsToRemoveBySwf = new HashMap<>();
+ for (Tag tag : tagsToRemove) {
+ SWF swf = tag.getSwf();
+ if (!tagsToRemoveBySwf.containsKey(swf)) {
+ tagsToRemoveBySwf.put(swf, new ArrayList<>());
+ }
+
+ tagsToRemoveBySwf.get(swf).add(tag);
+ }
+
+ for (SWF swf : tagsToRemoveBySwf.keySet()) {
+ swf.removeTags(tagsToRemoveBySwf.get(swf), removeDependencies);
+ }
+
+ mainPanel.refreshTree();
+ }
+ }
+ }
+
+ private void undoTagActionPerformed(ActionEvent evt) {
+ List sel = tagTree.getSelected(tagTree);
+
+ for (TreeItem item : sel) {
+ if (item instanceof Tag) {
+ try {
+ Tag tag = (Tag) item;
+ tag.undo();
+ tag.getSwf().clearAllCache();
+ tagTree.getModel().updateNode(item);
+ } catch (InterruptedException | IOException ex) {
+ logger.log(Level.SEVERE, null, ex);
+ }
+ }
+ }
+
+ mainPanel.repaintTree();
+ }
+
+ private void closeSwfActionPerformed(ActionEvent evt) {
+ List sel = tagTree.getSelected(tagTree);
+ for (TreeItem item : sel) {
+ if (item instanceof SWF) {
+ SWF swf = (SWF) item;
+ if (swf.binaryData != null) {
+ // embedded swf
+ swf.binaryData.innerSwf = null;
+ swf.clearTagSwfs();
+ mainPanel.refreshTree();
+ } else {
+ Main.closeFile(swf.swfList);
+ }
+ } else if (item instanceof SWFList) {
+ Main.closeFile((SWFList) item);
+ }
+ }
+ }
+}