diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/dumpview/DumpInfoSpecial.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/dumpview/DumpInfoSpecial.java index 53c7dc876..c81568811 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/dumpview/DumpInfoSpecial.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/dumpview/DumpInfoSpecial.java @@ -1,39 +1,39 @@ -/* - * Copyright (C) 2010-2016 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.dumpview; - -/** - * - * @author JPEXS - */ -public class DumpInfoSpecial extends DumpInfo { - - public DumpInfoSpecialType specialType; - - public Object specialValue; - - public DumpInfoSpecial(String name, String type, Object value, long startByte, int startBit, long lengthBytes, int lengthBits, DumpInfoSpecialType specialType) { - super(name, type, value, startByte, startBit, lengthBytes, lengthBits); - this.specialType = specialType; - } - - public DumpInfoSpecial(String name, String type, Object value, long startByte, int startBit, long lengthBytes, int lengthBits, DumpInfoSpecialType specialType, Object specialValue) { - super(name, type, value, startByte, startBit, lengthBytes, lengthBits); - this.specialType = specialType; - this.specialValue = specialValue; - } -} +/* + * Copyright (C) 2010-2016 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.dumpview; + +/** + * + * @author JPEXS + */ +public class DumpInfoSpecial extends DumpInfo { + + public DumpInfoSpecialType specialType; + + public Object specialValue; + + public DumpInfoSpecial(String name, String type, Object value, long startByte, int startBit, long lengthBytes, int lengthBits, DumpInfoSpecialType specialType) { + super(name, type, value, startByte, startBit, lengthBytes, lengthBits); + this.specialType = specialType; + } + + public DumpInfoSpecial(String name, String type, Object value, long startByte, int startBit, long lengthBytes, int lengthBits, DumpInfoSpecialType specialType, Object specialValue) { + super(name, type, value, startByte, startBit, lengthBytes, lengthBits); + this.specialType = specialType; + this.specialValue = specialValue; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/DataType.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/DataType.java index b5f1fc8cc..f0b155ff8 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/DataType.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/DataType.java @@ -1,9 +1,9 @@ -package com.jpexs.decompiler.flash.iggy; - -/** - * @author JPEXS - */ -public enum DataType { - ubits, uint8_t, uint16_t, uint32_t, uint64_t, float_t, unknown, int64_t, - wchar_t //or maybe just "string"? It has two bytes per character and is null terminated -} +package com.jpexs.decompiler.flash.iggy; + +/** + * @author JPEXS + */ +public enum DataType { + ubits, uint8_t, uint16_t, uint32_t, uint64_t, float_t, unknown, int64_t, + wchar_t //or maybe just "string"? It has two bytes per character and is null terminated +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyCharAdvances.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyCharAdvances.java index b7a5e7fce..f03bd0858 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyCharAdvances.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyCharAdvances.java @@ -1,47 +1,47 @@ -package com.jpexs.decompiler.flash.iggy; - -import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface; -import com.jpexs.decompiler.flash.iggy.streams.StructureInterface; -import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -/** - * - * @author JPEXS - */ -public class IggyCharAdvances implements StructureInterface { - - List advances; - private long charCount; - - public List getScales() { - return advances; - } - - public IggyCharAdvances(List advances) { - this.advances = advances; - this.charCount = advances.size(); - } - - public IggyCharAdvances(ReadDataStreamInterface stream, long charCount) throws IOException { - this.charCount = charCount; - readFromDataStream(stream); - } - - @Override - public void readFromDataStream(ReadDataStreamInterface stream) throws IOException { - advances = new ArrayList<>(); - for (int i = 0; i < charCount; i++) { - advances.add(stream.readFloat()); - } - } - - @Override - public void writeToDataStream(WriteDataStreamInterface stream) throws IOException { - for (int i = 0; i < advances.size(); i++) { - stream.writeFloat(advances.get(i)); - } - } -} +package com.jpexs.decompiler.flash.iggy; + +import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface; +import com.jpexs.decompiler.flash.iggy.streams.StructureInterface; +import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author JPEXS + */ +public class IggyCharAdvances implements StructureInterface { + + List advances; + private long charCount; + + public List getScales() { + return advances; + } + + public IggyCharAdvances(List advances) { + this.advances = advances; + this.charCount = advances.size(); + } + + public IggyCharAdvances(ReadDataStreamInterface stream, long charCount) throws IOException { + this.charCount = charCount; + readFromDataStream(stream); + } + + @Override + public void readFromDataStream(ReadDataStreamInterface stream) throws IOException { + advances = new ArrayList<>(); + for (int i = 0; i < charCount; i++) { + advances.add(stream.readFloat()); + } + } + + @Override + public void writeToDataStream(WriteDataStreamInterface stream) throws IOException { + for (int i = 0; i < advances.size(); i++) { + stream.writeFloat(advances.get(i)); + } + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyCharIndices.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyCharIndices.java index cf3d28e95..6815def24 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyCharIndices.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyCharIndices.java @@ -1,56 +1,56 @@ -package com.jpexs.decompiler.flash.iggy; - -import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType; -import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface; -import com.jpexs.decompiler.flash.iggy.streams.StructureInterface; -import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -/** - * - * @author JPEXS - */ -public class IggyCharIndices implements StructureInterface { - - @IggyFieldType(value = DataType.wchar_t) - List chars; - @IggyFieldType(DataType.uint32_t) - long padd; - - public List getChars() { - return chars; - } - - private long charCount; - - public IggyCharIndices(List chars) { - this.chars = chars; - this.charCount = chars.size(); - padd = 0; - } - - public IggyCharIndices(ReadDataStreamInterface stream, long charCount) throws IOException { - this.charCount = charCount; - readFromDataStream(stream); - } - - @Override - public void readFromDataStream(ReadDataStreamInterface stream) throws IOException { - chars = new ArrayList<>(); - for (int i = 0; i < charCount; i++) { - chars.add((char) stream.readUI16()); - } - padd = stream.readUI32(); - } - - @Override - public void writeToDataStream(WriteDataStreamInterface stream) throws IOException { - for (int i = 0; i < chars.size(); i++) { - stream.writeUI16(chars.get(i)); - } - stream.writeUI32(padd); - } - -} +package com.jpexs.decompiler.flash.iggy; + +import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType; +import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface; +import com.jpexs.decompiler.flash.iggy.streams.StructureInterface; +import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author JPEXS + */ +public class IggyCharIndices implements StructureInterface { + + @IggyFieldType(value = DataType.wchar_t) + List chars; + @IggyFieldType(DataType.uint32_t) + long padd; + + public List getChars() { + return chars; + } + + private long charCount; + + public IggyCharIndices(List chars) { + this.chars = chars; + this.charCount = chars.size(); + padd = 0; + } + + public IggyCharIndices(ReadDataStreamInterface stream, long charCount) throws IOException { + this.charCount = charCount; + readFromDataStream(stream); + } + + @Override + public void readFromDataStream(ReadDataStreamInterface stream) throws IOException { + chars = new ArrayList<>(); + for (int i = 0; i < charCount; i++) { + chars.add((char) stream.readUI16()); + } + padd = stream.readUI32(); + } + + @Override + public void writeToDataStream(WriteDataStreamInterface stream) throws IOException { + for (int i = 0; i < chars.size(); i++) { + stream.writeUI16(chars.get(i)); + } + stream.writeUI32(padd); + } + +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyCharKerning.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyCharKerning.java index 6b60bdd20..155dbb535 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyCharKerning.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyCharKerning.java @@ -1,75 +1,75 @@ -package com.jpexs.decompiler.flash.iggy; - -import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface; -import com.jpexs.decompiler.flash.iggy.streams.StructureInterface; -import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -/** - * - * @author JPEXS - */ -public class IggyCharKerning implements StructureInterface { - - public static final int STRUCT_SIZE = 6; - - private long kernCount; - List charsA; - List charsB; - List kerningOffsets; - - public long getKernCount() { - return kernCount; - } - - public List getCharsA() { - return charsA; - } - - public List getCharsB() { - return charsB; - } - - public List getKerningOffsets() { - return kerningOffsets; - } - - public IggyCharKerning(List charsA, List charsB, List kerningOffsets) { - if ((charsA.size() != charsB.size()) || (charsB.size() != kerningOffsets.size())) { - throw new RuntimeException("sizes of charsA, charsB and offsets must match"); - } - this.kernCount = charsA.size(); - this.charsA = charsA; - this.charsB = charsB; - this.kerningOffsets = kerningOffsets; - } - - public IggyCharKerning(ReadDataStreamInterface stream, long kernCount) throws IOException { - this.kernCount = kernCount; - readFromDataStream(stream); - } - - @Override - public void readFromDataStream(ReadDataStreamInterface stream) throws IOException { - charsA = new ArrayList<>(); - charsB = new ArrayList<>(); - kerningOffsets = new ArrayList<>(); - for (int i = 0; i < kernCount; i++) { - charsA.add((char) stream.readUI16()); - charsB.add((char) stream.readUI16()); - kerningOffsets.add((short) stream.readUI16()); - } - } - - @Override - public void writeToDataStream(WriteDataStreamInterface stream) throws IOException { - for (int i = 0; i < kernCount; i++) { - stream.writeUI16(charsA.get(i)); - stream.writeUI16(charsB.get(i)); - stream.writeUI16(kerningOffsets.get(i)); - } - } - -} +package com.jpexs.decompiler.flash.iggy; + +import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface; +import com.jpexs.decompiler.flash.iggy.streams.StructureInterface; +import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author JPEXS + */ +public class IggyCharKerning implements StructureInterface { + + public static final int STRUCT_SIZE = 6; + + private long kernCount; + List charsA; + List charsB; + List kerningOffsets; + + public long getKernCount() { + return kernCount; + } + + public List getCharsA() { + return charsA; + } + + public List getCharsB() { + return charsB; + } + + public List getKerningOffsets() { + return kerningOffsets; + } + + public IggyCharKerning(List charsA, List charsB, List kerningOffsets) { + if ((charsA.size() != charsB.size()) || (charsB.size() != kerningOffsets.size())) { + throw new RuntimeException("sizes of charsA, charsB and offsets must match"); + } + this.kernCount = charsA.size(); + this.charsA = charsA; + this.charsB = charsB; + this.kerningOffsets = kerningOffsets; + } + + public IggyCharKerning(ReadDataStreamInterface stream, long kernCount) throws IOException { + this.kernCount = kernCount; + readFromDataStream(stream); + } + + @Override + public void readFromDataStream(ReadDataStreamInterface stream) throws IOException { + charsA = new ArrayList<>(); + charsB = new ArrayList<>(); + kerningOffsets = new ArrayList<>(); + for (int i = 0; i < kernCount; i++) { + charsA.add((char) stream.readUI16()); + charsB.add((char) stream.readUI16()); + kerningOffsets.add((short) stream.readUI16()); + } + } + + @Override + public void writeToDataStream(WriteDataStreamInterface stream) throws IOException { + for (int i = 0; i < kernCount; i++) { + stream.writeUI16(charsA.get(i)); + stream.writeUI16(charsB.get(i)); + stream.writeUI16(kerningOffsets.get(i)); + } + } + +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyCharOffset.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyCharOffset.java index b3632d94e..1ec941fa1 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyCharOffset.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyCharOffset.java @@ -1,108 +1,108 @@ -package com.jpexs.decompiler.flash.iggy; - -import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType; -import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface; -import com.jpexs.decompiler.flash.iggy.streams.StructureInterface; -import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface; -import java.io.IOException; -import java.util.logging.Logger; - -/** - * - * @author JPEXS - */ -public class IggyCharOffset implements StructureInterface { - - public static final int STRUCT_SIZE = 32; - - private static Logger LOGGER = Logger.getLogger(IggyCharOffset.class.getName()); - - @IggyFieldType(DataType.uint64_t) - long zero; - @IggyFieldType(DataType.uint16_t) - int ischar1; - @IggyFieldType(DataType.uint16_t) - int ischar2; - @IggyFieldType(DataType.uint32_t) - long zero2; - @IggyFieldType(DataType.uint16_t) - int xscale; - @IggyFieldType(DataType.uint16_t) - int yscale; - @IggyFieldType(DataType.uint32_t) - long zero3; - @IggyFieldType(DataType.uint64_t) - long offset; - - public IggyCharOffset(ReadDataStreamInterface stream) throws IOException { - readFromDataStream(stream); - } - - public IggyCharOffset(int ischar1, int ischar2, int xscale, int yscale) { - this.zero = 0; - this.ischar1 = ischar1; - this.ischar2 = ischar2; - this.zero2 = 0; - this.xscale = xscale; - this.yscale = yscale; - this.zero3 = 0; - this.offset = 0; - } - - @Override - public void readFromDataStream(ReadDataStreamInterface stream) throws IOException { - zero = stream.readUI64(); - ischar1 = stream.readUI16(); - ischar2 = stream.readUI16(); - zero2 = stream.readUI32(); - xscale = stream.readUI16(); - yscale = stream.readUI16(); - zero3 = stream.readUI32(); - offset = stream.readUI64(); - } - - @Override - public void writeToDataStream(WriteDataStreamInterface stream) throws IOException { - stream.writeUI64(zero); - stream.writeUI16(ischar1); - stream.writeUI16(ischar2); - stream.writeUI32(zero2); - stream.writeUI16(xscale); - stream.writeUI16(yscale); - stream.writeUI32(zero3); - stream.writeUI64(offset); - } - - public boolean hasGlyph() { - return offset > 0; - } - - public long getZero() { - return zero; - } - - public boolean isChar1() { - return ischar1 > 0; - } - - public boolean isChar2() { - return ischar2 > 0; - } - - public long getZero2() { - return zero2; - } - - public int getXscale() { - return xscale; - } - - public int getYscale() { - return yscale; - } - - public long getZero3() { - return zero3; - } - -} +package com.jpexs.decompiler.flash.iggy; + +import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType; +import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface; +import com.jpexs.decompiler.flash.iggy.streams.StructureInterface; +import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface; +import java.io.IOException; +import java.util.logging.Logger; + +/** + * + * @author JPEXS + */ +public class IggyCharOffset implements StructureInterface { + + public static final int STRUCT_SIZE = 32; + + private static Logger LOGGER = Logger.getLogger(IggyCharOffset.class.getName()); + + @IggyFieldType(DataType.uint64_t) + long zero; + @IggyFieldType(DataType.uint16_t) + int ischar1; + @IggyFieldType(DataType.uint16_t) + int ischar2; + @IggyFieldType(DataType.uint32_t) + long zero2; + @IggyFieldType(DataType.uint16_t) + int xscale; + @IggyFieldType(DataType.uint16_t) + int yscale; + @IggyFieldType(DataType.uint32_t) + long zero3; + @IggyFieldType(DataType.uint64_t) + long offset; + + public IggyCharOffset(ReadDataStreamInterface stream) throws IOException { + readFromDataStream(stream); + } + + public IggyCharOffset(int ischar1, int ischar2, int xscale, int yscale) { + this.zero = 0; + this.ischar1 = ischar1; + this.ischar2 = ischar2; + this.zero2 = 0; + this.xscale = xscale; + this.yscale = yscale; + this.zero3 = 0; + this.offset = 0; + } + + @Override + public void readFromDataStream(ReadDataStreamInterface stream) throws IOException { + zero = stream.readUI64(); + ischar1 = stream.readUI16(); + ischar2 = stream.readUI16(); + zero2 = stream.readUI32(); + xscale = stream.readUI16(); + yscale = stream.readUI16(); + zero3 = stream.readUI32(); + offset = stream.readUI64(); + } + + @Override + public void writeToDataStream(WriteDataStreamInterface stream) throws IOException { + stream.writeUI64(zero); + stream.writeUI16(ischar1); + stream.writeUI16(ischar2); + stream.writeUI32(zero2); + stream.writeUI16(xscale); + stream.writeUI16(yscale); + stream.writeUI32(zero3); + stream.writeUI64(offset); + } + + public boolean hasGlyph() { + return offset > 0; + } + + public long getZero() { + return zero; + } + + public boolean isChar1() { + return ischar1 > 0; + } + + public boolean isChar2() { + return ischar2 > 0; + } + + public long getZero2() { + return zero2; + } + + public int getXscale() { + return xscale; + } + + public int getYscale() { + return yscale; + } + + public long getZero3() { + return zero3; + } + +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyDeclStrings.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyDeclStrings.java index c9c21b2c8..ac14b3d2b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyDeclStrings.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyDeclStrings.java @@ -1,68 +1,68 @@ -package com.jpexs.decompiler.flash.iggy; - -import com.jpexs.decompiler.flash.iggy.annotations.IggyArrayFieldType; -import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType; -import com.jpexs.decompiler.flash.iggy.streams.IggyIndexBuilder; -import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface; -import com.jpexs.decompiler.flash.iggy.streams.StructureInterface; -import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface; -import java.io.IOException; - -/** - * - * @author JPEXS - */ -public class IggyDeclStrings implements StructureInterface { - - @IggyFieldType(DataType.uint64_t) - long one; - @IggyFieldType(DataType.uint32_t) - long size; - @IggyArrayFieldType(value = DataType.uint8_t, count = 3) - byte xxx[]; - @IggyArrayFieldType(value = DataType.uint8_t, countField = "size") - byte data[]; - byte padd[]; - @IggyFieldType(DataType.uint64_t) - long one2; - @IggyFieldType(DataType.uint64_t) - long zero; - - public IggyDeclStrings(ReadDataStreamInterface stream) throws IOException { - readFromDataStream(stream); - } - - @Override - public void readFromDataStream(ReadDataStreamInterface s) throws IOException { - one = s.readUI64(); - size = s.readUI32(); - xxx = s.readBytes(3); - data = s.readBytes((int) size); - if ((15 + size) % 8 != 0) { - padd = s.readBytes((int) (((15 + size) / 8 + 1) * 8 - 15 - size)); - } else { - padd = new byte[0]; - } - one = s.readUI64(); - if (one != 1) { - throw new IOException("Wrong iggy font format (declend)!"); - } - zero = s.readUI64(); - } - - @Override - public void writeToDataStream(WriteDataStreamInterface s) throws IOException { - IggyIndexBuilder ib = s.getIndexing(); - s.writeUI64(one); - s.writeUI32(size); - s.writeBytes(xxx); - ib.writeLengthCustom(15, new int[]{0x00, 0x08}, new int[]{2, 5}); - ib.writeLengthUI32(size); - s.writeBytes(data); - ib.writeConstLength(IggyIndexBuilder.CONST_SEQUENCE_SIZE); - s.writeBytes(padd); - s.writeUI64(one); - s.writeUI64(zero); - } - -} +package com.jpexs.decompiler.flash.iggy; + +import com.jpexs.decompiler.flash.iggy.annotations.IggyArrayFieldType; +import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType; +import com.jpexs.decompiler.flash.iggy.streams.IggyIndexBuilder; +import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface; +import com.jpexs.decompiler.flash.iggy.streams.StructureInterface; +import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface; +import java.io.IOException; + +/** + * + * @author JPEXS + */ +public class IggyDeclStrings implements StructureInterface { + + @IggyFieldType(DataType.uint64_t) + long one; + @IggyFieldType(DataType.uint32_t) + long size; + @IggyArrayFieldType(value = DataType.uint8_t, count = 3) + byte xxx[]; + @IggyArrayFieldType(value = DataType.uint8_t, countField = "size") + byte data[]; + byte padd[]; + @IggyFieldType(DataType.uint64_t) + long one2; + @IggyFieldType(DataType.uint64_t) + long zero; + + public IggyDeclStrings(ReadDataStreamInterface stream) throws IOException { + readFromDataStream(stream); + } + + @Override + public void readFromDataStream(ReadDataStreamInterface s) throws IOException { + one = s.readUI64(); + size = s.readUI32(); + xxx = s.readBytes(3); + data = s.readBytes((int) size); + if ((15 + size) % 8 != 0) { + padd = s.readBytes((int) (((15 + size) / 8 + 1) * 8 - 15 - size)); + } else { + padd = new byte[0]; + } + one = s.readUI64(); + if (one != 1) { + throw new IOException("Wrong iggy font format (declend)!"); + } + zero = s.readUI64(); + } + + @Override + public void writeToDataStream(WriteDataStreamInterface s) throws IOException { + IggyIndexBuilder ib = s.getIndexing(); + s.writeUI64(one); + s.writeUI32(size); + s.writeBytes(xxx); + ib.writeLengthCustom(15, new int[]{0x00, 0x08}, new int[]{2, 5}); + ib.writeLengthUI32(size); + s.writeBytes(data); + ib.writeConstLength(IggyIndexBuilder.CONST_SEQUENCE_SIZE); + s.writeBytes(padd); + s.writeUI64(one); + s.writeUI64(zero); + } + +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFile.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFile.java index 4b248ef66..b358da0bd 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFile.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFile.java @@ -1,718 +1,718 @@ -package com.jpexs.decompiler.flash.iggy; - -import com.jpexs.decompiler.flash.iggy.streams.DataStreamInterface; -import com.jpexs.decompiler.flash.iggy.streams.IggyIndexBuilder; -import com.jpexs.decompiler.flash.iggy.streams.RandomAccessFileDataStream; -import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface; -import com.jpexs.decompiler.flash.iggy.streams.SeekMode; -import com.jpexs.decompiler.flash.iggy.streams.StructureInterface; -import com.jpexs.decompiler.flash.iggy.streams.TemporaryDataStream; -import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface; -import java.io.File; -import java.io.FileOutputStream; -import java.io.FilenameFilter; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - * @author JPEXS - * - * Based of works of somebody called eternity. - * - */ -public class IggyFile implements StructureInterface { - - final static Logger LOGGER = Logger.getLogger(IggyFile.class.getName()); - - private File originalFile; - private IggyHeader header; - private List subFileEntries = new ArrayList<>(); - private List subFileEntriesData = new ArrayList<>(); - - private IggySwf iggySwf; - - public static final int FIRST_TAG_POSITION = 3; - - public IggySwf getSwf() { - return iggySwf; - } - - public int getFontCount() { - return iggySwf.fonts.size(); - } - - public IggyFont getFont(int fontId) { - return iggySwf.fonts.get(fontId); - } - - public IggyFile(String filePath) throws IOException { - this(new File(filePath)); - } - - public IggyFile(File file) throws IOException { - this.originalFile = file; - try (ReadDataStreamInterface stream = new RandomAccessFileDataStream(file)) { - readFromDataStream(stream); - } - } - - public File getOriginalFile() { - return originalFile; - } - - public IggyHeader getHeader() { - return header; - } - - public IggySubFileEntry getSubFileEntry(int entryIndex) { - if (entryIndex < 0 || entryIndex >= subFileEntries.size()) { - throw new ArrayIndexOutOfBoundsException("No entry with index " + entryIndex + " exists"); - } - return subFileEntries.get(entryIndex); - } - - public int getNumEntries() { - return subFileEntries.size(); - } - - public byte[] getEntryData(int entryIndex) { - if (entryIndex < 0 || entryIndex >= subFileEntries.size()) { - throw new ArrayIndexOutOfBoundsException("No entry with index " + entryIndex + " exists"); - } - return subFileEntriesData.get(entryIndex); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("[IggyFile:").append("\r\n"); - sb.append(header).append("\r\n"); - sb.append("Entries:").append("\r\n"); - for (IggySubFileEntry entry : subFileEntries) { - sb.append(entry).append("\r\n"); - } - sb.append("]"); - return sb.toString(); - } - - public static void extractIggyFile(File iggyFile, File extractDir) throws IOException { - final String FILENAME_FORMAT = "index%d_type%d.bin"; - IggyFile ir = new IggyFile(iggyFile); - for (int i = 0; i < ir.getNumEntries(); i++) { - IggySubFileEntry entry = ir.getSubFileEntry(i); - try (FileOutputStream fos = new FileOutputStream(new File(extractDir, String.format(FILENAME_FORMAT, i, entry.type)))) { - fos.write(ir.getEntryData(i)); - } - } - } - - private static void processFile(File f) { - if (f.isDirectory()) { - System.out.println("Processing directory " + f + ":"); - File iggyFiles[] = f.listFiles(new FilenameFilter() { - @Override - public boolean accept(File dir, String name) { - return name.endsWith(".iggy"); - } - }); - for (File sf : iggyFiles) { - processFile(sf); - } - return; - } - System.out.print("Processing file " + f + "..."); - try { - File dir = f.getParentFile(); - File extractDir = new File(dir, "extracted_" + (f.getName()).replace(".iggy", "")); - extractDir.mkdir(); - extractIggyFile(f, extractDir); - System.out.println("OK"); - } catch (Exception ex) { - System.err.println("FAIL"); - System.exit(1); - } - } - - public static void main(String[] args) throws IOException { - /* - String indexFileName = "d:\\Dropbox\\jpexs-laptop\\iggi\\extraxtdir_orig\\index4_type0.bin"; - IggyIndexParser.parseIndex(true, new TemporaryDataStream(Helper.readFile(indexFileName)), new ArrayList<>(), new ArrayList<>()); - - System.exit(0);*/ - String inFileName = "d:\\Dropbox\\jpexs-laptop\\iggi\\lib_loc_english_font.iggy"; - String outFileName = "d:\\Dropbox\\jpexs-laptop\\iggi\\lib_loc_english_font2.iggy"; - - File extractDirOrig = new File("d:\\Dropbox\\jpexs-laptop\\iggi\\extraxtdir_orig"); - File extractDirNew = new File("d:\\Dropbox\\jpexs-laptop\\iggi\\extraxtdir_new"); - - if (!extractDirOrig.exists()) { - extractDirOrig.mkdir(); - } - if (!extractDirNew.exists()) { - extractDirNew.mkdir(); - } - - File inFile = new File(inFileName); - File outFile = new File(outFileName); - IggyFile iggyFile = new IggyFile(inFile); - extractIggyFile(inFile, extractDirOrig); - iggyFile.updateFlashEntry(); - outFile.delete(); - try (RandomAccessFileDataStream outputStream = new RandomAccessFileDataStream(outFile)) { - iggyFile.writeToDataStream(outputStream); - } - extractIggyFile(outFile, extractDirNew); - System.exit(0); - } - - private static void copyStream(InputStream is, OutputStream os) { - try { - final int bufSize = 4096; - byte[] buf = new byte[bufSize]; - int cnt; - while ((cnt = is.read(buf)) > 0) { - os.write(buf, 0, cnt); - } - } catch (IOException ex) { - // ignore - } - } - - private static boolean updateIndex(long item_offset /*uint32_t*/, boolean is_64, byte index_bytes[], long item_size_change /*int32_t*/) throws IOException { - TemporaryDataStream stream = new TemporaryDataStream(index_bytes); - - /* - index_table: - n = UI8 - for i=0..n-1 - table[i] = UI8 - cnt = UI8 - cnt * UI16 - - */ - int index_table_size = stream.readUI8(); - int index_table[] = new int[index_table_size]; - - for (int i = 0; i < index_table_size; i++) { - index_table[i] = stream.readUI8(); - int num = stream.readUI8(); - stream.seek(num * 2, SeekMode.CUR); - //num * UI16 - } - - int state = 0; - long offset = 0;//uint32_t - int code; //uint8_t - - while ((code = stream.readUI8()) >= 0) { - if (state == 1) { - if (code != 0xFD) { - LOGGER.log(Level.WARNING, "We were expecting code 0xFD in state 1."); - return false; - } - } else if (state == 2) { - if (code != 0xFF) { - LOGGER.log(Level.WARNING, "We were expecting code 0xFF in state 2."); - return false; - } - } - - if (code < 0x80) // 0-0x7F - { - // code is directly an index to the index_table - if (code >= index_table_size) { - LOGGER.log(Level.WARNING, String.format("< 0x80: index is greater than index_table_size. %x > %x", code, index_table_size)); - return false; - } - - offset += index_table[code]; - } else if (code < 0xC0) // 0x80-BF - { - int index; //uint8_t - - if ((index = stream.readUI8()) < 0) { - LOGGER.log(Level.WARNING, "< 0xC0: Cannot read index."); - return false; - } - - if (index >= index_table_size) { - LOGGER.log(Level.WARNING, String.format("< 0xC0: index is greater than index_table_size. %x > %x", index, index_table_size)); - return false; - } - - int n = code - 0x7F; - offset += index_table[index] * n; - } else if (code < 0xD0) // 0xC0-0xCF - { - offset += ((code * 2) - 0x17E); - } else if (code < 0xE0) // 0xD0-0xDF - { - // Code here depends on plattform[0], we are assuming it is 1, as we checked in load function - int i = code & 0xF; //uint8_t - int n8; //uint8_t - int n; - - if ((n8 = stream.readUI8()) < 0) { - LOGGER.log(Level.WARNING, "< 0xE0: Cannot read n."); - return false; - } - - n = n8 + 1; - - if (is_64) { - if (i <= 2) { - offset += 8 * n; // Ptr type - } else if (i <= 4) { - offset += 2 * n; - } else if (i == 5) { - offset += 4 * n; - } else if (i == 6) { - offset += 8 * n; // 64 bits type - } else { - LOGGER.log(Level.WARNING, String.format("< 0xE0: Invalid value for i (%x %x)", i, code)); - } - } else { - switch (i) { - case 2: - offset += 4 * n; // Ptr type - break; - case 4: - offset += 2 * n; - break; - case 5: - offset += 4 * n; // 32 bits type - break; - case 6: - offset += 8 * n; - break; - default: - LOGGER.log(Level.WARNING, String.format("< 0xE0: invalid value for i (%x %x)", i, code)); - } - } - } else if (code == 0xFC) { - stream.seek(1, SeekMode.CUR); - } else if (code == 0xFD) { - int n, m; //uint8_t - - if ((n = stream.readUI8()) < 0) { - LOGGER.log(Level.WARNING, "0xFD: Cannot read n."); - return false; - } - - if (state == 1) { - if (is_64) { - if (n != 0xF) { - LOGGER.log(Level.WARNING, String.format("We were expecting an offset of 0xF in state 1.")); - return false; - } - } else if (n != 0xB) { - LOGGER.log(Level.WARNING, "We were expecting an offset of 0xB in state 1."); - return false; - } - - state = 2; - } - - if ((m = stream.readUI8()) < 0) { - LOGGER.log(Level.WARNING, "0xFD: Cannot read m."); - return false; - } - - offset += n; - stream.seek(m * 2, SeekMode.CUR); - } else if (code == 0xFE) { - int n8; //uint8_t - int n; - - if ((n8 = stream.readUI8()) < 0) { - LOGGER.log(Level.WARNING, "0xFE: Cannot read n."); - return false; - } - - n = n8 + 1; - offset += n; - } else if (code == 0xFF) { - long n; //uint32_t - - if ((n = stream.readUI32()) < 0) { - LOGGER.log(Level.WARNING, "0xFF: Cannot read n."); - return false; - } - - if (state == 2) { - n += item_size_change; - stream.seek(-4, SeekMode.CUR); - return stream.writeUI32(n); - } - - offset += n; - } else { - LOGGER.log(Level.WARNING, String.format("Unrecognized code: %x", code)); - } - - if (state == 0 && offset == item_offset) { - state = 1; - } - } - return false; - } - - /** - * Gets length of an item. - * - * @param item_offset - * @param is_64 - * @param index_bytes - * @return null when item not exists, item length otherwise - * @throws IOException - */ - private static Long getItemLength(long item_offset /*uint32_t*/, boolean is_64, byte index_bytes[]) throws IOException { - return itemLength(item_offset, is_64, index_bytes, null); - } - - /** - * Sets new length of an item. - * - * @param item_offset - * @param is_64 - * @param index_bytes - * @param newLength - * @return null when item not exists, old item length otherwise - * @throws IOException - */ - private static Long setItemLength(long item_offset /*uint32_t*/, boolean is_64, byte index_bytes[], long newLength) throws IOException { - return itemLength(item_offset, is_64, index_bytes, newLength); - } - - /** - * Sets/Gets length of an item - * - * @param item_offset - * @param is_64 - * @param index_bytes - * @param newValue New value to set. If null then no change. - * @return null when item does not exists, old item length otherwise - * @throws IOException - */ - private static Long itemLength(long item_offset /*uint32_t*/, boolean is_64, byte index_bytes[], Long newValue) throws IOException { - TemporaryDataStream stream = new TemporaryDataStream(index_bytes); - - /* - index_table: - n = UI8 - for i=0..n-1 - table[i] = UI8 - cnt = UI8 - cnt * UI16 - - */ - int index_table_size = stream.readUI8(); - int index_table[] = new int[index_table_size]; - - for (int i = 0; i < index_table_size; i++) { - index_table[i] = stream.readUI8(); - int num = stream.readUI8(); - stream.seek(num * 2, SeekMode.CUR); - //num * UI16 - } - - int state = 0; - long offset = 0;//uint32_t - int code; //uint8_t - - while ((code = stream.readUI8()) >= 0) { - if (state == 1) { - if (code != 0xFD) { - LOGGER.log(Level.WARNING, "We were expecting code 0xFD in state 1."); - return null; - } - } else if (state == 2) { - if (code != 0xFF) { - LOGGER.log(Level.WARNING, "We were expecting code 0xFF in state 2."); - return null; - } - } - - if (code < 0x80) // 0-0x7F - { - // code is directly an index to the index_table - if (code >= index_table_size) { - LOGGER.log(Level.WARNING, String.format("< 0x80: index is greater than index_table_size. %x > %x", code, index_table_size)); - return null; - } - - offset += index_table[code]; - } else if (code < 0xC0) // 0x80-BF - { - int index; //uint8_t - - if ((index = stream.readUI8()) < 0) { - LOGGER.log(Level.WARNING, "< 0xC0: Cannot read index."); - return null; - } - - if (index >= index_table_size) { - LOGGER.log(Level.WARNING, String.format("< 0xC0: index is greater than index_table_size. %x > %x", index, index_table_size)); - return null; - } - - int n = code - 0x7F; - offset += index_table[index] * n; - } else if (code < 0xD0) // 0xC0-0xCF - { - offset += ((code * 2) - 0x17E); - } else if (code < 0xE0) // 0xD0-0xDF - { - // Code here depends on plattform[0], we are assuming it is 1, as we checked in load function - int i = code & 0xF; //uint8_t - int n8; //uint8_t - int n; - - if ((n8 = stream.readUI8()) < 0) { - LOGGER.log(Level.WARNING, "< 0xE0: Cannot read n."); - return null; - } - - n = n8 + 1; - - if (is_64) { - if (i <= 2) { - offset += 8 * n; // Ptr type - } else if (i <= 4) { - offset += 2 * n; - } else if (i == 5) { - offset += 4 * n; - } else if (i == 6) { - offset += 8 * n; // 64 bits type - } else { - LOGGER.log(Level.WARNING, String.format("< 0xE0: Invalid value for i (%x %x)", i, code)); - } - } else { - switch (i) { - case 2: - offset += 4 * n; // Ptr type - break; - case 4: - offset += 2 * n; - break; - case 5: - offset += 4 * n; // 32 bits type - break; - case 6: - offset += 8 * n; - break; - default: - LOGGER.log(Level.WARNING, String.format("< 0xE0: invalid value for i (%x %x)", i, code)); - } - } - } else if (code == 0xFC) { - stream.seek(1, SeekMode.CUR); - } else if (code == 0xFD) { - int n, m; //uint8_t - - if ((n = stream.readUI8()) < 0) { - LOGGER.log(Level.WARNING, "0xFD: Cannot read n."); - return null; - } - - if (state == 1) { - if (is_64) { - if (n != 0xF) { - LOGGER.log(Level.WARNING, String.format("We were expecting an offset of 0xF in state 1.")); - return null; - } - } else if (n != 0xB) { - LOGGER.log(Level.WARNING, "We were expecting an offset of 0xB in state 1."); - return null; - } - - state = 2; - } - - if ((m = stream.readUI8()) < 0) { - LOGGER.log(Level.WARNING, "0xFD: Cannot read m."); - return null; - } - - offset += n; - stream.seek(m * 2, SeekMode.CUR); - } else if (code == 0xFE) { - int n8; //uint8_t - int n; - - if ((n8 = stream.readUI8()) < 0) { - LOGGER.log(Level.WARNING, "0xFE: Cannot read n."); - return null; - } - - n = n8 + 1; - offset += n; - } else if (code == 0xFF) { - long n; //uint32_t - - if ((n = stream.readUI32()) < 0) { - LOGGER.log(Level.WARNING, "0xFF: Cannot read n."); - return null; - } - - if (state == 2) { - if (newValue != null) { - stream.seek(-4, SeekMode.CUR); - stream.writeUI32(newValue); - } - return n; - } - - offset += n; - } else { - LOGGER.log(Level.WARNING, String.format("Unrecognized code: %x", code)); - } - - if (state == 0 && offset == item_offset) { - state = 1; - } - } - return null; - } - - public String getSwfName() { - return iggySwf.getName(); - } - - public long getSwfXMin() { - return iggySwf.getHdr().getXMin(); - } - - public long getSwfYMin() { - return iggySwf.getHdr().getYMin(); - } - - public long getSwfXMax() { - return iggySwf.getHdr().getXMax(); - } - - public long getSwfYMax() { - return iggySwf.getHdr().getYMax(); - } - - public float getSwfFrameRate() { - return iggySwf.getHdr().getFrameRate(); - } - - /** - * Removes entries of type INDEX.There can be more than one INDEX, - * continuous. This removes all ot them. - */ - public void removeIndexEntries() { - long offsetsChange = 0; - final int ENTRY_SIZE = 16; - for (int i = 0; i < subFileEntries.size(); i++) { - IggySubFileEntry entry = subFileEntries.get(i); - entry.offset += offsetsChange; - if (entry.type == IggySubFileEntry.TYPE_INDEX) { - offsetsChange = offsetsChange - entry.size - ENTRY_SIZE; - subFileEntriesData.remove(i); - subFileEntries.remove(i); - i--; - } - } - } - - public boolean updateFlashEntry() throws IOException { - - byte replacementData[]; - byte replacementIndexData[]; - IggyIndexBuilder ib = new IggyIndexBuilder(); - try (DataStreamInterface stream = new TemporaryDataStream()) { - stream.setIndexing(ib); - iggySwf.writeToDataStream(stream); - replacementData = stream.getAllBytes(); - replacementIndexData = ib.getIndexBytes(); - } catch (IOException ex) { - Logger.getLogger(IggyFile.class.getName()).log(Level.SEVERE, "Error during updating SWF", ex); - return false; - } - - long offsetsChange = 0; - for (int i = 0; i < subFileEntries.size(); i++) { - IggySubFileEntry entry = subFileEntries.get(i); - entry.offset += offsetsChange; - if (entry.type == IggySubFileEntry.TYPE_FLASH) { - long oldSize = entry.size; - long newSize = replacementData.length; - entry.size = newSize; - entry.size2 = newSize; - offsetsChange = offsetsChange + (newSize - oldSize); //entries after this one will have modified offsets - subFileEntriesData.set(i, replacementData); - } - } - - removeIndexEntries(); - IggySubFileEntry indexEntry = new IggySubFileEntry(IggySubFileEntry.TYPE_INDEX, replacementIndexData.length, replacementIndexData.length, 0 /*offset will be set automatically*/); - subFileEntries.add(indexEntry); - subFileEntriesData.add(replacementIndexData); - return true; - } - - private void parseEntries() throws IOException { - for (int i = 0; i < subFileEntries.size(); i++) { - IggySubFileEntry entry = subFileEntries.get(i); - if (entry.type == IggySubFileEntry.TYPE_FLASH) { - iggySwf = new IggySwf(new TemporaryDataStream(getEntryData(i))); - break; - } - /*if (entry.type == IggySubFileEntry.TYPE_INDEX) { - IggyIndexParser.parseIndex(true, new TemporaryDataStream(getEntryData(i)), new ArrayList<>(), new ArrayList<>()); - }*/ - } - } - - @Override - public void readFromDataStream(ReadDataStreamInterface stream) throws IOException { - header = new IggyHeader(stream); - for (int i = 0; i < header.getNumSubfiles(); i++) { - subFileEntries.add(new IggySubFileEntry(stream)); - } - for (IggySubFileEntry entry : subFileEntries) { - stream.seek(entry.offset, SeekMode.SET); - byte[] entryData = stream.readBytes((int) entry.size); - subFileEntriesData.add(entryData); - } - parseEntries(); - } - - public void saveChanges() throws IOException { - updateFlashEntry(); - try (RandomAccessFileDataStream raf = new RandomAccessFileDataStream(originalFile)) { - writeToDataStream(raf); - } - } - - @Override - public void writeToDataStream(WriteDataStreamInterface stream) throws IOException { - header.writeToDataStream(stream); - - long startOffset = IggyHeader.STRUCT_SIZE + IggySubFileEntry.STRUCTURE_SIZE * subFileEntries.size(); - long currentOffset = startOffset; - - for (int i = 0; i < subFileEntries.size(); i++) { - IggySubFileEntry entry = subFileEntries.get(i); - entry.offset = currentOffset; - currentOffset += entry.size; - entry.writeToDataStream(stream); - } - - for (int i = 0; i < subFileEntries.size(); i++) { - byte[] entryData = subFileEntriesData.get(i); - stream.writeBytes(entryData); - } - - } - -} +package com.jpexs.decompiler.flash.iggy; + +import com.jpexs.decompiler.flash.iggy.streams.DataStreamInterface; +import com.jpexs.decompiler.flash.iggy.streams.IggyIndexBuilder; +import com.jpexs.decompiler.flash.iggy.streams.RandomAccessFileDataStream; +import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface; +import com.jpexs.decompiler.flash.iggy.streams.SeekMode; +import com.jpexs.decompiler.flash.iggy.streams.StructureInterface; +import com.jpexs.decompiler.flash.iggy.streams.TemporaryDataStream; +import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface; +import java.io.File; +import java.io.FileOutputStream; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author JPEXS + * + * Based of works of somebody called eternity. + * + */ +public class IggyFile implements StructureInterface { + + final static Logger LOGGER = Logger.getLogger(IggyFile.class.getName()); + + private File originalFile; + private IggyHeader header; + private List subFileEntries = new ArrayList<>(); + private List subFileEntriesData = new ArrayList<>(); + + private IggySwf iggySwf; + + public static final int FIRST_TAG_POSITION = 3; + + public IggySwf getSwf() { + return iggySwf; + } + + public int getFontCount() { + return iggySwf.fonts.size(); + } + + public IggyFont getFont(int fontId) { + return iggySwf.fonts.get(fontId); + } + + public IggyFile(String filePath) throws IOException { + this(new File(filePath)); + } + + public IggyFile(File file) throws IOException { + this.originalFile = file; + try (ReadDataStreamInterface stream = new RandomAccessFileDataStream(file)) { + readFromDataStream(stream); + } + } + + public File getOriginalFile() { + return originalFile; + } + + public IggyHeader getHeader() { + return header; + } + + public IggySubFileEntry getSubFileEntry(int entryIndex) { + if (entryIndex < 0 || entryIndex >= subFileEntries.size()) { + throw new ArrayIndexOutOfBoundsException("No entry with index " + entryIndex + " exists"); + } + return subFileEntries.get(entryIndex); + } + + public int getNumEntries() { + return subFileEntries.size(); + } + + public byte[] getEntryData(int entryIndex) { + if (entryIndex < 0 || entryIndex >= subFileEntries.size()) { + throw new ArrayIndexOutOfBoundsException("No entry with index " + entryIndex + " exists"); + } + return subFileEntriesData.get(entryIndex); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("[IggyFile:").append("\r\n"); + sb.append(header).append("\r\n"); + sb.append("Entries:").append("\r\n"); + for (IggySubFileEntry entry : subFileEntries) { + sb.append(entry).append("\r\n"); + } + sb.append("]"); + return sb.toString(); + } + + public static void extractIggyFile(File iggyFile, File extractDir) throws IOException { + final String FILENAME_FORMAT = "index%d_type%d.bin"; + IggyFile ir = new IggyFile(iggyFile); + for (int i = 0; i < ir.getNumEntries(); i++) { + IggySubFileEntry entry = ir.getSubFileEntry(i); + try (FileOutputStream fos = new FileOutputStream(new File(extractDir, String.format(FILENAME_FORMAT, i, entry.type)))) { + fos.write(ir.getEntryData(i)); + } + } + } + + private static void processFile(File f) { + if (f.isDirectory()) { + System.out.println("Processing directory " + f + ":"); + File iggyFiles[] = f.listFiles(new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + return name.endsWith(".iggy"); + } + }); + for (File sf : iggyFiles) { + processFile(sf); + } + return; + } + System.out.print("Processing file " + f + "..."); + try { + File dir = f.getParentFile(); + File extractDir = new File(dir, "extracted_" + (f.getName()).replace(".iggy", "")); + extractDir.mkdir(); + extractIggyFile(f, extractDir); + System.out.println("OK"); + } catch (Exception ex) { + System.err.println("FAIL"); + System.exit(1); + } + } + + public static void main(String[] args) throws IOException { + /* + String indexFileName = "d:\\Dropbox\\jpexs-laptop\\iggi\\extraxtdir_orig\\index4_type0.bin"; + IggyIndexParser.parseIndex(true, new TemporaryDataStream(Helper.readFile(indexFileName)), new ArrayList<>(), new ArrayList<>()); + + System.exit(0);*/ + String inFileName = "d:\\Dropbox\\jpexs-laptop\\iggi\\lib_loc_english_font.iggy"; + String outFileName = "d:\\Dropbox\\jpexs-laptop\\iggi\\lib_loc_english_font2.iggy"; + + File extractDirOrig = new File("d:\\Dropbox\\jpexs-laptop\\iggi\\extraxtdir_orig"); + File extractDirNew = new File("d:\\Dropbox\\jpexs-laptop\\iggi\\extraxtdir_new"); + + if (!extractDirOrig.exists()) { + extractDirOrig.mkdir(); + } + if (!extractDirNew.exists()) { + extractDirNew.mkdir(); + } + + File inFile = new File(inFileName); + File outFile = new File(outFileName); + IggyFile iggyFile = new IggyFile(inFile); + extractIggyFile(inFile, extractDirOrig); + iggyFile.updateFlashEntry(); + outFile.delete(); + try (RandomAccessFileDataStream outputStream = new RandomAccessFileDataStream(outFile)) { + iggyFile.writeToDataStream(outputStream); + } + extractIggyFile(outFile, extractDirNew); + System.exit(0); + } + + private static void copyStream(InputStream is, OutputStream os) { + try { + final int bufSize = 4096; + byte[] buf = new byte[bufSize]; + int cnt; + while ((cnt = is.read(buf)) > 0) { + os.write(buf, 0, cnt); + } + } catch (IOException ex) { + // ignore + } + } + + private static boolean updateIndex(long item_offset /*uint32_t*/, boolean is_64, byte index_bytes[], long item_size_change /*int32_t*/) throws IOException { + TemporaryDataStream stream = new TemporaryDataStream(index_bytes); + + /* + index_table: + n = UI8 + for i=0..n-1 + table[i] = UI8 + cnt = UI8 + cnt * UI16 + + */ + int index_table_size = stream.readUI8(); + int index_table[] = new int[index_table_size]; + + for (int i = 0; i < index_table_size; i++) { + index_table[i] = stream.readUI8(); + int num = stream.readUI8(); + stream.seek(num * 2, SeekMode.CUR); + //num * UI16 + } + + int state = 0; + long offset = 0;//uint32_t + int code; //uint8_t + + while ((code = stream.readUI8()) >= 0) { + if (state == 1) { + if (code != 0xFD) { + LOGGER.log(Level.WARNING, "We were expecting code 0xFD in state 1."); + return false; + } + } else if (state == 2) { + if (code != 0xFF) { + LOGGER.log(Level.WARNING, "We were expecting code 0xFF in state 2."); + return false; + } + } + + if (code < 0x80) // 0-0x7F + { + // code is directly an index to the index_table + if (code >= index_table_size) { + LOGGER.log(Level.WARNING, String.format("< 0x80: index is greater than index_table_size. %x > %x", code, index_table_size)); + return false; + } + + offset += index_table[code]; + } else if (code < 0xC0) // 0x80-BF + { + int index; //uint8_t + + if ((index = stream.readUI8()) < 0) { + LOGGER.log(Level.WARNING, "< 0xC0: Cannot read index."); + return false; + } + + if (index >= index_table_size) { + LOGGER.log(Level.WARNING, String.format("< 0xC0: index is greater than index_table_size. %x > %x", index, index_table_size)); + return false; + } + + int n = code - 0x7F; + offset += index_table[index] * n; + } else if (code < 0xD0) // 0xC0-0xCF + { + offset += ((code * 2) - 0x17E); + } else if (code < 0xE0) // 0xD0-0xDF + { + // Code here depends on plattform[0], we are assuming it is 1, as we checked in load function + int i = code & 0xF; //uint8_t + int n8; //uint8_t + int n; + + if ((n8 = stream.readUI8()) < 0) { + LOGGER.log(Level.WARNING, "< 0xE0: Cannot read n."); + return false; + } + + n = n8 + 1; + + if (is_64) { + if (i <= 2) { + offset += 8 * n; // Ptr type + } else if (i <= 4) { + offset += 2 * n; + } else if (i == 5) { + offset += 4 * n; + } else if (i == 6) { + offset += 8 * n; // 64 bits type + } else { + LOGGER.log(Level.WARNING, String.format("< 0xE0: Invalid value for i (%x %x)", i, code)); + } + } else { + switch (i) { + case 2: + offset += 4 * n; // Ptr type + break; + case 4: + offset += 2 * n; + break; + case 5: + offset += 4 * n; // 32 bits type + break; + case 6: + offset += 8 * n; + break; + default: + LOGGER.log(Level.WARNING, String.format("< 0xE0: invalid value for i (%x %x)", i, code)); + } + } + } else if (code == 0xFC) { + stream.seek(1, SeekMode.CUR); + } else if (code == 0xFD) { + int n, m; //uint8_t + + if ((n = stream.readUI8()) < 0) { + LOGGER.log(Level.WARNING, "0xFD: Cannot read n."); + return false; + } + + if (state == 1) { + if (is_64) { + if (n != 0xF) { + LOGGER.log(Level.WARNING, String.format("We were expecting an offset of 0xF in state 1.")); + return false; + } + } else if (n != 0xB) { + LOGGER.log(Level.WARNING, "We were expecting an offset of 0xB in state 1."); + return false; + } + + state = 2; + } + + if ((m = stream.readUI8()) < 0) { + LOGGER.log(Level.WARNING, "0xFD: Cannot read m."); + return false; + } + + offset += n; + stream.seek(m * 2, SeekMode.CUR); + } else if (code == 0xFE) { + int n8; //uint8_t + int n; + + if ((n8 = stream.readUI8()) < 0) { + LOGGER.log(Level.WARNING, "0xFE: Cannot read n."); + return false; + } + + n = n8 + 1; + offset += n; + } else if (code == 0xFF) { + long n; //uint32_t + + if ((n = stream.readUI32()) < 0) { + LOGGER.log(Level.WARNING, "0xFF: Cannot read n."); + return false; + } + + if (state == 2) { + n += item_size_change; + stream.seek(-4, SeekMode.CUR); + return stream.writeUI32(n); + } + + offset += n; + } else { + LOGGER.log(Level.WARNING, String.format("Unrecognized code: %x", code)); + } + + if (state == 0 && offset == item_offset) { + state = 1; + } + } + return false; + } + + /** + * Gets length of an item. + * + * @param item_offset + * @param is_64 + * @param index_bytes + * @return null when item not exists, item length otherwise + * @throws IOException + */ + private static Long getItemLength(long item_offset /*uint32_t*/, boolean is_64, byte index_bytes[]) throws IOException { + return itemLength(item_offset, is_64, index_bytes, null); + } + + /** + * Sets new length of an item. + * + * @param item_offset + * @param is_64 + * @param index_bytes + * @param newLength + * @return null when item not exists, old item length otherwise + * @throws IOException + */ + private static Long setItemLength(long item_offset /*uint32_t*/, boolean is_64, byte index_bytes[], long newLength) throws IOException { + return itemLength(item_offset, is_64, index_bytes, newLength); + } + + /** + * Sets/Gets length of an item + * + * @param item_offset + * @param is_64 + * @param index_bytes + * @param newValue New value to set. If null then no change. + * @return null when item does not exists, old item length otherwise + * @throws IOException + */ + private static Long itemLength(long item_offset /*uint32_t*/, boolean is_64, byte index_bytes[], Long newValue) throws IOException { + TemporaryDataStream stream = new TemporaryDataStream(index_bytes); + + /* + index_table: + n = UI8 + for i=0..n-1 + table[i] = UI8 + cnt = UI8 + cnt * UI16 + + */ + int index_table_size = stream.readUI8(); + int index_table[] = new int[index_table_size]; + + for (int i = 0; i < index_table_size; i++) { + index_table[i] = stream.readUI8(); + int num = stream.readUI8(); + stream.seek(num * 2, SeekMode.CUR); + //num * UI16 + } + + int state = 0; + long offset = 0;//uint32_t + int code; //uint8_t + + while ((code = stream.readUI8()) >= 0) { + if (state == 1) { + if (code != 0xFD) { + LOGGER.log(Level.WARNING, "We were expecting code 0xFD in state 1."); + return null; + } + } else if (state == 2) { + if (code != 0xFF) { + LOGGER.log(Level.WARNING, "We were expecting code 0xFF in state 2."); + return null; + } + } + + if (code < 0x80) // 0-0x7F + { + // code is directly an index to the index_table + if (code >= index_table_size) { + LOGGER.log(Level.WARNING, String.format("< 0x80: index is greater than index_table_size. %x > %x", code, index_table_size)); + return null; + } + + offset += index_table[code]; + } else if (code < 0xC0) // 0x80-BF + { + int index; //uint8_t + + if ((index = stream.readUI8()) < 0) { + LOGGER.log(Level.WARNING, "< 0xC0: Cannot read index."); + return null; + } + + if (index >= index_table_size) { + LOGGER.log(Level.WARNING, String.format("< 0xC0: index is greater than index_table_size. %x > %x", index, index_table_size)); + return null; + } + + int n = code - 0x7F; + offset += index_table[index] * n; + } else if (code < 0xD0) // 0xC0-0xCF + { + offset += ((code * 2) - 0x17E); + } else if (code < 0xE0) // 0xD0-0xDF + { + // Code here depends on plattform[0], we are assuming it is 1, as we checked in load function + int i = code & 0xF; //uint8_t + int n8; //uint8_t + int n; + + if ((n8 = stream.readUI8()) < 0) { + LOGGER.log(Level.WARNING, "< 0xE0: Cannot read n."); + return null; + } + + n = n8 + 1; + + if (is_64) { + if (i <= 2) { + offset += 8 * n; // Ptr type + } else if (i <= 4) { + offset += 2 * n; + } else if (i == 5) { + offset += 4 * n; + } else if (i == 6) { + offset += 8 * n; // 64 bits type + } else { + LOGGER.log(Level.WARNING, String.format("< 0xE0: Invalid value for i (%x %x)", i, code)); + } + } else { + switch (i) { + case 2: + offset += 4 * n; // Ptr type + break; + case 4: + offset += 2 * n; + break; + case 5: + offset += 4 * n; // 32 bits type + break; + case 6: + offset += 8 * n; + break; + default: + LOGGER.log(Level.WARNING, String.format("< 0xE0: invalid value for i (%x %x)", i, code)); + } + } + } else if (code == 0xFC) { + stream.seek(1, SeekMode.CUR); + } else if (code == 0xFD) { + int n, m; //uint8_t + + if ((n = stream.readUI8()) < 0) { + LOGGER.log(Level.WARNING, "0xFD: Cannot read n."); + return null; + } + + if (state == 1) { + if (is_64) { + if (n != 0xF) { + LOGGER.log(Level.WARNING, String.format("We were expecting an offset of 0xF in state 1.")); + return null; + } + } else if (n != 0xB) { + LOGGER.log(Level.WARNING, "We were expecting an offset of 0xB in state 1."); + return null; + } + + state = 2; + } + + if ((m = stream.readUI8()) < 0) { + LOGGER.log(Level.WARNING, "0xFD: Cannot read m."); + return null; + } + + offset += n; + stream.seek(m * 2, SeekMode.CUR); + } else if (code == 0xFE) { + int n8; //uint8_t + int n; + + if ((n8 = stream.readUI8()) < 0) { + LOGGER.log(Level.WARNING, "0xFE: Cannot read n."); + return null; + } + + n = n8 + 1; + offset += n; + } else if (code == 0xFF) { + long n; //uint32_t + + if ((n = stream.readUI32()) < 0) { + LOGGER.log(Level.WARNING, "0xFF: Cannot read n."); + return null; + } + + if (state == 2) { + if (newValue != null) { + stream.seek(-4, SeekMode.CUR); + stream.writeUI32(newValue); + } + return n; + } + + offset += n; + } else { + LOGGER.log(Level.WARNING, String.format("Unrecognized code: %x", code)); + } + + if (state == 0 && offset == item_offset) { + state = 1; + } + } + return null; + } + + public String getSwfName() { + return iggySwf.getName(); + } + + public long getSwfXMin() { + return iggySwf.getHdr().getXMin(); + } + + public long getSwfYMin() { + return iggySwf.getHdr().getYMin(); + } + + public long getSwfXMax() { + return iggySwf.getHdr().getXMax(); + } + + public long getSwfYMax() { + return iggySwf.getHdr().getYMax(); + } + + public float getSwfFrameRate() { + return iggySwf.getHdr().getFrameRate(); + } + + /** + * Removes entries of type INDEX.There can be more than one INDEX, + * continuous. This removes all ot them. + */ + public void removeIndexEntries() { + long offsetsChange = 0; + final int ENTRY_SIZE = 16; + for (int i = 0; i < subFileEntries.size(); i++) { + IggySubFileEntry entry = subFileEntries.get(i); + entry.offset += offsetsChange; + if (entry.type == IggySubFileEntry.TYPE_INDEX) { + offsetsChange = offsetsChange - entry.size - ENTRY_SIZE; + subFileEntriesData.remove(i); + subFileEntries.remove(i); + i--; + } + } + } + + public boolean updateFlashEntry() throws IOException { + + byte replacementData[]; + byte replacementIndexData[]; + IggyIndexBuilder ib = new IggyIndexBuilder(); + try (DataStreamInterface stream = new TemporaryDataStream()) { + stream.setIndexing(ib); + iggySwf.writeToDataStream(stream); + replacementData = stream.getAllBytes(); + replacementIndexData = ib.getIndexBytes(); + } catch (IOException ex) { + Logger.getLogger(IggyFile.class.getName()).log(Level.SEVERE, "Error during updating SWF", ex); + return false; + } + + long offsetsChange = 0; + for (int i = 0; i < subFileEntries.size(); i++) { + IggySubFileEntry entry = subFileEntries.get(i); + entry.offset += offsetsChange; + if (entry.type == IggySubFileEntry.TYPE_FLASH) { + long oldSize = entry.size; + long newSize = replacementData.length; + entry.size = newSize; + entry.size2 = newSize; + offsetsChange = offsetsChange + (newSize - oldSize); //entries after this one will have modified offsets + subFileEntriesData.set(i, replacementData); + } + } + + removeIndexEntries(); + IggySubFileEntry indexEntry = new IggySubFileEntry(IggySubFileEntry.TYPE_INDEX, replacementIndexData.length, replacementIndexData.length, 0 /*offset will be set automatically*/); + subFileEntries.add(indexEntry); + subFileEntriesData.add(replacementIndexData); + return true; + } + + private void parseEntries() throws IOException { + for (int i = 0; i < subFileEntries.size(); i++) { + IggySubFileEntry entry = subFileEntries.get(i); + if (entry.type == IggySubFileEntry.TYPE_FLASH) { + iggySwf = new IggySwf(new TemporaryDataStream(getEntryData(i))); + break; + } + /*if (entry.type == IggySubFileEntry.TYPE_INDEX) { + IggyIndexParser.parseIndex(true, new TemporaryDataStream(getEntryData(i)), new ArrayList<>(), new ArrayList<>()); + }*/ + } + } + + @Override + public void readFromDataStream(ReadDataStreamInterface stream) throws IOException { + header = new IggyHeader(stream); + for (int i = 0; i < header.getNumSubfiles(); i++) { + subFileEntries.add(new IggySubFileEntry(stream)); + } + for (IggySubFileEntry entry : subFileEntries) { + stream.seek(entry.offset, SeekMode.SET); + byte[] entryData = stream.readBytes((int) entry.size); + subFileEntriesData.add(entryData); + } + parseEntries(); + } + + public void saveChanges() throws IOException { + updateFlashEntry(); + try (RandomAccessFileDataStream raf = new RandomAccessFileDataStream(originalFile)) { + writeToDataStream(raf); + } + } + + @Override + public void writeToDataStream(WriteDataStreamInterface stream) throws IOException { + header.writeToDataStream(stream); + + long startOffset = IggyHeader.STRUCT_SIZE + IggySubFileEntry.STRUCTURE_SIZE * subFileEntries.size(); + long currentOffset = startOffset; + + for (int i = 0; i < subFileEntries.size(); i++) { + IggySubFileEntry entry = subFileEntries.get(i); + entry.offset = currentOffset; + currentOffset += entry.size; + entry.writeToDataStream(stream); + } + + for (int i = 0; i < subFileEntries.size(); i++) { + byte[] entryData = subFileEntriesData.get(i); + stream.writeBytes(entryData); + } + + } + +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFlashHeader32.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFlashHeader32.java index 55178b372..6006b1c6a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFlashHeader32.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFlashHeader32.java @@ -1,197 +1,197 @@ -package com.jpexs.decompiler.flash.iggy; - -import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType; -import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface; -import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface; -import java.io.IOException; - -/** - * - * @author JPEXS - * - * Based of works of somebody called eternity. - * - * All relative offsets are relative from that specific field position All - * relative offsets can get value "1" to indicate "nothing" - */ -public class IggyFlashHeader32 implements IggyFlashHeaderInterface { - - @IggyFieldType(DataType.uint32_t) - long main_offset; // 0 Relative offset to first section (matches sizeof header) - @IggyFieldType(DataType.uint32_t) - long as3_section_offset; // 4 Relative offset to as3 file names table... - @IggyFieldType(DataType.uint32_t) - long unk_offset; // 8 relative offset to something - @IggyFieldType(DataType.uint32_t) - long unk_offset2; // 0xC relative offset to something - @IggyFieldType(DataType.uint32_t) - long unk_offset3; // 0x10 relative offset to something - @IggyFieldType(DataType.uint32_t) - long unk_offset4; // 0x14 relative offset to something - @IggyFieldType(DataType.uint32_t) - long xmin; //0x18 in pixels - @IggyFieldType(DataType.uint32_t) - long ymin; //0x0C in pixels - @IggyFieldType(DataType.uint32_t) - long xmax; // 0x20 in pixels - @IggyFieldType(DataType.uint32_t) - long ymax; // 0x24 in pixels - @IggyFieldType(DataType.uint32_t) - long unk_28; // probably number of blocks/objects after header - @IggyFieldType(DataType.uint32_t) - long unk_2C; - @IggyFieldType(DataType.uint32_t) - long unk_30; - @IggyFieldType(DataType.uint32_t) - long unk_34; - @IggyFieldType(DataType.uint32_t) - long unk_38; - @IggyFieldType(DataType.uint32_t) - long unk_3C; - @IggyFieldType(DataType.float_t) - float frameRate; - @IggyFieldType(DataType.uint32_t) - long unk_44; - @IggyFieldType(DataType.uint32_t) - long unk_48; - @IggyFieldType(DataType.uint32_t) - long unk_4C; - @IggyFieldType(DataType.uint32_t) - long names_offset; // 0x50 relative offset to the names/import section of the file - @IggyFieldType(DataType.uint32_t) - long unk_offset5; // 0x54 relative offset to something - @IggyFieldType(DataType.uint64_t) - long unk_58; // Maybe number of imports/names pointed by names_offset - @IggyFieldType(DataType.uint32_t) - long last_section_offset; // 0x60 relative offset, points to the small last section of the file - @IggyFieldType(DataType.uint32_t) - long unk_offset6; // 0x64 relative offset to something - @IggyFieldType(DataType.uint32_t) - long as3_code_offset; // 0x68 relative offset to as3 code (8 bytes header + abc blob) - @IggyFieldType(DataType.uint32_t) - long as3_names_offset; // 0x6C relative offset to as3 file names table (or classes names or whatever) - @IggyFieldType(DataType.uint32_t) - long unk_70; - @IggyFieldType(DataType.uint32_t) - long unk_74; - @IggyFieldType(DataType.uint32_t) - long unk_78; // Maybe number of classes / as3 names - @IggyFieldType(DataType.uint32_t) - long unk_7C; - - // Offset 0x80 (outside header): there are *unk_28* relative offsets that point to flash objects. - // The flash objects are in a format different to swf but there is probably a way to convert between them. - // After the offsets, the bodies of objects pointed above, which apparently have a code like 0xFFXX to identify the type of object, followed by a (unique?) identifier - // for the object. - // A DefineEditText-like object can be easily spotted and apparently uses type code 0x06 (or 0xFF06) but as stated above, - // it is written in a different way. - public IggyFlashHeader32(ReadDataStreamInterface stream) throws IOException { - readFromDataStream(stream); - } - - @Override - public void readFromDataStream(ReadDataStreamInterface stream) throws IOException { - main_offset = stream.readUI32(); - as3_section_offset = stream.readUI32(); - unk_offset = stream.readUI32(); - unk_offset2 = stream.readUI32(); - unk_offset3 = stream.readUI32(); - unk_offset4 = stream.readUI32(); - xmin = stream.readUI32(); - ymin = stream.readUI32(); - xmax = stream.readUI32(); - ymax = stream.readUI32(); - unk_28 = stream.readUI32(); - unk_2C = stream.readUI32(); - unk_30 = stream.readUI32(); - unk_34 = stream.readUI32(); - unk_38 = stream.readUI32(); - unk_3C = stream.readUI32(); - frameRate = stream.readFloat(); - unk_44 = stream.readUI32(); - unk_48 = stream.readUI32(); - unk_4C = stream.readUI32(); - unk_3C = stream.readUI32(); - names_offset = stream.readUI32(); - unk_offset5 = stream.readUI32(); - unk_58 = stream.readUI64(); - last_section_offset = stream.readUI32(); - unk_offset6 = stream.readUI32(); - as3_code_offset = stream.readUI32(); - as3_names_offset = stream.readUI32(); - unk_70 = stream.readUI32(); - unk_74 = stream.readUI32(); - unk_78 = stream.readUI32(); - unk_7C = stream.readUI32(); - } - - @Override - public void writeToDataStream(WriteDataStreamInterface stream) throws IOException { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - - sb.append("[\r\n"); - sb.append("main_offset ").append(main_offset).append("\r\n"); - sb.append("as3_section_offset ").append(as3_section_offset).append("\r\n"); - sb.append("unk_offset ").append(unk_offset).append("\r\n"); - sb.append("unk_offset2 ").append(unk_offset2).append("\r\n"); - sb.append("unk_offset3 ").append(unk_offset3).append("\r\n"); - sb.append("unk_offset4 ").append(unk_offset4).append("\r\n"); - sb.append("xmin ").append(xmin).append("\r\n"); - sb.append("ymin ").append(ymin).append("\r\n"); - sb.append("xmax ").append(xmax).append("\r\n"); - sb.append("ymax ").append(ymax).append("\r\n"); - sb.append("unk_28 ").append(unk_28).append("\r\n"); - sb.append("unk_2C ").append(unk_2C).append("\r\n"); - sb.append("unk_30 ").append(unk_30).append("\r\n"); - sb.append("unk_34 ").append(unk_34).append("\r\n"); - sb.append("unk_38 ").append(unk_38).append("\r\n"); - sb.append("unk_3C ").append(unk_3C).append("\r\n"); - sb.append("frameRate ").append(frameRate).append("\r\n"); - sb.append("unk_44 ").append(unk_44).append("\r\n"); - sb.append("unk_48 ").append(unk_48).append("\r\n"); - sb.append("unk_4C ").append(unk_4C).append("\r\n"); - sb.append("names_offset ").append(names_offset).append("\r\n"); - sb.append("unk_offset5 ").append(unk_offset5).append("\r\n"); - sb.append("unk_58 ").append(unk_58).append("\r\n"); - sb.append("last_section_offset ").append(last_section_offset).append("\r\n"); - sb.append("unk_offset6 ").append(unk_offset6).append("\r\n"); - sb.append("as3_code_offset ").append(as3_code_offset).append("\r\n"); - sb.append("as3_names_offset ").append(as3_names_offset).append("\r\n"); - sb.append("unk_70 ").append(unk_70).append("\r\n"); - sb.append("unk_74 ").append(unk_74).append("\r\n"); - sb.append("unk_78 ").append(unk_78).append("\r\n"); - sb.append("unk_7C ").append(unk_7C).append("\r\n"); - sb.append("]"); - return sb.toString(); - } - - @Override - public long getXMin() { - return xmin; - } - - @Override - public long getYMin() { - return ymin; - } - - @Override - public long getXMax() { - return xmax; - } - - @Override - public long getYMax() { - return ymax; - } - - @Override - public float getFrameRate() { - return frameRate; - } -} +package com.jpexs.decompiler.flash.iggy; + +import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType; +import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface; +import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface; +import java.io.IOException; + +/** + * + * @author JPEXS + * + * Based of works of somebody called eternity. + * + * All relative offsets are relative from that specific field position All + * relative offsets can get value "1" to indicate "nothing" + */ +public class IggyFlashHeader32 implements IggyFlashHeaderInterface { + + @IggyFieldType(DataType.uint32_t) + long main_offset; // 0 Relative offset to first section (matches sizeof header) + @IggyFieldType(DataType.uint32_t) + long as3_section_offset; // 4 Relative offset to as3 file names table... + @IggyFieldType(DataType.uint32_t) + long unk_offset; // 8 relative offset to something + @IggyFieldType(DataType.uint32_t) + long unk_offset2; // 0xC relative offset to something + @IggyFieldType(DataType.uint32_t) + long unk_offset3; // 0x10 relative offset to something + @IggyFieldType(DataType.uint32_t) + long unk_offset4; // 0x14 relative offset to something + @IggyFieldType(DataType.uint32_t) + long xmin; //0x18 in pixels + @IggyFieldType(DataType.uint32_t) + long ymin; //0x0C in pixels + @IggyFieldType(DataType.uint32_t) + long xmax; // 0x20 in pixels + @IggyFieldType(DataType.uint32_t) + long ymax; // 0x24 in pixels + @IggyFieldType(DataType.uint32_t) + long unk_28; // probably number of blocks/objects after header + @IggyFieldType(DataType.uint32_t) + long unk_2C; + @IggyFieldType(DataType.uint32_t) + long unk_30; + @IggyFieldType(DataType.uint32_t) + long unk_34; + @IggyFieldType(DataType.uint32_t) + long unk_38; + @IggyFieldType(DataType.uint32_t) + long unk_3C; + @IggyFieldType(DataType.float_t) + float frameRate; + @IggyFieldType(DataType.uint32_t) + long unk_44; + @IggyFieldType(DataType.uint32_t) + long unk_48; + @IggyFieldType(DataType.uint32_t) + long unk_4C; + @IggyFieldType(DataType.uint32_t) + long names_offset; // 0x50 relative offset to the names/import section of the file + @IggyFieldType(DataType.uint32_t) + long unk_offset5; // 0x54 relative offset to something + @IggyFieldType(DataType.uint64_t) + long unk_58; // Maybe number of imports/names pointed by names_offset + @IggyFieldType(DataType.uint32_t) + long last_section_offset; // 0x60 relative offset, points to the small last section of the file + @IggyFieldType(DataType.uint32_t) + long unk_offset6; // 0x64 relative offset to something + @IggyFieldType(DataType.uint32_t) + long as3_code_offset; // 0x68 relative offset to as3 code (8 bytes header + abc blob) + @IggyFieldType(DataType.uint32_t) + long as3_names_offset; // 0x6C relative offset to as3 file names table (or classes names or whatever) + @IggyFieldType(DataType.uint32_t) + long unk_70; + @IggyFieldType(DataType.uint32_t) + long unk_74; + @IggyFieldType(DataType.uint32_t) + long unk_78; // Maybe number of classes / as3 names + @IggyFieldType(DataType.uint32_t) + long unk_7C; + + // Offset 0x80 (outside header): there are *unk_28* relative offsets that point to flash objects. + // The flash objects are in a format different to swf but there is probably a way to convert between them. + // After the offsets, the bodies of objects pointed above, which apparently have a code like 0xFFXX to identify the type of object, followed by a (unique?) identifier + // for the object. + // A DefineEditText-like object can be easily spotted and apparently uses type code 0x06 (or 0xFF06) but as stated above, + // it is written in a different way. + public IggyFlashHeader32(ReadDataStreamInterface stream) throws IOException { + readFromDataStream(stream); + } + + @Override + public void readFromDataStream(ReadDataStreamInterface stream) throws IOException { + main_offset = stream.readUI32(); + as3_section_offset = stream.readUI32(); + unk_offset = stream.readUI32(); + unk_offset2 = stream.readUI32(); + unk_offset3 = stream.readUI32(); + unk_offset4 = stream.readUI32(); + xmin = stream.readUI32(); + ymin = stream.readUI32(); + xmax = stream.readUI32(); + ymax = stream.readUI32(); + unk_28 = stream.readUI32(); + unk_2C = stream.readUI32(); + unk_30 = stream.readUI32(); + unk_34 = stream.readUI32(); + unk_38 = stream.readUI32(); + unk_3C = stream.readUI32(); + frameRate = stream.readFloat(); + unk_44 = stream.readUI32(); + unk_48 = stream.readUI32(); + unk_4C = stream.readUI32(); + unk_3C = stream.readUI32(); + names_offset = stream.readUI32(); + unk_offset5 = stream.readUI32(); + unk_58 = stream.readUI64(); + last_section_offset = stream.readUI32(); + unk_offset6 = stream.readUI32(); + as3_code_offset = stream.readUI32(); + as3_names_offset = stream.readUI32(); + unk_70 = stream.readUI32(); + unk_74 = stream.readUI32(); + unk_78 = stream.readUI32(); + unk_7C = stream.readUI32(); + } + + @Override + public void writeToDataStream(WriteDataStreamInterface stream) throws IOException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + + sb.append("[\r\n"); + sb.append("main_offset ").append(main_offset).append("\r\n"); + sb.append("as3_section_offset ").append(as3_section_offset).append("\r\n"); + sb.append("unk_offset ").append(unk_offset).append("\r\n"); + sb.append("unk_offset2 ").append(unk_offset2).append("\r\n"); + sb.append("unk_offset3 ").append(unk_offset3).append("\r\n"); + sb.append("unk_offset4 ").append(unk_offset4).append("\r\n"); + sb.append("xmin ").append(xmin).append("\r\n"); + sb.append("ymin ").append(ymin).append("\r\n"); + sb.append("xmax ").append(xmax).append("\r\n"); + sb.append("ymax ").append(ymax).append("\r\n"); + sb.append("unk_28 ").append(unk_28).append("\r\n"); + sb.append("unk_2C ").append(unk_2C).append("\r\n"); + sb.append("unk_30 ").append(unk_30).append("\r\n"); + sb.append("unk_34 ").append(unk_34).append("\r\n"); + sb.append("unk_38 ").append(unk_38).append("\r\n"); + sb.append("unk_3C ").append(unk_3C).append("\r\n"); + sb.append("frameRate ").append(frameRate).append("\r\n"); + sb.append("unk_44 ").append(unk_44).append("\r\n"); + sb.append("unk_48 ").append(unk_48).append("\r\n"); + sb.append("unk_4C ").append(unk_4C).append("\r\n"); + sb.append("names_offset ").append(names_offset).append("\r\n"); + sb.append("unk_offset5 ").append(unk_offset5).append("\r\n"); + sb.append("unk_58 ").append(unk_58).append("\r\n"); + sb.append("last_section_offset ").append(last_section_offset).append("\r\n"); + sb.append("unk_offset6 ").append(unk_offset6).append("\r\n"); + sb.append("as3_code_offset ").append(as3_code_offset).append("\r\n"); + sb.append("as3_names_offset ").append(as3_names_offset).append("\r\n"); + sb.append("unk_70 ").append(unk_70).append("\r\n"); + sb.append("unk_74 ").append(unk_74).append("\r\n"); + sb.append("unk_78 ").append(unk_78).append("\r\n"); + sb.append("unk_7C ").append(unk_7C).append("\r\n"); + sb.append("]"); + return sb.toString(); + } + + @Override + public long getXMin() { + return xmin; + } + + @Override + public long getYMin() { + return ymin; + } + + @Override + public long getXMax() { + return xmax; + } + + @Override + public long getYMax() { + return ymax; + } + + @Override + public float getFrameRate() { + return frameRate; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFlashHeader64.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFlashHeader64.java index ecf77100c..6f627bb76 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFlashHeader64.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFlashHeader64.java @@ -1,393 +1,393 @@ -package com.jpexs.decompiler.flash.iggy; - -import com.jpexs.decompiler.flash.iggy.annotations.FieldPrinter; -import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType; -import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface; -import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface; -import java.io.IOException; -import java.lang.reflect.Field; - -/** - * - * @author Jindra - * - * Based of works of somebody called eternity. - */ -public class IggyFlashHeader64 implements IggyFlashHeaderInterface { - - @IggyFieldType(DataType.uint64_t) - long off_base; // 0 Relative offset to first section (matches sizeof header); - @IggyFieldType(DataType.uint64_t) - long off_sequence_end; // 8 Relative offset to as3 file names table... - @IggyFieldType(DataType.uint64_t) - long off_font_end; // 0x10 relative offset to something - @IggyFieldType(DataType.uint64_t) - long off_sequence_start1; // 0x18 relative offset to something - @IggyFieldType(DataType.uint64_t) - long off_sequence_start2; // 0x20 relative offset to something - @IggyFieldType(DataType.uint64_t) - long off_sequence_start3; // 0x28 names_offset; 0x50 relative pointer to the names/import section of the file - @IggyFieldType(DataType.uint32_t) - long xmin; // 0x30 in pixels - @IggyFieldType(DataType.uint32_t) - long ymin; // 0x34 in pixels - @IggyFieldType(DataType.uint32_t) - long xmax; // 0x38 in pixels - @IggyFieldType(DataType.uint32_t) - long ymax; // 0x3C in pixels - @IggyFieldType(DataType.uint32_t) - long unk_40; // probably numer of blocks/objects after header - @IggyFieldType(DataType.uint32_t) - long unk_44; - @IggyFieldType(DataType.uint32_t) - long unk_48; - @IggyFieldType(DataType.uint32_t) - long unk_4C; - @IggyFieldType(DataType.uint32_t) - long unk_50; - @IggyFieldType(DataType.uint32_t) - long unk_54; - @IggyFieldType(DataType.float_t) - float frame_rate; - @IggyFieldType(DataType.uint32_t) - long unk_5C; - @IggyFieldType(DataType.uint64_t) - long imported_guid; - @IggyFieldType(DataType.uint64_t) - long my_guid; // same for some fonts (eng + chinese) - @IggyFieldType(DataType.uint64_t) - long off_names; // 0x70 relative offset to the names/import section of the file - end of fonts - @IggyFieldType(DataType.uint64_t) - long off_unk78; // 0x78 relative offset to something - @IggyFieldType(DataType.uint64_t) - long unk80; - @IggyFieldType(DataType.uint64_t) - long off_last_section; - @IggyFieldType(DataType.uint64_t) - long off_flash_filename; - @IggyFieldType(DataType.uint64_t) - long off_decl_strings; - @IggyFieldType(DataType.uint64_t) - long off_type_of_fonts; - @IggyFieldType(DataType.uint64_t) - long flags; - @IggyFieldType(DataType.uint32_t) - long font_count; - @IggyFieldType(DataType.uint32_t) - long zero2; - - // Offset 0xB8 (outside header): there are *unk_40* relative offsets that point to flash objects. - // The flash objects are in a format different to swf but there is probably a way to convert between them. - // After the offsets, the bodies of objects pointed above, which apparently have a code like 0xFFXX to identify the type of object, followed by a (unique?) identifier - // for the object. - // A DefineEditText-like object can be easily spotted and apparently uses type code 0x06 (or 0xFF06) but as stated above, - // it is written in a different way. - public IggyFlashHeader64(ReadDataStreamInterface stream) throws IOException { - readFromDataStream(stream); - } - - private long base_address; - private long sequence_end_address; - private long font_end_address; - private long sequence_start_address1; - private long sequence_start_address2; - private long sequence_start_address3; - private long names_address; - private long unk78_address; - private long last_section_address; - private long flash_filename_address; - private long decl_strings_address; - private long type_fonts_address; - - private long base_ofs_pos; - private long sequence_end_ofs_pos; - private long font_end_ofs_pos; - private long sequence_start1_ofs_pos; - private long sequence_start2_ofs_pos; - private long sequence_start3_ofs_pos; - private long names_ofs_pos; - private long unk78_ofs_pos; - private long last_section_ofs_pos; - private long flash_filename_ofs_pos; - private long decl_strings_ofs_pos; - private long type_fonts_ofs_pos; - - public long getBase_ofs_pos() { - return base_ofs_pos; - } - - public long getSequence_end_ofs_pos() { - return sequence_end_ofs_pos; - } - - public long getFont_end_ofs_pos() { - return font_end_ofs_pos; - } - - public long getSequence_start1_ofs_pos() { - return sequence_start1_ofs_pos; - } - - public long getSequence_start2_ofs_pos() { - return sequence_start2_ofs_pos; - } - - public long getSequence_start3_ofs_pos() { - return sequence_start3_ofs_pos; - } - - public long getNames_ofs_pos() { - return names_ofs_pos; - } - - public long getUnk78_ofs_pos() { - return unk78_ofs_pos; - } - - public long getLast_section_ofs_pos() { - return last_section_ofs_pos; - } - - public long getFlash_filename_ofs_pos() { - return flash_filename_ofs_pos; - } - - public long getDecl_strings_ofs_pos() { - return decl_strings_ofs_pos; - } - - public long getType_fonts_ofs_pos() { - return type_fonts_ofs_pos; - } - - /** - * Updates all addresses by inserting gap - * - * @param pos Position to insert bytes - * @param size Number of bytes - */ - public void insertGapAfter(long pos, long size) { - for (Field f : IggyFlashHeader64.class.getDeclaredFields()) { - if (f.getName().endsWith("_address")) { - try { - long val = f.getLong(this); - if (val > pos) { - long newval = val + size; - f.setLong(this, newval); - } - } catch (IllegalAccessException iex) { - //should not happen - } - } - } - } - - public long getImported_guid() { - return imported_guid; - } - - public long getBaseAddress() { - return base_address; - } - - public long getSequenceEndAddress() { - return sequence_end_address; - } - - public long getFontEndAddress() { - return font_end_address; - } - - public void setFontEndAddress(long val) { - this.font_end_address = val; - } - - public long getSequenceStartAddress1() { - return sequence_start_address1; - } - - public long getSequenceStartAddress2() { - return sequence_start_address2; - } - - public long getSequenceStartAddress3() { - return sequence_start_address3; - } - - public long getNamesAddress() { - return names_address; - } - - public long getUnk78Address() { - return unk78_address; - } - - public long getLastSectionAddress() { - return last_section_address; - } - - public long getFlashFilenameAddress() { - return flash_filename_address; - } - - public long getDeclStringsAddress() { - return decl_strings_address; - } - - public long getTypeFontsAddress() { - return type_fonts_address; - } - - @Override - public void readFromDataStream(ReadDataStreamInterface stream) throws IOException { - base_ofs_pos = stream.position(); - off_base = stream.readUI64(); - base_address = off_base == 1 ? 0 : off_base + stream.position() - 8; - - sequence_end_ofs_pos = stream.position(); - off_sequence_end = stream.readUI64(); - sequence_end_address = off_sequence_end == 1 ? 0 : off_sequence_end + stream.position() - 8; - - font_end_ofs_pos = stream.position(); - off_font_end = stream.readUI64(); - font_end_address = off_font_end == 1 ? 0 : off_font_end + stream.position() - 8; - - sequence_start1_ofs_pos = stream.position(); - off_sequence_start1 = stream.readUI64(); - sequence_start_address1 = off_sequence_start1 == 1 ? 0 : off_sequence_start1 + stream.position() - 8; - - sequence_start2_ofs_pos = stream.position(); - off_sequence_start2 = stream.readUI64(); - sequence_start_address2 = off_sequence_start2 == 1 ? 0 : off_sequence_start2 + stream.position() - 8; - - sequence_start3_ofs_pos = stream.position(); - off_sequence_start3 = stream.readUI64(); - sequence_start_address3 = off_sequence_start3 == 1 ? 0 : off_sequence_start3 + stream.position() - 8; - - xmin = stream.readUI32(); - ymin = stream.readUI32(); - xmax = stream.readUI32(); - ymax = stream.readUI32(); - - unk_40 = stream.readUI32(); // probably number of blocks/objects after header - unk_44 = stream.readUI32(); - unk_48 = stream.readUI32(); - unk_4C = stream.readUI32(); - unk_50 = stream.readUI32(); - unk_54 = stream.readUI32(); - frame_rate = stream.readFloat(); - unk_5C = stream.readUI32(); - imported_guid = stream.readUI64(); - my_guid = stream.readUI64(); - - names_ofs_pos = stream.position(); - off_names = stream.readUI64(); - names_address = off_names == 1 ? 0 : off_names + stream.position() - 8; - - unk78_ofs_pos = stream.position(); - off_unk78 = stream.readUI64(); - unk78_address = off_unk78 == 1 ? 0 : off_unk78 + stream.position() - 8; - - unk80 = stream.readUI64(); //Maybe number of imports/names pointed by names_offset - - last_section_ofs_pos = stream.position(); - off_last_section = stream.readUI64(); - last_section_address = off_last_section == 1 ? 0 : off_last_section + stream.position() - 8; - - flash_filename_ofs_pos = stream.position(); - off_flash_filename = stream.readUI64(); - flash_filename_address = off_flash_filename == 1 ? 0 : off_flash_filename + stream.position() - 8; - - decl_strings_ofs_pos = stream.position(); - off_decl_strings = stream.readUI64(); //relative offset to as3 code (16 bytes header + abc blob) - decl_strings_address = off_decl_strings == 1 ? 0 : off_decl_strings + stream.position() - 8; - - type_fonts_ofs_pos = stream.position(); - off_type_of_fonts = stream.readUI64(); //relative offset to as3 file names table (or classes names or whatever) - type_fonts_address = off_type_of_fonts == 1 ? 0 : off_type_of_fonts + stream.position() - 8; - - flags = stream.readUI64(); - font_count = stream.readUI32(); - zero2 = stream.readUI32(); - } - - @Override - public void writeToDataStream(WriteDataStreamInterface stream) throws IOException { - off_base = base_address == 0 ? 1 : base_address - stream.position(); - stream.writeUI64(off_base); - off_sequence_end = sequence_end_address == 0 ? 1 : sequence_end_address - stream.position(); - stream.writeUI64(off_sequence_end); - off_font_end = font_end_address == 0 ? 1 : font_end_address - stream.position(); - stream.writeUI64(off_font_end); - off_sequence_start1 = sequence_start_address1 == 0 ? 1 : sequence_start_address1 - stream.position(); - stream.writeUI64(off_sequence_start1); - off_sequence_start2 = sequence_start_address2 == 0 ? 1 : sequence_start_address2 - stream.position(); - stream.writeUI64(off_sequence_start2); - off_sequence_start3 = sequence_start_address3 == 0 ? 1 : sequence_start_address3 - stream.position(); - stream.writeUI64(off_sequence_start3); - stream.writeUI32(xmin); - stream.writeUI32(ymin); - stream.writeUI32(xmax); - stream.writeUI32(ymax); - stream.writeUI32(unk_40); - stream.writeUI32(unk_44); - stream.writeUI32(unk_48); - stream.writeUI32(unk_4C); - stream.writeUI32(unk_50); - stream.writeUI32(unk_54); - stream.writeFloat(frame_rate); - stream.writeUI32(unk_5C); - stream.writeUI64(imported_guid); - stream.writeUI64(my_guid); - off_names = names_address == 0 ? 1 : names_address - stream.position(); - stream.writeUI64(off_names); - off_unk78 = unk78_address == 0 ? 1 : unk78_address - stream.position(); - stream.writeUI64(off_unk78); - stream.writeUI64(unk80); - off_last_section = last_section_address == 0 ? 1 : last_section_address - stream.position(); - stream.writeUI64(off_last_section); - off_flash_filename = flash_filename_address == 0 ? 1 : flash_filename_address - stream.position(); - stream.writeUI64(off_flash_filename); - off_decl_strings = decl_strings_address == 0 ? 1 : decl_strings_address - stream.position(); - stream.writeUI64(off_decl_strings); - off_type_of_fonts = type_fonts_address == 0 ? 1 : type_fonts_address - stream.position(); - stream.writeUI64(off_type_of_fonts); - stream.writeUI64(flags); - stream.writeUI32(font_count); - stream.writeUI32(zero2); - - stream.getIndexing().writeLengthCustom(184, new int[]{0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x34, 0x38, 0x3C, 0x40, 0x44, 0x48, 0x4C, 0x50, 0x58, 0x70, 0x78, 0x80, 0x84, 0x88, 0x90, 0x98, 0xA0, 0xB0}, new int[]{2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 5, 5, 2, 2, 2, 2, 5}); - - } - - @Override - public String toString() { - return FieldPrinter.getObjectSummary(this); - } - - @Override - public long getXMin() { - return xmin; - } - - @Override - public long getYMin() { - return ymin; - } - - @Override - public long getXMax() { - return xmax; - } - - @Override - public long getYMax() { - return ymax; - } - - @Override - public float getFrameRate() { - return frame_rate; - } - -} +package com.jpexs.decompiler.flash.iggy; + +import com.jpexs.decompiler.flash.iggy.annotations.FieldPrinter; +import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType; +import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface; +import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface; +import java.io.IOException; +import java.lang.reflect.Field; + +/** + * + * @author Jindra + * + * Based of works of somebody called eternity. + */ +public class IggyFlashHeader64 implements IggyFlashHeaderInterface { + + @IggyFieldType(DataType.uint64_t) + long off_base; // 0 Relative offset to first section (matches sizeof header); + @IggyFieldType(DataType.uint64_t) + long off_sequence_end; // 8 Relative offset to as3 file names table... + @IggyFieldType(DataType.uint64_t) + long off_font_end; // 0x10 relative offset to something + @IggyFieldType(DataType.uint64_t) + long off_sequence_start1; // 0x18 relative offset to something + @IggyFieldType(DataType.uint64_t) + long off_sequence_start2; // 0x20 relative offset to something + @IggyFieldType(DataType.uint64_t) + long off_sequence_start3; // 0x28 names_offset; 0x50 relative pointer to the names/import section of the file + @IggyFieldType(DataType.uint32_t) + long xmin; // 0x30 in pixels + @IggyFieldType(DataType.uint32_t) + long ymin; // 0x34 in pixels + @IggyFieldType(DataType.uint32_t) + long xmax; // 0x38 in pixels + @IggyFieldType(DataType.uint32_t) + long ymax; // 0x3C in pixels + @IggyFieldType(DataType.uint32_t) + long unk_40; // probably numer of blocks/objects after header + @IggyFieldType(DataType.uint32_t) + long unk_44; + @IggyFieldType(DataType.uint32_t) + long unk_48; + @IggyFieldType(DataType.uint32_t) + long unk_4C; + @IggyFieldType(DataType.uint32_t) + long unk_50; + @IggyFieldType(DataType.uint32_t) + long unk_54; + @IggyFieldType(DataType.float_t) + float frame_rate; + @IggyFieldType(DataType.uint32_t) + long unk_5C; + @IggyFieldType(DataType.uint64_t) + long imported_guid; + @IggyFieldType(DataType.uint64_t) + long my_guid; // same for some fonts (eng + chinese) + @IggyFieldType(DataType.uint64_t) + long off_names; // 0x70 relative offset to the names/import section of the file - end of fonts + @IggyFieldType(DataType.uint64_t) + long off_unk78; // 0x78 relative offset to something + @IggyFieldType(DataType.uint64_t) + long unk80; + @IggyFieldType(DataType.uint64_t) + long off_last_section; + @IggyFieldType(DataType.uint64_t) + long off_flash_filename; + @IggyFieldType(DataType.uint64_t) + long off_decl_strings; + @IggyFieldType(DataType.uint64_t) + long off_type_of_fonts; + @IggyFieldType(DataType.uint64_t) + long flags; + @IggyFieldType(DataType.uint32_t) + long font_count; + @IggyFieldType(DataType.uint32_t) + long zero2; + + // Offset 0xB8 (outside header): there are *unk_40* relative offsets that point to flash objects. + // The flash objects are in a format different to swf but there is probably a way to convert between them. + // After the offsets, the bodies of objects pointed above, which apparently have a code like 0xFFXX to identify the type of object, followed by a (unique?) identifier + // for the object. + // A DefineEditText-like object can be easily spotted and apparently uses type code 0x06 (or 0xFF06) but as stated above, + // it is written in a different way. + public IggyFlashHeader64(ReadDataStreamInterface stream) throws IOException { + readFromDataStream(stream); + } + + private long base_address; + private long sequence_end_address; + private long font_end_address; + private long sequence_start_address1; + private long sequence_start_address2; + private long sequence_start_address3; + private long names_address; + private long unk78_address; + private long last_section_address; + private long flash_filename_address; + private long decl_strings_address; + private long type_fonts_address; + + private long base_ofs_pos; + private long sequence_end_ofs_pos; + private long font_end_ofs_pos; + private long sequence_start1_ofs_pos; + private long sequence_start2_ofs_pos; + private long sequence_start3_ofs_pos; + private long names_ofs_pos; + private long unk78_ofs_pos; + private long last_section_ofs_pos; + private long flash_filename_ofs_pos; + private long decl_strings_ofs_pos; + private long type_fonts_ofs_pos; + + public long getBase_ofs_pos() { + return base_ofs_pos; + } + + public long getSequence_end_ofs_pos() { + return sequence_end_ofs_pos; + } + + public long getFont_end_ofs_pos() { + return font_end_ofs_pos; + } + + public long getSequence_start1_ofs_pos() { + return sequence_start1_ofs_pos; + } + + public long getSequence_start2_ofs_pos() { + return sequence_start2_ofs_pos; + } + + public long getSequence_start3_ofs_pos() { + return sequence_start3_ofs_pos; + } + + public long getNames_ofs_pos() { + return names_ofs_pos; + } + + public long getUnk78_ofs_pos() { + return unk78_ofs_pos; + } + + public long getLast_section_ofs_pos() { + return last_section_ofs_pos; + } + + public long getFlash_filename_ofs_pos() { + return flash_filename_ofs_pos; + } + + public long getDecl_strings_ofs_pos() { + return decl_strings_ofs_pos; + } + + public long getType_fonts_ofs_pos() { + return type_fonts_ofs_pos; + } + + /** + * Updates all addresses by inserting gap + * + * @param pos Position to insert bytes + * @param size Number of bytes + */ + public void insertGapAfter(long pos, long size) { + for (Field f : IggyFlashHeader64.class.getDeclaredFields()) { + if (f.getName().endsWith("_address")) { + try { + long val = f.getLong(this); + if (val > pos) { + long newval = val + size; + f.setLong(this, newval); + } + } catch (IllegalAccessException iex) { + //should not happen + } + } + } + } + + public long getImported_guid() { + return imported_guid; + } + + public long getBaseAddress() { + return base_address; + } + + public long getSequenceEndAddress() { + return sequence_end_address; + } + + public long getFontEndAddress() { + return font_end_address; + } + + public void setFontEndAddress(long val) { + this.font_end_address = val; + } + + public long getSequenceStartAddress1() { + return sequence_start_address1; + } + + public long getSequenceStartAddress2() { + return sequence_start_address2; + } + + public long getSequenceStartAddress3() { + return sequence_start_address3; + } + + public long getNamesAddress() { + return names_address; + } + + public long getUnk78Address() { + return unk78_address; + } + + public long getLastSectionAddress() { + return last_section_address; + } + + public long getFlashFilenameAddress() { + return flash_filename_address; + } + + public long getDeclStringsAddress() { + return decl_strings_address; + } + + public long getTypeFontsAddress() { + return type_fonts_address; + } + + @Override + public void readFromDataStream(ReadDataStreamInterface stream) throws IOException { + base_ofs_pos = stream.position(); + off_base = stream.readUI64(); + base_address = off_base == 1 ? 0 : off_base + stream.position() - 8; + + sequence_end_ofs_pos = stream.position(); + off_sequence_end = stream.readUI64(); + sequence_end_address = off_sequence_end == 1 ? 0 : off_sequence_end + stream.position() - 8; + + font_end_ofs_pos = stream.position(); + off_font_end = stream.readUI64(); + font_end_address = off_font_end == 1 ? 0 : off_font_end + stream.position() - 8; + + sequence_start1_ofs_pos = stream.position(); + off_sequence_start1 = stream.readUI64(); + sequence_start_address1 = off_sequence_start1 == 1 ? 0 : off_sequence_start1 + stream.position() - 8; + + sequence_start2_ofs_pos = stream.position(); + off_sequence_start2 = stream.readUI64(); + sequence_start_address2 = off_sequence_start2 == 1 ? 0 : off_sequence_start2 + stream.position() - 8; + + sequence_start3_ofs_pos = stream.position(); + off_sequence_start3 = stream.readUI64(); + sequence_start_address3 = off_sequence_start3 == 1 ? 0 : off_sequence_start3 + stream.position() - 8; + + xmin = stream.readUI32(); + ymin = stream.readUI32(); + xmax = stream.readUI32(); + ymax = stream.readUI32(); + + unk_40 = stream.readUI32(); // probably number of blocks/objects after header + unk_44 = stream.readUI32(); + unk_48 = stream.readUI32(); + unk_4C = stream.readUI32(); + unk_50 = stream.readUI32(); + unk_54 = stream.readUI32(); + frame_rate = stream.readFloat(); + unk_5C = stream.readUI32(); + imported_guid = stream.readUI64(); + my_guid = stream.readUI64(); + + names_ofs_pos = stream.position(); + off_names = stream.readUI64(); + names_address = off_names == 1 ? 0 : off_names + stream.position() - 8; + + unk78_ofs_pos = stream.position(); + off_unk78 = stream.readUI64(); + unk78_address = off_unk78 == 1 ? 0 : off_unk78 + stream.position() - 8; + + unk80 = stream.readUI64(); //Maybe number of imports/names pointed by names_offset + + last_section_ofs_pos = stream.position(); + off_last_section = stream.readUI64(); + last_section_address = off_last_section == 1 ? 0 : off_last_section + stream.position() - 8; + + flash_filename_ofs_pos = stream.position(); + off_flash_filename = stream.readUI64(); + flash_filename_address = off_flash_filename == 1 ? 0 : off_flash_filename + stream.position() - 8; + + decl_strings_ofs_pos = stream.position(); + off_decl_strings = stream.readUI64(); //relative offset to as3 code (16 bytes header + abc blob) + decl_strings_address = off_decl_strings == 1 ? 0 : off_decl_strings + stream.position() - 8; + + type_fonts_ofs_pos = stream.position(); + off_type_of_fonts = stream.readUI64(); //relative offset to as3 file names table (or classes names or whatever) + type_fonts_address = off_type_of_fonts == 1 ? 0 : off_type_of_fonts + stream.position() - 8; + + flags = stream.readUI64(); + font_count = stream.readUI32(); + zero2 = stream.readUI32(); + } + + @Override + public void writeToDataStream(WriteDataStreamInterface stream) throws IOException { + off_base = base_address == 0 ? 1 : base_address - stream.position(); + stream.writeUI64(off_base); + off_sequence_end = sequence_end_address == 0 ? 1 : sequence_end_address - stream.position(); + stream.writeUI64(off_sequence_end); + off_font_end = font_end_address == 0 ? 1 : font_end_address - stream.position(); + stream.writeUI64(off_font_end); + off_sequence_start1 = sequence_start_address1 == 0 ? 1 : sequence_start_address1 - stream.position(); + stream.writeUI64(off_sequence_start1); + off_sequence_start2 = sequence_start_address2 == 0 ? 1 : sequence_start_address2 - stream.position(); + stream.writeUI64(off_sequence_start2); + off_sequence_start3 = sequence_start_address3 == 0 ? 1 : sequence_start_address3 - stream.position(); + stream.writeUI64(off_sequence_start3); + stream.writeUI32(xmin); + stream.writeUI32(ymin); + stream.writeUI32(xmax); + stream.writeUI32(ymax); + stream.writeUI32(unk_40); + stream.writeUI32(unk_44); + stream.writeUI32(unk_48); + stream.writeUI32(unk_4C); + stream.writeUI32(unk_50); + stream.writeUI32(unk_54); + stream.writeFloat(frame_rate); + stream.writeUI32(unk_5C); + stream.writeUI64(imported_guid); + stream.writeUI64(my_guid); + off_names = names_address == 0 ? 1 : names_address - stream.position(); + stream.writeUI64(off_names); + off_unk78 = unk78_address == 0 ? 1 : unk78_address - stream.position(); + stream.writeUI64(off_unk78); + stream.writeUI64(unk80); + off_last_section = last_section_address == 0 ? 1 : last_section_address - stream.position(); + stream.writeUI64(off_last_section); + off_flash_filename = flash_filename_address == 0 ? 1 : flash_filename_address - stream.position(); + stream.writeUI64(off_flash_filename); + off_decl_strings = decl_strings_address == 0 ? 1 : decl_strings_address - stream.position(); + stream.writeUI64(off_decl_strings); + off_type_of_fonts = type_fonts_address == 0 ? 1 : type_fonts_address - stream.position(); + stream.writeUI64(off_type_of_fonts); + stream.writeUI64(flags); + stream.writeUI32(font_count); + stream.writeUI32(zero2); + + stream.getIndexing().writeLengthCustom(184, new int[]{0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x34, 0x38, 0x3C, 0x40, 0x44, 0x48, 0x4C, 0x50, 0x58, 0x70, 0x78, 0x80, 0x84, 0x88, 0x90, 0x98, 0xA0, 0xB0}, new int[]{2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 5, 5, 2, 2, 2, 2, 5}); + + } + + @Override + public String toString() { + return FieldPrinter.getObjectSummary(this); + } + + @Override + public long getXMin() { + return xmin; + } + + @Override + public long getYMin() { + return ymin; + } + + @Override + public long getXMax() { + return xmax; + } + + @Override + public long getYMax() { + return ymax; + } + + @Override + public float getFrameRate() { + return frame_rate; + } + +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFlashHeaderInterface.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFlashHeaderInterface.java index 42dabf338..6ee44627a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFlashHeaderInterface.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFlashHeaderInterface.java @@ -1,20 +1,20 @@ -package com.jpexs.decompiler.flash.iggy; - -import com.jpexs.decompiler.flash.iggy.streams.StructureInterface; - -/** - * - * @author JPEXS - */ -public interface IggyFlashHeaderInterface extends StructureInterface { - - public long getXMin(); - - public long getYMin(); - - public long getXMax(); - - public long getYMax(); - - public float getFrameRate(); -} +package com.jpexs.decompiler.flash.iggy; + +import com.jpexs.decompiler.flash.iggy.streams.StructureInterface; + +/** + * + * @author JPEXS + */ +public interface IggyFlashHeaderInterface extends StructureInterface { + + public long getXMin(); + + public long getYMin(); + + public long getXMax(); + + public long getYMax(); + + public float getFrameRate(); +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFont.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFont.java index 978d05c8e..56242af73 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFont.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFont.java @@ -1,608 +1,608 @@ -package com.jpexs.decompiler.flash.iggy; - -import com.jpexs.decompiler.flash.iggy.annotations.IggyArrayFieldType; -import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType; -import com.jpexs.decompiler.flash.iggy.streams.IggyIndexBuilder; -import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface; -import com.jpexs.decompiler.flash.iggy.streams.SeekMode; -import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -/** - * - * @author JPEXS - */ -public class IggyFont extends IggyTag { - - public static final int ID = 0xFF16; - - @IggyFieldType(DataType.uint16_t) - int type; //stejny pro rozdilne fonty - @IggyFieldType(DataType.uint16_t) - int fontId; - @IggyArrayFieldType(value = DataType.uint8_t, count = 28) - byte[] zeroone; // stejny pro rozdilne fonty - @IggyFieldType(DataType.uint16_t) - int char_count2; - @IggyFieldType(value = DataType.uint16_t) - int ascent; - @IggyFieldType(value = DataType.uint16_t) - int descent; - @IggyFieldType(value = DataType.uint16_t) - int leading; - @IggyFieldType(DataType.uint64_t) - long flags; - //@IggyFieldType(DataType.uint64_t) - //long start_of_char_struct; - //@IggyFieldType(DataType.uint64_t) - //long start_of_char_index; - //@IggyFieldType(DataType.uint64_t) - //long start_of_scale; - @IggyFieldType(DataType.uint32_t) - long kern_count; - @IggyArrayFieldType(value = DataType.float_t, count = 5) - float[] unk_float; - //@IggyFieldType(DataType.uint64_t) - //long start_of_kern; - @IggyFieldType(DataType.uint64_t) - long zero_padd; - @IggyFieldType(DataType.uint64_t) - long what_2; - @IggyFieldType(DataType.uint64_t) - long zero_padd_2; - //@IggyFieldType(DataType.uint64_t) - //long start_of_name; - @IggyFieldType(DataType.uint64_t) - long one_padd; - @IggyFieldType(DataType.uint16_t) - int xscale; - @IggyFieldType(DataType.uint16_t) - int yscale; - @IggyFieldType(DataType.uint64_t) - long zero_padd_3; - @IggyFieldType(DataType.float_t) - float ssr1; - @IggyFieldType(DataType.float_t) - float ssr2; - @IggyFieldType(DataType.uint32_t) - long char_count; - @IggyFieldType(DataType.uint64_t) - long zero_padd_4; - @IggyFieldType(DataType.uint64_t) - long what_3; - @IggyFieldType(value = DataType.wchar_t, count = 40) - String subName = ""; - @IggyFieldType(value = DataType.uint8_t, count = 48) - byte[] zeroes48a; - - @IggyFieldType(value = DataType.uint8_t, count = 48) - byte[] zeroes48b; - - @IggyFieldType(DataType.float_t) - float sss1; - @IggyFieldType(DataType.uint32_t) - long one_padd2; - @IggyFieldType(DataType.float_t) - float sss2; - @IggyFieldType(DataType.uint32_t) - long one_padd3; - @IggyFieldType(DataType.float_t) - float sss3; - @IggyFieldType(DataType.uint32_t) - long one_padd4; - @IggyFieldType(DataType.float_t) - float sss4; - @IggyFieldType(DataType.uint32_t) - long one_padd5; - - @IggyFieldType(value = DataType.wchar_t, count = 16) - String name; - - List charOffsets; - List glyphs; - IggyCharIndices codePoints; - IggyCharAdvances charScales; - IggyCharKerning charKernings; - - public IggyFont(int type, int fontId, byte[] zeroone, int char_count2, int ascent, int descent, int leading, long flags, long kern_count, float[] unk_float, long zero_padd, long what_2, long zero_padd_2, long one_padd, int xscale, int yscale, long zero_padd_3, float ssr1, float ssr2, long char_count, long zero_padd_4, long what_3, byte[] zeroes48a, byte[] zeroes48b, float sss1, long one_padd2, float sss2, long one_padd3, float sss3, long one_padd4, float sss4, long one_padd5, String name, List charOffsets, List glyphs, IggyCharIndices codePoints, IggyCharAdvances charScales, IggyCharKerning charKernings) { - this.type = type; - this.fontId = fontId; - this.zeroone = zeroone; - this.char_count2 = char_count2; - this.ascent = ascent; - this.descent = descent; - this.leading = leading; - this.flags = flags; - this.kern_count = kern_count; - this.unk_float = unk_float; - this.zero_padd = zero_padd; - this.what_2 = what_2; - this.zero_padd_2 = zero_padd_2; - this.one_padd = one_padd; - this.xscale = xscale; - this.yscale = yscale; - this.zero_padd_3 = zero_padd_3; - this.ssr1 = ssr1; - this.ssr2 = ssr2; - this.char_count = char_count; - this.zero_padd_4 = zero_padd_4; - this.what_3 = what_3; - this.zeroes48a = zeroes48a; - this.zeroes48b = zeroes48b; - this.sss1 = sss1; - this.one_padd2 = one_padd2; - this.sss2 = sss2; - this.one_padd3 = one_padd3; - this.sss3 = sss3; - this.one_padd4 = one_padd4; - this.sss4 = sss4; - this.one_padd5 = one_padd5; - this.name = name; - this.charOffsets = charOffsets; - this.glyphs = glyphs; - this.codePoints = codePoints; - this.charScales = charScales; - this.charKernings = charKernings; - } - - public IggyFont(ReadDataStreamInterface stream) throws IOException { - readFromDataStream(stream); - } - - private long readAbsoluteOffset(ReadDataStreamInterface stream) throws IOException { - long offset = stream.readUI64(); - if (offset == 1) { - return 0; - } - return stream.position() - 8 + offset; - } - - private void writeAbsoluteOffset(WriteDataStreamInterface stream, long offset) throws IOException { - if (offset == 0) { - stream.writeUI64(1); - } else { - stream.writeUI64(offset - stream.position()); - } - } - - private void writeRelativeOffset(WriteDataStreamInterface stream, long offset) throws IOException { - if (offset == 0) { - stream.writeUI64(1); - } else { - stream.writeUI64(offset); - } - } - - private long makeAbsOffset(ReadDataStreamInterface s, long offset) { - return offset == 1 ? 0 : offset + s.position() - 8; - } - - private long makeAbsOffset(WriteDataStreamInterface s, long offset) { - return offset == 1 ? 0 : offset + s.position() - 8; - } - - @Override - public void readFromDataStream(ReadDataStreamInterface s) throws IOException { - type = s.readUI16(); - fontId = s.readUI16(); - zeroone = s.readBytes(28); - char_count2 = s.readUI16(); - ascent = s.readUI16(); - descent = s.readUI16(); - leading = s.readUI16(); - flags = s.readUI64(); - long start_of_char_struct = s.readUI64(); - long abs_start_of_char_struct = makeAbsOffset(s, start_of_char_struct); - long start_of_char_index = s.readUI64(); - long abs_start_of_char_index = makeAbsOffset(s, start_of_char_index); - long start_of_scale = s.readUI64(); - long abs_start_of_scale = makeAbsOffset(s, start_of_scale); - - kern_count = s.readUI32(); - unk_float = new float[5]; - for (int i = 0; i < unk_float.length; i++) { - unk_float[i] = s.readFloat(); - } - long start_of_kern = s.readUI64(); - long abs_start_of_kern = makeAbsOffset(s, start_of_kern); - zero_padd = s.readUI64(); - - //-------------------------------------- - what_2 = s.readUI64(); - zero_padd_2 = s.readUI64(); - long start_of_name = s.readUI64(); - long abs_start_of_name = makeAbsOffset(s, start_of_name); - one_padd = s.readUI64(); - xscale = s.readUI16(); - yscale = s.readUI16(); - zero_padd_3 = s.readUI64(); - ssr1 = s.readFloat(); - ssr2 = s.readFloat(); - char_count = s.readUI32(); - zero_padd_4 = s.readUI64(); - what_3 = s.readUI64(); - StringBuilder subNameBuilder = new StringBuilder(); - - boolean snFinish = false; - for (int i = 0; i < 20; i++) { - char c = (char) s.readUI16(); - if (c == '\0') { - snFinish = true; - } - if (!snFinish) { - subNameBuilder.append(c); - } - } - subName = subNameBuilder.toString(); - zeroes48a = s.readBytes(48); - - sss1 = s.readFloat(); - one_padd2 = s.readUI32(); - sss2 = s.readFloat(); - one_padd3 = s.readUI32(); - sss3 = s.readFloat(); - one_padd4 = s.readUI32(); - sss4 = s.readFloat(); - one_padd5 = s.readUI32(); - zeroes48b = s.readBytes(48); - - if (abs_start_of_name != 0) { - //here is offset [5] - 1096 - s.seek(abs_start_of_name, SeekMode.SET); - name = s.readWChar(); - //here is offset [6] - 1130 - s.pad8bytes(); - } - if (abs_start_of_char_struct != 0) { - //here is offset [7] - 1136 - s.seek(abs_start_of_char_struct, SeekMode.SET); - charOffsets = new ArrayList<>(); - List charAddresses = new ArrayList<>(); - for (int i = 0; i < char_count; i++) { - IggyCharOffset iggyOffset = new IggyCharOffset(s); - charOffsets.add(iggyOffset); - if (iggyOffset.offset == 1) { - charAddresses.add(0L); - } else { - charAddresses.add(iggyOffset.offset + s.position() - 8); - } - } - glyphs = new ArrayList<>(); - for (int i = 0; i < char_count; i++) { - long addr = charAddresses.get(i); - if (addr != 0) { - s.seek(addr, SeekMode.SET); - glyphs.add(new IggyShape(s)); - } else { - glyphs.add(null); - } - } - } - if (abs_start_of_char_index != 0) { - s.seek(abs_start_of_char_index, SeekMode.SET); - codePoints = new IggyCharIndices(s, char_count); - } - if (abs_start_of_scale != 0) { - s.seek(abs_start_of_scale, SeekMode.SET); - charScales = new IggyCharAdvances(s, char_count); - } - if (abs_start_of_kern != 0) { - s.seek(abs_start_of_kern, SeekMode.SET); - charKernings = new IggyCharKerning(s, kern_count); - } - } - - @Override - public void writeToDataStream(WriteDataStreamInterface s) throws IOException { - final int FILL_LATER_IF_AVAILABLE = 1; - IggyIndexBuilder ib = s.getIndexing(); - ib.writeConstLength(IggyIndexBuilder.CONST_GENERAL_FONT_INFO_SIZE); - s.writeUI16(type); - s.writeUI16(fontId); - s.writeBytes(zeroone); - s.writeUI16(char_count2); - s.writeUI16(ascent); - s.writeUI16(descent); - s.writeUI16(leading); - s.writeUI64(flags); - long start_of_char_struct_ofs_pos = s.position(); - s.writeUI64(FILL_LATER_IF_AVAILABLE); - long start_of_char_index_ofs_pos = s.position(); - s.writeUI64(FILL_LATER_IF_AVAILABLE); - long start_of_scale_ofs_pos = s.position(); - s.writeUI64(FILL_LATER_IF_AVAILABLE); - s.writeUI32(kern_count); - for (int i = 0; i < unk_float.length; i++) { - s.writeFloat(unk_float[i]); - } - long start_of_kern_ofs_pos = s.position(); - s.writeUI64(FILL_LATER_IF_AVAILABLE); - s.writeUI64(zero_padd); - ib.writeConstLength(IggyIndexBuilder.CONST_GENERAL_FONT_INFO2_SIZE); - s.writeUI64(what_2); - s.writeUI64(zero_padd_2); - long start_of_name_ofs_pos = s.position(); - s.writeUI64(FILL_LATER_IF_AVAILABLE); - s.writeUI64(one_padd); - s.writeUI16(xscale); - s.writeUI16(yscale); - s.writeUI64(zero_padd_3); - s.writeFloat(ssr1); - s.writeFloat(ssr2); - s.writeUI32(char_count); - s.writeUI64(zero_padd_4); - s.writeUI64(what_3); - for (int i = 0; i < 20; i++) { - if (i < subName.length()) { - s.writeUI16((char) subName.charAt(i)); - } else { - s.writeUI16(0); - } - } - s.writeBytes(zeroes48a); - s.writeFloat(sss1); - s.writeUI32(one_padd2); - s.writeFloat(sss2); - s.writeUI32(one_padd3); - s.writeFloat(sss3); - s.writeUI32(one_padd4); - s.writeFloat(sss4); - s.writeUI32(one_padd5); - s.writeBytes(zeroes48b); - if (name != null) { - s.setOlderOffsetToThisPos(start_of_name_ofs_pos); - for (char c : name.toCharArray()) { - s.writeUI16(c); - } - s.writeUI16(0); - - //align to 8 bytes boundary - int len = name.length() * 2 + 2; - - ib.write16bitArray(name.length() + 1); - ib.pad8bytes(); - int pad8 = 8 - (len % 8); - if (pad8 < 8) { - for (int i = 0; i < pad8; i++) { - s.write(0); - } - } - } - - //s.writeUI64(0); //pad zero - if (charOffsets != null) { - s.setOlderOffsetToThisPos(start_of_char_struct_ofs_pos); - - ib.writeConstLengthArray(IggyIndexBuilder.CONST_CHAR_OFFSET_SIZE, charOffsets.size()); - - List toFixOffsets = new ArrayList<>(); - //offsets of shapes - for (IggyCharOffset ofs : charOffsets) { - ofs.offset = FILL_LATER_IF_AVAILABLE; - ofs.writeToDataStream(s); - toFixOffsets.add(s.position() - 8); - } - for (int i = 0; i < glyphs.size(); i++) { - IggyShape shp = glyphs.get(i); - if (shp != null) { - s.setOlderOffsetToThisPos(toFixOffsets.get(i)); - shp.writeToDataStream(s); - } - } - } - if (codePoints != null) { - s.setOlderOffsetToThisPos(start_of_char_index_ofs_pos); - for (char c : codePoints.chars) { - s.writeUI16(c); - } - ib.write16bitArray(codePoints.chars.size()); - ib.pad8bytes(); - s.pad8bytes(); - } - if (charScales != null) { - s.setOlderOffsetToThisPos(start_of_scale_ofs_pos); - charScales.writeToDataStream(s); - ib.write32bitArray(charScales.advances.size()); - ib.pad8bytes(); - s.pad8bytes(); - } - if (charKernings != null) { - s.setOlderOffsetToThisPos(start_of_kern_ofs_pos); - ib.writeConstLengthArray(IggyIndexBuilder.CONST_KERNING_RECORD_SIZE, kern_count); - charKernings.writeToDataStream(s); - ib.pad8bytes(); - s.pad8bytes(); - } - - /*if ((s.position() - abs_start_of_char_index) % 8 != 0) { - byte padd[] = new byte[(int) (((s.position() - abs_start_of_char_index) / 8 + 1) * 8 - (s.position() - abs_start_of_char_index))]; - s.writeBytes(padd); - } - ib.writePaddingTo8(s.position());*/ - } - - public int getType() { - return type; - } - - public long getFlags() { - return flags; - } - - public int getXscale() { - return xscale; - } - - public int getYscale() { - return yscale; - } - - public long getCharacterCount() { - return char_count; - } - - public String getName() { - return name; - } - - public List getChars() { - return glyphs; - } - - public IggyCharIndices getCharIndices() { - return codePoints; - } - - public IggyCharAdvances getCharAdvances() { - return charScales; - } - - public IggyCharKerning getCharKernings() { - return charKernings; - } - - public float[] getUnk_float() { - return unk_float; - } - - public int getAscent() { - return ascent; - } - - public int getDescent() { - return descent; - } - - public int getLeading() { - return leading; - } - - public long getWhat_2() { - return what_2; - } - - public long getWhat_3() { - return what_3; - } - - public List getCharOffsets() { - return charOffsets; - } - - @Override - public int getTagType() { - return ID; - } - - @Override - public String toString() { - return String.format("IggyFontTag (%04X)", ID); - } - - public void setType(int type) { - this.type = type; - } - - public void setFontId(int fontId) { - this.fontId = fontId; - } - - public void setCharCount2(int char_count2) { - this.char_count2 = char_count2; - } - - public void setAscent(int ascent) { - this.ascent = ascent; - } - - public void setDescent(int descent) { - this.descent = descent; - } - - public void setLeading(int leading) { - this.leading = leading; - } - - public void setFlags(long flags) { - this.flags = flags; - } - - public void setUnkFloat(float[] unk_float) { - this.unk_float = unk_float; - } - - public void setWhat2(long what_2) { - this.what_2 = what_2; - } - - public void setXScale(int xscale) { - this.xscale = xscale; - } - - public void setYScale(int yscale) { - this.yscale = yscale; - } - - public void setSsr1(float ssr1) { - this.ssr1 = ssr1; - } - - public void setSsr2(float ssr2) { - this.ssr2 = ssr2; - } - - public void setCharCount(long char_count) { - this.char_count = char_count; - } - - public void setWhat3(long what_3) { - this.what_3 = what_3; - } - - public void setSubName(String subName) { - this.subName = subName; - } - - public void setSss1(float sss1) { - this.sss1 = sss1; - } - - public void setSss2(float sss2) { - this.sss2 = sss2; - } - - public void setSss3(float sss3) { - this.sss3 = sss3; - } - - public void setSss4(float sss4) { - this.sss4 = sss4; - } - - public void setName(String name) { - this.name = name; - } - - public void setCharOffsets(List charOffsets) { - this.charOffsets = charOffsets; - } - - public void setGlyphs(List glyphs) { - this.glyphs = glyphs; - } - - public void setCodePoints(IggyCharIndices codePoints) { - this.codePoints = codePoints; - } - - public void setCharScales(IggyCharAdvances charScales) { - this.charScales = charScales; - } - - public void setCharKernings(IggyCharKerning charKernings) { - this.charKernings = charKernings; - } - -} +package com.jpexs.decompiler.flash.iggy; + +import com.jpexs.decompiler.flash.iggy.annotations.IggyArrayFieldType; +import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType; +import com.jpexs.decompiler.flash.iggy.streams.IggyIndexBuilder; +import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface; +import com.jpexs.decompiler.flash.iggy.streams.SeekMode; +import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author JPEXS + */ +public class IggyFont extends IggyTag { + + public static final int ID = 0xFF16; + + @IggyFieldType(DataType.uint16_t) + int type; //stejny pro rozdilne fonty + @IggyFieldType(DataType.uint16_t) + int fontId; + @IggyArrayFieldType(value = DataType.uint8_t, count = 28) + byte[] zeroone; // stejny pro rozdilne fonty + @IggyFieldType(DataType.uint16_t) + int char_count2; + @IggyFieldType(value = DataType.uint16_t) + int ascent; + @IggyFieldType(value = DataType.uint16_t) + int descent; + @IggyFieldType(value = DataType.uint16_t) + int leading; + @IggyFieldType(DataType.uint64_t) + long flags; + //@IggyFieldType(DataType.uint64_t) + //long start_of_char_struct; + //@IggyFieldType(DataType.uint64_t) + //long start_of_char_index; + //@IggyFieldType(DataType.uint64_t) + //long start_of_scale; + @IggyFieldType(DataType.uint32_t) + long kern_count; + @IggyArrayFieldType(value = DataType.float_t, count = 5) + float[] unk_float; + //@IggyFieldType(DataType.uint64_t) + //long start_of_kern; + @IggyFieldType(DataType.uint64_t) + long zero_padd; + @IggyFieldType(DataType.uint64_t) + long what_2; + @IggyFieldType(DataType.uint64_t) + long zero_padd_2; + //@IggyFieldType(DataType.uint64_t) + //long start_of_name; + @IggyFieldType(DataType.uint64_t) + long one_padd; + @IggyFieldType(DataType.uint16_t) + int xscale; + @IggyFieldType(DataType.uint16_t) + int yscale; + @IggyFieldType(DataType.uint64_t) + long zero_padd_3; + @IggyFieldType(DataType.float_t) + float ssr1; + @IggyFieldType(DataType.float_t) + float ssr2; + @IggyFieldType(DataType.uint32_t) + long char_count; + @IggyFieldType(DataType.uint64_t) + long zero_padd_4; + @IggyFieldType(DataType.uint64_t) + long what_3; + @IggyFieldType(value = DataType.wchar_t, count = 40) + String subName = ""; + @IggyFieldType(value = DataType.uint8_t, count = 48) + byte[] zeroes48a; + + @IggyFieldType(value = DataType.uint8_t, count = 48) + byte[] zeroes48b; + + @IggyFieldType(DataType.float_t) + float sss1; + @IggyFieldType(DataType.uint32_t) + long one_padd2; + @IggyFieldType(DataType.float_t) + float sss2; + @IggyFieldType(DataType.uint32_t) + long one_padd3; + @IggyFieldType(DataType.float_t) + float sss3; + @IggyFieldType(DataType.uint32_t) + long one_padd4; + @IggyFieldType(DataType.float_t) + float sss4; + @IggyFieldType(DataType.uint32_t) + long one_padd5; + + @IggyFieldType(value = DataType.wchar_t, count = 16) + String name; + + List charOffsets; + List glyphs; + IggyCharIndices codePoints; + IggyCharAdvances charScales; + IggyCharKerning charKernings; + + public IggyFont(int type, int fontId, byte[] zeroone, int char_count2, int ascent, int descent, int leading, long flags, long kern_count, float[] unk_float, long zero_padd, long what_2, long zero_padd_2, long one_padd, int xscale, int yscale, long zero_padd_3, float ssr1, float ssr2, long char_count, long zero_padd_4, long what_3, byte[] zeroes48a, byte[] zeroes48b, float sss1, long one_padd2, float sss2, long one_padd3, float sss3, long one_padd4, float sss4, long one_padd5, String name, List charOffsets, List glyphs, IggyCharIndices codePoints, IggyCharAdvances charScales, IggyCharKerning charKernings) { + this.type = type; + this.fontId = fontId; + this.zeroone = zeroone; + this.char_count2 = char_count2; + this.ascent = ascent; + this.descent = descent; + this.leading = leading; + this.flags = flags; + this.kern_count = kern_count; + this.unk_float = unk_float; + this.zero_padd = zero_padd; + this.what_2 = what_2; + this.zero_padd_2 = zero_padd_2; + this.one_padd = one_padd; + this.xscale = xscale; + this.yscale = yscale; + this.zero_padd_3 = zero_padd_3; + this.ssr1 = ssr1; + this.ssr2 = ssr2; + this.char_count = char_count; + this.zero_padd_4 = zero_padd_4; + this.what_3 = what_3; + this.zeroes48a = zeroes48a; + this.zeroes48b = zeroes48b; + this.sss1 = sss1; + this.one_padd2 = one_padd2; + this.sss2 = sss2; + this.one_padd3 = one_padd3; + this.sss3 = sss3; + this.one_padd4 = one_padd4; + this.sss4 = sss4; + this.one_padd5 = one_padd5; + this.name = name; + this.charOffsets = charOffsets; + this.glyphs = glyphs; + this.codePoints = codePoints; + this.charScales = charScales; + this.charKernings = charKernings; + } + + public IggyFont(ReadDataStreamInterface stream) throws IOException { + readFromDataStream(stream); + } + + private long readAbsoluteOffset(ReadDataStreamInterface stream) throws IOException { + long offset = stream.readUI64(); + if (offset == 1) { + return 0; + } + return stream.position() - 8 + offset; + } + + private void writeAbsoluteOffset(WriteDataStreamInterface stream, long offset) throws IOException { + if (offset == 0) { + stream.writeUI64(1); + } else { + stream.writeUI64(offset - stream.position()); + } + } + + private void writeRelativeOffset(WriteDataStreamInterface stream, long offset) throws IOException { + if (offset == 0) { + stream.writeUI64(1); + } else { + stream.writeUI64(offset); + } + } + + private long makeAbsOffset(ReadDataStreamInterface s, long offset) { + return offset == 1 ? 0 : offset + s.position() - 8; + } + + private long makeAbsOffset(WriteDataStreamInterface s, long offset) { + return offset == 1 ? 0 : offset + s.position() - 8; + } + + @Override + public void readFromDataStream(ReadDataStreamInterface s) throws IOException { + type = s.readUI16(); + fontId = s.readUI16(); + zeroone = s.readBytes(28); + char_count2 = s.readUI16(); + ascent = s.readUI16(); + descent = s.readUI16(); + leading = s.readUI16(); + flags = s.readUI64(); + long start_of_char_struct = s.readUI64(); + long abs_start_of_char_struct = makeAbsOffset(s, start_of_char_struct); + long start_of_char_index = s.readUI64(); + long abs_start_of_char_index = makeAbsOffset(s, start_of_char_index); + long start_of_scale = s.readUI64(); + long abs_start_of_scale = makeAbsOffset(s, start_of_scale); + + kern_count = s.readUI32(); + unk_float = new float[5]; + for (int i = 0; i < unk_float.length; i++) { + unk_float[i] = s.readFloat(); + } + long start_of_kern = s.readUI64(); + long abs_start_of_kern = makeAbsOffset(s, start_of_kern); + zero_padd = s.readUI64(); + + //-------------------------------------- + what_2 = s.readUI64(); + zero_padd_2 = s.readUI64(); + long start_of_name = s.readUI64(); + long abs_start_of_name = makeAbsOffset(s, start_of_name); + one_padd = s.readUI64(); + xscale = s.readUI16(); + yscale = s.readUI16(); + zero_padd_3 = s.readUI64(); + ssr1 = s.readFloat(); + ssr2 = s.readFloat(); + char_count = s.readUI32(); + zero_padd_4 = s.readUI64(); + what_3 = s.readUI64(); + StringBuilder subNameBuilder = new StringBuilder(); + + boolean snFinish = false; + for (int i = 0; i < 20; i++) { + char c = (char) s.readUI16(); + if (c == '\0') { + snFinish = true; + } + if (!snFinish) { + subNameBuilder.append(c); + } + } + subName = subNameBuilder.toString(); + zeroes48a = s.readBytes(48); + + sss1 = s.readFloat(); + one_padd2 = s.readUI32(); + sss2 = s.readFloat(); + one_padd3 = s.readUI32(); + sss3 = s.readFloat(); + one_padd4 = s.readUI32(); + sss4 = s.readFloat(); + one_padd5 = s.readUI32(); + zeroes48b = s.readBytes(48); + + if (abs_start_of_name != 0) { + //here is offset [5] - 1096 + s.seek(abs_start_of_name, SeekMode.SET); + name = s.readWChar(); + //here is offset [6] - 1130 + s.pad8bytes(); + } + if (abs_start_of_char_struct != 0) { + //here is offset [7] - 1136 + s.seek(abs_start_of_char_struct, SeekMode.SET); + charOffsets = new ArrayList<>(); + List charAddresses = new ArrayList<>(); + for (int i = 0; i < char_count; i++) { + IggyCharOffset iggyOffset = new IggyCharOffset(s); + charOffsets.add(iggyOffset); + if (iggyOffset.offset == 1) { + charAddresses.add(0L); + } else { + charAddresses.add(iggyOffset.offset + s.position() - 8); + } + } + glyphs = new ArrayList<>(); + for (int i = 0; i < char_count; i++) { + long addr = charAddresses.get(i); + if (addr != 0) { + s.seek(addr, SeekMode.SET); + glyphs.add(new IggyShape(s)); + } else { + glyphs.add(null); + } + } + } + if (abs_start_of_char_index != 0) { + s.seek(abs_start_of_char_index, SeekMode.SET); + codePoints = new IggyCharIndices(s, char_count); + } + if (abs_start_of_scale != 0) { + s.seek(abs_start_of_scale, SeekMode.SET); + charScales = new IggyCharAdvances(s, char_count); + } + if (abs_start_of_kern != 0) { + s.seek(abs_start_of_kern, SeekMode.SET); + charKernings = new IggyCharKerning(s, kern_count); + } + } + + @Override + public void writeToDataStream(WriteDataStreamInterface s) throws IOException { + final int FILL_LATER_IF_AVAILABLE = 1; + IggyIndexBuilder ib = s.getIndexing(); + ib.writeConstLength(IggyIndexBuilder.CONST_GENERAL_FONT_INFO_SIZE); + s.writeUI16(type); + s.writeUI16(fontId); + s.writeBytes(zeroone); + s.writeUI16(char_count2); + s.writeUI16(ascent); + s.writeUI16(descent); + s.writeUI16(leading); + s.writeUI64(flags); + long start_of_char_struct_ofs_pos = s.position(); + s.writeUI64(FILL_LATER_IF_AVAILABLE); + long start_of_char_index_ofs_pos = s.position(); + s.writeUI64(FILL_LATER_IF_AVAILABLE); + long start_of_scale_ofs_pos = s.position(); + s.writeUI64(FILL_LATER_IF_AVAILABLE); + s.writeUI32(kern_count); + for (int i = 0; i < unk_float.length; i++) { + s.writeFloat(unk_float[i]); + } + long start_of_kern_ofs_pos = s.position(); + s.writeUI64(FILL_LATER_IF_AVAILABLE); + s.writeUI64(zero_padd); + ib.writeConstLength(IggyIndexBuilder.CONST_GENERAL_FONT_INFO2_SIZE); + s.writeUI64(what_2); + s.writeUI64(zero_padd_2); + long start_of_name_ofs_pos = s.position(); + s.writeUI64(FILL_LATER_IF_AVAILABLE); + s.writeUI64(one_padd); + s.writeUI16(xscale); + s.writeUI16(yscale); + s.writeUI64(zero_padd_3); + s.writeFloat(ssr1); + s.writeFloat(ssr2); + s.writeUI32(char_count); + s.writeUI64(zero_padd_4); + s.writeUI64(what_3); + for (int i = 0; i < 20; i++) { + if (i < subName.length()) { + s.writeUI16((char) subName.charAt(i)); + } else { + s.writeUI16(0); + } + } + s.writeBytes(zeroes48a); + s.writeFloat(sss1); + s.writeUI32(one_padd2); + s.writeFloat(sss2); + s.writeUI32(one_padd3); + s.writeFloat(sss3); + s.writeUI32(one_padd4); + s.writeFloat(sss4); + s.writeUI32(one_padd5); + s.writeBytes(zeroes48b); + if (name != null) { + s.setOlderOffsetToThisPos(start_of_name_ofs_pos); + for (char c : name.toCharArray()) { + s.writeUI16(c); + } + s.writeUI16(0); + + //align to 8 bytes boundary + int len = name.length() * 2 + 2; + + ib.write16bitArray(name.length() + 1); + ib.pad8bytes(); + int pad8 = 8 - (len % 8); + if (pad8 < 8) { + for (int i = 0; i < pad8; i++) { + s.write(0); + } + } + } + + //s.writeUI64(0); //pad zero + if (charOffsets != null) { + s.setOlderOffsetToThisPos(start_of_char_struct_ofs_pos); + + ib.writeConstLengthArray(IggyIndexBuilder.CONST_CHAR_OFFSET_SIZE, charOffsets.size()); + + List toFixOffsets = new ArrayList<>(); + //offsets of shapes + for (IggyCharOffset ofs : charOffsets) { + ofs.offset = FILL_LATER_IF_AVAILABLE; + ofs.writeToDataStream(s); + toFixOffsets.add(s.position() - 8); + } + for (int i = 0; i < glyphs.size(); i++) { + IggyShape shp = glyphs.get(i); + if (shp != null) { + s.setOlderOffsetToThisPos(toFixOffsets.get(i)); + shp.writeToDataStream(s); + } + } + } + if (codePoints != null) { + s.setOlderOffsetToThisPos(start_of_char_index_ofs_pos); + for (char c : codePoints.chars) { + s.writeUI16(c); + } + ib.write16bitArray(codePoints.chars.size()); + ib.pad8bytes(); + s.pad8bytes(); + } + if (charScales != null) { + s.setOlderOffsetToThisPos(start_of_scale_ofs_pos); + charScales.writeToDataStream(s); + ib.write32bitArray(charScales.advances.size()); + ib.pad8bytes(); + s.pad8bytes(); + } + if (charKernings != null) { + s.setOlderOffsetToThisPos(start_of_kern_ofs_pos); + ib.writeConstLengthArray(IggyIndexBuilder.CONST_KERNING_RECORD_SIZE, kern_count); + charKernings.writeToDataStream(s); + ib.pad8bytes(); + s.pad8bytes(); + } + + /*if ((s.position() - abs_start_of_char_index) % 8 != 0) { + byte padd[] = new byte[(int) (((s.position() - abs_start_of_char_index) / 8 + 1) * 8 - (s.position() - abs_start_of_char_index))]; + s.writeBytes(padd); + } + ib.writePaddingTo8(s.position());*/ + } + + public int getType() { + return type; + } + + public long getFlags() { + return flags; + } + + public int getXscale() { + return xscale; + } + + public int getYscale() { + return yscale; + } + + public long getCharacterCount() { + return char_count; + } + + public String getName() { + return name; + } + + public List getChars() { + return glyphs; + } + + public IggyCharIndices getCharIndices() { + return codePoints; + } + + public IggyCharAdvances getCharAdvances() { + return charScales; + } + + public IggyCharKerning getCharKernings() { + return charKernings; + } + + public float[] getUnk_float() { + return unk_float; + } + + public int getAscent() { + return ascent; + } + + public int getDescent() { + return descent; + } + + public int getLeading() { + return leading; + } + + public long getWhat_2() { + return what_2; + } + + public long getWhat_3() { + return what_3; + } + + public List getCharOffsets() { + return charOffsets; + } + + @Override + public int getTagType() { + return ID; + } + + @Override + public String toString() { + return String.format("IggyFontTag (%04X)", ID); + } + + public void setType(int type) { + this.type = type; + } + + public void setFontId(int fontId) { + this.fontId = fontId; + } + + public void setCharCount2(int char_count2) { + this.char_count2 = char_count2; + } + + public void setAscent(int ascent) { + this.ascent = ascent; + } + + public void setDescent(int descent) { + this.descent = descent; + } + + public void setLeading(int leading) { + this.leading = leading; + } + + public void setFlags(long flags) { + this.flags = flags; + } + + public void setUnkFloat(float[] unk_float) { + this.unk_float = unk_float; + } + + public void setWhat2(long what_2) { + this.what_2 = what_2; + } + + public void setXScale(int xscale) { + this.xscale = xscale; + } + + public void setYScale(int yscale) { + this.yscale = yscale; + } + + public void setSsr1(float ssr1) { + this.ssr1 = ssr1; + } + + public void setSsr2(float ssr2) { + this.ssr2 = ssr2; + } + + public void setCharCount(long char_count) { + this.char_count = char_count; + } + + public void setWhat3(long what_3) { + this.what_3 = what_3; + } + + public void setSubName(String subName) { + this.subName = subName; + } + + public void setSss1(float sss1) { + this.sss1 = sss1; + } + + public void setSss2(float sss2) { + this.sss2 = sss2; + } + + public void setSss3(float sss3) { + this.sss3 = sss3; + } + + public void setSss4(float sss4) { + this.sss4 = sss4; + } + + public void setName(String name) { + this.name = name; + } + + public void setCharOffsets(List charOffsets) { + this.charOffsets = charOffsets; + } + + public void setGlyphs(List glyphs) { + this.glyphs = glyphs; + } + + public void setCodePoints(IggyCharIndices codePoints) { + this.codePoints = codePoints; + } + + public void setCharScales(IggyCharAdvances charScales) { + this.charScales = charScales; + } + + public void setCharKernings(IggyCharKerning charKernings) { + this.charKernings = charKernings; + } + +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFontBinInfo.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFontBinInfo.java index a76f2127b..97d01c1dc 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFontBinInfo.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFontBinInfo.java @@ -1,83 +1,83 @@ -package com.jpexs.decompiler.flash.iggy; - -import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType; -import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface; -import com.jpexs.decompiler.flash.iggy.streams.StructureInterface; -import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface; -import java.io.IOException; - -/** - * - * @author JPEXS - */ -public class IggyFontBinInfo implements StructureInterface { - - public static final int STRUCT_SIZE = 96; - - @IggyFieldType(DataType.uint64_t) - long size_of_this_info = STRUCT_SIZE; - @IggyFieldType(value = DataType.uint16_t, count = 4) - int font_specific[]; - @IggyFieldType(DataType.float_t) - float normX; - @IggyFieldType(DataType.float_t) - float zero; - @IggyFieldType(DataType.float_t) - float zero2; - @IggyFieldType(DataType.float_t) - float normY; - @IggyFieldType(DataType.float_t) - float minSize; - @IggyFieldType(DataType.float_t) - float maxSize; - @IggyFieldType(DataType.uint64_t) - long order_in_iggy_file; - @IggyFieldType(DataType.int64_t) - long address_back; //relative - @IggyFieldType(value = DataType.uint8_t, count = 40) - byte pad[]; - - public IggyFontBinInfo(ReadDataStreamInterface s) throws IOException { - readFromDataStream(s); - } - - @Override - public void readFromDataStream(ReadDataStreamInterface s) throws IOException { - size_of_this_info = s.readUI64(); - if (size_of_this_info != 96) { - throw new IOException(String.format("Wrong iggy font format (bininfo)!")); - } - font_specific = new int[4]; - for (int i = 0; i < font_specific.length; i++) { - font_specific[i] = s.readUI16(); - } - normX = s.readFloat(); - zero = s.readFloat(); - zero2 = s.readFloat(); - normY = s.readFloat(); - minSize = s.readFloat(); - maxSize = s.readFloat(); - order_in_iggy_file = s.readUI64(); - address_back = s.readSI64(); -//if(address_back + s.position() - 8 != text_offsets[i]) Printf("Wrong iggy font format (bininfo-offsetback) (%u)!\n",i); - pad = s.readBytes(40); - } - - @Override - public void writeToDataStream(WriteDataStreamInterface s) throws IOException { - s.writeUI64(size_of_this_info); - for (int i = 0; i < font_specific.length; i++) { - s.writeUI16(font_specific[i]); - } - s.writeFloat(normX); - s.writeFloat(zero); - s.writeFloat(zero2); - s.writeFloat(normY); - s.writeFloat(minSize); - s.writeFloat(maxSize); - s.writeUI64(order_in_iggy_file); - s.writeSI64(address_back); - s.writeBytes(pad); - } - -} +package com.jpexs.decompiler.flash.iggy; + +import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType; +import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface; +import com.jpexs.decompiler.flash.iggy.streams.StructureInterface; +import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface; +import java.io.IOException; + +/** + * + * @author JPEXS + */ +public class IggyFontBinInfo implements StructureInterface { + + public static final int STRUCT_SIZE = 96; + + @IggyFieldType(DataType.uint64_t) + long size_of_this_info = STRUCT_SIZE; + @IggyFieldType(value = DataType.uint16_t, count = 4) + int font_specific[]; + @IggyFieldType(DataType.float_t) + float normX; + @IggyFieldType(DataType.float_t) + float zero; + @IggyFieldType(DataType.float_t) + float zero2; + @IggyFieldType(DataType.float_t) + float normY; + @IggyFieldType(DataType.float_t) + float minSize; + @IggyFieldType(DataType.float_t) + float maxSize; + @IggyFieldType(DataType.uint64_t) + long order_in_iggy_file; + @IggyFieldType(DataType.int64_t) + long address_back; //relative + @IggyFieldType(value = DataType.uint8_t, count = 40) + byte pad[]; + + public IggyFontBinInfo(ReadDataStreamInterface s) throws IOException { + readFromDataStream(s); + } + + @Override + public void readFromDataStream(ReadDataStreamInterface s) throws IOException { + size_of_this_info = s.readUI64(); + if (size_of_this_info != 96) { + throw new IOException(String.format("Wrong iggy font format (bininfo)!")); + } + font_specific = new int[4]; + for (int i = 0; i < font_specific.length; i++) { + font_specific[i] = s.readUI16(); + } + normX = s.readFloat(); + zero = s.readFloat(); + zero2 = s.readFloat(); + normY = s.readFloat(); + minSize = s.readFloat(); + maxSize = s.readFloat(); + order_in_iggy_file = s.readUI64(); + address_back = s.readSI64(); +//if(address_back + s.position() - 8 != text_offsets[i]) Printf("Wrong iggy font format (bininfo-offsetback) (%u)!\n",i); + pad = s.readBytes(40); + } + + @Override + public void writeToDataStream(WriteDataStreamInterface s) throws IOException { + s.writeUI64(size_of_this_info); + for (int i = 0; i < font_specific.length; i++) { + s.writeUI16(font_specific[i]); + } + s.writeFloat(normX); + s.writeFloat(zero); + s.writeFloat(zero2); + s.writeFloat(normY); + s.writeFloat(minSize); + s.writeFloat(maxSize); + s.writeUI64(order_in_iggy_file); + s.writeSI64(address_back); + s.writeBytes(pad); + } + +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFontTypeInfo.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFontTypeInfo.java index b326f6673..40f0ab23a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFontTypeInfo.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFontTypeInfo.java @@ -1,49 +1,49 @@ -package com.jpexs.decompiler.flash.iggy; - -import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType; -import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface; -import com.jpexs.decompiler.flash.iggy.streams.StructureInterface; -import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface; -import java.io.IOException; - -/** - * - * @author JPEXS - */ -public class IggyFontTypeInfo implements StructureInterface { - - public static final int STRUCT_SIZE = 24; - @IggyFieldType(DataType.uint64_t) - long zero; - @IggyFieldType(DataType.uint64_t) - long ofs_local_name; - @IggyFieldType(DataType.uint64_t) - long font_info_num; - - private long local_name_ofs_pos; - - public long getLocal_name_ofs_pos() { - return local_name_ofs_pos; - } - - public IggyFontTypeInfo(ReadDataStreamInterface s) throws IOException { - readFromDataStream(s); - } - - @Override - public void readFromDataStream(ReadDataStreamInterface s) throws IOException { - zero = s.readUI64(); - local_name_ofs_pos = s.position(); - ofs_local_name = s.readUI64(); - font_info_num = s.readUI64(); - } - - @Override - public void writeToDataStream(WriteDataStreamInterface s) throws IOException { - s.writeUI64(zero); - local_name_ofs_pos = s.position(); - s.writeUI64(ofs_local_name); - s.writeUI64(font_info_num); - } - -} +package com.jpexs.decompiler.flash.iggy; + +import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType; +import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface; +import com.jpexs.decompiler.flash.iggy.streams.StructureInterface; +import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface; +import java.io.IOException; + +/** + * + * @author JPEXS + */ +public class IggyFontTypeInfo implements StructureInterface { + + public static final int STRUCT_SIZE = 24; + @IggyFieldType(DataType.uint64_t) + long zero; + @IggyFieldType(DataType.uint64_t) + long ofs_local_name; + @IggyFieldType(DataType.uint64_t) + long font_info_num; + + private long local_name_ofs_pos; + + public long getLocal_name_ofs_pos() { + return local_name_ofs_pos; + } + + public IggyFontTypeInfo(ReadDataStreamInterface s) throws IOException { + readFromDataStream(s); + } + + @Override + public void readFromDataStream(ReadDataStreamInterface s) throws IOException { + zero = s.readUI64(); + local_name_ofs_pos = s.position(); + ofs_local_name = s.readUI64(); + font_info_num = s.readUI64(); + } + + @Override + public void writeToDataStream(WriteDataStreamInterface s) throws IOException { + s.writeUI64(zero); + local_name_ofs_pos = s.position(); + s.writeUI64(ofs_local_name); + s.writeUI64(font_info_num); + } + +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyHeader.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyHeader.java index c6890e6a2..7fbd74d48 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyHeader.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyHeader.java @@ -1,166 +1,166 @@ -package com.jpexs.decompiler.flash.iggy; - -import com.jpexs.decompiler.flash.iggy.annotations.IggyArrayFieldType; -import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType; -import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface; -import com.jpexs.decompiler.flash.iggy.streams.StructureInterface; -import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface; -import java.io.IOException; - -/** - * - * @author JPEXS - * - * little endian all - * - * Based of works of somebody called eternity. - */ -public class IggyHeader implements StructureInterface { - - public static int STRUCT_SIZE = 32; - - public static long MAGIC = 0xED0A6749; - - //Must be 0xED0A6749 - @IggyFieldType(DataType.uint32_t) - private long magic = MAGIC; - - //Assume 0x900 - @IggyFieldType(DataType.uint32_t) - private long version; - - //Assuming: 1 - @IggyFieldType(value = DataType.uint8_t) - private int platform1; - - //32/64 - @IggyFieldType(value = DataType.uint8_t) - private int platform2; - - //Assuming: 1 - @IggyFieldType(value = DataType.uint8_t) - private int platform3; - - //Usually: 3 - @IggyFieldType(value = DataType.uint8_t) - private int platform4; - - //flags for platform 64? - @IggyFieldType(DataType.uint32_t) - private long unk_0C; - - @IggyArrayFieldType(value = DataType.uint8_t, count = 12) - private byte[] reserved; - - @IggyFieldType(value = DataType.uint32_t) - private long numSubfiles; - - public IggyHeader(ReadDataStreamInterface stream) throws IOException { - readFromDataStream(stream); - } - - /** - * - * @param version - * @param platform1 - * @param platform2 32/64 - * @param platform3 - * @param platform4 - * @param unk_0C - * @param reserved - * @param num_subfiles - */ - public IggyHeader(long version, int platform1, int platform2, int platform3, int platform4, long unk_0C, byte[] reserved, long num_subfiles) { - this.version = version; - this.platform1 = platform1; - this.platform2 = platform2; - this.platform3 = platform3; - this.platform4 = platform4; - this.unk_0C = unk_0C; - this.reserved = reserved; - this.numSubfiles = num_subfiles; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("["); - sb.append("version: ").append(version).append(", "); - sb.append("platform: ").append(platform1).append(" ").append(platform2).append(" ").append(platform3).append(" ").append(platform4).append(", "); - sb.append("unk_0C: ").append(String.format("%08X", unk_0C)).append(", "); - sb.append("reserved: 12 bytes").append(", "); - sb.append("num_subfiles: ").append(numSubfiles); - sb.append("]"); - return sb.toString(); - } - - @Override - public void readFromDataStream(ReadDataStreamInterface stream) throws IOException { - magic = stream.readUI32(); - if (magic != IggyHeader.MAGIC) { - throw new IOException("Invalid Iggy file"); - } - version = stream.readUI32(); - platform1 = stream.readUI8(); - platform2 = stream.readUI8(); //32/64 - platform3 = stream.readUI8(); - platform4 = stream.readUI8(); - unk_0C = stream.readUI32(); - reserved = stream.readBytes(12); - numSubfiles = stream.readUI32(); - } - - @Override - public void writeToDataStream(WriteDataStreamInterface s) throws IOException { - s.writeUI32(magic); - s.writeUI32(version); - s.writeUI8(platform1); - s.writeUI8(platform2); - s.writeUI8(platform3); - s.writeUI8(platform4); - s.writeUI32(unk_0C); - s.writeBytes(reserved); - s.writeUI32(numSubfiles); - } - - public boolean is64() { - return platform2 == 64; - } - - public long getMagic() { - return magic; - } - - public long getVersion() { - return version; - } - - public int getPlatform1() { - return platform1; - } - - public int getPlatform2() { - return platform2; - } - - public int getPlatform3() { - return platform3; - } - - public int getPlatform4() { - return platform4; - } - - public long getUnk_0C() { - return unk_0C; - } - - public byte[] getReserved() { - return reserved; - } - - public long getNumSubfiles() { - return numSubfiles; - } - -} +package com.jpexs.decompiler.flash.iggy; + +import com.jpexs.decompiler.flash.iggy.annotations.IggyArrayFieldType; +import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType; +import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface; +import com.jpexs.decompiler.flash.iggy.streams.StructureInterface; +import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface; +import java.io.IOException; + +/** + * + * @author JPEXS + * + * little endian all + * + * Based of works of somebody called eternity. + */ +public class IggyHeader implements StructureInterface { + + public static int STRUCT_SIZE = 32; + + public static long MAGIC = 0xED0A6749; + + //Must be 0xED0A6749 + @IggyFieldType(DataType.uint32_t) + private long magic = MAGIC; + + //Assume 0x900 + @IggyFieldType(DataType.uint32_t) + private long version; + + //Assuming: 1 + @IggyFieldType(value = DataType.uint8_t) + private int platform1; + + //32/64 + @IggyFieldType(value = DataType.uint8_t) + private int platform2; + + //Assuming: 1 + @IggyFieldType(value = DataType.uint8_t) + private int platform3; + + //Usually: 3 + @IggyFieldType(value = DataType.uint8_t) + private int platform4; + + //flags for platform 64? + @IggyFieldType(DataType.uint32_t) + private long unk_0C; + + @IggyArrayFieldType(value = DataType.uint8_t, count = 12) + private byte[] reserved; + + @IggyFieldType(value = DataType.uint32_t) + private long numSubfiles; + + public IggyHeader(ReadDataStreamInterface stream) throws IOException { + readFromDataStream(stream); + } + + /** + * + * @param version + * @param platform1 + * @param platform2 32/64 + * @param platform3 + * @param platform4 + * @param unk_0C + * @param reserved + * @param num_subfiles + */ + public IggyHeader(long version, int platform1, int platform2, int platform3, int platform4, long unk_0C, byte[] reserved, long num_subfiles) { + this.version = version; + this.platform1 = platform1; + this.platform2 = platform2; + this.platform3 = platform3; + this.platform4 = platform4; + this.unk_0C = unk_0C; + this.reserved = reserved; + this.numSubfiles = num_subfiles; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("["); + sb.append("version: ").append(version).append(", "); + sb.append("platform: ").append(platform1).append(" ").append(platform2).append(" ").append(platform3).append(" ").append(platform4).append(", "); + sb.append("unk_0C: ").append(String.format("%08X", unk_0C)).append(", "); + sb.append("reserved: 12 bytes").append(", "); + sb.append("num_subfiles: ").append(numSubfiles); + sb.append("]"); + return sb.toString(); + } + + @Override + public void readFromDataStream(ReadDataStreamInterface stream) throws IOException { + magic = stream.readUI32(); + if (magic != IggyHeader.MAGIC) { + throw new IOException("Invalid Iggy file"); + } + version = stream.readUI32(); + platform1 = stream.readUI8(); + platform2 = stream.readUI8(); //32/64 + platform3 = stream.readUI8(); + platform4 = stream.readUI8(); + unk_0C = stream.readUI32(); + reserved = stream.readBytes(12); + numSubfiles = stream.readUI32(); + } + + @Override + public void writeToDataStream(WriteDataStreamInterface s) throws IOException { + s.writeUI32(magic); + s.writeUI32(version); + s.writeUI8(platform1); + s.writeUI8(platform2); + s.writeUI8(platform3); + s.writeUI8(platform4); + s.writeUI32(unk_0C); + s.writeBytes(reserved); + s.writeUI32(numSubfiles); + } + + public boolean is64() { + return platform2 == 64; + } + + public long getMagic() { + return magic; + } + + public long getVersion() { + return version; + } + + public int getPlatform1() { + return platform1; + } + + public int getPlatform2() { + return platform2; + } + + public int getPlatform3() { + return platform3; + } + + public int getPlatform4() { + return platform4; + } + + public long getUnk_0C() { + return unk_0C; + } + + public byte[] getReserved() { + return reserved; + } + + public long getNumSubfiles() { + return numSubfiles; + } + +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyShape.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyShape.java index 1cecf0e49..31c935eb2 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyShape.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyShape.java @@ -1,174 +1,174 @@ -package com.jpexs.decompiler.flash.iggy; - -import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType; -import com.jpexs.decompiler.flash.iggy.streams.IggyIndexBuilder; -import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface; -import com.jpexs.decompiler.flash.iggy.streams.StructureInterface; -import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Logger; - -/** - * - * @author JPEXS - */ -public class IggyShape implements StructureInterface { - - public static final int STRUCT_SIZE = 64; - - private static Logger LOGGER = Logger.getLogger(IggyShape.class.getName()); - - @IggyFieldType(DataType.float_t) - float minx; //bearing X - this is the horizontal distance from the current pen position to the glyph's left bbox edge. - @IggyFieldType(DataType.float_t) - float miny; //bearing Y - this is the vertical distance from the baseline to the top of the glyph's bbox. - @IggyFieldType(DataType.float_t) - float maxx; //advanceX - bearingX - @IggyFieldType(DataType.float_t) - float maxy; //advanceY - bearingY - @IggyFieldType(DataType.uint64_t) - long unk; // stejny vetsinou - napr. 48 - JP: to by mohlo byt advance - @IggyFieldType(DataType.uint64_t) - long count; - @IggyFieldType(DataType.uint64_t) - long one; // 1 - @IggyFieldType(DataType.uint64_t) - long one2; // 1 - @IggyFieldType(DataType.uint64_t) - long one3; // 1 - @IggyFieldType(DataType.uint32_t) - long one4; // 1 - @IggyFieldType(DataType.uint32_t) - long two1; // 2 - - public float getBearingX() { - return minx; - } - - public float getBearingY() { - return miny; - } - - public float getWidth() { - return maxx - minx; - } - - public float getHeight() { - return maxy - miny; - } - - List nodes; - - public IggyShape(ReadDataStreamInterface stream) throws IOException { - readFromDataStream(stream); - } - - public IggyShape(float minx, float miny, float maxx, float maxy, List nodes) { - this.minx = minx; - this.miny = miny; - this.maxx = maxx; - this.maxy = maxy; - this.unk = 0; //?? - this.one = 1; - this.one2 = 1; - this.one3 = 1; - this.one4 = 1; - this.two1 = 2; - this.count = nodes.size(); - this.nodes = nodes; - } - - @Override - public void readFromDataStream(ReadDataStreamInterface s) throws IOException { - minx = s.readFloat(); - miny = s.readFloat(); - maxx = s.readFloat(); - maxy = s.readFloat(); - unk = s.readUI64(); - count = s.readUI64(); - one = s.readUI64(); - one2 = s.readUI64(); - one3 = s.readUI64(); - one4 = s.readUI32(); - two1 = s.readUI32(); - - if ((one != 1) || (one2 != 1) || (one3 != 1) || (one4 != 1) || (two1 != 2)) { - LOGGER.fine(String.format("Unique header at one: %d, one2: %d, one3: %d, one4: %d, two1: %d\n", one, one2, one3, one4, two1)); - } - - nodes = new ArrayList<>(); - for (int i = 0; i < count; i++) { - nodes.add(new IggyShapeNode(s, i == 0)); - } - - } - - @Override - public void writeToDataStream(WriteDataStreamInterface s) throws IOException { - s.getIndexing().writeConstLength(IggyIndexBuilder.CONST_SHAPE_SIZE); - s.writeFloat(minx); - s.writeFloat(miny); - s.writeFloat(maxx); - s.writeFloat(maxy); - s.writeUI64(unk); - s.writeUI64(count); - s.writeUI64(one); - s.writeUI64(one2); - s.writeUI64(one3); - s.writeUI32(one4); - s.writeUI32(two1); - - s.getIndexing().writeConstLengthArray(IggyIndexBuilder.CONST_SHAPE_NODE_SIZE, nodes.size()); - - for (IggyShapeNode node : nodes) { - node.writeToDataStream(s); - } - } - - public float getMinx() { - return minx; - } - - public float getMiny() { - return miny; - } - - public float getMaxx() { - return maxx; - } - - public float getMaxy() { - return maxy; - } - - public long getUnk() { - return unk; - } - - public long getOne() { - return one; - } - - public long getOne2() { - return one2; - } - - public long getOne3() { - return one3; - } - - public long getOne4() { - return one4; - } - - public long getTwo1() { - return two1; - } - - public List getNodes() { - return nodes; - } - -} +package com.jpexs.decompiler.flash.iggy; + +import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType; +import com.jpexs.decompiler.flash.iggy.streams.IggyIndexBuilder; +import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface; +import com.jpexs.decompiler.flash.iggy.streams.StructureInterface; +import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Logger; + +/** + * + * @author JPEXS + */ +public class IggyShape implements StructureInterface { + + public static final int STRUCT_SIZE = 64; + + private static Logger LOGGER = Logger.getLogger(IggyShape.class.getName()); + + @IggyFieldType(DataType.float_t) + float minx; //bearing X - this is the horizontal distance from the current pen position to the glyph's left bbox edge. + @IggyFieldType(DataType.float_t) + float miny; //bearing Y - this is the vertical distance from the baseline to the top of the glyph's bbox. + @IggyFieldType(DataType.float_t) + float maxx; //advanceX - bearingX + @IggyFieldType(DataType.float_t) + float maxy; //advanceY - bearingY + @IggyFieldType(DataType.uint64_t) + long unk; // stejny vetsinou - napr. 48 - JP: to by mohlo byt advance + @IggyFieldType(DataType.uint64_t) + long count; + @IggyFieldType(DataType.uint64_t) + long one; // 1 + @IggyFieldType(DataType.uint64_t) + long one2; // 1 + @IggyFieldType(DataType.uint64_t) + long one3; // 1 + @IggyFieldType(DataType.uint32_t) + long one4; // 1 + @IggyFieldType(DataType.uint32_t) + long two1; // 2 + + public float getBearingX() { + return minx; + } + + public float getBearingY() { + return miny; + } + + public float getWidth() { + return maxx - minx; + } + + public float getHeight() { + return maxy - miny; + } + + List nodes; + + public IggyShape(ReadDataStreamInterface stream) throws IOException { + readFromDataStream(stream); + } + + public IggyShape(float minx, float miny, float maxx, float maxy, List nodes) { + this.minx = minx; + this.miny = miny; + this.maxx = maxx; + this.maxy = maxy; + this.unk = 0; //?? + this.one = 1; + this.one2 = 1; + this.one3 = 1; + this.one4 = 1; + this.two1 = 2; + this.count = nodes.size(); + this.nodes = nodes; + } + + @Override + public void readFromDataStream(ReadDataStreamInterface s) throws IOException { + minx = s.readFloat(); + miny = s.readFloat(); + maxx = s.readFloat(); + maxy = s.readFloat(); + unk = s.readUI64(); + count = s.readUI64(); + one = s.readUI64(); + one2 = s.readUI64(); + one3 = s.readUI64(); + one4 = s.readUI32(); + two1 = s.readUI32(); + + if ((one != 1) || (one2 != 1) || (one3 != 1) || (one4 != 1) || (two1 != 2)) { + LOGGER.fine(String.format("Unique header at one: %d, one2: %d, one3: %d, one4: %d, two1: %d\n", one, one2, one3, one4, two1)); + } + + nodes = new ArrayList<>(); + for (int i = 0; i < count; i++) { + nodes.add(new IggyShapeNode(s, i == 0)); + } + + } + + @Override + public void writeToDataStream(WriteDataStreamInterface s) throws IOException { + s.getIndexing().writeConstLength(IggyIndexBuilder.CONST_SHAPE_SIZE); + s.writeFloat(minx); + s.writeFloat(miny); + s.writeFloat(maxx); + s.writeFloat(maxy); + s.writeUI64(unk); + s.writeUI64(count); + s.writeUI64(one); + s.writeUI64(one2); + s.writeUI64(one3); + s.writeUI32(one4); + s.writeUI32(two1); + + s.getIndexing().writeConstLengthArray(IggyIndexBuilder.CONST_SHAPE_NODE_SIZE, nodes.size()); + + for (IggyShapeNode node : nodes) { + node.writeToDataStream(s); + } + } + + public float getMinx() { + return minx; + } + + public float getMiny() { + return miny; + } + + public float getMaxx() { + return maxx; + } + + public float getMaxy() { + return maxy; + } + + public long getUnk() { + return unk; + } + + public long getOne() { + return one; + } + + public long getOne2() { + return one2; + } + + public long getOne3() { + return one3; + } + + public long getOne4() { + return one4; + } + + public long getTwo1() { + return two1; + } + + public List getNodes() { + return nodes; + } + +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyShapeNode.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyShapeNode.java index 0961f838e..e8b063154 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyShapeNode.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyShapeNode.java @@ -1,135 +1,135 @@ -package com.jpexs.decompiler.flash.iggy; - -import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType; -import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface; -import com.jpexs.decompiler.flash.iggy.streams.StructureInterface; -import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface; -import java.io.IOException; -import java.util.logging.Logger; - -/** - * - * @author JPEXS - */ -public class IggyShapeNode implements StructureInterface { - - public static final int STRUCT_SIZE = 24; - - private static Logger LOGGER = Logger.getLogger(IggyShapeNode.class.getName()); - - public static int NODE_TYPE_MOVE = 1; - public static int NODE_TYPE_LINE_TO = 2; - public static int NODE_TYPE_CURVE_POINT = 3; - - @IggyFieldType(DataType.float_t) - float targetX; - @IggyFieldType(DataType.float_t) - float targetY; // negative - @IggyFieldType(DataType.float_t) - float controlX; // for curves - @IggyFieldType(DataType.float_t) - float controlY; // for curves, negative - @IggyFieldType(DataType.uint8_t) //1-moveto, 2-lineto , 3 - curve to - int node_type; - @IggyFieldType(DataType.uint8_t) // 208 start smooth (for j=1 only), 61 smooth interupt (muze a nemusi byt pro novy oddeleny kus charu - kdyz je subtype predchoziho vetsi nez 0 (kupr 5) bude pro oddeleny usek 61, jinak pokud je subtype predchoziho 0 bude pro oddeleny usek 0) - int node_subtype; - @IggyFieldType(DataType.uint8_t) - int zer1; - @IggyFieldType(DataType.uint8_t) - int zer2; - @IggyFieldType(DataType.uint32_t) - long isstart; // 1 v prubehu nebo 0 pouze pro prvni (i kdyz jsou delene jako dvojtecka!!!) - - private boolean first; - - public IggyShapeNode(float targetX, float targetY, float controlX, float controlY, int node_type, int node_subtype, boolean first) { - this.targetX = targetX; - this.targetY = targetY; - this.controlX = controlX; - this.controlY = controlY; - this.node_type = node_type; - this.node_subtype = node_subtype; - this.zer1 = 0; - this.zer2 = 0; - this.first = first; - this.isstart = first ? 0 : 1; - } - - public IggyShapeNode(ReadDataStreamInterface s, boolean first) throws IOException { - this.first = first; - readFromDataStream(s); - } - - @Override - public void readFromDataStream(ReadDataStreamInterface s) throws IOException { - targetX = s.readFloat(); - targetY = s.readFloat(); - controlX = s.readFloat(); - controlY = s.readFloat(); - node_type = s.readUI8(); - node_subtype = s.readUI8(); - zer1 = s.readUI8(); - zer2 = s.readUI8(); - isstart = s.readUI32(); - - if ((zer1 != 0) | (zer2 != 0)) { - LOGGER.fine(String.format("Unknown zeroes at pos %08X\n", s.position() - 6)); - } - if ((!first) & (isstart != 1)) { - LOGGER.fine(String.format("Unknown format at pos %08X\n", s.position() - 4)); - } - if ((first) & (isstart != 0)) { - LOGGER.fine(String.format("Unknown format at pos %08X\n", s.position() - 4)); - } - } - - @Override - public void writeToDataStream(WriteDataStreamInterface s) throws IOException { - s.writeFloat(targetX); - s.writeFloat(targetY); - s.writeFloat(controlX); - s.writeFloat(controlY); - s.writeUI8(node_type); - s.writeUI8(node_subtype); - s.writeUI8(zer1); - s.writeUI8(zer2); - s.writeUI32(isstart); - } - - public float getTargetX() { - return targetX; - } - - public float getTargetY() { - return targetY; - } - - public float getControlX() { - return controlX; - } - - public float getControlY() { - return controlY; - } - - public int getNodeType() { - return node_type; - } - - public int getNodeSubType() { - return node_subtype; - } - - public int getZer1() { - return zer1; - } - - public int getZer2() { - return zer2; - } - - public boolean isStart() { - return isstart == 1; - } - -} +package com.jpexs.decompiler.flash.iggy; + +import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType; +import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface; +import com.jpexs.decompiler.flash.iggy.streams.StructureInterface; +import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface; +import java.io.IOException; +import java.util.logging.Logger; + +/** + * + * @author JPEXS + */ +public class IggyShapeNode implements StructureInterface { + + public static final int STRUCT_SIZE = 24; + + private static Logger LOGGER = Logger.getLogger(IggyShapeNode.class.getName()); + + public static int NODE_TYPE_MOVE = 1; + public static int NODE_TYPE_LINE_TO = 2; + public static int NODE_TYPE_CURVE_POINT = 3; + + @IggyFieldType(DataType.float_t) + float targetX; + @IggyFieldType(DataType.float_t) + float targetY; // negative + @IggyFieldType(DataType.float_t) + float controlX; // for curves + @IggyFieldType(DataType.float_t) + float controlY; // for curves, negative + @IggyFieldType(DataType.uint8_t) //1-moveto, 2-lineto , 3 - curve to + int node_type; + @IggyFieldType(DataType.uint8_t) // 208 start smooth (for j=1 only), 61 smooth interupt (muze a nemusi byt pro novy oddeleny kus charu - kdyz je subtype predchoziho vetsi nez 0 (kupr 5) bude pro oddeleny usek 61, jinak pokud je subtype predchoziho 0 bude pro oddeleny usek 0) + int node_subtype; + @IggyFieldType(DataType.uint8_t) + int zer1; + @IggyFieldType(DataType.uint8_t) + int zer2; + @IggyFieldType(DataType.uint32_t) + long isstart; // 1 v prubehu nebo 0 pouze pro prvni (i kdyz jsou delene jako dvojtecka!!!) + + private boolean first; + + public IggyShapeNode(float targetX, float targetY, float controlX, float controlY, int node_type, int node_subtype, boolean first) { + this.targetX = targetX; + this.targetY = targetY; + this.controlX = controlX; + this.controlY = controlY; + this.node_type = node_type; + this.node_subtype = node_subtype; + this.zer1 = 0; + this.zer2 = 0; + this.first = first; + this.isstart = first ? 0 : 1; + } + + public IggyShapeNode(ReadDataStreamInterface s, boolean first) throws IOException { + this.first = first; + readFromDataStream(s); + } + + @Override + public void readFromDataStream(ReadDataStreamInterface s) throws IOException { + targetX = s.readFloat(); + targetY = s.readFloat(); + controlX = s.readFloat(); + controlY = s.readFloat(); + node_type = s.readUI8(); + node_subtype = s.readUI8(); + zer1 = s.readUI8(); + zer2 = s.readUI8(); + isstart = s.readUI32(); + + if ((zer1 != 0) | (zer2 != 0)) { + LOGGER.fine(String.format("Unknown zeroes at pos %08X\n", s.position() - 6)); + } + if ((!first) & (isstart != 1)) { + LOGGER.fine(String.format("Unknown format at pos %08X\n", s.position() - 4)); + } + if ((first) & (isstart != 0)) { + LOGGER.fine(String.format("Unknown format at pos %08X\n", s.position() - 4)); + } + } + + @Override + public void writeToDataStream(WriteDataStreamInterface s) throws IOException { + s.writeFloat(targetX); + s.writeFloat(targetY); + s.writeFloat(controlX); + s.writeFloat(controlY); + s.writeUI8(node_type); + s.writeUI8(node_subtype); + s.writeUI8(zer1); + s.writeUI8(zer2); + s.writeUI32(isstart); + } + + public float getTargetX() { + return targetX; + } + + public float getTargetY() { + return targetY; + } + + public float getControlX() { + return controlX; + } + + public float getControlY() { + return controlY; + } + + public int getNodeType() { + return node_type; + } + + public int getNodeSubType() { + return node_subtype; + } + + public int getZer1() { + return zer1; + } + + public int getZer2() { + return zer2; + } + + public boolean isStart() { + return isstart == 1; + } + +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggySubFileEntry.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggySubFileEntry.java index 485789a04..28c330a87 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggySubFileEntry.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggySubFileEntry.java @@ -1,76 +1,76 @@ -package com.jpexs.decompiler.flash.iggy; - -import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface; -import com.jpexs.decompiler.flash.iggy.streams.StructureInterface; -import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import java.io.IOException; - -/** - * - * @author JPEXS - * - * Based of works of somebody called eternity. - */ -public class IggySubFileEntry implements StructureInterface { - - public static final int STRUCTURE_SIZE = 16; - - public static final int TYPE_INDEX = 0; - public static final int TYPE_FLASH = 1; - - @SWFType(BasicType.UI32) - long type; - - @SWFType(BasicType.UI32) - long size; - - //apparently same as size, maybe (un)compressed (?) - @SWFType(BasicType.UI32) - long size2; - - //absolute offset - @SWFType(BasicType.UI32) - long offset; - - public IggySubFileEntry(ReadDataStreamInterface stream) throws IOException { - readFromDataStream(stream); - } - - public IggySubFileEntry(long type, long size, long size2, long offset) { - this.type = type; - this.size = size; - this.size2 = size2; - this.offset = offset; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("["); - sb.append("id: ").append(type).append(", "); - sb.append("size: ").append(size).append(", "); - sb.append("size2: ").append(size2).append(", "); - sb.append("offset: ").append(offset); - sb.append("]"); - return sb.toString(); - } - - @Override - public void readFromDataStream(ReadDataStreamInterface stream) throws IOException { - type = stream.readUI32(); - size = stream.readUI32(); - size2 = stream.readUI32(); - offset = stream.readUI32(); - } - - @Override - public void writeToDataStream(WriteDataStreamInterface stream) throws IOException { - stream.writeUI32(type); - stream.writeUI32(size); - stream.writeUI32(size2); - stream.writeUI32(offset); - } - -} +package com.jpexs.decompiler.flash.iggy; + +import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface; +import com.jpexs.decompiler.flash.iggy.streams.StructureInterface; +import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import java.io.IOException; + +/** + * + * @author JPEXS + * + * Based of works of somebody called eternity. + */ +public class IggySubFileEntry implements StructureInterface { + + public static final int STRUCTURE_SIZE = 16; + + public static final int TYPE_INDEX = 0; + public static final int TYPE_FLASH = 1; + + @SWFType(BasicType.UI32) + long type; + + @SWFType(BasicType.UI32) + long size; + + //apparently same as size, maybe (un)compressed (?) + @SWFType(BasicType.UI32) + long size2; + + //absolute offset + @SWFType(BasicType.UI32) + long offset; + + public IggySubFileEntry(ReadDataStreamInterface stream) throws IOException { + readFromDataStream(stream); + } + + public IggySubFileEntry(long type, long size, long size2, long offset) { + this.type = type; + this.size = size; + this.size2 = size2; + this.offset = offset; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("["); + sb.append("id: ").append(type).append(", "); + sb.append("size: ").append(size).append(", "); + sb.append("size2: ").append(size2).append(", "); + sb.append("offset: ").append(offset); + sb.append("]"); + return sb.toString(); + } + + @Override + public void readFromDataStream(ReadDataStreamInterface stream) throws IOException { + type = stream.readUI32(); + size = stream.readUI32(); + size2 = stream.readUI32(); + offset = stream.readUI32(); + } + + @Override + public void writeToDataStream(WriteDataStreamInterface stream) throws IOException { + stream.writeUI32(type); + stream.writeUI32(size); + stream.writeUI32(size2); + stream.writeUI32(offset); + } + +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggySwf.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggySwf.java index b7d63576d..e03dc3457 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggySwf.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggySwf.java @@ -1,319 +1,319 @@ -package com.jpexs.decompiler.flash.iggy; - -import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType; -import com.jpexs.decompiler.flash.iggy.streams.IggyIndexBuilder; -import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface; -import com.jpexs.decompiler.flash.iggy.streams.SeekMode; -import com.jpexs.decompiler.flash.iggy.streams.StructureInterface; -import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -/** - * - * @author JPEXS - */ -public class IggySwf implements StructureInterface { - - final static int NO_OFFSET = 1; - - @IggyFieldType(value = DataType.wchar_t, count = 48) - String name; - - List fonts = new ArrayList<>(); - // private List font_data_addresses = new ArrayList<>(); - List add_fonts = new ArrayList<>(); -// private List add_font_data_addresses = new ArrayList<>(); - - private IggyFlashHeader64 hdr; - - public IggySwf(ReadDataStreamInterface stream) throws IOException { - readFromDataStream(stream); - } - private List texts = new ArrayList<>(); - //private List text_data_addresses = new ArrayList<>(); - private List add_texts = new ArrayList<>(); - //private List add_text_data_addresses = new ArrayList<>(); - - //private byte font_add_data[]; - //private List font_additional_size = new ArrayList<>(); - private IggyFontBinInfo font_bin_info[]; - private List sequenceNames = new ArrayList<>(); - //private List sequenceValues = new ArrayList<>(); - - private IggyFontTypeInfo type_info[]; - private String type_info_name[]; - private IggyDeclStrings decl_strings; - private long ofs_additional; - private long additional_address; - - public IggyFlashHeader64 getHdr() { - return hdr; - } - - @Override - public void readFromDataStream(ReadDataStreamInterface s) throws IOException { - this.hdr = new IggyFlashHeader64(s); - //Save all font bytes to buffer for later easy modification - //here is offset[0] - 184 - name = s.readWChar(); - //here is offset[1] - 230 - int pad8 = 8 - (int) (s.position() % 8); - if (pad8 > 8) { - s.seek(pad8, SeekMode.CUR); - } - //here is offset [2] - 232 - s.seek(hdr.getBaseAddress(), SeekMode.SET); - s.readUI64(); //pad 1 - - List itemsAddresses = new ArrayList<>(); - - while (true) { - long offset = s.readUI64(); - if (offset == 1) { - break; - } - itemsAddresses.add(offset + s.position() - 8); - } - if (hdr.getImported_guid() != 0) { - ofs_additional = s.readUI64(); - additional_address = ofs_additional == 1 ? 0 : ofs_additional + s.position() - 8; - } - for (Long addr : itemsAddresses) { - s.seek(addr, SeekMode.SET); - int kind = s.readUI8(); - s.seek(-1, SeekMode.CUR); - switch (kind) { - case 22 /*FONT*/: - IggyFont font = new IggyFont(s); - //font_data_addresses.add(addr); - fonts.add(font); - break; - case 6 /*TEXT*/: - IggyText text = new IggyText(s); - //text_data_addresses.add(addr); - texts.add(text); - break; - default: - throw new RuntimeException("Unknown item kind: " + kind); - } - } - - if (additional_address != 0) { - s.seek(additional_address, SeekMode.SET); - List additionalItemsAddresses = new ArrayList<>(); - while (true) { - long offset = s.readUI64(); - if (offset == 1) { - break; - } - additionalItemsAddresses.add(offset + s.position() - 8); - } - for (Long addr : additionalItemsAddresses) { - s.seek(addr, SeekMode.SET); - int kind = s.readUI8(); - s.seek(-1, SeekMode.CUR); - switch (kind) { - case 22 /*FONT*/: - IggyFont font = new IggyFont(s); - //add_font_data_addresses.add(addr); - add_fonts.add(font); - break; - case 6 /*TEXT*/: - IggyText text = new IggyText(s); - //add_text_data_addresses.add(addr); - add_texts.add(text); - break; - default: - throw new RuntimeException("Unknown imported item kind: " + kind); - } - } - } - s.seek(hdr.getFontEndAddress(), SeekMode.SET); - //here is offset [4] - 856 ? - font_bin_info = new IggyFontBinInfo[(int) hdr.font_count]; - for (int i = 0; i < hdr.font_count; i++) { - font_bin_info[i] = new IggyFontBinInfo(s); - } - - sequenceNames = new ArrayList<>(); - - long seq_addresses[] = new long[]{hdr.getSequenceStartAddress1(), hdr.getSequenceStartAddress2(), hdr.getSequenceStartAddress3()}; - long seq_name_addresses[] = new long[3]; - for (int i = 0; i < 3; i++) { - if (seq_addresses[i] == 0) { - seq_name_addresses[i] = 0; - //0 - } else { - s.seek(seq_addresses[i], SeekMode.SET); - long ofs_seq_name = s.readUI64(); - seq_name_addresses[i] = ofs_seq_name == 1 ? 0 : ofs_seq_name + s.position() - 8; - s.readUI64(); //is this crucial? - } - } - - for (int i = 0; i < 3; i++) { - if (seq_name_addresses[i] > 0) { - s.seek(seq_name_addresses[i], SeekMode.SET); - sequenceNames.add(s.readWChar()); - } else { - sequenceNames.add(null); - } - } - s.pad8bytes(); - - //sequence = new IggySequence(s); - s.seek(hdr.getTypeFontsAddress(), SeekMode.SET); - type_info = new IggyFontTypeInfo[(int) hdr.font_count]; - type_info_name = new String[(int) hdr.font_count]; - for (int i = 0; i < hdr.font_count; i++) { - type_info[i] = new IggyFontTypeInfo(s); - } - for (int i = 0; i < hdr.font_count; i++) { - s.seek(type_info[i].getLocal_name_ofs_pos() + type_info[i].ofs_local_name, SeekMode.SET); - type_info_name[i] = s.readWChar(); - } - - s.seek(hdr.getDeclStringsAddress(), SeekMode.SET); - decl_strings = new IggyDeclStrings(s); - /*WriteDataStreamInterface outs = new TemporaryDataStream(); - writeToDataStream(outs); - Helper.writeFile("d:\\Dropbox\\jpexs-laptop\\iggi\\parts\\swf_out.bin", outs.getAllBytes());*/ - } - - public String getName() { - return name; - } - - @Override - public void writeToDataStream(WriteDataStreamInterface s) throws IOException { - IggyIndexBuilder ib = s.getIndexing(); - hdr.writeToDataStream(s); - s.writeWChar(name); - s.pad8bytes(); - s.writeUI64(1); - ib.write16bitArray(name.length() + 1); - ib.writeTwoPaddingBytes(); - ib.write64bitPointerArray(64); - long posBeforeOffsets = s.position(); - - final int FILL_LATER = 1; - - List fontPosFillLater = new ArrayList<>(); - - for (int i = 0; i < fonts.size(); i++) { - fontPosFillLater.add(s.position()); - s.writeUI64(FILL_LATER); - } - List textPosFillLater = new ArrayList<>(); - for (int i = 0; i < texts.size(); i++) { - textPosFillLater.add(s.position()); - s.writeUI64(FILL_LATER); - } - s.writeUI64(1); - - long addPosFillLater = s.position(); - s.writeUI64(FILL_LATER); - long posAfter = posBeforeOffsets + 64 * 8; - long curPos = s.position(); - long numLeft = posAfter - curPos; - long ofsLeft = numLeft / 8; - for (int i = 0; i < ofsLeft - 1; i++) { - s.writeUI64(FILL_LATER); - } - - for (int i = 0; i < fonts.size(); i++) { - s.setOlderOffsetToThisPos(fontPosFillLater.get(i)); - fonts.get(i).writeToDataStream(s); - } - for (int i = 0; i < texts.size(); i++) { - s.setOlderOffsetToThisPos(textPosFillLater.get(i)); - texts.get(i).writeToDataStream(s); - } - - if (!add_fonts.isEmpty() || !add_texts.isEmpty()) { - s.setOlderOffsetToThisPos(addPosFillLater); - - List addFontPosFillLater = new ArrayList<>(); - - for (int i = 0; i < add_fonts.size(); i++) { - addFontPosFillLater.add(s.position()); - s.writeUI64(FILL_LATER); - } - List addTextPosFillLater = new ArrayList<>(); - for (int i = 0; i < add_texts.size(); i++) { - addTextPosFillLater.add(s.position()); - s.writeUI64(FILL_LATER); - } - s.writeUI64(FILL_LATER); - for (int i = 0; i < add_fonts.size(); i++) { - s.setOlderOffsetToThisPos(addFontPosFillLater.get(i)); - add_fonts.get(i).writeToDataStream(s); - } - for (int i = 0; i < add_texts.size(); i++) { - s.setOlderOffsetToThisPos(addTextPosFillLater.get(i)); - add_texts.get(i).writeToDataStream(s); - } - } - s.setOlderOffsetToThisPos(hdr.getFont_end_ofs_pos()); - ib.writeConstLengthArray(IggyIndexBuilder.CONST_BIN_INFO_SIZE, hdr.font_count); - for (int i = 0; i < hdr.font_count; i++) { - font_bin_info[i].writeToDataStream(s); - } - - long seq_ofs_pos[] = new long[]{hdr.getSequence_start1_ofs_pos(), hdr.getSequence_start2_ofs_pos(), hdr.getSequence_start3_ofs_pos()}; - long off_seq_expected[] = new long[]{hdr.off_sequence_start1, hdr.off_sequence_start2, hdr.off_sequence_start3}; - - long seq_name_fill_later[] = new long[3]; - - s.setOlderOffsetToThisPos(seq_ofs_pos[0]); - s.writeUI64(1); - s.writeUI64(1); - ib.writeLengthCustom(16, new int[]{0}, new int[]{2}); - - seq_name_fill_later[2] = s.position(); - s.setOlderOffsetToThisPos(seq_ofs_pos[2]); - s.writeUI64(FILL_LATER); - s.writeUI64(0); - ib.writeConstLength(IggyIndexBuilder.CONST_SEQUENCE_SIZE); - for (int i = 0; i < 3; i++) { - if (sequenceNames.get(i) != null) { - s.setOlderOffsetToThisPos(seq_name_fill_later[i]); - ib.write16bitArray(sequenceNames.get(i).length() + 1); - s.writeWChar(sequenceNames.get(i)); - } - } - s.setOlderOffsetToThisPos(hdr.getSequence_end_ofs_pos()); - s.pad8bytes(); - ib.pad8bytes(); - - ib.writeConstLengthArray(IggyIndexBuilder.CONST_TYPE_INFO_SIZE, hdr.font_count); - s.setOlderOffsetToThisPos(hdr.getType_fonts_ofs_pos()); - //s.seek(hdr.getTypeFontsAddress(), SeekMode.SET); - for (int i = 0; i < hdr.font_count; i++) { - type_info[i].writeToDataStream(s); - } - - for (int i = 0; i < hdr.font_count; i++) { - ib.write16bitArray(type_info_name[i].length() + 1); - s.setOlderOffsetToThisPos(type_info[i].getLocal_name_ofs_pos()); - s.writeWChar(type_info_name[i]); - } - s.pad8bytes(); - ib.pad8bytes(); - - s.setOlderOffsetToThisPos(hdr.getDecl_strings_ofs_pos()); - //s.seek(hdr.getDeclStringsAddress(), SeekMode.SET); - decl_strings.writeToDataStream(s); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("[\r\n"); - sb.append("name ").append(name).append("\r\n"); - return sb.toString(); - } - -} +package com.jpexs.decompiler.flash.iggy; + +import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType; +import com.jpexs.decompiler.flash.iggy.streams.IggyIndexBuilder; +import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface; +import com.jpexs.decompiler.flash.iggy.streams.SeekMode; +import com.jpexs.decompiler.flash.iggy.streams.StructureInterface; +import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author JPEXS + */ +public class IggySwf implements StructureInterface { + + final static int NO_OFFSET = 1; + + @IggyFieldType(value = DataType.wchar_t, count = 48) + String name; + + List fonts = new ArrayList<>(); + // private List font_data_addresses = new ArrayList<>(); + List add_fonts = new ArrayList<>(); +// private List add_font_data_addresses = new ArrayList<>(); + + private IggyFlashHeader64 hdr; + + public IggySwf(ReadDataStreamInterface stream) throws IOException { + readFromDataStream(stream); + } + private List texts = new ArrayList<>(); + //private List text_data_addresses = new ArrayList<>(); + private List add_texts = new ArrayList<>(); + //private List add_text_data_addresses = new ArrayList<>(); + + //private byte font_add_data[]; + //private List font_additional_size = new ArrayList<>(); + private IggyFontBinInfo font_bin_info[]; + private List sequenceNames = new ArrayList<>(); + //private List sequenceValues = new ArrayList<>(); + + private IggyFontTypeInfo type_info[]; + private String type_info_name[]; + private IggyDeclStrings decl_strings; + private long ofs_additional; + private long additional_address; + + public IggyFlashHeader64 getHdr() { + return hdr; + } + + @Override + public void readFromDataStream(ReadDataStreamInterface s) throws IOException { + this.hdr = new IggyFlashHeader64(s); + //Save all font bytes to buffer for later easy modification + //here is offset[0] - 184 + name = s.readWChar(); + //here is offset[1] - 230 + int pad8 = 8 - (int) (s.position() % 8); + if (pad8 > 8) { + s.seek(pad8, SeekMode.CUR); + } + //here is offset [2] - 232 + s.seek(hdr.getBaseAddress(), SeekMode.SET); + s.readUI64(); //pad 1 + + List itemsAddresses = new ArrayList<>(); + + while (true) { + long offset = s.readUI64(); + if (offset == 1) { + break; + } + itemsAddresses.add(offset + s.position() - 8); + } + if (hdr.getImported_guid() != 0) { + ofs_additional = s.readUI64(); + additional_address = ofs_additional == 1 ? 0 : ofs_additional + s.position() - 8; + } + for (Long addr : itemsAddresses) { + s.seek(addr, SeekMode.SET); + int kind = s.readUI8(); + s.seek(-1, SeekMode.CUR); + switch (kind) { + case 22 /*FONT*/: + IggyFont font = new IggyFont(s); + //font_data_addresses.add(addr); + fonts.add(font); + break; + case 6 /*TEXT*/: + IggyText text = new IggyText(s); + //text_data_addresses.add(addr); + texts.add(text); + break; + default: + throw new RuntimeException("Unknown item kind: " + kind); + } + } + + if (additional_address != 0) { + s.seek(additional_address, SeekMode.SET); + List additionalItemsAddresses = new ArrayList<>(); + while (true) { + long offset = s.readUI64(); + if (offset == 1) { + break; + } + additionalItemsAddresses.add(offset + s.position() - 8); + } + for (Long addr : additionalItemsAddresses) { + s.seek(addr, SeekMode.SET); + int kind = s.readUI8(); + s.seek(-1, SeekMode.CUR); + switch (kind) { + case 22 /*FONT*/: + IggyFont font = new IggyFont(s); + //add_font_data_addresses.add(addr); + add_fonts.add(font); + break; + case 6 /*TEXT*/: + IggyText text = new IggyText(s); + //add_text_data_addresses.add(addr); + add_texts.add(text); + break; + default: + throw new RuntimeException("Unknown imported item kind: " + kind); + } + } + } + s.seek(hdr.getFontEndAddress(), SeekMode.SET); + //here is offset [4] - 856 ? + font_bin_info = new IggyFontBinInfo[(int) hdr.font_count]; + for (int i = 0; i < hdr.font_count; i++) { + font_bin_info[i] = new IggyFontBinInfo(s); + } + + sequenceNames = new ArrayList<>(); + + long seq_addresses[] = new long[]{hdr.getSequenceStartAddress1(), hdr.getSequenceStartAddress2(), hdr.getSequenceStartAddress3()}; + long seq_name_addresses[] = new long[3]; + for (int i = 0; i < 3; i++) { + if (seq_addresses[i] == 0) { + seq_name_addresses[i] = 0; + //0 + } else { + s.seek(seq_addresses[i], SeekMode.SET); + long ofs_seq_name = s.readUI64(); + seq_name_addresses[i] = ofs_seq_name == 1 ? 0 : ofs_seq_name + s.position() - 8; + s.readUI64(); //is this crucial? + } + } + + for (int i = 0; i < 3; i++) { + if (seq_name_addresses[i] > 0) { + s.seek(seq_name_addresses[i], SeekMode.SET); + sequenceNames.add(s.readWChar()); + } else { + sequenceNames.add(null); + } + } + s.pad8bytes(); + + //sequence = new IggySequence(s); + s.seek(hdr.getTypeFontsAddress(), SeekMode.SET); + type_info = new IggyFontTypeInfo[(int) hdr.font_count]; + type_info_name = new String[(int) hdr.font_count]; + for (int i = 0; i < hdr.font_count; i++) { + type_info[i] = new IggyFontTypeInfo(s); + } + for (int i = 0; i < hdr.font_count; i++) { + s.seek(type_info[i].getLocal_name_ofs_pos() + type_info[i].ofs_local_name, SeekMode.SET); + type_info_name[i] = s.readWChar(); + } + + s.seek(hdr.getDeclStringsAddress(), SeekMode.SET); + decl_strings = new IggyDeclStrings(s); + /*WriteDataStreamInterface outs = new TemporaryDataStream(); + writeToDataStream(outs); + Helper.writeFile("d:\\Dropbox\\jpexs-laptop\\iggi\\parts\\swf_out.bin", outs.getAllBytes());*/ + } + + public String getName() { + return name; + } + + @Override + public void writeToDataStream(WriteDataStreamInterface s) throws IOException { + IggyIndexBuilder ib = s.getIndexing(); + hdr.writeToDataStream(s); + s.writeWChar(name); + s.pad8bytes(); + s.writeUI64(1); + ib.write16bitArray(name.length() + 1); + ib.writeTwoPaddingBytes(); + ib.write64bitPointerArray(64); + long posBeforeOffsets = s.position(); + + final int FILL_LATER = 1; + + List fontPosFillLater = new ArrayList<>(); + + for (int i = 0; i < fonts.size(); i++) { + fontPosFillLater.add(s.position()); + s.writeUI64(FILL_LATER); + } + List textPosFillLater = new ArrayList<>(); + for (int i = 0; i < texts.size(); i++) { + textPosFillLater.add(s.position()); + s.writeUI64(FILL_LATER); + } + s.writeUI64(1); + + long addPosFillLater = s.position(); + s.writeUI64(FILL_LATER); + long posAfter = posBeforeOffsets + 64 * 8; + long curPos = s.position(); + long numLeft = posAfter - curPos; + long ofsLeft = numLeft / 8; + for (int i = 0; i < ofsLeft - 1; i++) { + s.writeUI64(FILL_LATER); + } + + for (int i = 0; i < fonts.size(); i++) { + s.setOlderOffsetToThisPos(fontPosFillLater.get(i)); + fonts.get(i).writeToDataStream(s); + } + for (int i = 0; i < texts.size(); i++) { + s.setOlderOffsetToThisPos(textPosFillLater.get(i)); + texts.get(i).writeToDataStream(s); + } + + if (!add_fonts.isEmpty() || !add_texts.isEmpty()) { + s.setOlderOffsetToThisPos(addPosFillLater); + + List addFontPosFillLater = new ArrayList<>(); + + for (int i = 0; i < add_fonts.size(); i++) { + addFontPosFillLater.add(s.position()); + s.writeUI64(FILL_LATER); + } + List addTextPosFillLater = new ArrayList<>(); + for (int i = 0; i < add_texts.size(); i++) { + addTextPosFillLater.add(s.position()); + s.writeUI64(FILL_LATER); + } + s.writeUI64(FILL_LATER); + for (int i = 0; i < add_fonts.size(); i++) { + s.setOlderOffsetToThisPos(addFontPosFillLater.get(i)); + add_fonts.get(i).writeToDataStream(s); + } + for (int i = 0; i < add_texts.size(); i++) { + s.setOlderOffsetToThisPos(addTextPosFillLater.get(i)); + add_texts.get(i).writeToDataStream(s); + } + } + s.setOlderOffsetToThisPos(hdr.getFont_end_ofs_pos()); + ib.writeConstLengthArray(IggyIndexBuilder.CONST_BIN_INFO_SIZE, hdr.font_count); + for (int i = 0; i < hdr.font_count; i++) { + font_bin_info[i].writeToDataStream(s); + } + + long seq_ofs_pos[] = new long[]{hdr.getSequence_start1_ofs_pos(), hdr.getSequence_start2_ofs_pos(), hdr.getSequence_start3_ofs_pos()}; + long off_seq_expected[] = new long[]{hdr.off_sequence_start1, hdr.off_sequence_start2, hdr.off_sequence_start3}; + + long seq_name_fill_later[] = new long[3]; + + s.setOlderOffsetToThisPos(seq_ofs_pos[0]); + s.writeUI64(1); + s.writeUI64(1); + ib.writeLengthCustom(16, new int[]{0}, new int[]{2}); + + seq_name_fill_later[2] = s.position(); + s.setOlderOffsetToThisPos(seq_ofs_pos[2]); + s.writeUI64(FILL_LATER); + s.writeUI64(0); + ib.writeConstLength(IggyIndexBuilder.CONST_SEQUENCE_SIZE); + for (int i = 0; i < 3; i++) { + if (sequenceNames.get(i) != null) { + s.setOlderOffsetToThisPos(seq_name_fill_later[i]); + ib.write16bitArray(sequenceNames.get(i).length() + 1); + s.writeWChar(sequenceNames.get(i)); + } + } + s.setOlderOffsetToThisPos(hdr.getSequence_end_ofs_pos()); + s.pad8bytes(); + ib.pad8bytes(); + + ib.writeConstLengthArray(IggyIndexBuilder.CONST_TYPE_INFO_SIZE, hdr.font_count); + s.setOlderOffsetToThisPos(hdr.getType_fonts_ofs_pos()); + //s.seek(hdr.getTypeFontsAddress(), SeekMode.SET); + for (int i = 0; i < hdr.font_count; i++) { + type_info[i].writeToDataStream(s); + } + + for (int i = 0; i < hdr.font_count; i++) { + ib.write16bitArray(type_info_name[i].length() + 1); + s.setOlderOffsetToThisPos(type_info[i].getLocal_name_ofs_pos()); + s.writeWChar(type_info_name[i]); + } + s.pad8bytes(); + ib.pad8bytes(); + + s.setOlderOffsetToThisPos(hdr.getDecl_strings_ofs_pos()); + //s.seek(hdr.getDeclStringsAddress(), SeekMode.SET); + decl_strings.writeToDataStream(s); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("[\r\n"); + sb.append("name ").append(name).append("\r\n"); + return sb.toString(); + } + +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyTag.java index eeae0f3cb..7f1a44796 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyTag.java @@ -1,17 +1,17 @@ -package com.jpexs.decompiler.flash.iggy; - -import com.jpexs.decompiler.flash.iggy.streams.StructureInterface; - -/** - * - * @author JPEXS - */ -public abstract class IggyTag implements StructureInterface { - - public abstract int getTagType(); - - @Override - public String toString() { - return String.format("IggyTag (%04X)", getTagType()); - } -} +package com.jpexs.decompiler.flash.iggy; + +import com.jpexs.decompiler.flash.iggy.streams.StructureInterface; + +/** + * + * @author JPEXS + */ +public abstract class IggyTag implements StructureInterface { + + public abstract int getTagType(); + + @Override + public String toString() { + return String.format("IggyTag (%04X)", getTagType()); + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyText.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyText.java index 8aee23b66..55da18db9 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyText.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyText.java @@ -1,194 +1,194 @@ -package com.jpexs.decompiler.flash.iggy; - -import com.jpexs.decompiler.flash.iggy.annotations.IggyArrayFieldType; -import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType; -import com.jpexs.decompiler.flash.iggy.streams.IggyIndexBuilder; -import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface; -import com.jpexs.decompiler.flash.iggy.streams.SeekMode; -import com.jpexs.decompiler.flash.iggy.streams.StructureInterface; -import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface; -import java.io.IOException; - -/** - * - * @author JPEXS - */ -public class IggyText implements StructureInterface { - - public static final int STRUCT_SIZE = 104; - - public static final int ID = 0xFF06; - - @IggyFieldType(DataType.uint16_t) - int type; // Tag type - @IggyFieldType(DataType.uint16_t) - int textIndex; - @IggyArrayFieldType(value = DataType.uint8_t, count = 28) - byte zeroone[]; - @IggyFieldType(DataType.float_t) - float par1; - @IggyFieldType(DataType.float_t) - float par2; - @IggyFieldType(DataType.float_t) - float par3; - @IggyFieldType(DataType.float_t) - float par4; - @IggyFieldType(DataType.uint16_t) - int enum_hex; - - //Guessed - boolean hasText; - boolean wordWrap; - boolean multiline; - boolean password; - boolean readOnly; - boolean hasTextColor; - boolean hasMaxLength; - boolean hasFont; - boolean hasFontClass; - boolean autosize; - boolean hasLayout; - boolean noSelect; - boolean border; - boolean wasStatic; - boolean html; - boolean useOutlines; - - @IggyFieldType(DataType.uint16_t) - int fontIndex; - @IggyFieldType(DataType.uint32_t) - long zero; - @IggyFieldType(DataType.uint64_t) - long one; - @IggyArrayFieldType(value = DataType.uint8_t, count = 32) - byte[] some; // same for different fonts - long ofs_name; - - @IggyArrayFieldType(value = DataType.wchar_t) - String initialText; //till end of info file? - - public IggyText(int type, int order_in_iggy_file, byte[] zeroone, float par1, float par2, float par3, float par4, int enum_hex, int for_which_font_order_in_iggyfile, long zero, long one, byte[] some, long offset_of_name, String name) { - this.type = type; - this.textIndex = order_in_iggy_file; - this.zeroone = zeroone; - this.par1 = par1; - this.par2 = par2; - this.par3 = par3; - this.par4 = par4; - this.enum_hex = enum_hex; - this.fontIndex = for_which_font_order_in_iggyfile; - this.zero = zero; - this.one = one; - this.some = some; - this.initialText = name; - } - - public IggyText(ReadDataStreamInterface stream) throws IOException { - this.readFromDataStream(stream); - } - - @Override - public void readFromDataStream(ReadDataStreamInterface s) throws IOException { - - type = s.readUI16(); - //characterId - iggy Id - textIndex = s.readUI16(); - zeroone = s.readBytes(28); - - //bounds?: - par1 = s.readFloat(); - par2 = s.readFloat(); - par3 = s.readFloat(); - par4 = s.readFloat(); - - enum_hex = s.readUI16(); - fontIndex = s.readUI16(); //fontId - zero = s.readUI32(); - one = s.readUI64(); //01CB FF33 3333 - some = s.readBytes(32); // [6] => 40, [24] => 8 - ofs_name = s.readUI64(); - long name_address = ofs_name + s.position() - 8; - s.seek(name_address, SeekMode.SET); - initialText = s.readWChar(); - s.pad8bytes(); - } - - @Override - public void writeToDataStream(WriteDataStreamInterface s) throws IOException { - s.getIndexing().writeConstLength(IggyIndexBuilder.CONST_TEXT_DATA_SIZE); - s.writeUI16(type); - s.writeUI16(textIndex); - s.writeBytes(zeroone); - s.writeFloat(par1); - s.writeFloat(par2); - s.writeFloat(par3); - s.writeFloat(par4); - s.writeUI16(enum_hex); - s.writeUI16(fontIndex); - s.writeUI32(zero); - s.writeUI64(one); - s.writeBytes(some); - s.writeUI64(ofs_name); - long name_address = ofs_name + s.position() - 8; - s.seek(name_address, SeekMode.SET); - s.writeWChar(initialText); - s.pad8bytes(); - - s.getIndexing().write16bitArray(initialText.length() + 1); - s.getIndexing().pad8bytes(); - - } - - public int getType() { - return type; - } - - public int getTextIndex() { - return textIndex; - } - - public byte[] getZeroone() { - return zeroone; - } - - public float getPar1() { - return par1; - } - - public float getPar2() { - return par2; - } - - public float getPar3() { - return par3; - } - - public float getPar4() { - return par4; - } - - public int getEnum_hex() { - return enum_hex; - } - - public int getFontIndex() { - return fontIndex; - } - - public long getZero() { - return zero; - } - - public long getOne() { - return one; - } - - public byte[] getSome() { - return some; - } - - public String getInitialText() { - return initialText; - } - -} +package com.jpexs.decompiler.flash.iggy; + +import com.jpexs.decompiler.flash.iggy.annotations.IggyArrayFieldType; +import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType; +import com.jpexs.decompiler.flash.iggy.streams.IggyIndexBuilder; +import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface; +import com.jpexs.decompiler.flash.iggy.streams.SeekMode; +import com.jpexs.decompiler.flash.iggy.streams.StructureInterface; +import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface; +import java.io.IOException; + +/** + * + * @author JPEXS + */ +public class IggyText implements StructureInterface { + + public static final int STRUCT_SIZE = 104; + + public static final int ID = 0xFF06; + + @IggyFieldType(DataType.uint16_t) + int type; // Tag type + @IggyFieldType(DataType.uint16_t) + int textIndex; + @IggyArrayFieldType(value = DataType.uint8_t, count = 28) + byte zeroone[]; + @IggyFieldType(DataType.float_t) + float par1; + @IggyFieldType(DataType.float_t) + float par2; + @IggyFieldType(DataType.float_t) + float par3; + @IggyFieldType(DataType.float_t) + float par4; + @IggyFieldType(DataType.uint16_t) + int enum_hex; + + //Guessed + boolean hasText; + boolean wordWrap; + boolean multiline; + boolean password; + boolean readOnly; + boolean hasTextColor; + boolean hasMaxLength; + boolean hasFont; + boolean hasFontClass; + boolean autosize; + boolean hasLayout; + boolean noSelect; + boolean border; + boolean wasStatic; + boolean html; + boolean useOutlines; + + @IggyFieldType(DataType.uint16_t) + int fontIndex; + @IggyFieldType(DataType.uint32_t) + long zero; + @IggyFieldType(DataType.uint64_t) + long one; + @IggyArrayFieldType(value = DataType.uint8_t, count = 32) + byte[] some; // same for different fonts + long ofs_name; + + @IggyArrayFieldType(value = DataType.wchar_t) + String initialText; //till end of info file? + + public IggyText(int type, int order_in_iggy_file, byte[] zeroone, float par1, float par2, float par3, float par4, int enum_hex, int for_which_font_order_in_iggyfile, long zero, long one, byte[] some, long offset_of_name, String name) { + this.type = type; + this.textIndex = order_in_iggy_file; + this.zeroone = zeroone; + this.par1 = par1; + this.par2 = par2; + this.par3 = par3; + this.par4 = par4; + this.enum_hex = enum_hex; + this.fontIndex = for_which_font_order_in_iggyfile; + this.zero = zero; + this.one = one; + this.some = some; + this.initialText = name; + } + + public IggyText(ReadDataStreamInterface stream) throws IOException { + this.readFromDataStream(stream); + } + + @Override + public void readFromDataStream(ReadDataStreamInterface s) throws IOException { + + type = s.readUI16(); + //characterId - iggy Id + textIndex = s.readUI16(); + zeroone = s.readBytes(28); + + //bounds?: + par1 = s.readFloat(); + par2 = s.readFloat(); + par3 = s.readFloat(); + par4 = s.readFloat(); + + enum_hex = s.readUI16(); + fontIndex = s.readUI16(); //fontId + zero = s.readUI32(); + one = s.readUI64(); //01CB FF33 3333 + some = s.readBytes(32); // [6] => 40, [24] => 8 + ofs_name = s.readUI64(); + long name_address = ofs_name + s.position() - 8; + s.seek(name_address, SeekMode.SET); + initialText = s.readWChar(); + s.pad8bytes(); + } + + @Override + public void writeToDataStream(WriteDataStreamInterface s) throws IOException { + s.getIndexing().writeConstLength(IggyIndexBuilder.CONST_TEXT_DATA_SIZE); + s.writeUI16(type); + s.writeUI16(textIndex); + s.writeBytes(zeroone); + s.writeFloat(par1); + s.writeFloat(par2); + s.writeFloat(par3); + s.writeFloat(par4); + s.writeUI16(enum_hex); + s.writeUI16(fontIndex); + s.writeUI32(zero); + s.writeUI64(one); + s.writeBytes(some); + s.writeUI64(ofs_name); + long name_address = ofs_name + s.position() - 8; + s.seek(name_address, SeekMode.SET); + s.writeWChar(initialText); + s.pad8bytes(); + + s.getIndexing().write16bitArray(initialText.length() + 1); + s.getIndexing().pad8bytes(); + + } + + public int getType() { + return type; + } + + public int getTextIndex() { + return textIndex; + } + + public byte[] getZeroone() { + return zeroone; + } + + public float getPar1() { + return par1; + } + + public float getPar2() { + return par2; + } + + public float getPar3() { + return par3; + } + + public float getPar4() { + return par4; + } + + public int getEnum_hex() { + return enum_hex; + } + + public int getFontIndex() { + return fontIndex; + } + + public long getZero() { + return zero; + } + + public long getOne() { + return one; + } + + public byte[] getSome() { + return some; + } + + public String getInitialText() { + return initialText; + } + +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/RawIggyPart.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/RawIggyPart.java index 9f1e0aeaa..609139f7b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/RawIggyPart.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/RawIggyPart.java @@ -1,38 +1,38 @@ -package com.jpexs.decompiler.flash.iggy; - -import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface; -import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface; -import java.io.IOException; - -/** - * - * @author JPEXS - */ -public class RawIggyPart extends IggyTag { - - byte[] rawData; - int tagType; - private int length; - - public RawIggyPart(int tagType, ReadDataStreamInterface stream, int length) throws IOException { - this.length = length; - this.tagType = tagType; - readFromDataStream(stream); - } - - @Override - public int getTagType() { - return tagType; - } - - @Override - public void readFromDataStream(ReadDataStreamInterface stream) throws IOException { - rawData = stream.readBytes(length); - } - - @Override - public void writeToDataStream(WriteDataStreamInterface stream) throws IOException { - stream.writeBytes(rawData); - } - -} +package com.jpexs.decompiler.flash.iggy; + +import com.jpexs.decompiler.flash.iggy.streams.ReadDataStreamInterface; +import com.jpexs.decompiler.flash.iggy.streams.WriteDataStreamInterface; +import java.io.IOException; + +/** + * + * @author JPEXS + */ +public class RawIggyPart extends IggyTag { + + byte[] rawData; + int tagType; + private int length; + + public RawIggyPart(int tagType, ReadDataStreamInterface stream, int length) throws IOException { + this.length = length; + this.tagType = tagType; + readFromDataStream(stream); + } + + @Override + public int getTagType() { + return tagType; + } + + @Override + public void readFromDataStream(ReadDataStreamInterface stream) throws IOException { + rawData = stream.readBytes(length); + } + + @Override + public void writeToDataStream(WriteDataStreamInterface stream) throws IOException { + stream.writeBytes(rawData); + } + +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/annotations/FieldPrinter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/annotations/FieldPrinter.java index 9d3325283..cbf87f659 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/annotations/FieldPrinter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/annotations/FieldPrinter.java @@ -1,80 +1,80 @@ -package com.jpexs.decompiler.flash.iggy.annotations; - -import java.lang.reflect.Field; - -/** - * - * @author JPEXS - */ -public class FieldPrinter { - - public static String getObjectSummary(Object val) { - StringBuilder sb = new StringBuilder(); - sb.append("/---" + val.getClass().getSimpleName() + "---\r\n"); - for (Field f : val.getClass().getDeclaredFields()) { - sb.append(f.getName()).append(": "); - IggyFieldType an = f.getAnnotation(IggyFieldType.class); - if (an != null) { - f.setAccessible(true); - try { - switch (an.value()) { - case float_t: - sb.append(f.getFloat(val)); - break; - case uint8_t: - case uint16_t: - sb.append(f.getInt(val)); - break; - case uint32_t: - case uint64_t: - sb.append(f.getLong(val)); - break; - case wchar_t: - sb.append("\"").append(f.get(val)).append("\""); - break; - } - } catch (IllegalAccessException ex) { - - } - } - sb.append("\r\n"); - } - sb.append("---/"); - return sb.toString(); - } - - public static String getObjectWriteTo(Class cls) { - StringBuilder sb = new StringBuilder(); - for (Field f : cls.getDeclaredFields()) { - sb.append("stream.write"); - IggyFieldType an = f.getAnnotation(IggyFieldType.class); - if (an != null) { - switch (an.value()) { - case float_t: - sb.append("Float"); - break; - case uint8_t: - sb.append("UI8"); - break; - case uint16_t: - sb.append("UI16"); - break; - case uint32_t: - sb.append("UI32"); - break; - case uint64_t: - sb.append("UI64"); - break; - case wchar_t: - sb.append("//FIXME"); - break; - } - sb.append("(").append(f.getName()).append(");\r\n"); - if (an.count() > 0) { - sb.append("//FIXME count"); - } - } - } - return sb.toString(); - } -} +package com.jpexs.decompiler.flash.iggy.annotations; + +import java.lang.reflect.Field; + +/** + * + * @author JPEXS + */ +public class FieldPrinter { + + public static String getObjectSummary(Object val) { + StringBuilder sb = new StringBuilder(); + sb.append("/---" + val.getClass().getSimpleName() + "---\r\n"); + for (Field f : val.getClass().getDeclaredFields()) { + sb.append(f.getName()).append(": "); + IggyFieldType an = f.getAnnotation(IggyFieldType.class); + if (an != null) { + f.setAccessible(true); + try { + switch (an.value()) { + case float_t: + sb.append(f.getFloat(val)); + break; + case uint8_t: + case uint16_t: + sb.append(f.getInt(val)); + break; + case uint32_t: + case uint64_t: + sb.append(f.getLong(val)); + break; + case wchar_t: + sb.append("\"").append(f.get(val)).append("\""); + break; + } + } catch (IllegalAccessException ex) { + + } + } + sb.append("\r\n"); + } + sb.append("---/"); + return sb.toString(); + } + + public static String getObjectWriteTo(Class cls) { + StringBuilder sb = new StringBuilder(); + for (Field f : cls.getDeclaredFields()) { + sb.append("stream.write"); + IggyFieldType an = f.getAnnotation(IggyFieldType.class); + if (an != null) { + switch (an.value()) { + case float_t: + sb.append("Float"); + break; + case uint8_t: + sb.append("UI8"); + break; + case uint16_t: + sb.append("UI16"); + break; + case uint32_t: + sb.append("UI32"); + break; + case uint64_t: + sb.append("UI64"); + break; + case wchar_t: + sb.append("//FIXME"); + break; + } + sb.append("(").append(f.getName()).append(");\r\n"); + if (an.count() > 0) { + sb.append("//FIXME count"); + } + } + } + return sb.toString(); + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/conversion/IggyShapeToSwfConvertor.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/conversion/IggyShapeToSwfConvertor.java index 00ab98dce..f8bed725b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/conversion/IggyShapeToSwfConvertor.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/conversion/IggyShapeToSwfConvertor.java @@ -1,105 +1,105 @@ -package com.jpexs.decompiler.flash.iggy.conversion; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.iggy.IggyShape; -import com.jpexs.decompiler.flash.iggy.IggyShapeNode; -import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY; -import com.jpexs.decompiler.flash.types.LINESTYLE; -import com.jpexs.decompiler.flash.types.LINESTYLEARRAY; -import com.jpexs.decompiler.flash.types.RGB; -import com.jpexs.decompiler.flash.types.SHAPE; -import com.jpexs.decompiler.flash.types.shaperecords.CurvedEdgeRecord; -import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord; -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 java.awt.Color; -import java.util.ArrayList; -import java.util.List; - -/** - * - * @author JPEXS - */ -public class IggyShapeToSwfConvertor { - - private static int makeLengthsEmX(double val) { - return (int) (val * 1024.0); - } - - private static int makeLengthsEmY(double val) { - return (int) (val * 1024.0); - } - - public static SHAPE convertCharToShape(IggyShape igchar) { - SHAPE shape = new SHAPE(); - List retList = new ArrayList<>(); - List ignodes = igchar.getNodes(); - - int prevX = 0; - int prevY = 0; - - for (IggyShapeNode ign : ignodes) { - if (ign.getNodeType() == IggyShapeNode.NODE_TYPE_MOVE) { - StyleChangeRecord scr = new StyleChangeRecord(); - scr.stateMoveTo = true; - prevX = scr.moveDeltaX = makeLengthsEmX(ign.getTargetX()); - prevY = scr.moveDeltaY = makeLengthsEmY(ign.getTargetY()); - scr.fillStyles = new FILLSTYLEARRAY(); - scr.lineStyles = new LINESTYLEARRAY(); - scr.calculateBits(); - retList.add(scr); - } else { - - int curX1 = makeLengthsEmX(ign.getTargetX()); - int curY1 = makeLengthsEmY(ign.getTargetY()); - - int curX2 = makeLengthsEmX(ign.getControlX()); - int curY2 = makeLengthsEmY(ign.getControlY()); - - if (ign.getNodeType() == IggyShapeNode.NODE_TYPE_LINE_TO) { - StraightEdgeRecord ser = new StraightEdgeRecord(); - ser.deltaX = curX1 - prevX; - ser.deltaY = curY1 - prevY; - ser.generalLineFlag = true; - ser.simplify(); - ser.calculateBits(); - prevX = curX1; - prevY = curY1; - retList.add(ser); - } else if (ign.getNodeType() == IggyShapeNode.NODE_TYPE_CURVE_POINT) { - CurvedEdgeRecord cer = new CurvedEdgeRecord(); - cer.controlDeltaX = curX2 - prevX; - cer.controlDeltaY = curY2 - prevY; - cer.anchorDeltaX = curX1 - curX2; - cer.anchorDeltaY = curY1 - curY2; - prevX = curX1; - prevY = curY1; - cer.calculateBits(); - retList.add(cer); - } - } - } - if (!retList.isEmpty()) { - StyleChangeRecord init; - if (retList.get(0) instanceof StyleChangeRecord) { - init = (StyleChangeRecord) retList.get(0); - } else { - init = new StyleChangeRecord(); - retList.add(0, init); - } - init.stateFillStyle0 = true; - init.fillStyle0 = 1; - shape.numFillBits = 1; - - } else { - shape.numFillBits = 0; - - } - retList.add(new EndShapeRecord()); - shape.shapeRecords = retList; - shape.numLineBits = 0; - - return shape; - } -} +package com.jpexs.decompiler.flash.iggy.conversion; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.iggy.IggyShape; +import com.jpexs.decompiler.flash.iggy.IggyShapeNode; +import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY; +import com.jpexs.decompiler.flash.types.LINESTYLE; +import com.jpexs.decompiler.flash.types.LINESTYLEARRAY; +import com.jpexs.decompiler.flash.types.RGB; +import com.jpexs.decompiler.flash.types.SHAPE; +import com.jpexs.decompiler.flash.types.shaperecords.CurvedEdgeRecord; +import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord; +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 java.awt.Color; +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author JPEXS + */ +public class IggyShapeToSwfConvertor { + + private static int makeLengthsEmX(double val) { + return (int) (val * 1024.0); + } + + private static int makeLengthsEmY(double val) { + return (int) (val * 1024.0); + } + + public static SHAPE convertCharToShape(IggyShape igchar) { + SHAPE shape = new SHAPE(); + List retList = new ArrayList<>(); + List ignodes = igchar.getNodes(); + + int prevX = 0; + int prevY = 0; + + for (IggyShapeNode ign : ignodes) { + if (ign.getNodeType() == IggyShapeNode.NODE_TYPE_MOVE) { + StyleChangeRecord scr = new StyleChangeRecord(); + scr.stateMoveTo = true; + prevX = scr.moveDeltaX = makeLengthsEmX(ign.getTargetX()); + prevY = scr.moveDeltaY = makeLengthsEmY(ign.getTargetY()); + scr.fillStyles = new FILLSTYLEARRAY(); + scr.lineStyles = new LINESTYLEARRAY(); + scr.calculateBits(); + retList.add(scr); + } else { + + int curX1 = makeLengthsEmX(ign.getTargetX()); + int curY1 = makeLengthsEmY(ign.getTargetY()); + + int curX2 = makeLengthsEmX(ign.getControlX()); + int curY2 = makeLengthsEmY(ign.getControlY()); + + if (ign.getNodeType() == IggyShapeNode.NODE_TYPE_LINE_TO) { + StraightEdgeRecord ser = new StraightEdgeRecord(); + ser.deltaX = curX1 - prevX; + ser.deltaY = curY1 - prevY; + ser.generalLineFlag = true; + ser.simplify(); + ser.calculateBits(); + prevX = curX1; + prevY = curY1; + retList.add(ser); + } else if (ign.getNodeType() == IggyShapeNode.NODE_TYPE_CURVE_POINT) { + CurvedEdgeRecord cer = new CurvedEdgeRecord(); + cer.controlDeltaX = curX2 - prevX; + cer.controlDeltaY = curY2 - prevY; + cer.anchorDeltaX = curX1 - curX2; + cer.anchorDeltaY = curY1 - curY2; + prevX = curX1; + prevY = curY1; + cer.calculateBits(); + retList.add(cer); + } + } + } + if (!retList.isEmpty()) { + StyleChangeRecord init; + if (retList.get(0) instanceof StyleChangeRecord) { + init = (StyleChangeRecord) retList.get(0); + } else { + init = new StyleChangeRecord(); + retList.add(0, init); + } + init.stateFillStyle0 = true; + init.fillStyle0 = 1; + shape.numFillBits = 1; + + } else { + shape.numFillBits = 0; + + } + retList.add(new EndShapeRecord()); + shape.shapeRecords = retList; + shape.numLineBits = 0; + + return shape; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/conversion/IggySwfBundle.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/conversion/IggySwfBundle.java index 058f010e1..f27390ded 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/conversion/IggySwfBundle.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/conversion/IggySwfBundle.java @@ -1,134 +1,134 @@ -package com.jpexs.decompiler.flash.iggy.conversion; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFBundle; -import com.jpexs.decompiler.flash.iggy.IggyFile; -import com.jpexs.decompiler.flash.iggy.IggyFont; -import com.jpexs.decompiler.flash.tags.DefineFont2Tag; -import com.jpexs.decompiler.flash.tags.base.CharacterTag; -import com.jpexs.helpers.Helper; -import com.jpexs.helpers.MemoryInputStream; -import com.jpexs.helpers.ReReadableInputStream; -import com.jpexs.helpers.streams.SeekableInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeSet; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - * @author JPEXS - */ -public class IggySwfBundle implements SWFBundle { - - private IggyFile iggyFile; - - public IggySwfBundle(InputStream is) throws IOException { - this(is, null); - } - - public IggySwfBundle(File filename) throws IOException { - this(null, filename); - } - - protected IggySwfBundle(InputStream is, File filename) throws IOException { - initBundle(is, filename); - } - - protected void initBundle(InputStream is, File filename) throws IOException { - if (filename == null) { - filename = File.createTempFile("bundle", ".iggy"); - Helper.saveStream(is, filename); - } - iggyFile = new IggyFile(filename); - } - - @Override - public int length() { - return 1; - } - - @Override - public Set getKeys() { - Set ret = new TreeSet<>(); - for (int i = 0; i < length(); i++) { - ret.add(iggyFile.getSwfName()); - } - return ret; - } - - private int keyToSwfIndex(String key) { - for (int i = 0; i < length(); i++) { - if (key.equals(iggyFile.getSwfName())) { - return i; - } - } - throw new IllegalArgumentException("Key " + key + " does not exist!"); - } - - @Override - public SeekableInputStream getSWF(String key) throws IOException { - SWF swf = IggyToSwfConvertor.getSwf(iggyFile); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - swf.saveTo(baos); - MemoryInputStream mis = new MemoryInputStream(baos.toByteArray()); - return mis; - } - - @Override - public Map getAll() throws IOException { - Map ret = new HashMap<>(); - for (String key : getKeys()) { - ret.put(key, getSWF(key)); - } - return ret; - } - - @Override - public String getExtension() { - return "iggy"; - } - - @Override - public boolean isReadOnly() { - return false; - } - - @Override - public boolean putSWF(String key, InputStream is) throws IOException { - try { - int swfIndex = 0; - SWF swf = new SWF(is, false, false); - List fontTags = new ArrayList<>(); - for (CharacterTag ct : swf.getCharacters().values()) { - if (ct instanceof DefineFont2Tag) { - fontTags.add((DefineFont2Tag) ct); - } - } - int fontCount = iggyFile.getFontCount(); - if (fontCount != fontTags.size()) { - throw new IOException("Font count is different from original iggy file"); - } - for (int i = 0; i < fontCount; i++) { - IggyFont iggyFont = iggyFile.getFont(i); - DefineFont2Tag fontTag = fontTags.get(i); - SwfToIggyConvertor.updateIggyFont(iggyFont, fontTag); - } - iggyFile.saveChanges(); - return true; - } catch (InterruptedException ex) { - return false; - } - - } - -} +package com.jpexs.decompiler.flash.iggy.conversion; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFBundle; +import com.jpexs.decompiler.flash.iggy.IggyFile; +import com.jpexs.decompiler.flash.iggy.IggyFont; +import com.jpexs.decompiler.flash.tags.DefineFont2Tag; +import com.jpexs.decompiler.flash.tags.base.CharacterTag; +import com.jpexs.helpers.Helper; +import com.jpexs.helpers.MemoryInputStream; +import com.jpexs.helpers.ReReadableInputStream; +import com.jpexs.helpers.streams.SeekableInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author JPEXS + */ +public class IggySwfBundle implements SWFBundle { + + private IggyFile iggyFile; + + public IggySwfBundle(InputStream is) throws IOException { + this(is, null); + } + + public IggySwfBundle(File filename) throws IOException { + this(null, filename); + } + + protected IggySwfBundle(InputStream is, File filename) throws IOException { + initBundle(is, filename); + } + + protected void initBundle(InputStream is, File filename) throws IOException { + if (filename == null) { + filename = File.createTempFile("bundle", ".iggy"); + Helper.saveStream(is, filename); + } + iggyFile = new IggyFile(filename); + } + + @Override + public int length() { + return 1; + } + + @Override + public Set getKeys() { + Set ret = new TreeSet<>(); + for (int i = 0; i < length(); i++) { + ret.add(iggyFile.getSwfName()); + } + return ret; + } + + private int keyToSwfIndex(String key) { + for (int i = 0; i < length(); i++) { + if (key.equals(iggyFile.getSwfName())) { + return i; + } + } + throw new IllegalArgumentException("Key " + key + " does not exist!"); + } + + @Override + public SeekableInputStream getSWF(String key) throws IOException { + SWF swf = IggyToSwfConvertor.getSwf(iggyFile); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + swf.saveTo(baos); + MemoryInputStream mis = new MemoryInputStream(baos.toByteArray()); + return mis; + } + + @Override + public Map getAll() throws IOException { + Map ret = new HashMap<>(); + for (String key : getKeys()) { + ret.put(key, getSWF(key)); + } + return ret; + } + + @Override + public String getExtension() { + return "iggy"; + } + + @Override + public boolean isReadOnly() { + return false; + } + + @Override + public boolean putSWF(String key, InputStream is) throws IOException { + try { + int swfIndex = 0; + SWF swf = new SWF(is, false, false); + List fontTags = new ArrayList<>(); + for (CharacterTag ct : swf.getCharacters().values()) { + if (ct instanceof DefineFont2Tag) { + fontTags.add((DefineFont2Tag) ct); + } + } + int fontCount = iggyFile.getFontCount(); + if (fontCount != fontTags.size()) { + throw new IOException("Font count is different from original iggy file"); + } + for (int i = 0; i < fontCount; i++) { + IggyFont iggyFont = iggyFile.getFont(i); + DefineFont2Tag fontTag = fontTags.get(i); + SwfToIggyConvertor.updateIggyFont(iggyFont, fontTag); + } + iggyFile.saveChanges(); + return true; + } catch (InterruptedException ex) { + return false; + } + + } + +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/conversion/IggyToSwfConvertor.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/conversion/IggyToSwfConvertor.java index 3fcaafad2..16acd29c2 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/conversion/IggyToSwfConvertor.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/conversion/IggyToSwfConvertor.java @@ -1,244 +1,244 @@ -package com.jpexs.decompiler.flash.iggy.conversion; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFCompression; -import com.jpexs.decompiler.flash.iggy.IggyShape; -import com.jpexs.decompiler.flash.iggy.IggyCharKerning; -import com.jpexs.decompiler.flash.iggy.IggyShapeNode; -import com.jpexs.decompiler.flash.iggy.IggyCharOffset; -import com.jpexs.decompiler.flash.iggy.IggyCharAdvances; -import com.jpexs.decompiler.flash.iggy.IggyFile; -import com.jpexs.decompiler.flash.iggy.IggyFont; -import com.jpexs.decompiler.flash.iggy.IggySwf; -import com.jpexs.decompiler.flash.iggy.IggyText; -import com.jpexs.decompiler.flash.tags.DefineEditTextTag; -import com.jpexs.decompiler.flash.tags.DefineFont2Tag; -import com.jpexs.decompiler.flash.tags.EndTag; -import com.jpexs.decompiler.flash.tags.FileAttributesTag; -import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY; -import com.jpexs.decompiler.flash.types.KERNINGRECORD; -import com.jpexs.decompiler.flash.types.LINESTYLEARRAY; -import com.jpexs.decompiler.flash.types.RECT; -import com.jpexs.decompiler.flash.types.RGBA; -import com.jpexs.decompiler.flash.types.SHAPE; -import com.jpexs.decompiler.flash.types.shaperecords.CurvedEdgeRecord; -import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord; -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 java.awt.Color; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * - * WIP - * - * @author JPEXS - */ -public class IggyToSwfConvertor { - - public static void exportAllSwfsToDir(IggyFile file, File outputDir) throws IOException { - exportSwfToDir(file, outputDir); - } - - public static void exportSwfToDir(IggyFile file, File outputDir) throws IOException { - try (FileOutputStream fos = new FileOutputStream(new File(outputDir, file.getSwfName()))) { - exportSwf(file, fos); - } - } - - public static void exportSwfToFile(IggyFile file, File outputFile) throws IOException { - try (FileOutputStream fos = new FileOutputStream(outputFile)) { - exportSwf(file, fos); - } - } - - public static void exportSwf(IggyFile file, OutputStream output) throws IOException { - SWF swf = getSwf(file); - swf.saveTo(output); - } - - private static int makeLengthsEm(double val) { - return (int) (val * 1024.0); - } - - public static SWF getSwf(IggyFile file) { - SWF swf = new SWF(); - swf.compression = SWFCompression.NONE; - swf.frameCount = 1; //FIXME!! - swf.frameRate = file.getSwfFrameRate(); - swf.gfx = false; - swf.displayRect = new RECT( - (int) (file.getSwfXMin() * SWF.unitDivisor), - (int) (file.getSwfXMax() * SWF.unitDivisor), - (int) (file.getSwfYMin() * SWF.unitDivisor), - (int) (file.getSwfYMax() * SWF.unitDivisor)); - swf.version = 10; //FIXME - - FileAttributesTag fat = new FileAttributesTag(swf); - fat.actionScript3 = false; - fat.hasMetadata = false; - fat.useNetwork = false; - swf.addTag(fat); - //Set fontIndices = file.getFontIds(swfIndex); - int fontCount = file.getFontCount(); - - int currentCharId = 0; - Map fontIndex2CharId = new HashMap<>(); - - for (int fontIndex = 0; fontIndex < fontCount; fontIndex++) { - IggyFont iggyFont = file.getFont(fontIndex); - DefineFont2Tag fontTag = new DefineFont2Tag(swf); - currentCharId++; - fontIndex2CharId.put(fontIndex, currentCharId); - fontTag.fontID = currentCharId; - /*System.out.println("==================="); - System.out.println("xscale: " + iggyFont.getXscale()); //80 - System.out.println("yscale: " + iggyFont.getYscale()); //19 - - System.out.println("unk_float1: " + iggyFont.getUnk_float()[0]); - System.out.println("unk_float2: " + iggyFont.getUnk_float()[1]); - System.out.println("unk_float3: " + iggyFont.getUnk_float()[2]); - System.out.println("unk_float4: " + iggyFont.getUnk_float()[3]); - System.out.println("unk_float5: " + iggyFont.getUnk_float()[4]); - System.out.println("what_2: " + iggyFont.getWhat_2()); - System.out.println("what_3: " + iggyFont.getWhat_3());*/ - - fontTag.fontKerningTable = new ArrayList<>(); - IggyCharKerning ker = iggyFont.getCharKernings(); - if (ker != null) { - for (int i = 0; i < ker.getKernCount(); i++) { - int kerningCode1 = ker.getCharsA().get(i); - int kerningCode2 = ker.getCharsA().get(i); - int kerningOffset = ker.getKerningOffsets().get(i); - fontTag.fontKerningTable.add(new KERNINGRECORD(kerningCode1, kerningCode2, kerningOffset)); - } - } - - fontTag.fontFlagsWideCodes = true; - fontTag.fontFlagsWideOffsets = true; - fontTag.fontAscent = iggyFont.getAscent(); - fontTag.fontDescent = iggyFont.getDescent(); - fontTag.fontLeading = iggyFont.getLeading(); - fontTag.codeTable = new ArrayList<>(); - fontTag.fontName = iggyFont.getName(); - fontTag.glyphShapeTable = new ArrayList<>(); - fontTag.fontBoundsTable = new ArrayList<>(); - fontTag.fontAdvanceTable = new ArrayList<>(); - fontTag.fontFlagsHasLayout = true; - IggyCharAdvances advanceValues = iggyFont.getCharAdvances(); - for (int i = 0; i < iggyFont.getCharacterCount(); i++) { - int code = iggyFont.getCharIndices().getChars().get(i); - fontTag.codeTable.add(code); - IggyShape glyph = iggyFont.getChars().get(i); - SHAPE shp; - if (glyph != null) { - shp = IggyShapeToSwfConvertor.convertCharToShape(glyph); - fontTag.fontBoundsTable.add(shp.getBounds()); - } else { - shp = new SHAPE(); - shp.shapeRecords = new ArrayList<>(); - shp.shapeRecords.add(new EndShapeRecord()); - fontTag.fontBoundsTable.add(new RECT()); //?? - } - fontTag.glyphShapeTable.add(shp); - - fontTag.fontAdvanceTable.add(makeLengthsEm(advanceValues.getScales().get(i))); - - } - fontTag.setModified(true); - swf.addTag(fontTag); - } - - /* - //TODO: Texts, they are incomplete - - Map textIndex2CharId = new HashMap<>(); - - Set textIds = file.getTextIds(swfIndex); - for (int textId : textIds) { - IggyText iggyText = file.getText(swfIndex, textId); - DefineEditTextTag textTag = new DefineEditTextTag(swf); - currentCharId++; - textIndex2CharId.put(iggyText.getTextIndex(), currentCharId); - textTag.characterID = currentCharId; - textTag.hasText = true; - textTag.initialText = iggyText.getInitialText(); - textTag.html = true; - textTag.noSelect = true; - textTag.wasStatic = true; - textTag.hasFont = false; - textTag.hasFontClass = false; - textTag.hasMaxLength = false; - //textTag.multiline = true; - //textTag.wordWrap = true; - //textTag.hasTextColor = true; - //textTag.textColor = new RGBA(Color.black); - //textTag.fontHeight = 40; //?? - textTag.readOnly = true; - textTag.bounds = new RECT( - makeLengthsTwip(iggyText.getPar3()), - makeLengthsTwip(iggyText.getPar1()), - makeLengthsTwip(iggyText.getPar4()), - makeLengthsTwip(iggyText.getPar2()) - ); - - //textTag.hasFont = true; - //textTag.fontId = fontIndex2CharId.get(iggyText.getFontIndex()); - textTag.setModified(true); - swf.addTag(textTag); - } - */ - swf.addTag( - new EndTag(swf)); - swf.setModified( - true); - - return swf; - } - - public static void main(String[] args) { - - if (args.length < 2 || (args[0].isEmpty() || args[1].isEmpty())) { - System.err.println("Invalid arguments"); - System.err.println("Usage: iggy-extract.bat file.iggy d:/outdir/"); - System.exit(1); - } - - File file = new File(args[0]); - if (!file.exists()) { - System.err.println("FAIL: Input file: " + file.getAbsolutePath() + " does not exist."); - System.exit(1); - } - File outDir = new File(args[1]); - if (!outDir.exists()) { - if (!outDir.mkdirs()) { - System.err.println("FAIL: Cannot create output directory"); - System.exit(1); - } - } - - try { - System.out.print("(1/2) Loading file " + args[0] + "..."); - IggyFile iggyFile = new IggyFile(new File(args[0])); - System.out.println("OK"); - System.out.print("(2/2) Exporting SWF files to " + args[1] + "..."); - exportAllSwfsToDir(iggyFile, new File(args[1])); - System.out.println("OK"); - System.out.println("All finished sucessfully."); - System.exit(0); - } catch (IOException ex) { - System.out.println("FAIL"); - System.err.println("Error while converting: " + ex.getMessage()); - System.exit(1); - } - } -} +package com.jpexs.decompiler.flash.iggy.conversion; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFCompression; +import com.jpexs.decompiler.flash.iggy.IggyShape; +import com.jpexs.decompiler.flash.iggy.IggyCharKerning; +import com.jpexs.decompiler.flash.iggy.IggyShapeNode; +import com.jpexs.decompiler.flash.iggy.IggyCharOffset; +import com.jpexs.decompiler.flash.iggy.IggyCharAdvances; +import com.jpexs.decompiler.flash.iggy.IggyFile; +import com.jpexs.decompiler.flash.iggy.IggyFont; +import com.jpexs.decompiler.flash.iggy.IggySwf; +import com.jpexs.decompiler.flash.iggy.IggyText; +import com.jpexs.decompiler.flash.tags.DefineEditTextTag; +import com.jpexs.decompiler.flash.tags.DefineFont2Tag; +import com.jpexs.decompiler.flash.tags.EndTag; +import com.jpexs.decompiler.flash.tags.FileAttributesTag; +import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY; +import com.jpexs.decompiler.flash.types.KERNINGRECORD; +import com.jpexs.decompiler.flash.types.LINESTYLEARRAY; +import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.decompiler.flash.types.RGBA; +import com.jpexs.decompiler.flash.types.SHAPE; +import com.jpexs.decompiler.flash.types.shaperecords.CurvedEdgeRecord; +import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord; +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 java.awt.Color; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * + * WIP + * + * @author JPEXS + */ +public class IggyToSwfConvertor { + + public static void exportAllSwfsToDir(IggyFile file, File outputDir) throws IOException { + exportSwfToDir(file, outputDir); + } + + public static void exportSwfToDir(IggyFile file, File outputDir) throws IOException { + try (FileOutputStream fos = new FileOutputStream(new File(outputDir, file.getSwfName()))) { + exportSwf(file, fos); + } + } + + public static void exportSwfToFile(IggyFile file, File outputFile) throws IOException { + try (FileOutputStream fos = new FileOutputStream(outputFile)) { + exportSwf(file, fos); + } + } + + public static void exportSwf(IggyFile file, OutputStream output) throws IOException { + SWF swf = getSwf(file); + swf.saveTo(output); + } + + private static int makeLengthsEm(double val) { + return (int) (val * 1024.0); + } + + public static SWF getSwf(IggyFile file) { + SWF swf = new SWF(); + swf.compression = SWFCompression.NONE; + swf.frameCount = 1; //FIXME!! + swf.frameRate = file.getSwfFrameRate(); + swf.gfx = false; + swf.displayRect = new RECT( + (int) (file.getSwfXMin() * SWF.unitDivisor), + (int) (file.getSwfXMax() * SWF.unitDivisor), + (int) (file.getSwfYMin() * SWF.unitDivisor), + (int) (file.getSwfYMax() * SWF.unitDivisor)); + swf.version = 10; //FIXME + + FileAttributesTag fat = new FileAttributesTag(swf); + fat.actionScript3 = false; + fat.hasMetadata = false; + fat.useNetwork = false; + swf.addTag(fat); + //Set fontIndices = file.getFontIds(swfIndex); + int fontCount = file.getFontCount(); + + int currentCharId = 0; + Map fontIndex2CharId = new HashMap<>(); + + for (int fontIndex = 0; fontIndex < fontCount; fontIndex++) { + IggyFont iggyFont = file.getFont(fontIndex); + DefineFont2Tag fontTag = new DefineFont2Tag(swf); + currentCharId++; + fontIndex2CharId.put(fontIndex, currentCharId); + fontTag.fontID = currentCharId; + /*System.out.println("==================="); + System.out.println("xscale: " + iggyFont.getXscale()); //80 + System.out.println("yscale: " + iggyFont.getYscale()); //19 + + System.out.println("unk_float1: " + iggyFont.getUnk_float()[0]); + System.out.println("unk_float2: " + iggyFont.getUnk_float()[1]); + System.out.println("unk_float3: " + iggyFont.getUnk_float()[2]); + System.out.println("unk_float4: " + iggyFont.getUnk_float()[3]); + System.out.println("unk_float5: " + iggyFont.getUnk_float()[4]); + System.out.println("what_2: " + iggyFont.getWhat_2()); + System.out.println("what_3: " + iggyFont.getWhat_3());*/ + + fontTag.fontKerningTable = new ArrayList<>(); + IggyCharKerning ker = iggyFont.getCharKernings(); + if (ker != null) { + for (int i = 0; i < ker.getKernCount(); i++) { + int kerningCode1 = ker.getCharsA().get(i); + int kerningCode2 = ker.getCharsA().get(i); + int kerningOffset = ker.getKerningOffsets().get(i); + fontTag.fontKerningTable.add(new KERNINGRECORD(kerningCode1, kerningCode2, kerningOffset)); + } + } + + fontTag.fontFlagsWideCodes = true; + fontTag.fontFlagsWideOffsets = true; + fontTag.fontAscent = iggyFont.getAscent(); + fontTag.fontDescent = iggyFont.getDescent(); + fontTag.fontLeading = iggyFont.getLeading(); + fontTag.codeTable = new ArrayList<>(); + fontTag.fontName = iggyFont.getName(); + fontTag.glyphShapeTable = new ArrayList<>(); + fontTag.fontBoundsTable = new ArrayList<>(); + fontTag.fontAdvanceTable = new ArrayList<>(); + fontTag.fontFlagsHasLayout = true; + IggyCharAdvances advanceValues = iggyFont.getCharAdvances(); + for (int i = 0; i < iggyFont.getCharacterCount(); i++) { + int code = iggyFont.getCharIndices().getChars().get(i); + fontTag.codeTable.add(code); + IggyShape glyph = iggyFont.getChars().get(i); + SHAPE shp; + if (glyph != null) { + shp = IggyShapeToSwfConvertor.convertCharToShape(glyph); + fontTag.fontBoundsTable.add(shp.getBounds()); + } else { + shp = new SHAPE(); + shp.shapeRecords = new ArrayList<>(); + shp.shapeRecords.add(new EndShapeRecord()); + fontTag.fontBoundsTable.add(new RECT()); //?? + } + fontTag.glyphShapeTable.add(shp); + + fontTag.fontAdvanceTable.add(makeLengthsEm(advanceValues.getScales().get(i))); + + } + fontTag.setModified(true); + swf.addTag(fontTag); + } + + /* + //TODO: Texts, they are incomplete + + Map textIndex2CharId = new HashMap<>(); + + Set textIds = file.getTextIds(swfIndex); + for (int textId : textIds) { + IggyText iggyText = file.getText(swfIndex, textId); + DefineEditTextTag textTag = new DefineEditTextTag(swf); + currentCharId++; + textIndex2CharId.put(iggyText.getTextIndex(), currentCharId); + textTag.characterID = currentCharId; + textTag.hasText = true; + textTag.initialText = iggyText.getInitialText(); + textTag.html = true; + textTag.noSelect = true; + textTag.wasStatic = true; + textTag.hasFont = false; + textTag.hasFontClass = false; + textTag.hasMaxLength = false; + //textTag.multiline = true; + //textTag.wordWrap = true; + //textTag.hasTextColor = true; + //textTag.textColor = new RGBA(Color.black); + //textTag.fontHeight = 40; //?? + textTag.readOnly = true; + textTag.bounds = new RECT( + makeLengthsTwip(iggyText.getPar3()), + makeLengthsTwip(iggyText.getPar1()), + makeLengthsTwip(iggyText.getPar4()), + makeLengthsTwip(iggyText.getPar2()) + ); + + //textTag.hasFont = true; + //textTag.fontId = fontIndex2CharId.get(iggyText.getFontIndex()); + textTag.setModified(true); + swf.addTag(textTag); + } + */ + swf.addTag( + new EndTag(swf)); + swf.setModified( + true); + + return swf; + } + + public static void main(String[] args) { + + if (args.length < 2 || (args[0].isEmpty() || args[1].isEmpty())) { + System.err.println("Invalid arguments"); + System.err.println("Usage: iggy-extract.bat file.iggy d:/outdir/"); + System.exit(1); + } + + File file = new File(args[0]); + if (!file.exists()) { + System.err.println("FAIL: Input file: " + file.getAbsolutePath() + " does not exist."); + System.exit(1); + } + File outDir = new File(args[1]); + if (!outDir.exists()) { + if (!outDir.mkdirs()) { + System.err.println("FAIL: Cannot create output directory"); + System.exit(1); + } + } + + try { + System.out.print("(1/2) Loading file " + args[0] + "..."); + IggyFile iggyFile = new IggyFile(new File(args[0])); + System.out.println("OK"); + System.out.print("(2/2) Exporting SWF files to " + args[1] + "..."); + exportAllSwfsToDir(iggyFile, new File(args[1])); + System.out.println("OK"); + System.out.println("All finished sucessfully."); + System.exit(0); + } catch (IOException ex) { + System.out.println("FAIL"); + System.err.println("Error while converting: " + ex.getMessage()); + System.exit(1); + } + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/conversion/SwfShapeToIggyConvertor.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/conversion/SwfShapeToIggyConvertor.java index c23c6a009..60fa2c7d1 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/conversion/SwfShapeToIggyConvertor.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/conversion/SwfShapeToIggyConvertor.java @@ -1,59 +1,59 @@ -package com.jpexs.decompiler.flash.iggy.conversion; - -import com.jpexs.decompiler.flash.iggy.IggyShape; -import com.jpexs.decompiler.flash.iggy.IggyShapeNode; -import com.jpexs.decompiler.flash.types.RECT; -import com.jpexs.decompiler.flash.types.SHAPE; -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 java.util.ArrayList; -import java.util.List; - -/** - * - * @author JPEXS - */ -public class SwfShapeToIggyConvertor { - - private static float normalizeLengths(int val) { - return (val / 1024f); - } - - public static IggyShape convertShape(SHAPE swfShape) { - /*if (swfShape.shapeRecords.size() == 1) { //no glyphs, maybe space - return null; - }*/ - List nodes = new ArrayList<>(); - RECT bounds = swfShape.getBounds(); - boolean first = true; - float curX = 0f; - float curY = 0f; - for (SHAPERECORD rec : swfShape.shapeRecords) { - if (rec instanceof StraightEdgeRecord) { - StraightEdgeRecord ser = (StraightEdgeRecord) rec; - curX += normalizeLengths(ser.deltaX); - curY += normalizeLengths(ser.deltaY); - nodes.add(new IggyShapeNode(curX, curY, 0f, 0f, IggyShapeNode.NODE_TYPE_LINE_TO, 0, first)); - } else if (rec instanceof CurvedEdgeRecord) { - CurvedEdgeRecord cer = (CurvedEdgeRecord) rec; - float controlX = curX + normalizeLengths(cer.controlDeltaX); - float controlY = curY + normalizeLengths(cer.controlDeltaY); - curX = curX + normalizeLengths(cer.controlDeltaX + cer.anchorDeltaX); - curY = curY + normalizeLengths(cer.controlDeltaY + cer.anchorDeltaY); - nodes.add(new IggyShapeNode(curX, curY, controlX, controlY, IggyShapeNode.NODE_TYPE_CURVE_POINT, 0, first)); - } else if (rec instanceof StyleChangeRecord) { - StyleChangeRecord scr = (StyleChangeRecord) rec; - if (scr.stateMoveTo) { - curX = normalizeLengths(scr.moveDeltaX); - curY = normalizeLengths(scr.moveDeltaY); - nodes.add(new IggyShapeNode(curX, curY, 0f, 0f, IggyShapeNode.NODE_TYPE_MOVE, 0, first)); - } - } - first = false; - } - IggyShape ret = new IggyShape(normalizeLengths(bounds.Xmin), normalizeLengths(bounds.Ymin), normalizeLengths(bounds.Xmax), normalizeLengths(bounds.Ymax), nodes); - return ret; - } -} +package com.jpexs.decompiler.flash.iggy.conversion; + +import com.jpexs.decompiler.flash.iggy.IggyShape; +import com.jpexs.decompiler.flash.iggy.IggyShapeNode; +import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.decompiler.flash.types.SHAPE; +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 java.util.ArrayList; +import java.util.List; + +/** + * + * @author JPEXS + */ +public class SwfShapeToIggyConvertor { + + private static float normalizeLengths(int val) { + return (val / 1024f); + } + + public static IggyShape convertShape(SHAPE swfShape) { + /*if (swfShape.shapeRecords.size() == 1) { //no glyphs, maybe space + return null; + }*/ + List nodes = new ArrayList<>(); + RECT bounds = swfShape.getBounds(); + boolean first = true; + float curX = 0f; + float curY = 0f; + for (SHAPERECORD rec : swfShape.shapeRecords) { + if (rec instanceof StraightEdgeRecord) { + StraightEdgeRecord ser = (StraightEdgeRecord) rec; + curX += normalizeLengths(ser.deltaX); + curY += normalizeLengths(ser.deltaY); + nodes.add(new IggyShapeNode(curX, curY, 0f, 0f, IggyShapeNode.NODE_TYPE_LINE_TO, 0, first)); + } else if (rec instanceof CurvedEdgeRecord) { + CurvedEdgeRecord cer = (CurvedEdgeRecord) rec; + float controlX = curX + normalizeLengths(cer.controlDeltaX); + float controlY = curY + normalizeLengths(cer.controlDeltaY); + curX = curX + normalizeLengths(cer.controlDeltaX + cer.anchorDeltaX); + curY = curY + normalizeLengths(cer.controlDeltaY + cer.anchorDeltaY); + nodes.add(new IggyShapeNode(curX, curY, controlX, controlY, IggyShapeNode.NODE_TYPE_CURVE_POINT, 0, first)); + } else if (rec instanceof StyleChangeRecord) { + StyleChangeRecord scr = (StyleChangeRecord) rec; + if (scr.stateMoveTo) { + curX = normalizeLengths(scr.moveDeltaX); + curY = normalizeLengths(scr.moveDeltaY); + nodes.add(new IggyShapeNode(curX, curY, 0f, 0f, IggyShapeNode.NODE_TYPE_MOVE, 0, first)); + } + } + first = false; + } + IggyShape ret = new IggyShape(normalizeLengths(bounds.Xmin), normalizeLengths(bounds.Ymin), normalizeLengths(bounds.Xmax), normalizeLengths(bounds.Ymax), nodes); + return ret; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/conversion/SwfToIggyConvertor.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/conversion/SwfToIggyConvertor.java index 649135c3b..c2f06c7ff 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/conversion/SwfToIggyConvertor.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/conversion/SwfToIggyConvertor.java @@ -1,157 +1,157 @@ -package com.jpexs.decompiler.flash.iggy.conversion; - -import com.jpexs.decompiler.flash.iggy.IggyCharAdvances; -import com.jpexs.decompiler.flash.iggy.IggyCharIndices; -import com.jpexs.decompiler.flash.iggy.IggyCharKerning; -import com.jpexs.decompiler.flash.iggy.IggyCharOffset; -import com.jpexs.decompiler.flash.iggy.IggyFont; -import com.jpexs.decompiler.flash.iggy.IggyShape; -import com.jpexs.decompiler.flash.tags.DefineFont2Tag; -import com.jpexs.decompiler.flash.types.KERNINGRECORD; -import com.jpexs.decompiler.flash.types.SHAPE; -import java.util.ArrayList; -import java.util.List; - -/** - * - * @author JPEXS - */ -public class SwfToIggyConvertor { - - private static float normalizeLengths(int val) { - return (val / 1024f); - } - - public static void updateIggyFont(IggyFont iggyFont, DefineFont2Tag fontTag) { - /*byte zeroone[] = new byte[28]; - zeroone[12] = 1; - long flags = 65795; - float unk_float[] = new float[]{ - -0.6484375f, - -1.116211f, - 1.116211f, - 0.6679688f, - 0f - }; - int xscale = 80; - int yscale = 28; - float ssr1 = 0.9f; - float ssr2 = 0.3f; - long what_2 = 33188160; - long what_3 = 33600216; - byte zeroes48a[] = new byte[48]; - byte zeroes48b[] = new byte[48]; - float sss1 = 1.1728859f; - float sss2 = 1.1728706f; - float sss3 = 1.1728821f; - float sss4 = 1.1729145f;*/ - List charOffsets = new ArrayList<>(); - - List glyphs = new ArrayList<>(); - - for (SHAPE s : fontTag.glyphShapeTable) { - glyphs.add(SwfShapeToIggyConvertor.convertShape(s)); - } - - List chars = new ArrayList<>(); - for (int code : fontTag.codeTable) { - chars.add((char) code); - } - IggyCharIndices codePoints = new IggyCharIndices(chars); - List scales = new ArrayList<>(); - for (int adv : fontTag.fontAdvanceTable) { - scales.add(normalizeLengths(adv)); - } - IggyCharAdvances charScales = new IggyCharAdvances(scales); - List charA = new ArrayList<>(); - List charB = new ArrayList<>(); - List kernOffs = new ArrayList<>(); - - //IggyCharOffset - for (KERNINGRECORD rec : fontTag.fontKerningTable) { - charA.add((char) rec.fontKerningCode1); - charB.add((char) rec.fontKerningCode2); - kernOffs.add((short) rec.fontKerningAdjustment); - } - IggyCharKerning charKernings = new IggyCharKerning(charA, charB, kernOffs); - - for (int i = 0; i < fontTag.getCharacterCount(); i++) { - charOffsets.add(new IggyCharOffset(1, 0, 80, 19)); //XSCALE, YSCALE??? - } - - iggyFont.setCharCount(fontTag.getCharacterCount()); - iggyFont.setCharCount2(fontTag.getCharacterCount()); - iggyFont.setAscent(fontTag.getAscent()); - iggyFont.setDescent(fontTag.getDescent()); - iggyFont.setLeading(fontTag.getLeading()); - iggyFont.setName(fontTag.getFontName()); - iggyFont.setCharOffsets(charOffsets); - iggyFont.setGlyphs(glyphs); - iggyFont.setCodePoints(codePoints); - iggyFont.setCharScales(charScales); - iggyFont.setCharKernings(charKernings); - /* - IggyFont iggyFont = new IggyFont(IggyFont.ID, 0, zeroone, fontTag.getCharacterCount(), - fontTag.getAscent(), fontTag.getDescent(), fontTag.getLeading(), flags, - fontTag.fontKerningTable.size(), unk_float, 0, what_2, 0, 1, - xscale, yscale, 0, ssr1, ssr2, fontTag.getCharacterCount(), 0, what_3, zeroes48a, zeroes48b, - sss1, 1, sss2, 1, sss3, 1, sss4, 1, fontTag.getFontName(), - charOffsets, glyphs, codePoints, charScales, charKernings); - */ - } - - public static IggyFont createIggyFont(DefineFont2Tag fontTag) { - byte zeroone[] = new byte[28]; - zeroone[12] = 1; - long flags = 65795; - float unk_float[] = new float[]{ - -0.6484375f, - -1.116211f, - 1.116211f, - 0.6679688f, - 0f - }; - int xscale = 80; - int yscale = 28; - float ssr1 = 0.9f; - float ssr2 = 0.3f; - long what_2 = 33188160; - long what_3 = 33600216; - byte zeroes48a[] = new byte[48]; - byte zeroes48b[] = new byte[48]; - float sss1 = 1.1728859f; - float sss2 = 1.1728706f; - float sss3 = 1.1728821f; - float sss4 = 1.1729145f; - List charOffsets = new ArrayList<>(); - List glyphs = new ArrayList<>(); - List chars = new ArrayList<>(); - for (int code : fontTag.codeTable) { - chars.add((char) code); - } - IggyCharIndices codePoints = new IggyCharIndices(chars); - List scales = new ArrayList<>(); - for (int adv : fontTag.fontAdvanceTable) { - scales.add((float) adv); - } - IggyCharAdvances charScales = new IggyCharAdvances(scales); - List charA = new ArrayList<>(); - List charB = new ArrayList<>(); - List kernOffs = new ArrayList<>(); - - for (KERNINGRECORD rec : fontTag.fontKerningTable) { - charA.add((char) rec.fontKerningCode1); - charB.add((char) rec.fontKerningCode2); - kernOffs.add((short) rec.fontKerningAdjustment); - } - IggyCharKerning charKernings = new IggyCharKerning(charA, charB, kernOffs); - - IggyFont iggyFont = new IggyFont(IggyFont.ID, 0, zeroone, fontTag.getCharacterCount(), - fontTag.getAscent(), fontTag.getDescent(), fontTag.getLeading(), flags, - fontTag.fontKerningTable.size(), unk_float, 0, what_2, 0, 1, - xscale, yscale, 0, ssr1, ssr2, fontTag.getCharacterCount(), 0, what_3, zeroes48a, zeroes48b, - sss1, 1, sss2, 1, sss3, 1, sss4, 1, fontTag.getFontName(), - charOffsets, glyphs, codePoints, charScales, charKernings); - return iggyFont; - } -} +package com.jpexs.decompiler.flash.iggy.conversion; + +import com.jpexs.decompiler.flash.iggy.IggyCharAdvances; +import com.jpexs.decompiler.flash.iggy.IggyCharIndices; +import com.jpexs.decompiler.flash.iggy.IggyCharKerning; +import com.jpexs.decompiler.flash.iggy.IggyCharOffset; +import com.jpexs.decompiler.flash.iggy.IggyFont; +import com.jpexs.decompiler.flash.iggy.IggyShape; +import com.jpexs.decompiler.flash.tags.DefineFont2Tag; +import com.jpexs.decompiler.flash.types.KERNINGRECORD; +import com.jpexs.decompiler.flash.types.SHAPE; +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author JPEXS + */ +public class SwfToIggyConvertor { + + private static float normalizeLengths(int val) { + return (val / 1024f); + } + + public static void updateIggyFont(IggyFont iggyFont, DefineFont2Tag fontTag) { + /*byte zeroone[] = new byte[28]; + zeroone[12] = 1; + long flags = 65795; + float unk_float[] = new float[]{ + -0.6484375f, + -1.116211f, + 1.116211f, + 0.6679688f, + 0f + }; + int xscale = 80; + int yscale = 28; + float ssr1 = 0.9f; + float ssr2 = 0.3f; + long what_2 = 33188160; + long what_3 = 33600216; + byte zeroes48a[] = new byte[48]; + byte zeroes48b[] = new byte[48]; + float sss1 = 1.1728859f; + float sss2 = 1.1728706f; + float sss3 = 1.1728821f; + float sss4 = 1.1729145f;*/ + List charOffsets = new ArrayList<>(); + + List glyphs = new ArrayList<>(); + + for (SHAPE s : fontTag.glyphShapeTable) { + glyphs.add(SwfShapeToIggyConvertor.convertShape(s)); + } + + List chars = new ArrayList<>(); + for (int code : fontTag.codeTable) { + chars.add((char) code); + } + IggyCharIndices codePoints = new IggyCharIndices(chars); + List scales = new ArrayList<>(); + for (int adv : fontTag.fontAdvanceTable) { + scales.add(normalizeLengths(adv)); + } + IggyCharAdvances charScales = new IggyCharAdvances(scales); + List charA = new ArrayList<>(); + List charB = new ArrayList<>(); + List kernOffs = new ArrayList<>(); + + //IggyCharOffset + for (KERNINGRECORD rec : fontTag.fontKerningTable) { + charA.add((char) rec.fontKerningCode1); + charB.add((char) rec.fontKerningCode2); + kernOffs.add((short) rec.fontKerningAdjustment); + } + IggyCharKerning charKernings = new IggyCharKerning(charA, charB, kernOffs); + + for (int i = 0; i < fontTag.getCharacterCount(); i++) { + charOffsets.add(new IggyCharOffset(1, 0, 80, 19)); //XSCALE, YSCALE??? + } + + iggyFont.setCharCount(fontTag.getCharacterCount()); + iggyFont.setCharCount2(fontTag.getCharacterCount()); + iggyFont.setAscent(fontTag.getAscent()); + iggyFont.setDescent(fontTag.getDescent()); + iggyFont.setLeading(fontTag.getLeading()); + iggyFont.setName(fontTag.getFontName()); + iggyFont.setCharOffsets(charOffsets); + iggyFont.setGlyphs(glyphs); + iggyFont.setCodePoints(codePoints); + iggyFont.setCharScales(charScales); + iggyFont.setCharKernings(charKernings); + /* + IggyFont iggyFont = new IggyFont(IggyFont.ID, 0, zeroone, fontTag.getCharacterCount(), + fontTag.getAscent(), fontTag.getDescent(), fontTag.getLeading(), flags, + fontTag.fontKerningTable.size(), unk_float, 0, what_2, 0, 1, + xscale, yscale, 0, ssr1, ssr2, fontTag.getCharacterCount(), 0, what_3, zeroes48a, zeroes48b, + sss1, 1, sss2, 1, sss3, 1, sss4, 1, fontTag.getFontName(), + charOffsets, glyphs, codePoints, charScales, charKernings); + */ + } + + public static IggyFont createIggyFont(DefineFont2Tag fontTag) { + byte zeroone[] = new byte[28]; + zeroone[12] = 1; + long flags = 65795; + float unk_float[] = new float[]{ + -0.6484375f, + -1.116211f, + 1.116211f, + 0.6679688f, + 0f + }; + int xscale = 80; + int yscale = 28; + float ssr1 = 0.9f; + float ssr2 = 0.3f; + long what_2 = 33188160; + long what_3 = 33600216; + byte zeroes48a[] = new byte[48]; + byte zeroes48b[] = new byte[48]; + float sss1 = 1.1728859f; + float sss2 = 1.1728706f; + float sss3 = 1.1728821f; + float sss4 = 1.1729145f; + List charOffsets = new ArrayList<>(); + List glyphs = new ArrayList<>(); + List chars = new ArrayList<>(); + for (int code : fontTag.codeTable) { + chars.add((char) code); + } + IggyCharIndices codePoints = new IggyCharIndices(chars); + List scales = new ArrayList<>(); + for (int adv : fontTag.fontAdvanceTable) { + scales.add((float) adv); + } + IggyCharAdvances charScales = new IggyCharAdvances(scales); + List charA = new ArrayList<>(); + List charB = new ArrayList<>(); + List kernOffs = new ArrayList<>(); + + for (KERNINGRECORD rec : fontTag.fontKerningTable) { + charA.add((char) rec.fontKerningCode1); + charB.add((char) rec.fontKerningCode2); + kernOffs.add((short) rec.fontKerningAdjustment); + } + IggyCharKerning charKernings = new IggyCharKerning(charA, charB, kernOffs); + + IggyFont iggyFont = new IggyFont(IggyFont.ID, 0, zeroone, fontTag.getCharacterCount(), + fontTag.getAscent(), fontTag.getDescent(), fontTag.getLeading(), flags, + fontTag.fontKerningTable.size(), unk_float, 0, what_2, 0, 1, + xscale, yscale, 0, ssr1, ssr2, fontTag.getCharacterCount(), 0, what_3, zeroes48a, zeroes48b, + sss1, 1, sss2, 1, sss3, 1, sss4, 1, fontTag.getFontName(), + charOffsets, glyphs, codePoints, charScales, charKernings); + return iggyFont; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/AbstractDataStream.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/AbstractDataStream.java index 2cda5f443..1c27d99d7 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/AbstractDataStream.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/AbstractDataStream.java @@ -1,241 +1,241 @@ -package com.jpexs.decompiler.flash.iggy.streams; - -import java.io.ByteArrayOutputStream; -import java.io.EOFException; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Logger; - -/** - * - * @author JPEXS - */ -public abstract class AbstractDataStream implements DataStreamInterface { - - /** - * Available bytes - * - * @return null if unknown, long value otherwise - */ - @Override - public abstract Long available(); - - @Override - public abstract long position(); - - @Override - public long readUI64() throws IOException { - long lsb = readUI32(); - long msb = readUI32(); - long result = msb << 32 | lsb; - return result & 0xffffffffffffffffL; - } - - @Override - public long readSI64() throws IOException { - long lsb = readUI32(); - long msb = readUI32(); - return msb << 32 | lsb; - } - - @Override - public boolean writeUI64(long val) throws IOException { - write((int) (val & 0xff)); - write((int) ((val >> 8) & 0xff)); - write((int) ((val >> 16) & 0xff)); - write((int) ((val >> 24) & 0xff)); - - write((int) ((val >> 32) & 0xff)); - write((int) ((val >> 40) & 0xff)); - write((int) ((val >> 48) & 0xff)); - write((int) ((val >> 56) & 0xff)); - return true; - } - - @Override - public boolean writeSI64(long val) throws IOException { - write((int) (val & 0xff)); - write((int) ((val >> 8) & 0xff)); - write((int) ((val >> 16) & 0xff)); - write((int) ((val >> 24) & 0xff)); - - write((int) ((val >> 32) & 0xff)); - write((int) ((val >> 40) & 0xff)); - write((int) ((val >> 48) & 0xff)); - write((int) ((val >> 56) & 0xff)); - return true; - } - - @Override - public long readUI32() throws IOException { - try { - return (readUI8() | (readUI8() << 8) | (readUI8() << 16) | (readUI8() << 24)); - } catch (EOFException ex) { - return -1; - } - } - - @Override - public boolean writeUI32(long val) throws IOException { - write((int) (val & 0xff)); - write((int) ((val >> 8) & 0xff)); - write((int) ((val >> 16) & 0xff)); - write((int) ((val >> 24) & 0xff)); - return true; - } - - @Override - public int readUI16() throws IOException { - try { - return (readUI8() | (readUI8() << 8)) & 0xffff; - } catch (EOFException ex) { - return -1; - } - } - - @Override - public boolean writeUI16(int val) throws IOException { - write(val & 0xff); - write((val >> 8) & 0xff); - return true; - } - - @Override - public int readUI8() throws IOException { - try { - return read() & 0xff; - } catch (EOFException ex) { - return -1; - } - } - - @Override - public boolean writeUI8(int val) throws IOException { - write(val); - return true; - } - - @Override - public float readFloat() throws IOException { - return Float.intBitsToFloat((int) readUI32()); - } - - @Override - public boolean writeFloat(float val) throws IOException { - return writeUI32(Float.floatToIntBits(val)); - } - - @Override - public byte[] readBytes(int numBytes) throws IOException { - byte[] ret = new byte[numBytes]; - for (int i = 0; i < numBytes; i++) { - ret[i] = (byte) read(); - } - return ret; - } - - public byte[] getAllBytes() throws IOException { - long oldPos = position(); - seek(0, SeekMode.SET); - byte[] ret = readBytes((int) (long) available()); - seek(oldPos, SeekMode.SET); - return ret; - } - - @Override - public void writeBytes(byte[] data) throws IOException { - for (int i = 0; i < data.length; i++) { - write(data[i] & 0xff); - } - } - - @Override - public abstract int read() throws IOException; - - @Override - public abstract void seek(long pos, SeekMode mode) throws IOException; - - @Override - public void write(int val) throws IOException { - //nothing - } - - @Override - public void close() { - //nothing - } - - @Override - public int readUI8(long addr) throws IOException { - long curPos = position(); - seek(addr, SeekMode.SET); - int val = readUI8(); - seek(curPos, SeekMode.SET); - return val; - } - - @Override - public boolean writeWChar(String name) throws IOException { - for (int i = 0; i < name.length(); i++) { - writeUI16(name.charAt(i)); - } - writeUI16(0); - return true; - } - - @Override - public String readWChar() throws IOException { - StringBuilder strBuilder = new StringBuilder(); - do { - char c = (char) readUI16(); - if (c == '\0') { - break; - } - strBuilder.append(c); - } while (true); - return strBuilder.toString(); - } - - @Override - public void pad8bytes() throws IOException { - int pad8 = (int) (position() % 8); - switch (pad8) { - case 1: - write(0); - case 2: - write(0); - case 3: - write(0); - case 4: - write(0); - case 5: - write(0); - case 6: - write(0); - case 7: - write(0); - } - } - - @Override - public void setOlderOffsetToThisPos(long savedPos) throws IOException { - long curPos = position(); - long actual = curPos - savedPos; - - seek(savedPos, SeekMode.SET); - writeUI64(actual); - seek(curPos, SeekMode.SET); - } - - public void setOlderOffsetToThisPosCheck(long savedPos, long expected) throws IOException { - if (expected == 1) { - return; - } - long curPos = position(); - long actual = curPos - savedPos; - if (actual != expected) { - throw new RuntimeException("Expected " + expected + " but found actual " + actual + ". Diff:" + ((actual - expected) > 0 ? "+" : "") + (actual - expected)); - } - } -} +package com.jpexs.decompiler.flash.iggy.streams; + +import java.io.ByteArrayOutputStream; +import java.io.EOFException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Logger; + +/** + * + * @author JPEXS + */ +public abstract class AbstractDataStream implements DataStreamInterface { + + /** + * Available bytes + * + * @return null if unknown, long value otherwise + */ + @Override + public abstract Long available(); + + @Override + public abstract long position(); + + @Override + public long readUI64() throws IOException { + long lsb = readUI32(); + long msb = readUI32(); + long result = msb << 32 | lsb; + return result & 0xffffffffffffffffL; + } + + @Override + public long readSI64() throws IOException { + long lsb = readUI32(); + long msb = readUI32(); + return msb << 32 | lsb; + } + + @Override + public boolean writeUI64(long val) throws IOException { + write((int) (val & 0xff)); + write((int) ((val >> 8) & 0xff)); + write((int) ((val >> 16) & 0xff)); + write((int) ((val >> 24) & 0xff)); + + write((int) ((val >> 32) & 0xff)); + write((int) ((val >> 40) & 0xff)); + write((int) ((val >> 48) & 0xff)); + write((int) ((val >> 56) & 0xff)); + return true; + } + + @Override + public boolean writeSI64(long val) throws IOException { + write((int) (val & 0xff)); + write((int) ((val >> 8) & 0xff)); + write((int) ((val >> 16) & 0xff)); + write((int) ((val >> 24) & 0xff)); + + write((int) ((val >> 32) & 0xff)); + write((int) ((val >> 40) & 0xff)); + write((int) ((val >> 48) & 0xff)); + write((int) ((val >> 56) & 0xff)); + return true; + } + + @Override + public long readUI32() throws IOException { + try { + return (readUI8() | (readUI8() << 8) | (readUI8() << 16) | (readUI8() << 24)); + } catch (EOFException ex) { + return -1; + } + } + + @Override + public boolean writeUI32(long val) throws IOException { + write((int) (val & 0xff)); + write((int) ((val >> 8) & 0xff)); + write((int) ((val >> 16) & 0xff)); + write((int) ((val >> 24) & 0xff)); + return true; + } + + @Override + public int readUI16() throws IOException { + try { + return (readUI8() | (readUI8() << 8)) & 0xffff; + } catch (EOFException ex) { + return -1; + } + } + + @Override + public boolean writeUI16(int val) throws IOException { + write(val & 0xff); + write((val >> 8) & 0xff); + return true; + } + + @Override + public int readUI8() throws IOException { + try { + return read() & 0xff; + } catch (EOFException ex) { + return -1; + } + } + + @Override + public boolean writeUI8(int val) throws IOException { + write(val); + return true; + } + + @Override + public float readFloat() throws IOException { + return Float.intBitsToFloat((int) readUI32()); + } + + @Override + public boolean writeFloat(float val) throws IOException { + return writeUI32(Float.floatToIntBits(val)); + } + + @Override + public byte[] readBytes(int numBytes) throws IOException { + byte[] ret = new byte[numBytes]; + for (int i = 0; i < numBytes; i++) { + ret[i] = (byte) read(); + } + return ret; + } + + public byte[] getAllBytes() throws IOException { + long oldPos = position(); + seek(0, SeekMode.SET); + byte[] ret = readBytes((int) (long) available()); + seek(oldPos, SeekMode.SET); + return ret; + } + + @Override + public void writeBytes(byte[] data) throws IOException { + for (int i = 0; i < data.length; i++) { + write(data[i] & 0xff); + } + } + + @Override + public abstract int read() throws IOException; + + @Override + public abstract void seek(long pos, SeekMode mode) throws IOException; + + @Override + public void write(int val) throws IOException { + //nothing + } + + @Override + public void close() { + //nothing + } + + @Override + public int readUI8(long addr) throws IOException { + long curPos = position(); + seek(addr, SeekMode.SET); + int val = readUI8(); + seek(curPos, SeekMode.SET); + return val; + } + + @Override + public boolean writeWChar(String name) throws IOException { + for (int i = 0; i < name.length(); i++) { + writeUI16(name.charAt(i)); + } + writeUI16(0); + return true; + } + + @Override + public String readWChar() throws IOException { + StringBuilder strBuilder = new StringBuilder(); + do { + char c = (char) readUI16(); + if (c == '\0') { + break; + } + strBuilder.append(c); + } while (true); + return strBuilder.toString(); + } + + @Override + public void pad8bytes() throws IOException { + int pad8 = (int) (position() % 8); + switch (pad8) { + case 1: + write(0); + case 2: + write(0); + case 3: + write(0); + case 4: + write(0); + case 5: + write(0); + case 6: + write(0); + case 7: + write(0); + } + } + + @Override + public void setOlderOffsetToThisPos(long savedPos) throws IOException { + long curPos = position(); + long actual = curPos - savedPos; + + seek(savedPos, SeekMode.SET); + writeUI64(actual); + seek(curPos, SeekMode.SET); + } + + public void setOlderOffsetToThisPosCheck(long savedPos, long expected) throws IOException { + if (expected == 1) { + return; + } + long curPos = position(); + long actual = curPos - savedPos; + if (actual != expected) { + throw new RuntimeException("Expected " + expected + " but found actual " + actual + ". Diff:" + ((actual - expected) > 0 ? "+" : "") + (actual - expected)); + } + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/DataStreamInterface.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/DataStreamInterface.java index d3a4f2916..11f37cc5a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/DataStreamInterface.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/DataStreamInterface.java @@ -1,9 +1,9 @@ -package com.jpexs.decompiler.flash.iggy.streams; - -/** - * - * @author JPEXS - */ -public interface DataStreamInterface extends ReadDataStreamInterface, WriteDataStreamInterface { - -} +package com.jpexs.decompiler.flash.iggy.streams; + +/** + * + * @author JPEXS + */ +public interface DataStreamInterface extends ReadDataStreamInterface, WriteDataStreamInterface { + +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/IggyIndexBuilder.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/IggyIndexBuilder.java index 49c6263be..33531d38a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/IggyIndexBuilder.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/IggyIndexBuilder.java @@ -1,401 +1,401 @@ -package com.jpexs.decompiler.flash.iggy.streams; - -import com.jpexs.decompiler.flash.iggy.IggyCharKerning; -import com.jpexs.decompiler.flash.iggy.IggyCharOffset; -import com.jpexs.decompiler.flash.iggy.IggyFontBinInfo; -import com.jpexs.decompiler.flash.iggy.IggyFontTypeInfo; -import com.jpexs.decompiler.flash.iggy.IggyShape; -import com.jpexs.decompiler.flash.iggy.IggyShapeNode; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.logging.Logger; - -/** - * - * @author JPEXS - */ -public class IggyIndexBuilder { - - private static Logger LOGGER = Logger.getLogger(IggyIndexBuilder.class.getName()); - private static final int CODE_FC_SKIP1 = 0xFC; - private static final int CODE_FD_OFS8_SKIP_TWICE8 = 0xFD; - private static final int CODE_FE_OFS8_POSITIVE = 0xFE; - private static final int CODE_FF_OFS32 = 0xFF; - - private List constTable = new ArrayList<>(); - private Map> constTableOffsets = new HashMap<>(); - private Map> constTableTypes = new HashMap<>(); - private WriteDataStreamInterface indexStream; - - private static final int CONST_VAL_SHAPE_NODE_SIZE = IggyShapeNode.STRUCT_SIZE; - private static final int CONST_VAL_KERNING_RECORD_SIZE = IggyCharKerning.STRUCT_SIZE; - private static final int CONST_VAL_CHAR_OFFSET_SIZE = IggyCharOffset.STRUCT_SIZE; - private static final int CONST_VAL_BIN_INFO_SIZE = IggyFontBinInfo.STRUCT_SIZE; - private static final int CONST_VAL_TYPE_INFO_SIZE = IggyFontTypeInfo.STRUCT_SIZE; - private static final int CONST_VAL_SHAPE_SIZE = IggyShape.STRUCT_SIZE; - private static final int CONST_VAL_GENERAL_FONT_INFO_SIZE = 112; - private static final int CONST_VAL_GENERAL_FONT_INFO2_SIZE = 240; - private static final int CONST_VAL_TEXT_DATA_SIZE = 104; - private static final int CONST_VAL_SEQUENCE_SIZE = 16; - - public static final int CONST_SHAPE_NODE_SIZE = 0; - public static final int CONST_KERNING_RECORD_SIZE = 1; - public static final int CONST_CHAR_OFFSET_SIZE = 2; - public static final int CONST_BIN_INFO_SIZE = 3; - public static final int CONST_TYPE_INFO_SIZE = 4; - public static final int CONST_SHAPE_SIZE = 5; - public static final int CONST_GENERAL_FONT_INFO_SIZE = 6; - public static final int CONST_GENERAL_FONT_INFO2_SIZE = 7; - public static final int CONST_TEXT_DATA_SIZE = 8; - public static final int CONST_SEQUENCE_SIZE = 9; - - private long position = 0; - - public IggyIndexBuilder() throws IOException { - indexStream = new TemporaryDataStream(); - - addConst(CONST_VAL_SHAPE_NODE_SIZE, new int[]{0, 4, 8, 0xC, 0x12, 0x14, 0x16}, new int[]{5, 5, 5, 5, 4, 4, 4}); - addConst(CONST_VAL_KERNING_RECORD_SIZE, new int[]{0, 2, 4}, new int[]{4, 4, 4}); - addConst(CONST_VAL_CHAR_OFFSET_SIZE, new int[]{8, 0x10, 0x18}, new int[]{4, 8, 2}); - addConst(CONST_VAL_BIN_INFO_SIZE, new int[]{0, 9, 0xC, 0x10, 0x14, 0x18, 0x1C, 0x20, 0x24, 0x28, 0x30, 0x38, 0x3A}, new int[]{2, 3, 5, 5, 5, 5, 5, 5, 5, 4, 2, 4, 4}); - addConst(CONST_VAL_TYPE_INFO_SIZE, new int[]{8, 0x10}, new int[]{2, 5}); - addConst(CONST_VAL_SHAPE_SIZE, new int[]{0, 4, 8, 0xC, 0x10, 0x18, 0x20, 0x28, 0x30}, new int[]{5, 5, 5, 5, 2, 5, 2, 2, 2}); - addConst(CONST_VAL_GENERAL_FONT_INFO_SIZE, new int[]{0x1, 0x02, 0x08, 0x10, 0x20, 0x22, 0x24, 0x26, 0x2B, 0x30, 0x38, 0x40, 0x48, 0x4C, 0x50, 0x54, 0x58, 0x60}, new int[]{0xC, 4, 5, 2, 4, 4, 4, 4, 3, 2, 2, 2, 5, 5, 5, 5, 5, 2}); - addConst(CONST_VAL_GENERAL_FONT_INFO2_SIZE, new int[]{0x10}, new int[]{2}); - addConst(CONST_VAL_TEXT_DATA_SIZE, new int[]{0x01, 0x02, 0x08, 0x10, 0x20, 0x24, 0x28, 0x2C, 0x30, 0x32, 0x38, 0x44, 0x46, 0x48, 0x4A, 0x4C, 0x4E, 0x60}, new int[]{0x0C, 4, 5, 2, 5, 5, 5, 5, 4, 4, 2, 4, 4, 4, 4, 4, 4, 2}); - addConst(CONST_VAL_SEQUENCE_SIZE, new int[]{0, 8}, new int[]{2, 5}); - } - - private void addConst(int totalLength, int[] localOffsets, int[] types) { - if (localOffsets.length != types.length) { - throw new RuntimeException("Size of localOffsets does not match size of types on adding consts with total length " + totalLength); - } - constTable.add(totalLength); - int newIndex = constTable.size() - 1; - List localOffsetsList = new ArrayList<>(); - for (int t : localOffsets) { - localOffsetsList.add(t); - } - List typesList = new ArrayList<>(); - for (int t : types) { - typesList.add(t); - } - constTableOffsets.put(newIndex, localOffsetsList); - constTableTypes.put(newIndex, typesList); - } - - private byte[] getIndexTableBytes() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - baos.write(constTable.size()); - for (int i = 0; i < constTable.size(); i++) { - baos.write(constTable.get(i)); - baos.write(constTableOffsets.get(i).size()); - for (int j = 0; j < constTableOffsets.get(i).size(); j++) { - baos.write(constTableOffsets.get(i).get(j)); - baos.write(constTableTypes.get(i).get(j)); - } - } - return baos.toByteArray(); - } - - public byte[] getIndexBytes() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try { - baos.write(getIndexTableBytes()); - baos.write(indexStream.getAllBytes()); - } catch (IOException ex) { - //should not happen - } - return baos.toByteArray(); - } - - public long writeConstLength(int constIndex) { - return writeIndex(constIndex, false, 0); - } - - public long writeConstLengthArray(int constIndex, long cnt) { - long ret = 0; - long rem = cnt; - while (true) { - if (rem == 0) { - break; - } - if (rem == 1) { - ret += writeIndex(constIndex, false, 0); - break; - } - if (rem <= 64) { - ret += writeIndex(0x80 + (int) rem - 1, false, constIndex); - break; - } else { - rem -= 64; - ret += writeIndex(0x80 + 64 - 1, false, constIndex); - } - } - return ret; - } - - public long pad8bytes() { - int pad8 = (int) (position % 8); - switch (pad8) { - case 2: - writePaddingBytes(2); //+6 - break; - case 4: - writePaddingBytes(1); //+4 - break; - case 6: - writePaddingBytes(0); // +2 - break; - - } - return 0; - } - - public long writeTwoPaddingBytes() { - return writePaddingBytes(0); - } - - public long writePadding16bit() { - return writePaddingBytes(0); - } - - public long writePadding32bit() { - return writePaddingBytes(1); - } - - public long writePadding64bit() { - return writePaddingBytes(2); - } - - public long writePaddingBytes(int twoPlusHowManyTwoBytes) { - return writeIndex(0xC0 + twoPlusHowManyTwoBytes, false, 0); - } - - public long writePointerArray(boolean is64, long cnt) { - return writeIndex(0xD0 + 0x2, is64, cnt - 1); - } - - public long write64bitPointerArray(long cnt) { - return writeIndex(0xD0 + 0x2, true, cnt - 1); - } - - public long write32bitPointerArray(long cnt) { - return writeIndex(0xD0 + 0x2, false, cnt - 1); - } - - public long write16bitArray(long cnt) { - return writeIndex(0xD0 + 0x4, false, cnt - 1); - } - - public long write32bitArray(long cnt) { - return writeIndex(0xD0 + 0x5, false, cnt - 1); - } - - public long write64bitArray(long cnt) { - return writeIndex(0xD0 + 0x6, false, cnt - 1); - } - - public long skipOneInIndex() { - return writeIndex(CODE_FC_SKIP1, false, 0); - } - - public long writeLengthCustom(int totalLen, int localOffsets[], int platformTypes[]) { - return writeIndex(CODE_FD_OFS8_SKIP_TWICE8, false, totalLen, localOffsets, platformTypes); - } - - public long writeLengthBytePositive(int valUI8) { - return writeIndex(CODE_FE_OFS8_POSITIVE, false, valUI8); - } - - public long writeLengthUI32(long offset) { - return writeIndex(CODE_FF_OFS32, false, offset); - } - - public static int platformNumSize(boolean is64, int i) { - if (i <= 2) { - return is64 ? 8 : 4; - } else if (i <= 4) { - return 2; - } else if (i == 5) { - return 4; - } else if (i == 6) { - return 8; - } - throw new RuntimeException("Uknown platform num"); - } - - private long writeIndex(int code, boolean is64, long val) { - return writeIndex(code, is64, val, null, null); - } - - private long writeIndex(int code, boolean is64, long val, int localOffsets[], int platformTypes[]) { - try { - //LOGGER.finest(String.format("index offset: %d, %04X", STATIC_HDR.length + indexStream.position(), STATIC_HDR.length + indexStream.position())); - LOGGER.finer(String.format("Code = 0x%02X", code)); - indexStream.writeUI8(code); - if (code < 0x80) // 0-0x7F - { - LOGGER.finest("0-0x7F: code is directly an index to the index_table"); - // code is directly an index to the index_table - if (code >= constTable.size()) { - LOGGER.severe(String.format("< 0x80: index is greater than index_table_size. %x > %x", code, constTable.size())); - return 0; - } - - LOGGER.finest(String.format("LENGTH = indexTable[%d] = %d", code, constTable.get(code))); - long ret = constTable.get(code); - position += ret; - return ret; - } else if (code < 0xC0) // 0x80-BF - { - LOGGER.finest("0x80-BF: table[0..255]*(code-0x7F)"); - int index; - - indexStream.writeUI8((int) val); - index = (int) val; - - if (index >= constTable.size()) { - LOGGER.severe(String.format("< 0xC0: index is greater than index_table_size. %x > %x", index, constTable.size())); - return 0; - } - - int n = code - 0x7F; - LOGGER.finest(String.format("index = %d, n = code - 0x7F = %d", index, n)); - LOGGER.finest(String.format("LENGTH = indexTable[index] * n = indexTable[%d] * %d = %d", index, n, constTable.get(index) * n)); - long ret = constTable.get(index) * n; - position += ret; - return ret; - } else if (code < 0xD0) // 0xC0-0xCF - { - LOGGER.finest("0xC0-CF: code*2-0x17E"); - long ret = ((code * 2) - 0x17E); - position += ret; - return ret; - } else if (code < 0xE0) // 0xD0-0xDF - { - LOGGER.finest("0xD0-0xDF: platform based"); - - // Code here depends on plattform[0], we are assuming it is 1, as we checked in load function - int i = code & 0xF; - int n8; - int n; - - indexStream.writeUI8((int) val); - if ((n8 = (int) val) < 0) { - LOGGER.severe(String.format("< 0xE0: Cannot read n.")); - return 0; - } - - n = n8 + 1; - - LOGGER.finest(String.format("i=%X", i)); - LOGGER.finest(String.format("n=%d", n)); - - if (is64) { - if (i <= 2) { - LOGGER.finest(String.format("offset += %d", 8 * n)); - position += 8 * n; - return 8 * n; // Ptr type - } else if (i <= 4) { - LOGGER.finest(String.format("offset += %d", 2 * n)); - position += 2 * n; - return 2 * n; - } else if (i == 5) { - LOGGER.finest(String.format("offset += %d", 4 * n)); - position += 4 * n; - return 4 * n; - } else if (i == 6) { - LOGGER.finest(String.format("offset += %d", 8 * n)); - position += 8 * n; - return 8 * n; // 64 bits type - } else { - LOGGER.severe(String.format("< 0xE0: Invalid value for i (%x %x)", i, code)); - return 0; - } - } else { - switch (i) { - case 2: - LOGGER.finest(String.format("offset += %d", 4 * n)); - position += 4 * n; - return 4 * n; // Ptr type; - case 4: - LOGGER.finest(String.format("offset += %d", 2 * n)); - position += 2 * n; - return 2 * n; - case 5: - LOGGER.finest(String.format("offset += %d", 4 * n)); - position += 4 * n; - return 4 * n; // 32 bits type - case 6: - LOGGER.finest(String.format("offset += %d", 8 * n)); - position += 8 * n; - return 8 * n; - default: - LOGGER.severe(String.format("< 0xE0: invalid value for i (%x %x)", i, code)); - return 0; - } - } - } else if (code == CODE_FC_SKIP1) { - LOGGER.finest(String.format("0xFC: skip 1 ")); - //indexStream.seek(1, SeekMode.CUR); - indexStream.write(0); //?? - return 1; //seek 1 - } else if (code == CODE_FD_OFS8_SKIP_TWICE8) { - LOGGER.finest(String.format("0xFD: 0..255, skip 2 * 0..255 ")); - int n, m; - - n = (int) val; - indexStream.writeUI8((int) val); - m = localOffsets.length; - indexStream.writeUI8(localOffsets.length); - - long offset = n; - position += n; - LOGGER.finest(String.format("offset += %d", n)); - for (int i = 0; i < localOffsets.length; i++) { - indexStream.writeUI8(localOffsets[i]); - indexStream.writeUI8(platformTypes[i]); - } - return offset; - } else if (code == CODE_FE_OFS8_POSITIVE) { - LOGGER.finest(String.format("0xFD: 0..255 + 1 ")); - int n8; - int n; - - indexStream.writeUI8((int) val); - if ((n8 = (int) val) < 0) { - LOGGER.severe(String.format("0xFE: Cannot read n.")); - return 0; - } - - n = n8 + 1; - position += n; - LOGGER.finest(String.format("offset += %d", n)); - return n; - } else if (code == CODE_FF_OFS32) { - LOGGER.finest(String.format("0xFF: 32bit ")); - long n; - - indexStream.writeUI32(val); - if ((n = val) < 0) { - LOGGER.severe(String.format("0xFF: Cannot read n.")); - return 0; - } - - LOGGER.finest(String.format("offset += %d", n)); - position += n; - return n; - } else { - LOGGER.warning(String.format("Unrecognized code: %x", code)); - return 0; - } - } catch (IOException ex) { - return 0; - } - } -} +package com.jpexs.decompiler.flash.iggy.streams; + +import com.jpexs.decompiler.flash.iggy.IggyCharKerning; +import com.jpexs.decompiler.flash.iggy.IggyCharOffset; +import com.jpexs.decompiler.flash.iggy.IggyFontBinInfo; +import com.jpexs.decompiler.flash.iggy.IggyFontTypeInfo; +import com.jpexs.decompiler.flash.iggy.IggyShape; +import com.jpexs.decompiler.flash.iggy.IggyShapeNode; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Logger; + +/** + * + * @author JPEXS + */ +public class IggyIndexBuilder { + + private static Logger LOGGER = Logger.getLogger(IggyIndexBuilder.class.getName()); + private static final int CODE_FC_SKIP1 = 0xFC; + private static final int CODE_FD_OFS8_SKIP_TWICE8 = 0xFD; + private static final int CODE_FE_OFS8_POSITIVE = 0xFE; + private static final int CODE_FF_OFS32 = 0xFF; + + private List constTable = new ArrayList<>(); + private Map> constTableOffsets = new HashMap<>(); + private Map> constTableTypes = new HashMap<>(); + private WriteDataStreamInterface indexStream; + + private static final int CONST_VAL_SHAPE_NODE_SIZE = IggyShapeNode.STRUCT_SIZE; + private static final int CONST_VAL_KERNING_RECORD_SIZE = IggyCharKerning.STRUCT_SIZE; + private static final int CONST_VAL_CHAR_OFFSET_SIZE = IggyCharOffset.STRUCT_SIZE; + private static final int CONST_VAL_BIN_INFO_SIZE = IggyFontBinInfo.STRUCT_SIZE; + private static final int CONST_VAL_TYPE_INFO_SIZE = IggyFontTypeInfo.STRUCT_SIZE; + private static final int CONST_VAL_SHAPE_SIZE = IggyShape.STRUCT_SIZE; + private static final int CONST_VAL_GENERAL_FONT_INFO_SIZE = 112; + private static final int CONST_VAL_GENERAL_FONT_INFO2_SIZE = 240; + private static final int CONST_VAL_TEXT_DATA_SIZE = 104; + private static final int CONST_VAL_SEQUENCE_SIZE = 16; + + public static final int CONST_SHAPE_NODE_SIZE = 0; + public static final int CONST_KERNING_RECORD_SIZE = 1; + public static final int CONST_CHAR_OFFSET_SIZE = 2; + public static final int CONST_BIN_INFO_SIZE = 3; + public static final int CONST_TYPE_INFO_SIZE = 4; + public static final int CONST_SHAPE_SIZE = 5; + public static final int CONST_GENERAL_FONT_INFO_SIZE = 6; + public static final int CONST_GENERAL_FONT_INFO2_SIZE = 7; + public static final int CONST_TEXT_DATA_SIZE = 8; + public static final int CONST_SEQUENCE_SIZE = 9; + + private long position = 0; + + public IggyIndexBuilder() throws IOException { + indexStream = new TemporaryDataStream(); + + addConst(CONST_VAL_SHAPE_NODE_SIZE, new int[]{0, 4, 8, 0xC, 0x12, 0x14, 0x16}, new int[]{5, 5, 5, 5, 4, 4, 4}); + addConst(CONST_VAL_KERNING_RECORD_SIZE, new int[]{0, 2, 4}, new int[]{4, 4, 4}); + addConst(CONST_VAL_CHAR_OFFSET_SIZE, new int[]{8, 0x10, 0x18}, new int[]{4, 8, 2}); + addConst(CONST_VAL_BIN_INFO_SIZE, new int[]{0, 9, 0xC, 0x10, 0x14, 0x18, 0x1C, 0x20, 0x24, 0x28, 0x30, 0x38, 0x3A}, new int[]{2, 3, 5, 5, 5, 5, 5, 5, 5, 4, 2, 4, 4}); + addConst(CONST_VAL_TYPE_INFO_SIZE, new int[]{8, 0x10}, new int[]{2, 5}); + addConst(CONST_VAL_SHAPE_SIZE, new int[]{0, 4, 8, 0xC, 0x10, 0x18, 0x20, 0x28, 0x30}, new int[]{5, 5, 5, 5, 2, 5, 2, 2, 2}); + addConst(CONST_VAL_GENERAL_FONT_INFO_SIZE, new int[]{0x1, 0x02, 0x08, 0x10, 0x20, 0x22, 0x24, 0x26, 0x2B, 0x30, 0x38, 0x40, 0x48, 0x4C, 0x50, 0x54, 0x58, 0x60}, new int[]{0xC, 4, 5, 2, 4, 4, 4, 4, 3, 2, 2, 2, 5, 5, 5, 5, 5, 2}); + addConst(CONST_VAL_GENERAL_FONT_INFO2_SIZE, new int[]{0x10}, new int[]{2}); + addConst(CONST_VAL_TEXT_DATA_SIZE, new int[]{0x01, 0x02, 0x08, 0x10, 0x20, 0x24, 0x28, 0x2C, 0x30, 0x32, 0x38, 0x44, 0x46, 0x48, 0x4A, 0x4C, 0x4E, 0x60}, new int[]{0x0C, 4, 5, 2, 5, 5, 5, 5, 4, 4, 2, 4, 4, 4, 4, 4, 4, 2}); + addConst(CONST_VAL_SEQUENCE_SIZE, new int[]{0, 8}, new int[]{2, 5}); + } + + private void addConst(int totalLength, int[] localOffsets, int[] types) { + if (localOffsets.length != types.length) { + throw new RuntimeException("Size of localOffsets does not match size of types on adding consts with total length " + totalLength); + } + constTable.add(totalLength); + int newIndex = constTable.size() - 1; + List localOffsetsList = new ArrayList<>(); + for (int t : localOffsets) { + localOffsetsList.add(t); + } + List typesList = new ArrayList<>(); + for (int t : types) { + typesList.add(t); + } + constTableOffsets.put(newIndex, localOffsetsList); + constTableTypes.put(newIndex, typesList); + } + + private byte[] getIndexTableBytes() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + baos.write(constTable.size()); + for (int i = 0; i < constTable.size(); i++) { + baos.write(constTable.get(i)); + baos.write(constTableOffsets.get(i).size()); + for (int j = 0; j < constTableOffsets.get(i).size(); j++) { + baos.write(constTableOffsets.get(i).get(j)); + baos.write(constTableTypes.get(i).get(j)); + } + } + return baos.toByteArray(); + } + + public byte[] getIndexBytes() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try { + baos.write(getIndexTableBytes()); + baos.write(indexStream.getAllBytes()); + } catch (IOException ex) { + //should not happen + } + return baos.toByteArray(); + } + + public long writeConstLength(int constIndex) { + return writeIndex(constIndex, false, 0); + } + + public long writeConstLengthArray(int constIndex, long cnt) { + long ret = 0; + long rem = cnt; + while (true) { + if (rem == 0) { + break; + } + if (rem == 1) { + ret += writeIndex(constIndex, false, 0); + break; + } + if (rem <= 64) { + ret += writeIndex(0x80 + (int) rem - 1, false, constIndex); + break; + } else { + rem -= 64; + ret += writeIndex(0x80 + 64 - 1, false, constIndex); + } + } + return ret; + } + + public long pad8bytes() { + int pad8 = (int) (position % 8); + switch (pad8) { + case 2: + writePaddingBytes(2); //+6 + break; + case 4: + writePaddingBytes(1); //+4 + break; + case 6: + writePaddingBytes(0); // +2 + break; + + } + return 0; + } + + public long writeTwoPaddingBytes() { + return writePaddingBytes(0); + } + + public long writePadding16bit() { + return writePaddingBytes(0); + } + + public long writePadding32bit() { + return writePaddingBytes(1); + } + + public long writePadding64bit() { + return writePaddingBytes(2); + } + + public long writePaddingBytes(int twoPlusHowManyTwoBytes) { + return writeIndex(0xC0 + twoPlusHowManyTwoBytes, false, 0); + } + + public long writePointerArray(boolean is64, long cnt) { + return writeIndex(0xD0 + 0x2, is64, cnt - 1); + } + + public long write64bitPointerArray(long cnt) { + return writeIndex(0xD0 + 0x2, true, cnt - 1); + } + + public long write32bitPointerArray(long cnt) { + return writeIndex(0xD0 + 0x2, false, cnt - 1); + } + + public long write16bitArray(long cnt) { + return writeIndex(0xD0 + 0x4, false, cnt - 1); + } + + public long write32bitArray(long cnt) { + return writeIndex(0xD0 + 0x5, false, cnt - 1); + } + + public long write64bitArray(long cnt) { + return writeIndex(0xD0 + 0x6, false, cnt - 1); + } + + public long skipOneInIndex() { + return writeIndex(CODE_FC_SKIP1, false, 0); + } + + public long writeLengthCustom(int totalLen, int localOffsets[], int platformTypes[]) { + return writeIndex(CODE_FD_OFS8_SKIP_TWICE8, false, totalLen, localOffsets, platformTypes); + } + + public long writeLengthBytePositive(int valUI8) { + return writeIndex(CODE_FE_OFS8_POSITIVE, false, valUI8); + } + + public long writeLengthUI32(long offset) { + return writeIndex(CODE_FF_OFS32, false, offset); + } + + public static int platformNumSize(boolean is64, int i) { + if (i <= 2) { + return is64 ? 8 : 4; + } else if (i <= 4) { + return 2; + } else if (i == 5) { + return 4; + } else if (i == 6) { + return 8; + } + throw new RuntimeException("Uknown platform num"); + } + + private long writeIndex(int code, boolean is64, long val) { + return writeIndex(code, is64, val, null, null); + } + + private long writeIndex(int code, boolean is64, long val, int localOffsets[], int platformTypes[]) { + try { + //LOGGER.finest(String.format("index offset: %d, %04X", STATIC_HDR.length + indexStream.position(), STATIC_HDR.length + indexStream.position())); + LOGGER.finer(String.format("Code = 0x%02X", code)); + indexStream.writeUI8(code); + if (code < 0x80) // 0-0x7F + { + LOGGER.finest("0-0x7F: code is directly an index to the index_table"); + // code is directly an index to the index_table + if (code >= constTable.size()) { + LOGGER.severe(String.format("< 0x80: index is greater than index_table_size. %x > %x", code, constTable.size())); + return 0; + } + + LOGGER.finest(String.format("LENGTH = indexTable[%d] = %d", code, constTable.get(code))); + long ret = constTable.get(code); + position += ret; + return ret; + } else if (code < 0xC0) // 0x80-BF + { + LOGGER.finest("0x80-BF: table[0..255]*(code-0x7F)"); + int index; + + indexStream.writeUI8((int) val); + index = (int) val; + + if (index >= constTable.size()) { + LOGGER.severe(String.format("< 0xC0: index is greater than index_table_size. %x > %x", index, constTable.size())); + return 0; + } + + int n = code - 0x7F; + LOGGER.finest(String.format("index = %d, n = code - 0x7F = %d", index, n)); + LOGGER.finest(String.format("LENGTH = indexTable[index] * n = indexTable[%d] * %d = %d", index, n, constTable.get(index) * n)); + long ret = constTable.get(index) * n; + position += ret; + return ret; + } else if (code < 0xD0) // 0xC0-0xCF + { + LOGGER.finest("0xC0-CF: code*2-0x17E"); + long ret = ((code * 2) - 0x17E); + position += ret; + return ret; + } else if (code < 0xE0) // 0xD0-0xDF + { + LOGGER.finest("0xD0-0xDF: platform based"); + + // Code here depends on plattform[0], we are assuming it is 1, as we checked in load function + int i = code & 0xF; + int n8; + int n; + + indexStream.writeUI8((int) val); + if ((n8 = (int) val) < 0) { + LOGGER.severe(String.format("< 0xE0: Cannot read n.")); + return 0; + } + + n = n8 + 1; + + LOGGER.finest(String.format("i=%X", i)); + LOGGER.finest(String.format("n=%d", n)); + + if (is64) { + if (i <= 2) { + LOGGER.finest(String.format("offset += %d", 8 * n)); + position += 8 * n; + return 8 * n; // Ptr type + } else if (i <= 4) { + LOGGER.finest(String.format("offset += %d", 2 * n)); + position += 2 * n; + return 2 * n; + } else if (i == 5) { + LOGGER.finest(String.format("offset += %d", 4 * n)); + position += 4 * n; + return 4 * n; + } else if (i == 6) { + LOGGER.finest(String.format("offset += %d", 8 * n)); + position += 8 * n; + return 8 * n; // 64 bits type + } else { + LOGGER.severe(String.format("< 0xE0: Invalid value for i (%x %x)", i, code)); + return 0; + } + } else { + switch (i) { + case 2: + LOGGER.finest(String.format("offset += %d", 4 * n)); + position += 4 * n; + return 4 * n; // Ptr type; + case 4: + LOGGER.finest(String.format("offset += %d", 2 * n)); + position += 2 * n; + return 2 * n; + case 5: + LOGGER.finest(String.format("offset += %d", 4 * n)); + position += 4 * n; + return 4 * n; // 32 bits type + case 6: + LOGGER.finest(String.format("offset += %d", 8 * n)); + position += 8 * n; + return 8 * n; + default: + LOGGER.severe(String.format("< 0xE0: invalid value for i (%x %x)", i, code)); + return 0; + } + } + } else if (code == CODE_FC_SKIP1) { + LOGGER.finest(String.format("0xFC: skip 1 ")); + //indexStream.seek(1, SeekMode.CUR); + indexStream.write(0); //?? + return 1; //seek 1 + } else if (code == CODE_FD_OFS8_SKIP_TWICE8) { + LOGGER.finest(String.format("0xFD: 0..255, skip 2 * 0..255 ")); + int n, m; + + n = (int) val; + indexStream.writeUI8((int) val); + m = localOffsets.length; + indexStream.writeUI8(localOffsets.length); + + long offset = n; + position += n; + LOGGER.finest(String.format("offset += %d", n)); + for (int i = 0; i < localOffsets.length; i++) { + indexStream.writeUI8(localOffsets[i]); + indexStream.writeUI8(platformTypes[i]); + } + return offset; + } else if (code == CODE_FE_OFS8_POSITIVE) { + LOGGER.finest(String.format("0xFD: 0..255 + 1 ")); + int n8; + int n; + + indexStream.writeUI8((int) val); + if ((n8 = (int) val) < 0) { + LOGGER.severe(String.format("0xFE: Cannot read n.")); + return 0; + } + + n = n8 + 1; + position += n; + LOGGER.finest(String.format("offset += %d", n)); + return n; + } else if (code == CODE_FF_OFS32) { + LOGGER.finest(String.format("0xFF: 32bit ")); + long n; + + indexStream.writeUI32(val); + if ((n = val) < 0) { + LOGGER.severe(String.format("0xFF: Cannot read n.")); + return 0; + } + + LOGGER.finest(String.format("offset += %d", n)); + position += n; + return n; + } else { + LOGGER.warning(String.format("Unrecognized code: %x", code)); + return 0; + } + } catch (IOException ex) { + return 0; + } + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/IggyIndexParser.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/IggyIndexParser.java index 87e7f02c8..7b55d3710 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/IggyIndexParser.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/IggyIndexParser.java @@ -1,246 +1,246 @@ -package com.jpexs.decompiler.flash.iggy.streams; - -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.PrintWriter; -import java.util.List; -import java.util.logging.ConsoleHandler; -import java.util.logging.Handler; -import java.util.logging.Level; -import java.util.logging.LogRecord; -import java.util.logging.Logger; - -/** - * - * @author JPEXS - */ -public class IggyIndexParser { - - private static Logger LOGGER = Logger.getLogger(IggyIndexParser.class.getName()); - - /*static PrintWriter pw; - - static { - try { - pw = new PrintWriter("d:\\Dropbox\\jpexs-laptop\\iggi\\extraxtdir_orig\\index2b.txt"); - } catch (FileNotFoundException ex) { - Logger.getLogger(IggyIndexParser.class.getName()).log(Level.SEVERE, null, ex); - } - LOGGER.setLevel(Level.ALL); - LOGGER.addHandler(new Handler() { - @Override - public void publish(LogRecord record) { - pw.println("" + record.getMessage()); - } - - @Override - public void flush() { - pw.flush(); - } - - @Override - public void close() throws SecurityException { - pw.close(); - } - }); - } - */ - /** - * Parser for index data. It creates table of indices and table of offsets - * - * @param indexStream Stream of index - * @param indexTableEntry Output index tabke - * @param offsets Output list of offsets - * @throws IOException on error - */ - public static void parseIndex(boolean is64, ReadDataStreamInterface indexStream, List indexTableEntry, List offsets) throws IOException { - int indexTableSize = indexStream.readUI8(); - int[] indexTable = new int[indexTableSize]; - for (int i = 0; i < indexTableSize; i++) { - int offset = indexStream.readUI8(); - LOGGER.fine(String.format("index_table_entry: %d", offset)); - indexTable[i] = offset; - indexTableEntry.add(offset); - int num = indexStream.readUI8(); - for (int j = 0; j < num; j++) { - int locOffset = indexStream.readUI8(); - int type = indexStream.readUI8(); - LOGGER.finer(String.format("- local offset: %d, type: %d", locOffset, type)); - } - } - - long offset = 0; - int code; - - String tabs = "\t\t\t\t"; - - LOGGER.finer(String.format("-- OFFSET: 0" + tabs)); - - while ((code = indexStream.readUI8()) > -1) { - LOGGER.finer(String.format("Code = 0x%02X", code)); - - if (code < 0x80) // 0-0x7F - { - LOGGER.finest("0-0x7F: code is directly an index to the index_table"); - // code is directly an index to the index_table - if (code >= indexTableSize) { - LOGGER.severe(String.format("< 0x80: index is greater than index_table_size. %x > %x", code, indexTableSize)); - return; - } - - offset += indexTable[code]; - LOGGER.finest(String.format("LENGTH = indexTable[%d] = %d", code, indexTable[code])); - - } else if (code < 0xC0) // 0x80-BF - { - LOGGER.finest("0x80-BF: table[0..255]*(code-0x7F)"); - int index; - - if ((index = indexStream.readUI8()) < 0) { - LOGGER.severe(String.format("< 0xC0: Cannot read index.")); - return; - } - - if (index >= indexTableSize) { - LOGGER.severe(String.format("< 0xC0: index is greater than index_table_size. %x > %x", index, indexTableSize)); - return; - } - - int n = code - 0x7F; - LOGGER.finest(String.format("index = %d, n = code - 0x7F = %d", index, n)); - LOGGER.finest(String.format("LENGTH = indexTable[index] * n = indexTable[%d] * %d = %d", index, n, indexTable[index] * n)); - offset += indexTable[index] * n; - } else if (code < 0xD0) // 0xC0-0xCF - { - LOGGER.finest("0xC0-CF: code*2-0x17E"); - offset += ((code * 2) - 0x17E); - LOGGER.finest(String.format("LENGTH = (code * 2) - 0x17E = (0x%02X * 2) - 0x17E = %d", code, ((code * 2) - 0x17E))); - } else if (code < 0xE0) // 0xD0-0xDF - { - LOGGER.finest("0xD0-0xDF: platform based"); - - // Code here depends on plattform[0], we are assuming it is 1, as we checked in load function - int i = code & 0xF; - int n8; - int n; - - if ((n8 = indexStream.readUI8()) < 0) { - LOGGER.severe(String.format("< 0xE0: Cannot read n.")); - return; - } - - n = n8 + 1; - - LOGGER.finest(String.format("i=%X", i)); - LOGGER.finest(String.format("n=%d", n)); - - if (is64) { - if (i <= 2) { - offset += 8 * n; // Ptr type - LOGGER.finest(String.format("LENGTH = 8 * n = 8 * %d = %d", n, 8 * n)); - } else if (i <= 4) { - offset += 2 * n; - LOGGER.finest(String.format("LENGTH = 2 * n = 2 * %d = %d", n, 2 * n)); - } else if (i == 5) { - offset += 4 * n; - LOGGER.finest(String.format("LENGTH = 4 * n = 4 * %d = %d", n, 4 * n)); - } else if (i == 6) { - offset += 8 * n; // 64 bits type - LOGGER.finest(String.format("LENGTH = 8 * n = 8 * %d = %d", n, 8 * n)); - } else { - LOGGER.severe(String.format("< 0xE0: Invalid value for i (%x %x)", i, code)); - } - } else { - switch (i) { - case 2: - offset += 4 * n; // Ptr type - LOGGER.finest(String.format("LENGTH = 4 * n = 4 * %d = %d", n, 4 * n)); - break; - case 4: - offset += 2 * n; - LOGGER.finest(String.format("LENGTH = 2 * n = 2 * %d = %d", n, 2 * n)); - break; - case 5: - offset += 4 * n; // 32 bits type - LOGGER.finest(String.format("LENGTH = 4 * n = 4 * %d = %d", n, 4 * n)); - break; - case 6: - offset += 8 * n; - LOGGER.finest(String.format("LENGTH = 8 * n = 8 * %d = %d", n, 8 * n)); - break; - default: - LOGGER.severe(String.format("< 0xE0: invalid value for i (%x %x)", i, code)); - } - } - } else if (code == 0xFC) { - LOGGER.finest(String.format("0xFC: SKIP 1 ")); - indexStream.seek(1, SeekMode.CUR); - } else if (code == 0xFD) { - LOGGER.finest(String.format("0xFD: 0..255, skip 2 * 0..255 ")); - int n, m; - - if ((n = indexStream.readUI8()) < 0) { - LOGGER.severe(String.format("0xFD: Cannot read n.")); - return; - } - LOGGER.finest(String.format("n = %d", n)); - - if ((m = indexStream.readUI8()) < 0) { - LOGGER.severe(String.format("0xFD: Cannot read m.")); - return; - } - LOGGER.finest(String.format("m = %d", m)); - - offset += n; - LOGGER.finest(String.format("LENGTH = n = %d", n)); - StringBuilder locOffStr = new StringBuilder(); - StringBuilder platStr = new StringBuilder(); - for (int i = 0; i < m; i++) { - int localOffset = indexStream.readUI8(); - int platformType = indexStream.readUI8(); - if (i > 0) { - locOffStr.append(", "); - platStr.append(", "); - } - locOffStr.append(String.format("0x%02X", localOffset)); - platStr.append(platformType); - LOGGER.finest(String.format("- localOffset 0x%02X, platformType %d", localOffset, platformType)); - } - LOGGER.finer(String.format("stream.writeLengthCustom(%s,new int[]{%s},new int[]{%s}", n, locOffStr, platStr)); - //indexStream.seek(m * 2, SeekMode.CUR); - //LOGGER.finest(String.format("SKIP m * 2 = skip %d * 2 = %d", m, m * 2)); - } else if (code == 0xFE) { - LOGGER.finest(String.format("0xFD: 0..255 + 1 ")); - int n8; - int n; - - if ((n8 = indexStream.readUI8()) < 0) { - LOGGER.severe(String.format("0xFE: Cannot read n.")); - return; - } - LOGGER.finest(String.format("n8 = %d", n8)); - - n = n8 + 1; - offset += n; - LOGGER.finest(String.format("LENGTH = n8 + 1 = %d + 1 = %d", n8, n)); - } else if (code == 0xFF) { - LOGGER.finest(String.format("0xFF: 32bit ")); - long n; - - if ((n = indexStream.readUI32()) < 0) { - LOGGER.severe(String.format("0xFF: Cannot read n.")); - return; - } - - offset += n; - LOGGER.finest(String.format("LENGTH = n = %d", n)); - } else { - LOGGER.warning(String.format("Unrecognized code: %x", code)); - } - - LOGGER.finer(String.format("-- OFFSET: %d" + tabs, offset)); - - offsets.add(offset); - } - } -} +package com.jpexs.decompiler.flash.iggy.streams; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.List; +import java.util.logging.ConsoleHandler; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.LogRecord; +import java.util.logging.Logger; + +/** + * + * @author JPEXS + */ +public class IggyIndexParser { + + private static Logger LOGGER = Logger.getLogger(IggyIndexParser.class.getName()); + + /*static PrintWriter pw; + + static { + try { + pw = new PrintWriter("d:\\Dropbox\\jpexs-laptop\\iggi\\extraxtdir_orig\\index2b.txt"); + } catch (FileNotFoundException ex) { + Logger.getLogger(IggyIndexParser.class.getName()).log(Level.SEVERE, null, ex); + } + LOGGER.setLevel(Level.ALL); + LOGGER.addHandler(new Handler() { + @Override + public void publish(LogRecord record) { + pw.println("" + record.getMessage()); + } + + @Override + public void flush() { + pw.flush(); + } + + @Override + public void close() throws SecurityException { + pw.close(); + } + }); + } + */ + /** + * Parser for index data. It creates table of indices and table of offsets + * + * @param indexStream Stream of index + * @param indexTableEntry Output index tabke + * @param offsets Output list of offsets + * @throws IOException on error + */ + public static void parseIndex(boolean is64, ReadDataStreamInterface indexStream, List indexTableEntry, List offsets) throws IOException { + int indexTableSize = indexStream.readUI8(); + int[] indexTable = new int[indexTableSize]; + for (int i = 0; i < indexTableSize; i++) { + int offset = indexStream.readUI8(); + LOGGER.fine(String.format("index_table_entry: %d", offset)); + indexTable[i] = offset; + indexTableEntry.add(offset); + int num = indexStream.readUI8(); + for (int j = 0; j < num; j++) { + int locOffset = indexStream.readUI8(); + int type = indexStream.readUI8(); + LOGGER.finer(String.format("- local offset: %d, type: %d", locOffset, type)); + } + } + + long offset = 0; + int code; + + String tabs = "\t\t\t\t"; + + LOGGER.finer(String.format("-- OFFSET: 0" + tabs)); + + while ((code = indexStream.readUI8()) > -1) { + LOGGER.finer(String.format("Code = 0x%02X", code)); + + if (code < 0x80) // 0-0x7F + { + LOGGER.finest("0-0x7F: code is directly an index to the index_table"); + // code is directly an index to the index_table + if (code >= indexTableSize) { + LOGGER.severe(String.format("< 0x80: index is greater than index_table_size. %x > %x", code, indexTableSize)); + return; + } + + offset += indexTable[code]; + LOGGER.finest(String.format("LENGTH = indexTable[%d] = %d", code, indexTable[code])); + + } else if (code < 0xC0) // 0x80-BF + { + LOGGER.finest("0x80-BF: table[0..255]*(code-0x7F)"); + int index; + + if ((index = indexStream.readUI8()) < 0) { + LOGGER.severe(String.format("< 0xC0: Cannot read index.")); + return; + } + + if (index >= indexTableSize) { + LOGGER.severe(String.format("< 0xC0: index is greater than index_table_size. %x > %x", index, indexTableSize)); + return; + } + + int n = code - 0x7F; + LOGGER.finest(String.format("index = %d, n = code - 0x7F = %d", index, n)); + LOGGER.finest(String.format("LENGTH = indexTable[index] * n = indexTable[%d] * %d = %d", index, n, indexTable[index] * n)); + offset += indexTable[index] * n; + } else if (code < 0xD0) // 0xC0-0xCF + { + LOGGER.finest("0xC0-CF: code*2-0x17E"); + offset += ((code * 2) - 0x17E); + LOGGER.finest(String.format("LENGTH = (code * 2) - 0x17E = (0x%02X * 2) - 0x17E = %d", code, ((code * 2) - 0x17E))); + } else if (code < 0xE0) // 0xD0-0xDF + { + LOGGER.finest("0xD0-0xDF: platform based"); + + // Code here depends on plattform[0], we are assuming it is 1, as we checked in load function + int i = code & 0xF; + int n8; + int n; + + if ((n8 = indexStream.readUI8()) < 0) { + LOGGER.severe(String.format("< 0xE0: Cannot read n.")); + return; + } + + n = n8 + 1; + + LOGGER.finest(String.format("i=%X", i)); + LOGGER.finest(String.format("n=%d", n)); + + if (is64) { + if (i <= 2) { + offset += 8 * n; // Ptr type + LOGGER.finest(String.format("LENGTH = 8 * n = 8 * %d = %d", n, 8 * n)); + } else if (i <= 4) { + offset += 2 * n; + LOGGER.finest(String.format("LENGTH = 2 * n = 2 * %d = %d", n, 2 * n)); + } else if (i == 5) { + offset += 4 * n; + LOGGER.finest(String.format("LENGTH = 4 * n = 4 * %d = %d", n, 4 * n)); + } else if (i == 6) { + offset += 8 * n; // 64 bits type + LOGGER.finest(String.format("LENGTH = 8 * n = 8 * %d = %d", n, 8 * n)); + } else { + LOGGER.severe(String.format("< 0xE0: Invalid value for i (%x %x)", i, code)); + } + } else { + switch (i) { + case 2: + offset += 4 * n; // Ptr type + LOGGER.finest(String.format("LENGTH = 4 * n = 4 * %d = %d", n, 4 * n)); + break; + case 4: + offset += 2 * n; + LOGGER.finest(String.format("LENGTH = 2 * n = 2 * %d = %d", n, 2 * n)); + break; + case 5: + offset += 4 * n; // 32 bits type + LOGGER.finest(String.format("LENGTH = 4 * n = 4 * %d = %d", n, 4 * n)); + break; + case 6: + offset += 8 * n; + LOGGER.finest(String.format("LENGTH = 8 * n = 8 * %d = %d", n, 8 * n)); + break; + default: + LOGGER.severe(String.format("< 0xE0: invalid value for i (%x %x)", i, code)); + } + } + } else if (code == 0xFC) { + LOGGER.finest(String.format("0xFC: SKIP 1 ")); + indexStream.seek(1, SeekMode.CUR); + } else if (code == 0xFD) { + LOGGER.finest(String.format("0xFD: 0..255, skip 2 * 0..255 ")); + int n, m; + + if ((n = indexStream.readUI8()) < 0) { + LOGGER.severe(String.format("0xFD: Cannot read n.")); + return; + } + LOGGER.finest(String.format("n = %d", n)); + + if ((m = indexStream.readUI8()) < 0) { + LOGGER.severe(String.format("0xFD: Cannot read m.")); + return; + } + LOGGER.finest(String.format("m = %d", m)); + + offset += n; + LOGGER.finest(String.format("LENGTH = n = %d", n)); + StringBuilder locOffStr = new StringBuilder(); + StringBuilder platStr = new StringBuilder(); + for (int i = 0; i < m; i++) { + int localOffset = indexStream.readUI8(); + int platformType = indexStream.readUI8(); + if (i > 0) { + locOffStr.append(", "); + platStr.append(", "); + } + locOffStr.append(String.format("0x%02X", localOffset)); + platStr.append(platformType); + LOGGER.finest(String.format("- localOffset 0x%02X, platformType %d", localOffset, platformType)); + } + LOGGER.finer(String.format("stream.writeLengthCustom(%s,new int[]{%s},new int[]{%s}", n, locOffStr, platStr)); + //indexStream.seek(m * 2, SeekMode.CUR); + //LOGGER.finest(String.format("SKIP m * 2 = skip %d * 2 = %d", m, m * 2)); + } else if (code == 0xFE) { + LOGGER.finest(String.format("0xFD: 0..255 + 1 ")); + int n8; + int n; + + if ((n8 = indexStream.readUI8()) < 0) { + LOGGER.severe(String.format("0xFE: Cannot read n.")); + return; + } + LOGGER.finest(String.format("n8 = %d", n8)); + + n = n8 + 1; + offset += n; + LOGGER.finest(String.format("LENGTH = n8 + 1 = %d + 1 = %d", n8, n)); + } else if (code == 0xFF) { + LOGGER.finest(String.format("0xFF: 32bit ")); + long n; + + if ((n = indexStream.readUI32()) < 0) { + LOGGER.severe(String.format("0xFF: Cannot read n.")); + return; + } + + offset += n; + LOGGER.finest(String.format("LENGTH = n = %d", n)); + } else { + LOGGER.warning(String.format("Unrecognized code: %x", code)); + } + + LOGGER.finer(String.format("-- OFFSET: %d" + tabs, offset)); + + offsets.add(offset); + } + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/RandomAccessFileDataStream.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/RandomAccessFileDataStream.java index 4b0f613bd..4d5b76db5 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/RandomAccessFileDataStream.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/RandomAccessFileDataStream.java @@ -1,128 +1,128 @@ -package com.jpexs.decompiler.flash.iggy.streams; - -import java.io.EOFException; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - * @author JPEXS - */ -public class RandomAccessFileDataStream extends AbstractDataStream { - - private File file; - private RandomAccessFile raf; - private IggyIndexBuilder indexing; - - protected File getFile() { - return file; - } - - @Override - public void setIndexing(IggyIndexBuilder indexing) { - this.indexing = indexing; - } - - public RandomAccessFileDataStream(File file) throws FileNotFoundException { - this.file = file; - raf = new RandomAccessFile(file, "rw"); - } - - @Override - public Long totalSize() { - try { - return raf.length(); - } catch (IOException ex) { - return null; - } - } - - @Override - public Long available() { - try { - return raf.length() - raf.getFilePointer(); - } catch (IOException ex) { - return null; - } - } - - @Override - public long position() { - try { - return raf.getFilePointer(); - } catch (IOException ex) { - return -1; - } - } - - @Override - public int read() throws IOException { - int val = raf.read(); - if (val == -1) { - throw new EOFException(); - } - return val; - } - - @Override - public byte[] readBytes(int numBytes) throws IOException { - byte buf[] = new byte[numBytes]; - raf.readFully(buf); - return buf; - } - - @Override - public void seek(long pos, SeekMode mode) throws IOException { - long newpos = pos; - if (mode == SeekMode.CUR) { - newpos = raf.getFilePointer() + pos; - } else if (mode == SeekMode.END) { - newpos = raf.length() - pos; - } - if (newpos > raf.length()) { - raf.seek(raf.length()); - long curpos = raf.length(); - for (long i = curpos; i < newpos; i++) { - raf.write(0); - } - } else if (newpos < 0) { - throw new ArrayIndexOutOfBoundsException("Negative position accessed: " + pos); - } else { - raf.seek(newpos); - } - } - - @Override - public void close() { - try { - raf.close(); - } catch (IOException ex) { - //ignore - } - } - - @Override - public void write(int val) throws IOException { - raf.write(val); - } - - @Override - public IggyIndexBuilder getIndexing() { - return indexing; - } - - @Override - public boolean writeWChar(String name) throws IOException { - return super.writeWChar(name); - } - - @Override - public void pad8bytes() throws IOException { - super.pad8bytes(); - } - -} +package com.jpexs.decompiler.flash.iggy.streams; + +import java.io.EOFException; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author JPEXS + */ +public class RandomAccessFileDataStream extends AbstractDataStream { + + private File file; + private RandomAccessFile raf; + private IggyIndexBuilder indexing; + + protected File getFile() { + return file; + } + + @Override + public void setIndexing(IggyIndexBuilder indexing) { + this.indexing = indexing; + } + + public RandomAccessFileDataStream(File file) throws FileNotFoundException { + this.file = file; + raf = new RandomAccessFile(file, "rw"); + } + + @Override + public Long totalSize() { + try { + return raf.length(); + } catch (IOException ex) { + return null; + } + } + + @Override + public Long available() { + try { + return raf.length() - raf.getFilePointer(); + } catch (IOException ex) { + return null; + } + } + + @Override + public long position() { + try { + return raf.getFilePointer(); + } catch (IOException ex) { + return -1; + } + } + + @Override + public int read() throws IOException { + int val = raf.read(); + if (val == -1) { + throw new EOFException(); + } + return val; + } + + @Override + public byte[] readBytes(int numBytes) throws IOException { + byte buf[] = new byte[numBytes]; + raf.readFully(buf); + return buf; + } + + @Override + public void seek(long pos, SeekMode mode) throws IOException { + long newpos = pos; + if (mode == SeekMode.CUR) { + newpos = raf.getFilePointer() + pos; + } else if (mode == SeekMode.END) { + newpos = raf.length() - pos; + } + if (newpos > raf.length()) { + raf.seek(raf.length()); + long curpos = raf.length(); + for (long i = curpos; i < newpos; i++) { + raf.write(0); + } + } else if (newpos < 0) { + throw new ArrayIndexOutOfBoundsException("Negative position accessed: " + pos); + } else { + raf.seek(newpos); + } + } + + @Override + public void close() { + try { + raf.close(); + } catch (IOException ex) { + //ignore + } + } + + @Override + public void write(int val) throws IOException { + raf.write(val); + } + + @Override + public IggyIndexBuilder getIndexing() { + return indexing; + } + + @Override + public boolean writeWChar(String name) throws IOException { + return super.writeWChar(name); + } + + @Override + public void pad8bytes() throws IOException { + super.pad8bytes(); + } + +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/ReadDataStreamInterface.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/ReadDataStreamInterface.java index 7536e6aef..37361c0fd 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/ReadDataStreamInterface.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/ReadDataStreamInterface.java @@ -1,50 +1,50 @@ -package com.jpexs.decompiler.flash.iggy.streams; - -import java.io.IOException; - -/** - * - * @author JPEXS - */ -public interface ReadDataStreamInterface extends AutoCloseable { - - /** - * Available bytes - * - * @return null if unknown, long value otherwise - */ - public Long available(); - - public Long totalSize(); - - public long position(); - - public long readUI64() throws IOException; - - public long readSI64() throws IOException; - - public long readUI32() throws IOException; - - public int readUI16() throws IOException; - - public int readUI8() throws IOException; - - public int readUI8(long addr) throws IOException; - - public int read() throws IOException; - - public byte[] readBytes(int numBytes) throws IOException; - - public float readFloat() throws IOException; - - public void seek(long pos, SeekMode mode) throws IOException; - - public byte[] getAllBytes() throws IOException; - - public String readWChar() throws IOException; - - public void pad8bytes() throws IOException; - - @Override - public void close(); -} +package com.jpexs.decompiler.flash.iggy.streams; + +import java.io.IOException; + +/** + * + * @author JPEXS + */ +public interface ReadDataStreamInterface extends AutoCloseable { + + /** + * Available bytes + * + * @return null if unknown, long value otherwise + */ + public Long available(); + + public Long totalSize(); + + public long position(); + + public long readUI64() throws IOException; + + public long readSI64() throws IOException; + + public long readUI32() throws IOException; + + public int readUI16() throws IOException; + + public int readUI8() throws IOException; + + public int readUI8(long addr) throws IOException; + + public int read() throws IOException; + + public byte[] readBytes(int numBytes) throws IOException; + + public float readFloat() throws IOException; + + public void seek(long pos, SeekMode mode) throws IOException; + + public byte[] getAllBytes() throws IOException; + + public String readWChar() throws IOException; + + public void pad8bytes() throws IOException; + + @Override + public void close(); +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/SeekMode.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/SeekMode.java index 237fb8c7f..3fd82daab 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/SeekMode.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/SeekMode.java @@ -1,9 +1,9 @@ -package com.jpexs.decompiler.flash.iggy.streams; - -/** - * - * @author Jindra - */ -public enum SeekMode { - SET, CUR, END -} +package com.jpexs.decompiler.flash.iggy.streams; + +/** + * + * @author Jindra + */ +public enum SeekMode { + SET, CUR, END +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/StructureInterface.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/StructureInterface.java index 526445ddd..588f22328 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/StructureInterface.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/StructureInterface.java @@ -1,16 +1,16 @@ -package com.jpexs.decompiler.flash.iggy.streams; - -import com.jpexs.decompiler.flash.iggy.streams.AbstractDataStream; -import java.io.IOException; -import java.util.List; - -/** - * - * @author JPEXS - */ -public interface StructureInterface { - - public void readFromDataStream(ReadDataStreamInterface stream) throws IOException; - - public void writeToDataStream(WriteDataStreamInterface stream) throws IOException; -} +package com.jpexs.decompiler.flash.iggy.streams; + +import com.jpexs.decompiler.flash.iggy.streams.AbstractDataStream; +import java.io.IOException; +import java.util.List; + +/** + * + * @author JPEXS + */ +public interface StructureInterface { + + public void readFromDataStream(ReadDataStreamInterface stream) throws IOException; + + public void writeToDataStream(WriteDataStreamInterface stream) throws IOException; +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/TemporaryDataStream.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/TemporaryDataStream.java index adb99afdd..d90273943 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/TemporaryDataStream.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/TemporaryDataStream.java @@ -1,31 +1,31 @@ -package com.jpexs.decompiler.flash.iggy.streams; - -import java.io.File; -import java.io.IOException; - -/** - * - * @author JPEXS - */ -public class TemporaryDataStream extends RandomAccessFileDataStream { - - public TemporaryDataStream() throws IOException { - this(new byte[0]); - } - - public TemporaryDataStream(byte[] data) throws IOException { - super(File.createTempFile("tempdatastream", ".bin")); - this.getFile().deleteOnExit(); - writeBytes(data); - seek(0, SeekMode.SET); - } - - @Override - public void close() { - try { - this.getFile().delete(); - } catch (Exception ex) { - //ignore - } - } -} +package com.jpexs.decompiler.flash.iggy.streams; + +import java.io.File; +import java.io.IOException; + +/** + * + * @author JPEXS + */ +public class TemporaryDataStream extends RandomAccessFileDataStream { + + public TemporaryDataStream() throws IOException { + this(new byte[0]); + } + + public TemporaryDataStream(byte[] data) throws IOException { + super(File.createTempFile("tempdatastream", ".bin")); + this.getFile().deleteOnExit(); + writeBytes(data); + seek(0, SeekMode.SET); + } + + @Override + public void close() { + try { + this.getFile().delete(); + } catch (Exception ex) { + //ignore + } + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/WriteDataStreamInterface.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/WriteDataStreamInterface.java index 079d53136..d022f5d8c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/WriteDataStreamInterface.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/WriteDataStreamInterface.java @@ -1,56 +1,56 @@ -package com.jpexs.decompiler.flash.iggy.streams; - -import java.io.IOException; - -/** - * - * @author JPEXS - */ -public interface WriteDataStreamInterface extends AutoCloseable { - - /** - * Available bytes - * - * @return null if unknown, long value otherwise - */ - public Long available(); - - public Long totalSize(); - - public long position(); - - public void setOlderOffsetToThisPos(long savedPos) throws IOException; - - public void setOlderOffsetToThisPosCheck(long savedPos, long expected) throws IOException; - - public boolean writeUI64(long val) throws IOException; - - public boolean writeSI64(long val) throws IOException; - - public boolean writeUI32(long val) throws IOException; - - public boolean writeUI16(int val) throws IOException; - - public boolean writeWChar(String val) throws IOException; - - public void pad8bytes() throws IOException; - - public boolean writeUI8(int val) throws IOException; - - public void write(int val) throws IOException; - - public void writeBytes(byte[] data) throws IOException; - - public boolean writeFloat(float val) throws IOException; - - public void seek(long pos, SeekMode mode) throws IOException; - - public byte[] getAllBytes() throws IOException; - - @Override - public void close(); - - public void setIndexing(IggyIndexBuilder indexing); - - public IggyIndexBuilder getIndexing(); -} +package com.jpexs.decompiler.flash.iggy.streams; + +import java.io.IOException; + +/** + * + * @author JPEXS + */ +public interface WriteDataStreamInterface extends AutoCloseable { + + /** + * Available bytes + * + * @return null if unknown, long value otherwise + */ + public Long available(); + + public Long totalSize(); + + public long position(); + + public void setOlderOffsetToThisPos(long savedPos) throws IOException; + + public void setOlderOffsetToThisPosCheck(long savedPos, long expected) throws IOException; + + public boolean writeUI64(long val) throws IOException; + + public boolean writeSI64(long val) throws IOException; + + public boolean writeUI32(long val) throws IOException; + + public boolean writeUI16(int val) throws IOException; + + public boolean writeWChar(String val) throws IOException; + + public void pad8bytes() throws IOException; + + public boolean writeUI8(int val) throws IOException; + + public void write(int val) throws IOException; + + public void writeBytes(byte[] data) throws IOException; + + public boolean writeFloat(float val) throws IOException; + + public void seek(long pos, SeekMode mode) throws IOException; + + public byte[] getAllBytes() throws IOException; + + @Override + public void close(); + + public void setIndexing(IggyIndexBuilder indexing); + + public IggyIndexBuilder getIndexing(); +} diff --git a/src/com/jpexs/decompiler/flash/gui/Main.java b/src/com/jpexs/decompiler/flash/gui/Main.java index 7de2c785b..472ed8156 100644 --- a/src/com/jpexs/decompiler/flash/gui/Main.java +++ b/src/com/jpexs/decompiler/flash/gui/Main.java @@ -1,2391 +1,2391 @@ -/* - * Copyright (C) 2010-2016 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; - -import com.jpexs.debugger.flash.Debugger; -import com.jpexs.debugger.flash.DebuggerCommands; -import com.jpexs.debugger.flash.Variable; -import com.jpexs.debugger.flash.VariableType; -import com.jpexs.debugger.flash.messages.in.InCallFunction; -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.SwfOpenException; -import com.jpexs.decompiler.flash.UrlResolver; -import com.jpexs.decompiler.flash.Version; -import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; -import com.jpexs.decompiler.flash.abc.avm2.parser.script.Reference; -import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.decompiler.flash.configuration.SwfSpecificConfiguration; -import com.jpexs.decompiler.flash.console.CommandLineArgumentParser; -import com.jpexs.decompiler.flash.console.ContextMenuTools; -import com.jpexs.decompiler.flash.exporters.modes.ExeExportMode; -import com.jpexs.decompiler.flash.gui.debugger.DebugListener; -import com.jpexs.decompiler.flash.gui.debugger.DebuggerTools; -import com.jpexs.decompiler.flash.gui.pipes.FirstInstance; -import com.jpexs.decompiler.flash.gui.proxy.ProxyFrame; -import com.jpexs.decompiler.flash.helpers.SWFDecompilerPlugin; -import com.jpexs.decompiler.flash.tags.Tag; -import com.jpexs.decompiler.flash.tags.base.FontTag; -import com.jpexs.decompiler.flash.tags.base.ImportTag; -import com.jpexs.decompiler.flash.treeitems.SWFList; -import com.jpexs.helpers.Cache; -import com.jpexs.helpers.CancellableWorker; -import com.jpexs.helpers.Helper; -import com.jpexs.helpers.Path; -import com.jpexs.helpers.ProgressListener; -import com.jpexs.helpers.Stopwatch; -import com.jpexs.helpers.streams.SeekableInputStream; -import com.sun.jna.Platform; -import com.sun.jna.platform.win32.Advapi32Util; -import com.sun.jna.platform.win32.Kernel32; -import com.sun.jna.platform.win32.WinReg; -import java.awt.AWTException; -import java.awt.Frame; -import java.awt.GraphicsEnvironment; -import java.awt.MenuItem; -import java.awt.PopupMenu; -import java.awt.SystemTray; -import java.awt.TrayIcon; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.FilenameFilter; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.lang.reflect.Field; -import java.net.InetSocketAddress; -import java.net.Proxy; -import java.net.URL; -import java.net.URLConnection; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Date; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Objects; -import java.util.Set; -import java.util.concurrent.CancellationException; -import java.util.concurrent.ExecutionException; -import java.util.logging.ConsoleHandler; -import java.util.logging.FileHandler; -import java.util.logging.Formatter; -import java.util.logging.Handler; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.logging.SimpleFormatter; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import javax.swing.JFileChooser; -import javax.swing.JFrame; -import javax.swing.JOptionPane; -import javax.swing.SwingWorker; -import javax.swing.UIManager; -import javax.swing.UnsupportedLookAndFeelException; -import javax.swing.filechooser.FileFilter; -import org.pushingpixels.substance.api.SubstanceLookAndFeel; - -/** - * Main executable class - * - * @author JPEXS - */ -public class Main { - - protected static ProxyFrame proxyFrame; - - private static List sourceInfos = new ArrayList<>(); - - public static LoadingDialog loadingDialog; - - private static boolean working = false; - - private static TrayIcon trayIcon; - - private static MenuItem stopMenuItem; - - private static volatile MainFrame mainFrame; - - public static final int UPDATE_SYSTEM_MAJOR = 1; - - public static final int UPDATE_SYSTEM_MINOR = 3; - - private static LoadFromMemoryFrame loadFromMemoryFrame; - - private static LoadFromCacheFrame loadFromCacheFrame; - - private static final Logger logger = Logger.getLogger(Main.class.getName()); - - public static DebugLogDialog debugDialog; - - public static boolean shouldCloseWhenClosingLoadingDialog; - - private static Debugger flashDebugger; - - private static DebuggerHandler debugHandler = null; - - //private static int ip = 0; - //private static String ipClass = null; - private static Process runProcess; - - private static boolean runProcessDebug; - - private static boolean runProcessDebugPCode; - - private static boolean inited = false; - - private static File runTempFile; - - private static List runTempFiles = new ArrayList<>(); - - public static void freeRun() { - synchronized (Main.class) { - if (runTempFile != null) { - runTempFile.delete(); - runTempFile = null; - } - for (File f : runTempFiles) { - f.delete(); - } - runTempFiles.clear(); - - runProcess = null; - } - if (mainFrame != null && mainFrame.getPanel() != null) { - mainFrame.getPanel().clearDebuggerColors(); - } - if (runProcessDebug) { - Main.getDebugHandler().disconnect(); - } - } - - public static synchronized boolean isDebugPaused() { - return runProcess != null && runProcessDebug && getDebugHandler().isPaused(); - } - - public static synchronized boolean isDebugRunning() { - return runProcess != null && runProcessDebug; - } - - public static synchronized boolean isDebugPCode() { - return runProcessDebugPCode; - } - - public static synchronized boolean isDebugConnected() { - return getDebugHandler().isConnected(); - } - - public static synchronized boolean isRunning() { - return runProcess != null && !runProcessDebug; - } - - /** - * FIXME! - * - * @param v - */ - public static synchronized void dumpBytes(Variable v) { - InCallFunction icf; - try { - long objectId = 0l; - if ((v.vType == VariableType.OBJECT || v.vType == VariableType.MOVIECLIP)) { - objectId = (Long) v.value; - } - Object oldPos = getDebugHandler().getVariable(objectId, "position", true).parent.value; - getDebugHandler().setVariable(objectId, "position", VariableType.NUMBER, 0); - icf = getDebugHandler().callFunction(false, "readUTF", v, new ArrayList<>()); - System.out.println("Result=" + icf.variables.get(0).value); - getDebugHandler().setVariable(objectId, "position", VariableType.NUMBER, oldPos); - } catch (DebuggerHandler.ActionScriptException ex) { - Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); - } - - } - - public static synchronized boolean addWatch(Variable v, long v_id, boolean watchRead, boolean watchWrite) { - DebuggerCommands.Watch w = getDebugHandler().addWatch(v, v_id, watchRead, watchWrite); - return w != null; - } - - public static void runPlayer(String title, final String exePath, String file, String flashVars) { - if (!new File(file).exists()) { - return; - } - if (flashVars != null && !flashVars.isEmpty()) { - file += "?" + flashVars; - } - final String ffile = file; - - CancellableWorker runWorker = new CancellableWorker() { - @Override - protected Object doInBackground() throws Exception { - Process proc; - try { - proc = Runtime.getRuntime().exec(new String[]{exePath, ffile}); - } catch (IOException ex) { - logger.log(Level.SEVERE, null, ex); - return null; - } - boolean isDebug; - - synchronized (Main.class) { - runProcess = proc; - isDebug = runProcessDebug; - } - if (isDebug) { - mainFrame.getMenu().hilightPath("/debugging"); - } - mainFrame.getMenu().updateComponents(); - try { - if (proc != null) { - proc.waitFor(); - } - } catch (InterruptedException ex) { - if (proc != null) { - try { - proc.destroy(); - } catch (Exception ex2) { - //ignore - } - } - } - freeRun(); - stopDebugger(); - mainFrame.getMenu().updateComponents(); - return null; - } - - @Override - protected void done() { - Main.stopWork(); - } - - @Override - public void workerCancelled() { - Main.stopWork(); - synchronized (Main.class) { - if (runProcess != null) { - try { - runProcess.destroy(); - } catch (Exception ex) { - - } - } - } - freeRun(); - mainFrame.getMenu().updateComponents(); - } - }; - - mainFrame.getMenu().updateComponents(); - Main.startWork(title + "...", runWorker); - runWorker.execute(); - } - - public static void stopRun() { - - synchronized (Main.class) { - if (runProcess != null) { - runProcess.destroy(); - } - } - freeRun(); - stopDebugger(); - mainFrame.getMenu().updateComponents(); - } - - private static interface SwfPreparation { - - public SWF prepare(SWF swf); - } - - private static class SwfRunPrepare implements SwfPreparation { - - @Override - public SWF prepare(SWF swf) { - if (Configuration.autoOpenLoadedSWFs.get()) { - if (!DebuggerTools.hasDebugger(swf)) { - DebuggerTools.switchDebugger(swf); - } - DebuggerTools.injectDebugLoader(swf); - } - return swf; - } - } - - private static class SwfDebugPrepare extends SwfRunPrepare { - - private boolean doPCode; - - public SwfDebugPrepare(boolean doPCode) { - this.doPCode = doPCode; - } - - @Override - public SWF prepare(SWF instrSWF) { - instrSWF = super.prepare(instrSWF); - try { - File fTempFile = new File(instrSWF.getFile()); - instrSWF.enableDebugging(true, new File("."), true, doPCode); - FileOutputStream fos = new FileOutputStream(fTempFile); - instrSWF.saveTo(fos); - fos.close(); - if (!instrSWF.isAS3()) { - //Read again, because line file offsets changed with adding debug tags - //TODO: handle somehow without rereading? - instrSWF = null; - try (FileInputStream fis = new FileInputStream(fTempFile)) { - instrSWF = new SWF(fis, false, false); - } catch (InterruptedException ex) { - logger.log(Level.SEVERE, null, ex); - } - if (instrSWF != null) { - String swfFileName = fTempFile.getAbsolutePath(); - if (swfFileName.toLowerCase().endsWith(".swf")) { - swfFileName = swfFileName.substring(0, swfFileName.length() - 4) + ".swd"; - } else { - swfFileName = swfFileName + ".swd"; - } - File swdFile = new File(swfFileName); - if (doPCode) { - instrSWF.generatePCodeSwdFile(swdFile, getPackBreakPoints(true)); - } else { - instrSWF.generateSwdFile(swdFile, getPackBreakPoints(true)); - } - } - } - } catch (IOException ex) { - //ignore, return instrSWF - } - return instrSWF; - } - } - - private static void prepareSwf(SwfPreparation prep, File toPrepareFile, File origFile, List tempFiles) throws IOException { - SWF instrSWF = null; - try (FileInputStream fis = new FileInputStream(toPrepareFile)) { - instrSWF = new SWF(fis, toPrepareFile.getAbsolutePath(), origFile.getName(), false); - } catch (InterruptedException ex) { - logger.log(Level.SEVERE, null, ex); - } - if (instrSWF != null) { - for (Tag t : instrSWF.getLocalTags()) { - if (t instanceof ImportTag) { - ImportTag it = (ImportTag) t; - String url = it.getUrl(); - File importedFile = new File(origFile.getParentFile(), url); - if (importedFile.exists()) { - File newTempFile = File.createTempFile("ffdec_run_import_", ".swf"); - it.setUrl("./" + newTempFile.getName()); - byte[] impData = Helper.readFile(importedFile.getAbsolutePath()); - Helper.writeFile(newTempFile.getAbsolutePath(), impData); - tempFiles.add(newTempFile); - prepareSwf(prep, newTempFile, importedFile, tempFiles); - } - } - } - if (prep != null) { - instrSWF = prep.prepare(instrSWF); - } - try (FileOutputStream fos = new FileOutputStream(toPrepareFile)) { - instrSWF.saveTo(fos); - } - } - } - - public static void run(SWF swf) { - String flashVars = "";//key=val&key2=val2 - String playerLocation = Configuration.playerLocation.get(); - if (playerLocation.isEmpty() || (!new File(playerLocation).exists())) { - View.showMessageDialog(null, AppStrings.translate("message.playerpath.notset"), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE); - advancedSettings("paths"); - return; - } - if (swf == null) { - return; - } - File tempFile; - List tempFiles = new ArrayList<>(); - try { - tempFile = File.createTempFile("ffdec_run_", ".swf"); - - try (FileOutputStream fos = new FileOutputStream(tempFile)) { - swf.saveTo(fos); - } - - prepareSwf(new SwfRunPrepare(), tempFile, new File(swf.getFile()), tempFiles); - - } catch (IOException ex) { - return; - - } - if (tempFile != null) { - synchronized (Main.class) { - runTempFile = tempFile; - runTempFiles = tempFiles; - runProcessDebug = false; - } - runPlayer(AppStrings.translate("work.running"), playerLocation, tempFile.getAbsolutePath(), flashVars); - } - } - - public static void runDebug(SWF swf, final boolean doPCode) { - String flashVars = "";//key=val&key2=val2 - String playerLocation = Configuration.playerDebugLocation.get(); - if (playerLocation.isEmpty() || (!new File(playerLocation).exists())) { - View.showMessageDialog(null, AppStrings.translate("message.playerpath.debug.notset"), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE); - Main.advancedSettings("paths"); - return; - } - if (swf == null) { - return; - } - File tempFile = null; - - try { - tempFile = File.createTempFile("ffdec_debug_", ".swf"); - } catch (Exception ex) { - - } - - if (tempFile != null) { - final File fTempFile = tempFile; - final List tempFiles = new ArrayList<>(); - CancellableWorker instrumentWorker = new CancellableWorker() { - @Override - protected Object doInBackground() throws Exception { - - try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(fTempFile))) { - swf.saveTo(fos); - } - prepareSwf(new SwfDebugPrepare(doPCode), fTempFile, new File(swf.getFile()), tempFiles); - return null; - } - - @Override - public void workerCancelled() { - Main.stopWork(); - } - - @Override - protected void done() { - synchronized (Main.class) { - runTempFile = fTempFile; - runProcessDebug = true; - runProcessDebugPCode = doPCode; - runTempFiles = tempFiles; - } - Main.stopWork(); - Main.startDebugger(); - runPlayer(AppStrings.translate("work.debugging.wait"), playerLocation, fTempFile.getAbsolutePath(), flashVars); - } - }; - - Main.startWork(AppStrings.translate("work.debugging.instrumenting"), instrumentWorker); - instrumentWorker.execute(); - } - } - - /* public static void debuggerNotSuspended() { - - }*/ - public static boolean isDebugging() { - return isDebugRunning(); - } - - public synchronized static int getIp(Object pack) { - return getDebugHandler().getBreakIp(); - } - - public synchronized static String getIpClass() { - return getDebugHandler().getBreakScriptName(); - } - - public static synchronized boolean isBreakPointValid(String scriptName, int line) { - return !getDebugHandler().isBreakpointInvalid(scriptName, line); - } - - public synchronized static void addBreakPoint(String scriptName, int line) { - getDebugHandler().addBreakPoint(scriptName, line); - } - - public synchronized static void removeBreakPoint(String scriptName, int line) { - getDebugHandler().removeBreakPoint(scriptName, line); - } - - public synchronized static boolean toggleBreakPoint(String scriptName, int line) { - if (getDebugHandler().isBreakpointToAdd(scriptName, line) || getDebugHandler().isBreakpointConfirmed(scriptName, line) || getDebugHandler().isBreakpointInvalid(scriptName, line)) { - getDebugHandler().removeBreakPoint(scriptName, line); - return false; - } else { - getDebugHandler().addBreakPoint(scriptName, line); - return true; - } - } - - public synchronized static Map> getPackBreakPoints(boolean validOnly) { - return getDebugHandler().getAllBreakPoints(validOnly); - } - - public synchronized static Set getScriptBreakPoints(String pack, boolean onlyValid) { - return getDebugHandler().getBreakPoints(pack, onlyValid); - } - - public static DebuggerHandler getDebugHandler() { - return debugHandler; - } - - public static void ensureMainFrame() { - if (mainFrame == null) { - synchronized (Main.class) { - if (mainFrame == null) { - MainFrame frame; - if (Configuration.useRibbonInterface.get()) { - frame = new MainFrameRibbon(); - } else { - frame = new MainFrameClassic(); - } - frame.getPanel().setErrorState(ErrorLogFrame.getInstance().getErrorState()); - mainFrame = frame; - } - } - } - } - - public static MainFrame getMainFrame() { - return mainFrame; - } - - public static void loadFromCache() { - if (loadFromCacheFrame == null) { - loadFromCacheFrame = new LoadFromCacheFrame(); - } - loadFromCacheFrame.setVisible(true); - } - - public static void loadFromMemory() { - if (loadFromMemoryFrame == null) { - loadFromMemoryFrame = new LoadFromMemoryFrame(mainFrame); - } - loadFromMemoryFrame.setVisible(true); - } - - public static void setVariable(long parentId, String varName, int valueType, Object value) { - getDebugHandler().setVariable(parentId, varName, valueType, value); - } - - public static void setSubLimiter(boolean value) { - if (value) { - AVM2Code.toSourceLimit = Configuration.sublimiter.get(); - } else { - AVM2Code.toSourceLimit = -1; - } - } - - public synchronized static boolean isInited() { - return inited; - } - - public synchronized static void setSessionLoaded(boolean v) { - inited = v; - } - - public static boolean isWorking() { - return working; - } - - public static void startProxy(int port) { - if (proxyFrame == null) { - proxyFrame = new ProxyFrame(mainFrame); - } - - proxyFrame.setPort(port); - addTrayIcon(); - switchProxy(); - } - - public static void showProxy() { - if (proxyFrame == null) { - proxyFrame = new ProxyFrame(mainFrame); - } - proxyFrame.setVisible(true); - proxyFrame.setState(Frame.NORMAL); - } - - public static void startWork(String name, CancellableWorker worker) { - startWork(name, -1, worker); - } - - public static void startWork(final String name, final int percent, final CancellableWorker worker) { - working = true; - View.execInEventDispatchLater(() -> { - if (mainFrame != null) { - mainFrame.getPanel().setWorkStatus(name, worker); - if (percent == -1) { - mainFrame.getPanel().hidePercent(); - } else { - mainFrame.getPanel().setPercent(percent); - } - } - if (loadingDialog != null) { - loadingDialog.setDetail(name); - loadingDialog.setPercent(percent); - } - if (CommandLineArgumentParser.isCommandLineMode()) { - System.out.println(name); - } - }); - } - - public static void stopWork() { - working = false; - View.execInEventDispatchLater(() -> { - if (mainFrame != null) { - mainFrame.getPanel().setWorkStatus("", null); - } - if (loadingDialog != null) { - loadingDialog.setDetail(""); - } - }); - } - - public static SWFList parseSWF(SWFSourceInfo sourceInfo) throws Exception { - SWFList result = new SWFList(); - - InputStream inputStream = sourceInfo.getInputStream(); - SWFBundle bundle = null; - FileInputStream fis = null; - if (inputStream == null) { - inputStream = new BufferedInputStream(fis = new FileInputStream(sourceInfo.getFile())); - bundle = sourceInfo.getBundle(false, SearchMode.ALL); - logger.log(Level.INFO, "Load file: {0}", sourceInfo.getFile()); - } else if (inputStream instanceof SeekableInputStream - || inputStream instanceof BufferedInputStream) { - try { - inputStream.reset(); - } catch (IOException ex) { - logger.log(Level.SEVERE, null, ex); - } - logger.log(Level.INFO, "Load stream: {0}", sourceInfo.getFileTitle()); - } - - Stopwatch sw = Stopwatch.startNew(); - if (bundle != null) { - result.bundle = bundle; - result.name = new File(sourceInfo.getFileTitleOrName()).getName(); - for (Entry streamEntry : bundle.getAll().entrySet()) { - InputStream stream = streamEntry.getValue(); - stream.reset(); - CancellableWorker worker = new CancellableWorker() { - @Override - public SWF doInBackground() throws Exception { - final CancellableWorker worker = this; - SWF swf = new SWF(stream, null, streamEntry.getKey(), new ProgressListener() { - @Override - public void progress(int p) { - startWork(AppStrings.translate("work.reading.swf"), p, worker); - } - }, Configuration.parallelSpeedUp.get()); - return swf; - } - }; - loadingDialog.setWroker(worker); - worker.execute(); - - try { - result.add(worker.get()); - } catch (CancellationException ex) { - logger.log(Level.WARNING, "Loading SWF {0} was cancelled.", streamEntry.getKey()); - } - } - } else { - InputStream fInputStream = inputStream; - - final String[] yesno = new String[]{AppStrings.translate("button.yes"), AppStrings.translate("button.no"), AppStrings.translate("button.yes.all"), AppStrings.translate("button.no.all")}; - - CancellableWorker worker = new CancellableWorker() { - private boolean yestoall = false; - - private boolean notoall = false; - - private SWF open(InputStream is, String file, String fileTitle) throws IOException, InterruptedException { - final CancellableWorker worker = this; - - SWF swf = new SWF(is, file, fileTitle, new ProgressListener() { - @Override - public void progress(int p) { - startWork(AppStrings.translate("work.reading.swf"), p, worker); - } - }, Configuration.parallelSpeedUp.get(), false, true, new UrlResolver() { - @Override - public SWF resolveUrl(final String url) { - int opt = -1; - if (!(yestoall || notoall)) { - opt = View.showOptionDialog(null, AppStrings.translate("message.imported.swf").replace("%url%", url), AppStrings.translate("message.warning"), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, yesno, AppStrings.translate("button.yes")); - if (opt == 2) { - yestoall = true; - } - if (opt == 3) { - notoall = true; - } - } - - if (yestoall) { - opt = 0; // yes - } else if (notoall) { - opt = 1; // no - } - - if (opt == 1) //no - { - return null; - } - - if (url.startsWith("http://") || url.startsWith("https://")) { - try { - URL u = new URL(url); - return open(u.openStream(), null, url); //? - } catch (Exception ex) { - //ignore - } - } else { - File f = new File(new File(file).getParentFile(), url); - if (f.exists()) { - try { - return open(new FileInputStream(f), f.getAbsolutePath(), f.getName()); - } catch (Exception ex) { - //ignore - } - } - } - Reference ret = new Reference<>(null); - View.execInEventDispatch(new Runnable() { - @Override - public void run() { - - while (JOptionPane.YES_OPTION == View.showConfirmDialog(null, AppStrings.translate("message.imported.swf.manually").replace("%url%", url), AppStrings.translate("error"), JOptionPane.YES_NO_OPTION, JOptionPane.ERROR_MESSAGE)) { - - JFileChooser fc = new JFileChooser(); - fc.setCurrentDirectory(new File(Configuration.lastOpenDir.get())); - FileFilter allSupportedFilter = new FileFilter() { - private final String[] supportedExtensions = new String[]{".swf", ".gfx"}; - - @Override - public boolean accept(File f) { - String name = f.getName().toLowerCase(); - for (String ext : supportedExtensions) { - if (name.endsWith(ext)) { - return true; - } - } - return f.isDirectory(); - } - - @Override - public String getDescription() { - String exts = Helper.joinStrings(supportedExtensions, "*%s", "; "); - return AppStrings.translate("filter.supported") + " (" + exts + ")"; - } - }; - fc.setFileFilter(allSupportedFilter); - FileFilter swfFilter = new FileFilter() { - @Override - public boolean accept(File f) { - return (f.getName().toLowerCase().endsWith(".swf")) || (f.isDirectory()); - } - - @Override - public String getDescription() { - return AppStrings.translate("filter.swf"); - } - }; - fc.addChoosableFileFilter(swfFilter); - - FileFilter gfxFilter = new FileFilter() { - @Override - public boolean accept(File f) { - return (f.getName().toLowerCase().endsWith(".gfx")) || (f.isDirectory()); - } - - @Override - public String getDescription() { - return AppStrings.translate("filter.gfx"); - } - }; - fc.addChoosableFileFilter(gfxFilter); - fc.setAcceptAllFileFilterUsed(false); - JFrame f = new JFrame(); - View.setWindowIcon(f); - int returnVal = fc.showOpenDialog(f); - if (returnVal == JFileChooser.APPROVE_OPTION) { - Configuration.lastOpenDir.set(Helper.fixDialogFile(fc.getSelectedFile()).getParentFile().getAbsolutePath()); - File selFile = Helper.fixDialogFile(fc.getSelectedFile()); - try { - ret.setVal(open(new FileInputStream(selFile), selFile.getAbsolutePath(), selFile.getName())); - break; - } catch (Exception ex) { - //ignore; - } - } else { - break; - } - } - } - }); - return ret.getVal(); - } - }); - return swf; - } - - @Override - public SWF doInBackground() throws Exception { - return open(fInputStream, sourceInfo.getFile(), sourceInfo.getFileTitle()); - } - }; - if (loadingDialog != null) { - loadingDialog.setWroker(worker); - } - worker.execute(); - - try { - result.add(worker.get()); - } catch (CancellationException ex) { - logger.log(Level.WARNING, "Loading SWF {0} was cancelled.", sourceInfo.getFileTitleOrName()); - } - } - - if (fis != null) { - logger.log(Level.INFO, "File loaded in {0} seconds.", (sw.getElapsedMilliseconds() / 1000)); - fis.close(); - } else { - logger.log(Level.INFO, "Stream loaded in {0} seconds.", (sw.getElapsedMilliseconds() / 1000)); - } - - result.sourceInfo = sourceInfo; - for (SWF swf : result) { - logger.log(Level.INFO, ""); - logger.log(Level.INFO, "== File information =="); - logger.log(Level.INFO, "Size: {0}", Helper.formatFileSize(swf.fileSize)); - logger.log(Level.INFO, "Flash version: {0}", swf.version); - int width = (int) ((swf.displayRect.Xmax - swf.displayRect.Xmin) / SWF.unitDivisor); - int height = (int) ((swf.displayRect.Ymax - swf.displayRect.Ymin) / SWF.unitDivisor); - logger.log(Level.INFO, "Width: {0}", width); - logger.log(Level.INFO, "Height: {0}", height); - - swf.swfList = result; - swf.addEventListener(new EventListener() { - @Override - public void handleExportingEvent(String type, int index, int count, Object data) { - String text = AppStrings.translate("work.exporting"); - if (type != null && type.length() > 0) { - text += " " + type; - } - - startWork(text + " " + index + "/" + count + " " + data, null); - } - - @Override - public void handleExportedEvent(String type, int index, int count, Object data) { - String text = AppStrings.translate("work.exported"); - if (type != null && type.length() > 0) { - text += " " + type; - } - - startWork(text + " " + index + "/" + count + " " + data, null); - } - - @Override - public void handleEvent(String event, Object data) { - if (event.equals("exporting") || event.equals("exported")) { - throw new Error("Event is not supported by this handler."); - } - if (event.equals("getVariables")) { - startWork(AppStrings.translate("work.gettingvariables") + "..." + (String) data, null); - } - if (event.equals("deobfuscate")) { - startWork(AppStrings.translate("work.deobfuscating") + "..." + (String) data, null); - } - if (event.equals("rename")) { - startWork(AppStrings.translate("work.renaming") + "..." + (String) data, null); - } - } - }); - } - - return result; - } - - public static void saveFile(SWF swf, String outfile) throws IOException { - saveFile(swf, outfile, SaveFileMode.SAVE, null); - } - - public static void saveFile(SWF swf, String outfile, SaveFileMode mode, ExeExportMode exeExportMode) throws IOException { - if (mode == SaveFileMode.SAVEAS && !swf.swfList.isBundle()) { - swf.setFile(outfile); - swf.swfList.sourceInfo.setFile(outfile); - } - File outfileF = new File(outfile); - File tmpFile = new File(outfile + ".tmp"); - try (FileOutputStream fos = new FileOutputStream(tmpFile); - BufferedOutputStream bos = new BufferedOutputStream(fos)) { - if (mode == SaveFileMode.EXE) { - switch (exeExportMode) { - case WRAPPER: - InputStream exeStream = View.class.getClassLoader().getResourceAsStream("com/jpexs/helpers/resource/Swf2Exe.bin"); - Helper.copyStream(exeStream, bos); - int width = swf.displayRect.Xmax - swf.displayRect.Xmin; - int height = swf.displayRect.Ymax - swf.displayRect.Ymin; - bos.write(width & 0xff); - bos.write((width >> 8) & 0xff); - bos.write((width >> 16) & 0xff); - bos.write((width >> 24) & 0xff); - bos.write(height & 0xff); - bos.write((height >> 8) & 0xff); - bos.write((height >> 16) & 0xff); - bos.write((height >> 24) & 0xff); - bos.write(Configuration.saveAsExeScaleMode.get()); - break; - case PROJECTOR_WIN: - case PROJECTOR_MAC: - case PROJECTOR_LINUX: - File projectorFile = Configuration.getProjectorFile(exeExportMode); - if (projectorFile == null) { - String message = "Projector not found, please place it to " + Configuration.getProjectorPath(); - logger.log(Level.SEVERE, message); - throw new IOException(message); - } - Helper.copyStream(new FileInputStream(projectorFile), bos); - bos.flush(); - break; - } - } - - long pos = fos.getChannel().position(); - swf.saveTo(bos); - - if (mode == SaveFileMode.EXE) { - switch (exeExportMode) { - case PROJECTOR_WIN: - case PROJECTOR_MAC: - case PROJECTOR_LINUX: - bos.flush(); - int swfSize = (int) (fos.getChannel().position() - pos); - - // write magic number - bos.write(0x56); - bos.write(0x34); - bos.write(0x12); - bos.write(0xfa); - - bos.write(swfSize & 0xff); - bos.write((swfSize >> 8) & 0xff); - bos.write((swfSize >> 16) & 0xff); - bos.write((swfSize >> 24) & 0xff); - } - } - } - if (tmpFile.exists()) { - if (tmpFile.length() > 0) { - outfileF.delete(); - if (!tmpFile.renameTo(outfileF)) { - tmpFile.delete(); - throw new IOException("Cannot access " + outfile); - } - } else { - throw new IOException("Output is empty"); - } - } else { - throw new IOException("Output not found"); - } - } - - private static class OpenFileWorker extends SwingWorker { - - private final SWFSourceInfo[] sourceInfos; - - private final Runnable executeAfterOpen; - - private final int[] reloadIndices; - - public OpenFileWorker(SWFSourceInfo sourceInfo) { - this(sourceInfo, -1); - } - - public OpenFileWorker(SWFSourceInfo sourceInfo, int reloadIndex) { - this(sourceInfo, null, reloadIndex); - } - - public OpenFileWorker(SWFSourceInfo sourceInfo, Runnable executeAfterOpen) { - this(sourceInfo, executeAfterOpen, -1); - } - - public OpenFileWorker(SWFSourceInfo sourceInfo, Runnable executeAfterOpen, int reloadIndex) { - this.sourceInfos = new SWFSourceInfo[]{sourceInfo}; - this.executeAfterOpen = executeAfterOpen; - this.reloadIndices = new int[]{reloadIndex}; - } - - public OpenFileWorker(SWFSourceInfo[] sourceInfos) { - this(sourceInfos, null, null); - } - - public OpenFileWorker(SWFSourceInfo[] sourceInfos, Runnable executeAfterOpen) { - this(sourceInfos, executeAfterOpen, null); - } - - public OpenFileWorker(SWFSourceInfo[] sourceInfos, Runnable executeAfterOpen, int[] reloadIndices) { - this.sourceInfos = sourceInfos; - this.executeAfterOpen = executeAfterOpen; - int[] indices = new int[sourceInfos.length]; - for (int i = 0; i < indices.length; i++) { - indices[i] = -1; - } - this.reloadIndices = reloadIndices == null ? indices : reloadIndices; - } - - @Override - protected Object doInBackground() throws Exception { - boolean first = true; - SWF firstSWF = null; - for (int index = 0; index < sourceInfos.length; index++) { - SWFSourceInfo sourceInfo = sourceInfos[index]; - SWFList swfs = null; - try { - Main.startWork(AppStrings.translate("work.reading.swf") + "...", null); - try { - swfs = parseSWF(sourceInfo); - } catch (ExecutionException ex) { - Throwable cause = ex.getCause(); - if (cause instanceof SwfOpenException) { - throw (SwfOpenException) cause; - } - - throw ex; - } - } catch (OutOfMemoryError ex) { - logger.log(Level.SEVERE, null, ex); - View.showMessageDialog(null, "Cannot load SWF file. Out of memory."); - continue; - } catch (SwfOpenException ex) { - logger.log(Level.SEVERE, null, ex); - View.showMessageDialog(null, ex.getMessage()); - continue; - } catch (Exception ex) { - logger.log(Level.SEVERE, null, ex); - View.showMessageDialog(null, "Cannot load SWF file."); - continue; - } - - final SWFList swfs1 = swfs; - final boolean first1 = first; - first = false; - if (firstSWF == null && swfs1.size() > 0) { - firstSWF = swfs1.get(0); - } - - final int findex = index; - try { - View.execInEventDispatch(() -> { - Main.startWork(AppStrings.translate("work.creatingwindow") + "...", null); - ensureMainFrame(); - if (reloadIndices[findex] > -1) { - mainFrame.getPanel().loadSwfAtPos(swfs1, reloadIndices[findex]); - } else { - mainFrame.getPanel().load(swfs1, first1); - } - }); - } catch (Exception ex) { - logger.log(Level.SEVERE, null, ex); - } - } - - loadingDialog.setVisible(false); - shouldCloseWhenClosingLoadingDialog = false; - - final SWF fswf = firstSWF; - View.execInEventDispatch(() -> { - if (mainFrame != null) { - mainFrame.setVisible(true); - } - - Main.stopWork(); - - if (mainFrame != null && Configuration.gotoMainClassOnStartup.get()) { - mainFrame.getPanel().gotoDocumentClass(fswf); - } - - if (mainFrame != null && fswf != null) { - SwfSpecificConfiguration swfConf = Configuration.getSwfSpecificConfiguration(fswf.getShortFileName()); - if (swfConf != null) { - String pathStr = swfConf.lastSelectedPath; - mainFrame.getPanel().tagTree.setSelectionPathString(pathStr); - } - } - - if (executeAfterOpen != null) { - executeAfterOpen.run(); - } - }); - - return true; - } - } - - public static boolean reloadSWFs() { - CancellableWorker.cancelBackgroundThreads(); - if (Main.sourceInfos.isEmpty()) { - Helper.freeMem(); - showModeFrame(); - return true; - } else { - SWFSourceInfo[] sourceInfosCopy = new SWFSourceInfo[sourceInfos.size()]; - sourceInfos.toArray(sourceInfosCopy); - sourceInfos.clear(); - openFile(sourceInfosCopy); - return true; - } - } - - public static void reloadApp() { - if (debugDialog != null) { - debugDialog.setVisible(false); - debugDialog.dispose(); - debugDialog = null; - } - if (loadingDialog != null) { - synchronized (Main.class) { - if (loadingDialog != null) { - loadingDialog.setVisible(false); - loadingDialog.dispose(); - loadingDialog = null; - } - } - } - if (proxyFrame != null) { - proxyFrame.setVisible(false); - proxyFrame.dispose(); - proxyFrame = null; - } - if (loadFromMemoryFrame != null) { - loadFromMemoryFrame.setVisible(false); - loadFromMemoryFrame.dispose(); - loadFromMemoryFrame = null; - } - if (loadFromCacheFrame != null) { - loadFromCacheFrame.setVisible(false); - loadFromCacheFrame.dispose(); - loadFromCacheFrame = null; - } - if (mainFrame != null) { - mainFrame.setVisible(false); - mainFrame.getPanel().closeAll(false); - mainFrame.dispose(); - mainFrame = null; - } - FontTag.reload(); - Cache.clearAll(); - initGui(); - reloadSWFs(); - } - - public static OpenFileResult openFile(String swfFile, String fileTitle) { - return openFile(swfFile, fileTitle, null); - } - - public static OpenFileResult openFile(String swfFile, String fileTitle, Runnable executeAfterOpen) { - try { - File file = new File(swfFile); - if (!file.exists()) { - View.showMessageDialog(null, AppStrings.translate("open.error.fileNotFound"), AppStrings.translate("open.error"), JOptionPane.ERROR_MESSAGE); - return OpenFileResult.NOT_FOUND; - } - swfFile = file.getCanonicalPath(); - SWFSourceInfo sourceInfo = new SWFSourceInfo(null, swfFile, fileTitle); - OpenFileResult openResult = openFile(sourceInfo); - return openResult; - } catch (IOException ex) { - View.showMessageDialog(null, AppStrings.translate("open.error.cannotOpen"), AppStrings.translate("open.error"), JOptionPane.ERROR_MESSAGE); - return OpenFileResult.ERROR; - } - } - - public static OpenFileResult openFile(SWFSourceInfo sourceInfo) { - return openFile(new SWFSourceInfo[]{sourceInfo}); - } - - public static OpenFileResult openFile(SWFSourceInfo sourceInfo, Runnable executeAfterOpen) { - return openFile(new SWFSourceInfo[]{sourceInfo}, executeAfterOpen); - } - - public static OpenFileResult openFile(SWFSourceInfo sourceInfo, Runnable executeAfterOpen, int reloadIndex) { - return openFile(new SWFSourceInfo[]{sourceInfo}, executeAfterOpen, new int[]{reloadIndex}); - } - - public static OpenFileResult openFile(SWFSourceInfo[] newSourceInfos) { - return openFile(newSourceInfos, null); - } - - public static OpenFileResult openFile(SWFSourceInfo[] newSourceInfos, Runnable executeAfterOpen) { - return openFile(newSourceInfos, executeAfterOpen, null); - } - - public static OpenFileResult openFile(SWFSourceInfo[] newSourceInfos, Runnable executeAfterOpen, int[] reloadIndices) { - if (mainFrame != null && !Configuration.openMultipleFiles.get()) { - sourceInfos.clear(); - mainFrame.getPanel().closeAll(false); - mainFrame.setVisible(false); - Helper.freeMem(); - reloadIndices = null; - } - - loadingDialog.setVisible(true); - - for (int i = 0; i < newSourceInfos.length; i++) { - SWFSourceInfo si = newSourceInfos[i]; - String fileName = si.getFile(); - if (fileName != null) { - Configuration.addRecentFile(fileName); - } - } - - OpenFileWorker wrk = new OpenFileWorker(newSourceInfos, executeAfterOpen, reloadIndices); - wrk.execute(); - if (reloadIndices == null) { - sourceInfos.addAll(Arrays.asList(newSourceInfos)); - } else { - for (int i = 0; i < reloadIndices.length; i++) { - sourceInfos.set(reloadIndices[i], newSourceInfos[i]); - } - } - return OpenFileResult.OK; - } - - public static void closeFile(SWFList swf) { - sourceInfos.remove(swf.sourceInfo); - mainFrame.getPanel().close(swf); - } - - public static void reloadFile(SWFList swf) { - //mainFrame.getPanel().close(swf); - openFile(swf.sourceInfo, null, sourceInfos.indexOf(swf.sourceInfo)); - } - - public static boolean closeAll() { - boolean closeResult = mainFrame.getPanel().closeAll(true); - if (closeResult) { - sourceInfos.clear(); - } - - return closeResult; - } - - public static boolean saveFileDialog(SWF swf, final SaveFileMode mode) { - JFileChooser fc = new JFileChooser(); - fc.setCurrentDirectory(new File(Configuration.lastSaveDir.get())); - String ext = ".swf"; - switch (mode) { - case SAVE: - case SAVEAS: - if (swf.getFile() != null) { - ext = Path.getExtension(swf.getFile()); - } - break; - case EXE: - ext = ".exe"; - break; - } - - FileFilter swfFilter = new FileFilter() { - @Override - public boolean accept(File f) { - return (f.getName().toLowerCase().endsWith(".swf")) || (f.isDirectory()); - } - - @Override - public String getDescription() { - return AppStrings.translate("filter.swf"); - } - }; - - FileFilter gfxFilter = new FileFilter() { - @Override - public boolean accept(File f) { - return (f.getName().toLowerCase().endsWith(".gfx")) || (f.isDirectory()); - } - - @Override - public String getDescription() { - return AppStrings.translate("filter.gfx"); - } - }; - - ExeExportMode exeExportMode = null; - if (mode == SaveFileMode.EXE) { - exeExportMode = Configuration.exeExportMode.get(); - if (exeExportMode == null) { - exeExportMode = ExeExportMode.WRAPPER; - } - String filterDescription = null; - switch (exeExportMode) { - case WRAPPER: - case PROJECTOR_WIN: - ext = ".exe"; - filterDescription = "filter.exe"; - break; - case PROJECTOR_MAC: - ext = ".dmg"; - filterDescription = "filter.dmg"; - break; - case PROJECTOR_LINUX: - // linux projector is compressed with tar.gz - // todo: decompress - ext = ""; - filterDescription = "filter.linuxExe"; - break; - } - - String fext = ext; - String ffilterDescription = filterDescription; - FileFilter exeFilter = new FileFilter() { - @Override - public boolean accept(File f) { - return (f.getName().toLowerCase().endsWith(fext)) || (f.isDirectory()); - } - - @Override - public String getDescription() { - return AppStrings.translate(ffilterDescription); - } - }; - fc.setFileFilter(exeFilter); - } else if (swf.gfx) { - fc.addChoosableFileFilter(swfFilter); - fc.setFileFilter(gfxFilter); - } else { - fc.setFileFilter(swfFilter); - fc.addChoosableFileFilter(gfxFilter); - } - final String extension = ext; - fc.setAcceptAllFileFilterUsed(false); - JFrame f = new JFrame(); - View.setWindowIcon(f); - if (fc.showSaveDialog(f) == JFileChooser.APPROVE_OPTION) { - File file = Helper.fixDialogFile(fc.getSelectedFile()); - FileFilter selFilter = fc.getFileFilter(); - try { - String fileName = file.getAbsolutePath(); - if (selFilter == swfFilter) { - if (!fileName.toLowerCase().endsWith(extension)) { - fileName += extension; - } - swf.gfx = false; - } - if (selFilter == gfxFilter) { - if (!fileName.toLowerCase().endsWith(".gfx")) { - fileName += ".gfx"; - } - swf.gfx = true; - } - Main.saveFile(swf, fileName, mode, exeExportMode); - Configuration.lastSaveDir.set(file.getParentFile().getAbsolutePath()); - return true; - } catch (IOException ex) { - View.showMessageDialog(null, AppStrings.translate("error.file.write")); - } - } - return false; - } - - public static boolean openFileDialog() { - JFileChooser fc = new JFileChooser(); - if (Configuration.openMultipleFiles.get()) { - fc.setMultiSelectionEnabled(true); - } - fc.setCurrentDirectory(new File(Configuration.lastOpenDir.get())); - FileFilter allSupportedFilter = new FileFilter() { - private final String[] supportedExtensions = new String[]{".swf", ".gfx", ".swc", ".zip", ".iggy"}; - - @Override - public boolean accept(File f) { - String name = f.getName().toLowerCase(); - for (String ext : supportedExtensions) { - if (name.endsWith(ext)) { - return true; - } - } - return f.isDirectory(); - } - - @Override - public String getDescription() { - String exts = Helper.joinStrings(supportedExtensions, "*%s", "; "); - return AppStrings.translate("filter.supported") + " (" + exts + ")"; - } - }; - fc.setFileFilter(allSupportedFilter); - FileFilter swfFilter = new FileFilter() { - @Override - public boolean accept(File f) { - return (f.getName().toLowerCase().endsWith(".swf")) || (f.isDirectory()); - } - - @Override - public String getDescription() { - return AppStrings.translate("filter.swf"); - } - }; - fc.addChoosableFileFilter(swfFilter); - - FileFilter swcFilter = new FileFilter() { - @Override - public boolean accept(File f) { - return (f.getName().toLowerCase().endsWith(".swc")) || (f.isDirectory()); - } - - @Override - public String getDescription() { - return AppStrings.translate("filter.swc"); - } - }; - fc.addChoosableFileFilter(swcFilter); - - FileFilter gfxFilter = new FileFilter() { - @Override - public boolean accept(File f) { - return (f.getName().toLowerCase().endsWith(".gfx")) || (f.isDirectory()); - } - - @Override - public String getDescription() { - return AppStrings.translate("filter.gfx"); - } - }; - fc.addChoosableFileFilter(gfxFilter); - - FileFilter iggyFilter = new FileFilter() { - @Override - public boolean accept(File f) { - return (f.getName().toLowerCase().endsWith(".iggy")) || (f.isDirectory()); - } - - @Override - public String getDescription() { - return AppStrings.translate("filter.iggy"); - } - }; - fc.addChoosableFileFilter(iggyFilter); - - FileFilter zipFilter = new FileFilter() { - @Override - public boolean accept(File f) { - return (f.getName().toLowerCase().endsWith(".zip")) || (f.isDirectory()); - } - - @Override - public String getDescription() { - return AppStrings.translate("filter.zip"); - } - }; - fc.addChoosableFileFilter(zipFilter); - - FileFilter binaryFilter = new FileFilter() { - @Override - public boolean accept(File f) { - return true; - } - - @Override - public String getDescription() { - return AppStrings.translate("filter.binary"); - } - }; - fc.addChoosableFileFilter(binaryFilter); - - fc.setAcceptAllFileFilterUsed(false); - JFrame f = new JFrame(); - View.setWindowIcon(f); - int returnVal = fc.showOpenDialog(f); - if (returnVal == JFileChooser.APPROVE_OPTION) { - Configuration.lastOpenDir.set(Helper.fixDialogFile(fc.getSelectedFile()).getParentFile().getAbsolutePath()); - File[] selFiles = fc.getSelectedFiles(); - for (File file : selFiles) { - File selfile = Helper.fixDialogFile(file); - Main.openFile(selfile.getAbsolutePath(), null); - } - return true; - } else { - return false; - } - } - - public static void displayErrorFrame() { - ErrorLogFrame.getInstance().setVisible(true); - } - - private static String md5(byte data[]) { - try { - java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5"); - byte[] array = md.digest(data); - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < array.length; ++i) { - sb.append(Integer.toHexString((array[i] & 0xFF) | 0x100).substring(1, 3)); - } - return sb.toString(); - } catch (java.security.NoSuchAlgorithmException e) { - } - return null; - } - - private static void initGui() { - if (GraphicsEnvironment.isHeadless()) { - System.err.println("Error: Your system does not support Graphic User Interface"); - exit(); - } - - System.setProperty("sun.java2d.d3d", "false"); - System.setProperty("sun.java2d.noddraw", "true"); - - if (Configuration.hwAcceleratedGraphics.get()) { - System.setProperty("sun.java2d.opengl", Configuration._debugMode.get() ? "True" : "true"); - } else { - System.setProperty("sun.java2d.opengl", "false"); - } - - initUiLang(); - - if (Configuration.useRibbonInterface.get()) { - View.setLookAndFeel(); - } else { - try { - UIManager.put(SubstanceLookAndFeel.COLORIZATION_FACTOR, null); - UIManager.put("Tree.expandedIcon", null); - UIManager.put("Tree.collapsedIcon", null); - UIManager.put("ColorChooserUI", null); - UIManager.put("ColorChooser.swatchesRecentSwatchSize", null); - UIManager.put("ColorChooser.swatchesSwatchSize", null); - UIManager.put("RibbonApplicationMenuPopupPanelUI", null); - UIManager.put("RibbonApplicationMenuButtonUI", null); - UIManager.put("ProgressBarUI", null); - UIManager.put("TextField.background", null); - UIManager.put("FormattedTextField.background", null); - UIManager.put("CommandButtonUI", null); - UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { - logger.log(Level.SEVERE, null, ex); - } - } - - View.execInEventDispatch(() -> { - ErrorLogFrame.createNewInstance(); - - autoCheckForUpdates(); - offerAssociation(); - loadingDialog = new LoadingDialog(); - - DebuggerTools.initDebugger().addMessageListener(new DebugListener() { - @Override - public void onMessage(String clientId, String msg) { - } - - @Override - public void onLoaderURL(String clientId, String url) { - } - - @Override - public void onLoaderBytes(String clientId, byte[] data) { - String hash = md5(data); - for (SWFList sl : Main.getMainFrame().getPanel().getSwfs()) { - for (int s = 0; s < sl.size(); s++) { - String t = sl.get(s).getFileTitle(); - if (t == null) { - t = ""; - } - if (t.endsWith(":" + hash)) { //this one is already opened - return; - } - } - } - SWF swf = Main.getMainFrame().getPanel().getCurrentSwf(); - - String title = swf == null ? "?" : swf.getFileTitle(); - title = title + ":" + hash; - String tfile; - try { - tfile = tempFile(title); - Helper.writeFile(tfile, data); - openFile(new SWFSourceInfo(null, tfile, title)); - } catch (IOException ex) { - logger.log(Level.SEVERE, "Cannot create tempfile"); - } - } - - @Override - public void onFinish(String clientId) { - } - }); - - try { - flashDebugger = new Debugger(); - debugHandler = new DebuggerHandler(); - debugHandler.addBreakListener(new DebuggerHandler.BreakListener() { - @Override - public void doContinue() { - mainFrame.getPanel().clearDebuggerColors(); - } - - @Override - public void breakAt(String scriptName, int line, final int classIndex, final int traitIndex, final int methodIndex) { - View.execInEventDispatch(new Runnable() { - @Override - public void run() { - mainFrame.getPanel().gotoScriptLine(getMainFrame().getPanel().getCurrentSwf(), scriptName, line, classIndex, traitIndex, methodIndex); - } - }); - } - }); - debugHandler.addConnectionListener(new DebuggerHandler.ConnectionListener() { - @Override - public void connected() { - Main.mainFrame.getMenu().updateComponents(); - } - - @Override - public void disconnected() { - if (Main.mainFrame != null && Main.mainFrame.getPanel() != null) { - Main.mainFrame.getPanel().refreshBreakPoints(); - } - } - }); - flashDebugger.addConnectionListener(debugHandler); - } catch (IOException ex) { - logger.log(Level.SEVERE, "eeex", ex); - } - }); - } - - public static void startDebugger() { - flashDebugger.startDebugger(); - } - - public static void stopDebugger() { - flashDebugger.stopDebugger(); - } - - public static void showModeFrame() { - ensureMainFrame(); - mainFrame.setVisible(true); - } - - private static void offerAssociation() { - boolean offered = Configuration.offeredAssociation.get(); - if (!offered) { - if (Platform.isWindows()) { - if ((!ContextMenuTools.isAddedToContextMenu()) && View.showConfirmDialog(null, "Do you want to add FFDec to context menu of SWF files?\n(Can be changed later from main menu)", "Context menu", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) { - ContextMenuTools.addToContextMenu(true, false); - } - } - - Configuration.offeredAssociation.set(true); - } - } - - public static void initUiLang() { - if (GraphicsEnvironment.isHeadless()) { //No GUI in OS - return; - } - try { - Class cl = Class.forName("org.pushingpixels.substance.api.SubstanceLookAndFeel"); - Field field = cl.getDeclaredField("LABEL_BUNDLE"); - field.setAccessible(true); - field.set(null, null); - } catch (Throwable ex) { - logger.log(Level.SEVERE, null, ex); - } - - UIManager.put("OptionPane.okButtonText", AppStrings.translate("button.ok")); - UIManager.put("OptionPane.yesButtonText", AppStrings.translate("button.yes")); - UIManager.put("OptionPane.noButtonText", AppStrings.translate("button.no")); - UIManager.put("OptionPane.cancelButtonText", AppStrings.translate("button.cancel")); - UIManager.put("OptionPane.messageDialogTitle", AppStrings.translate("dialog.message.title")); - UIManager.put("OptionPane.titleText", AppStrings.translate("dialog.select.title")); - - UIManager.put("FileChooser.acceptAllFileFilterText", AppStrings.translate("FileChooser.acceptAllFileFilterText")); - UIManager.put("FileChooser.lookInLabelText", AppStrings.translate("FileChooser.lookInLabelText")); - UIManager.put("FileChooser.cancelButtonText", AppStrings.translate("button.cancel")); - UIManager.put("FileChooser.cancelButtonToolTipText", AppStrings.translate("button.cancel")); - UIManager.put("FileChooser.openButtonText", AppStrings.translate("FileChooser.openButtonText")); - UIManager.put("FileChooser.openButtonToolTipText", AppStrings.translate("FileChooser.openButtonToolTipText")); - UIManager.put("FileChooser.filesOfTypeLabelText", AppStrings.translate("FileChooser.filesOfTypeLabelText")); - UIManager.put("FileChooser.fileNameLabelText", AppStrings.translate("FileChooser.fileNameLabelText")); - UIManager.put("FileChooser.listViewButtonToolTipText", AppStrings.translate("FileChooser.listViewButtonToolTipText")); - UIManager.put("FileChooser.listViewButtonAccessibleName", AppStrings.translate("FileChooser.listViewButtonAccessibleName")); - UIManager.put("FileChooser.detailsViewButtonToolTipText", AppStrings.translate("FileChooser.detailsViewButtonToolTipText")); - UIManager.put("FileChooser.detailsViewButtonAccessibleName", AppStrings.translate("FileChooser.detailsViewButtonAccessibleName")); - UIManager.put("FileChooser.upFolderToolTipText", AppStrings.translate("FileChooser.upFolderToolTipText")); - UIManager.put("FileChooser.upFolderAccessibleName", AppStrings.translate("FileChooser.upFolderAccessibleName")); - UIManager.put("FileChooser.homeFolderToolTipText", AppStrings.translate("FileChooser.homeFolderToolTipText")); - UIManager.put("FileChooser.homeFolderAccessibleName", AppStrings.translate("FileChooser.homeFolderAccessibleName")); - UIManager.put("FileChooser.fileNameHeaderText", AppStrings.translate("FileChooser.fileNameHeaderText")); - UIManager.put("FileChooser.fileSizeHeaderText", AppStrings.translate("FileChooser.fileSizeHeaderText")); - UIManager.put("FileChooser.fileTypeHeaderText", AppStrings.translate("FileChooser.fileTypeHeaderText")); - UIManager.put("FileChooser.fileDateHeaderText", AppStrings.translate("FileChooser.fileDateHeaderText")); - UIManager.put("FileChooser.fileAttrHeaderText", AppStrings.translate("FileChooser.fileAttrHeaderText")); - UIManager.put("FileChooser.openDialogTitleText", AppStrings.translate("FileChooser.openDialogTitleText")); - UIManager.put("FileChooser.directoryDescriptionText", AppStrings.translate("FileChooser.directoryDescriptionText")); - UIManager.put("FileChooser.directoryOpenButtonText", AppStrings.translate("FileChooser.directoryOpenButtonText")); - UIManager.put("FileChooser.directoryOpenButtonToolTipText", AppStrings.translate("FileChooser.directoryOpenButtonToolTipText")); - UIManager.put("FileChooser.fileDescriptionText", AppStrings.translate("FileChooser.fileDescriptionText")); - UIManager.put("FileChooser.fileNameLabelText", AppStrings.translate("FileChooser.fileNameLabelText")); - UIManager.put("FileChooser.helpButtonText", AppStrings.translate("FileChooser.helpButtonText")); - UIManager.put("FileChooser.helpButtonToolTipText", AppStrings.translate("FileChooser.helpButtonToolTipText")); - UIManager.put("FileChooser.newFolderAccessibleName", AppStrings.translate("FileChooser.newFolderAccessibleName")); - UIManager.put("FileChooser.newFolderErrorText", AppStrings.translate("FileChooser.newFolderErrorText")); - UIManager.put("FileChooser.newFolderToolTipText", AppStrings.translate("FileChooser.newFolderToolTipText")); - UIManager.put("FileChooser.other.newFolder", AppStrings.translate("FileChooser.other.newFolder")); - UIManager.put("FileChooser.other.newFolder.subsequent", AppStrings.translate("FileChooser.other.newFolder.subsequent")); - UIManager.put("FileChooser.win32.newFolder", AppStrings.translate("FileChooser.win32.newFolder")); - UIManager.put("FileChooser.win32.newFolder.subsequent", AppStrings.translate("FileChooser.win32.newFolder.subsequent")); - UIManager.put("FileChooser.saveButtonText", AppStrings.translate("FileChooser.saveButtonText")); - UIManager.put("FileChooser.saveButtonToolTipText", AppStrings.translate("FileChooser.saveButtonToolTipText")); - UIManager.put("FileChooser.saveDialogTitleText", AppStrings.translate("FileChooser.saveDialogTitleText")); - UIManager.put("FileChooser.saveInLabelText", AppStrings.translate("FileChooser.saveInLabelText")); - UIManager.put("FileChooser.updateButtonText", AppStrings.translate("FileChooser.updateButtonText")); - UIManager.put("FileChooser.updateButtonToolTipText", AppStrings.translate("FileChooser.updateButtonToolTipText")); - - UIManager.put("FileChooser.detailsViewActionLabel.textAndMnemonic", AppStrings.translate("FileChooser.detailsViewActionLabel.textAndMnemonic")); - UIManager.put("FileChooser.detailsViewButtonToolTip.textAndMnemonic", AppStrings.translate("FileChooser.detailsViewButtonToolTip.textAndMnemonic")); - UIManager.put("FileChooser.fileAttrHeader.textAndMnemonic", AppStrings.translate("FileChooser.fileAttrHeader.textAndMnemonic")); - UIManager.put("FileChooser.fileDateHeader.textAndMnemonic", AppStrings.translate("FileChooser.fileDateHeader.textAndMnemonic")); - UIManager.put("FileChooser.fileNameHeader.textAndMnemonic", AppStrings.translate("FileChooser.fileNameHeader.textAndMnemonic")); - UIManager.put("FileChooser.fileNameLabel.textAndMnemonic", AppStrings.translate("FileChooser.fileNameLabel.textAndMnemonic")); - UIManager.put("FileChooser.fileSizeHeader.textAndMnemonic", AppStrings.translate("FileChooser.fileSizeHeader.textAndMnemonic")); - UIManager.put("FileChooser.fileTypeHeader.textAndMnemonic", AppStrings.translate("FileChooser.fileTypeHeader.textAndMnemonic")); - UIManager.put("FileChooser.filesOfTypeLabel.textAndMnemonic", AppStrings.translate("FileChooser.filesOfTypeLabel.textAndMnemonic")); - UIManager.put("FileChooser.folderNameLabel.textAndMnemonic", AppStrings.translate("FileChooser.folderNameLabel.textAndMnemonic")); - UIManager.put("FileChooser.homeFolderToolTip.textAndMnemonic", AppStrings.translate("FileChooser.homeFolderToolTip.textAndMnemonic")); - UIManager.put("FileChooser.listViewActionLabel.textAndMnemonic", AppStrings.translate("FileChooser.listViewActionLabel.textAndMnemonic")); - UIManager.put("FileChooser.listViewButtonToolTip.textAndMnemonic", AppStrings.translate("FileChooser.listViewButtonToolTip.textAndMnemonic")); - UIManager.put("FileChooser.lookInLabel.textAndMnemonic", AppStrings.translate("FileChooser.lookInLabel.textAndMnemonic")); - UIManager.put("FileChooser.newFolderActionLabel.textAndMnemonic", AppStrings.translate("FileChooser.newFolderActionLabel.textAndMnemonic")); - UIManager.put("FileChooser.newFolderToolTip.textAndMnemonic", AppStrings.translate("FileChooser.newFolderToolTip.textAndMnemonic")); - UIManager.put("FileChooser.refreshActionLabel.textAndMnemonic", AppStrings.translate("FileChooser.refreshActionLabel.textAndMnemonic")); - UIManager.put("FileChooser.saveInLabel.textAndMnemonic", AppStrings.translate("FileChooser.saveInLabel.textAndMnemonic")); - UIManager.put("FileChooser.upFolderToolTip.textAndMnemonic", AppStrings.translate("FileChooser.upFolderToolTip.textAndMnemonic")); - UIManager.put("FileChooser.viewMenuButtonAccessibleName", AppStrings.translate("FileChooser.viewMenuButtonAccessibleName")); - UIManager.put("FileChooser.viewMenuButtonToolTipText", AppStrings.translate("FileChooser.viewMenuButtonToolTipText")); - UIManager.put("FileChooser.viewMenuLabel.textAndMnemonic", AppStrings.translate("FileChooser.viewMenuLabel.textAndMnemonic")); - UIManager.put("FileChooser.newFolderActionLabelText", AppStrings.translate("FileChooser.newFolderActionLabelText")); - UIManager.put("FileChooser.listViewActionLabelText", AppStrings.translate("FileChooser.listViewActionLabelText")); - UIManager.put("FileChooser.detailsViewActionLabelText", AppStrings.translate("FileChooser.detailsViewActionLabelText")); - UIManager.put("FileChooser.refreshActionLabelText", AppStrings.translate("FileChooser.refreshActionLabelText")); - UIManager.put("FileChooser.sortMenuLabelText", AppStrings.translate("FileChooser.sortMenuLabelText")); - UIManager.put("FileChooser.viewMenuLabelText", AppStrings.translate("FileChooser.viewMenuLabelText")); - UIManager.put("FileChooser.fileSizeKiloBytes", AppStrings.translate("FileChooser.fileSizeKiloBytes")); - UIManager.put("FileChooser.fileSizeMegaBytes", AppStrings.translate("FileChooser.fileSizeMegaBytes")); - UIManager.put("FileChooser.fileSizeGigaBytes", AppStrings.translate("FileChooser.fileSizeGigaBytes")); - UIManager.put("FileChooser.folderNameLabelText", AppStrings.translate("FileChooser.folderNameLabelText")); - - UIManager.put("ColorChooser.okText", AppStrings.translate("ColorChooser.okText")); - UIManager.put("ColorChooser.cancelText", AppStrings.translate("ColorChooser.cancelText")); - UIManager.put("ColorChooser.resetText", AppStrings.translate("ColorChooser.resetText")); - UIManager.put("ColorChooser.previewText", AppStrings.translate("ColorChooser.previewText")); - UIManager.put("ColorChooser.swatchesNameText", AppStrings.translate("ColorChooser.swatchesNameText")); - UIManager.put("ColorChooser.swatchesRecentText", AppStrings.translate("ColorChooser.swatchesRecentText")); - UIManager.put("ColorChooser.sampleText", AppStrings.translate("ColorChooser.sampleText")); - - } - - public static void initLang() { - if (!Configuration.locale.hasValue()) { - if (Platform.isWindows()) { - //Load from Installer - String uninstKey = "{E618D276-6596-41F4-8A98-447D442A77DB}_is1"; - uninstKey = "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\" + uninstKey; - try { - if (Advapi32Util.registryKeyExists(WinReg.HKEY_LOCAL_MACHINE, uninstKey)) { - if (Advapi32Util.registryValueExists(WinReg.HKEY_LOCAL_MACHINE, uninstKey, "NSIS: Language")) { - String installedLoc = Advapi32Util.registryGetStringValue(WinReg.HKEY_LOCAL_MACHINE, uninstKey, "NSIS: Language"); - int lcid = Integer.parseInt(installedLoc); - char[] buf = new char[9]; - int cnt = Kernel32.INSTANCE.GetLocaleInfo(lcid, Kernel32.LOCALE_SISO639LANGNAME, buf, 9); - String langCode = new String(buf, 0, cnt).trim().toLowerCase(); - - cnt = Kernel32.INSTANCE.GetLocaleInfo(lcid, Kernel32.LOCALE_SISO3166CTRYNAME, buf, 9); - String countryCode = new String(buf, 0, cnt).trim().toLowerCase(); - - List langs = Arrays.asList(SelectLanguageDialog.getAvailableLanguages()); - for (int i = 0; i < langs.size(); i++) { - langs.set(i, langs.get(i).toLowerCase()); - } - - String selectedLang = null; - - if (langs.contains(langCode + "-" + countryCode)) { - selectedLang = SelectLanguageDialog.getAvailableLanguages()[langs.indexOf(langCode + "-" + countryCode)]; - } else if (langs.contains(langCode)) { - selectedLang = SelectLanguageDialog.getAvailableLanguages()[langs.indexOf(langCode)]; - } - if (selectedLang != null) { - Configuration.locale.set(selectedLang); - } - } - } - } catch (Exception ex) { - //ignore - } - } - } - Locale.setDefault(Locale.forLanguageTag(Configuration.locale.get())); - AppStrings.updateLanguage(); - - Helper.decompilationErrorAdd = AppStrings.translate(Configuration.autoDeobfuscate.get() ? "deobfuscation.comment.failed" : "deobfuscation.comment.tryenable"); - } - - /** - * Clear old FFDec/JavactiveX temp files - */ - private static void clearTemp() { - String tempDirPath = System.getProperty("java.io.tmpdir"); - if (tempDirPath == null) { - return; - } - File tempDir = new File(tempDirPath); - if (!tempDir.exists()) { - return; - } - File[] delFiles = tempDir.listFiles(new FilenameFilter() { - @Override - public boolean accept(File dir, String name) { - return name.matches("ffdec_cache.*\\.tmp") || name.matches("javactivex_.*\\.exe") || name.matches("temp[0-9]+\\.swf") || name.matches("ffdec_view_.*\\.swf"); - } - }); - - if (delFiles != null) { - for (File f : delFiles) { - try { - f.delete(); - } catch (Exception ex) { - //ignore - } - } - } - } - - /** - * @param args the command line arguments - * @throws IOException On error - */ - public static void main(String[] args) throws IOException { - setSessionLoaded(false); - - clearTemp(); - - try { - SWFDecompilerPlugin.loadPlugins(); - } catch (Throwable ex) { - logger.log(Level.SEVERE, "Failed to load plugins", ex); - } - - AppStrings.setResourceClass(MainFrame.class); - initLogging(Configuration._debugMode.get()); - - initLang(); - - if (Configuration.cacheOnDisk.get()) { - Cache.setStorageType(Cache.STORAGE_FILES); - } else { - Cache.setStorageType(Cache.STORAGE_MEMORY); - } - - if (args.length == 0) { - initGui(); - checkLibraryVersion(); - View.execInEventDispatch(() -> { - if (Configuration.allowOnlyOneInstance.get() && FirstInstance.focus()) { //Try to focus first instance - Main.exit(); - } else { - showModeFrame(); - reloadLastSession(); - } - }); - } else { - checkLibraryVersion(); - setSessionLoaded(true); - String[] filesToOpen = CommandLineArgumentParser.parseArguments(args); - if (filesToOpen != null && filesToOpen.length > 0) { - View.execInEventDispatch(() -> { - initGui(); - shouldCloseWhenClosingLoadingDialog = true; - if (Configuration.allowOnlyOneInstance.get() && FirstInstance.openFiles(Arrays.asList(filesToOpen))) { //Try to open in first instance - Main.exit(); - } else { - for (String fileToOpen : filesToOpen) { - openFile(fileToOpen, null); - } - } - }); - } - } - } - - private static void checkLibraryVersion() { - if (!ApplicationInfo.version.equals("unknown") && !ApplicationInfo.libraryVersion.equals("unknown") - && !Objects.equals(ApplicationInfo.version, ApplicationInfo.libraryVersion)) { - logger.log(Level.WARNING, "Application version is different from library version. FFDec may not work properly."); - } - } - - private static void reloadLastSession() { - boolean openingFiles = false; - if (Configuration.saveSessionOnExit.get()) { - String lastSession = Configuration.lastSessionFiles.get(); - if (lastSession != null && lastSession.length() > 0) { - String[] filesToOpen = lastSession.split(File.pathSeparator, -1); - List exfiles = new ArrayList<>(); - List extitles = new ArrayList<>(); - String lastSessionTitles = Configuration.lastSessionFileTitles.get(); - String[] fileTitles = new String[0]; - if (lastSessionTitles != null && !lastSessionTitles.isEmpty()) { - fileTitles = lastSessionTitles.split(File.pathSeparator, -1); - } - for (int i = 0; i < filesToOpen.length; i++) { - if (new File(filesToOpen[i]).exists()) { - exfiles.add(filesToOpen[i]); - if (fileTitles.length > i) { - extitles.add(fileTitles[i]); - } else { - extitles.add(null); - } - } - } - SWFSourceInfo[] sourceInfos = new SWFSourceInfo[exfiles.size()]; - for (int i = 0; i < exfiles.size(); i++) { - String extitle = extitles.get(i); - sourceInfos[i] = new SWFSourceInfo(null, exfiles.get(i), extitle == null || extitle.isEmpty() ? null : extitle); - } - if (sourceInfos.length > 0) { - openingFiles = true; - openFile(sourceInfos, () -> { - mainFrame.getPanel().tagTree.setSelectionPathString(Configuration.lastSessionSelection.get()); - setSessionLoaded(true); - }); - } - } - } - - if (!openingFiles) { - setSessionLoaded(true); - } - } - - public static String tempFile(String url) throws IOException { - File f = new File(Configuration.getFFDecHome() + "saved" + File.separator); - Path.createDirectorySafe(f); - return Configuration.getFFDecHome() + "saved" + File.separator + "asdec_" + Integer.toHexString(url.hashCode()) + ".tmp"; - } - - public static void removeTrayIcon() { - if (SystemTray.isSupported()) { - SystemTray tray = SystemTray.getSystemTray(); - if (trayIcon != null) { - tray.remove(trayIcon); - trayIcon = null; - } - } - } - - public static void switchProxy() { - proxyFrame.switchState(); - if (stopMenuItem != null) { - if (proxyFrame.isRunning()) { - stopMenuItem.setLabel(AppStrings.translate("proxy.stop")); - } else { - stopMenuItem.setLabel(AppStrings.translate("proxy.start")); - } - } - } - - public static void addTrayIcon() { - if (trayIcon != null) { - return; - } - if (SystemTray.isSupported()) { - SystemTray tray = SystemTray.getSystemTray(); - trayIcon = new TrayIcon(View.loadImage("proxy16"), ApplicationInfo.VENDOR + " " + ApplicationInfo.SHORT_APPLICATION_NAME + " " + AppStrings.translate("proxy")); - trayIcon.setImageAutoSize(true); - PopupMenu trayPopup = new PopupMenu(); - - ActionListener trayListener = new ActionListener() { - /** - * Invoked when an action occurs. - */ - @Override - public void actionPerformed(ActionEvent e) { - if (e.getActionCommand().equals("EXIT")) { - Main.exit(); - } - if (e.getActionCommand().equals("SHOW")) { - Main.showProxy(); - } - if (e.getActionCommand().equals("SWITCH")) { - Main.switchProxy(); - } - } - }; - - MenuItem showMenuItem = new MenuItem(AppStrings.translate("proxy.show")); - showMenuItem.setActionCommand("SHOW"); - showMenuItem.addActionListener(trayListener); - trayPopup.add(showMenuItem); - stopMenuItem = new MenuItem(AppStrings.translate("proxy.start")); - stopMenuItem.setActionCommand("SWITCH"); - stopMenuItem.addActionListener(trayListener); - trayPopup.add(stopMenuItem); - trayPopup.addSeparator(); - MenuItem exitMenuItem = new MenuItem(AppStrings.translate("exit")); - exitMenuItem.setActionCommand("EXIT"); - exitMenuItem.addActionListener(trayListener); - trayPopup.add(exitMenuItem); - - trayIcon.setPopupMenu(trayPopup); - trayIcon.addMouseListener(new MouseAdapter() { - /** - * {@inheritDoc} - */ - @Override - public void mouseClicked(MouseEvent e) { - if (e.getButton() == MouseEvent.BUTTON1) { - Main.showProxy(); - } - } - }); - try { - tray.add(trayIcon); - } catch (AWTException ex) { - } - } - } - - public static void exit() { - Configuration.saveConfig(); - if (mainFrame != null && mainFrame.getPanel() != null) { - mainFrame.getPanel().unloadFlashPlayer(); - mainFrame.dispose(); - } - if (fileTxt != null) { - try { - fileTxt.flush(); - fileTxt.close(); - } catch (Exception ex) { - //ignore - } - } - System.exit(0); - } - - public static void about() { - (new AboutDialog()).setVisible(true); - } - - public static void advancedSettings() { - advancedSettings(null); - } - - public static void advancedSettings(String category) { - (new AdvancedSettingsDialog(category)).setVisible(true); - } - - public static void autoCheckForUpdates() { - if (Configuration.checkForUpdatesAuto.get()) { - Calendar lastUpdatesCheckDate = Configuration.lastUpdatesCheckDate.get(); - if ((lastUpdatesCheckDate == null) || (lastUpdatesCheckDate.getTime().getTime() < Calendar.getInstance().getTime().getTime() - Configuration.checkForUpdatesDelay.get())) { - new SwingWorker() { - @Override - protected Object doInBackground() throws Exception { - checkForUpdates(); - return null; - } - }.execute(); - } - } - } - - public static boolean checkForUpdates() { - String currentVersion = ApplicationInfo.version; - if (currentVersion.equals("unknown")) { - // sometimes during development the version information is not available - return false; - } - - List accepted = new ArrayList<>(); - if (Configuration.checkForUpdatesStable.get()) { - accepted.add("stable"); - } - if (Configuration.checkForUpdatesNightly.get()) { - accepted.add("nightly"); - } - - if (accepted.isEmpty()) { - return false; - } - - String acceptVersions = String.join(",", accepted); - try { - String proxyAddress = Configuration.updateProxyAddress.get(); - URL url = new URL(ApplicationInfo.updateCheckUrl); - - URLConnection uc; - if (proxyAddress != null && !proxyAddress.isEmpty()) { - int port = 8080; - if (proxyAddress.contains(":")) { - String[] parts = proxyAddress.split(":"); - port = Integer.parseInt(parts[1]); - proxyAddress = parts[0]; - } - - uc = url.openConnection(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyAddress, port))); - } else { - uc = url.openConnection(); - } - uc.setRequestProperty("X-Accept-Versions", acceptVersions); - uc.setRequestProperty("X-Update-Major", "" + UPDATE_SYSTEM_MAJOR); - uc.setRequestProperty("X-Update-Minor", "" + UPDATE_SYSTEM_MINOR); - uc.setRequestProperty("User-Agent", ApplicationInfo.shortApplicationVerName); - String currentLoc = Configuration.locale.get("en"); - uc.setRequestProperty("Accept-Language", currentLoc + ("en".equals(currentLoc) ? "" : ", en;q=0.8")); - - uc.connect(); - - BufferedReader br = new BufferedReader(new InputStreamReader(uc.getInputStream())); - String s; - final java.util.List versions = new ArrayList<>(); - String header = ""; - Pattern headerPat = Pattern.compile("\\[([a-zA-Z0-9]+)\\]"); - int updateMajor; - int updateMinor; - Version ver = null; - while ((s = br.readLine()) != null) { - - Matcher m = headerPat.matcher(s); - if (m.matches()) { - header = m.group(1); - if (header.equals("version")) { - ver = new Version(); - versions.add(ver); - } - if (header.equals("noversion")) { - break; - } - } else if (s.contains("=")) { - String key = s.substring(0, s.indexOf('=')); - String val = s.substring(s.indexOf('=') + 1); - if ("updateSystem".equals(header)) { - if (key.equals("majorVersion")) { - updateMajor = Integer.parseInt(val); - if (updateMajor > UPDATE_SYSTEM_MAJOR) { - break; - } - } - if (key.equals("minorVersion")) { - updateMinor = Integer.parseInt(val); - } - } - if ("version".equals(header) && (ver != null)) { - if (key.equals("versionId")) { - ver.versionId = Integer.parseInt(val); - } - if (key.equals("versionName")) { - ver.versionName = val; - } - if (key.equals("nightly")) { - ver.nightly = val.equals("true"); - } - if (key.equals("revision")) { - ver.revision = val; - } - if (key.equals("build")) { - ver.build = Integer.parseInt(val); - } - if (key.equals("major")) { - ver.major = Integer.parseInt(val); - } - if (key.equals("minor")) { - ver.minor = Integer.parseInt(val); - } - if (key.equals("release")) { - ver.release = Integer.parseInt(val); - } - if (key.equals("longVersionName")) { - ver.longVersionName = val; - } - if (key.equals("releaseDate")) { - ver.releaseDate = val; - } - if (key.equals("appName")) { - ver.appName = val; - } - if (key.equals("appFullName")) { - ver.appFullName = val; - } - if (key.equals("updateLink")) { - ver.updateLink = val; - } - if (key.equals("change[]")) { - String changeType = val.substring(0, val.indexOf('|')); - String change = val.substring(val.indexOf('|') + 1); - if (!ver.changes.containsKey(changeType)) { - ver.changes.put(changeType, new ArrayList<>()); - } - List chlist = ver.changes.get(changeType); - chlist.add(change); - } - } - } - } - - if (!versions.isEmpty()) { - View.execInEventDispatch(() -> { - NewVersionDialog newVersionDialog = new NewVersionDialog(versions); - newVersionDialog.setVisible(true); - Configuration.lastUpdatesCheckDate.set(Calendar.getInstance()); - }); - - return true; - } - } catch (IOException | NumberFormatException ex) { - return false; - } - Configuration.lastUpdatesCheckDate.set(Calendar.getInstance()); - return false; - } - - private static FileHandler fileTxt; - - public static void clearLogFile() { - Logger logger = Logger.getLogger(""); - - FileHandler oldFileTxt = fileTxt; - fileTxt = null; - if (oldFileTxt != null) { - logger.removeHandler(fileTxt); - oldFileTxt.flush(); - oldFileTxt.close(); - } - - String fileName = null; - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-hh-mm-ss"); - - try { - fileName = Configuration.getFFDecHome() + "logs" + File.separator; - if (Configuration.useDetailedLogging.get()) { - fileName += "log-" + sdf.format(new Date()) + ".txt"; - } else { - fileName += "log.txt"; - } - File f = new File(fileName).getParentFile(); - if (!f.exists()) { - f.mkdir(); - } - fileTxt = new FileHandler(fileName); - } catch (IOException | SecurityException ex) { - //cannot get lock error - if (ex.getMessage().contains("lock for")) { - //remove all old log files and their .lck - for (int i = 0; i <= 100; i++) { - File flog = new File(fileName + (i == 0 ? "" : "." + i)); - File flog_lock = new File(fileName + (i == 0 ? "" : "." + i) + ".lck"); - flog.delete(); - flog_lock.delete(); - } - try { - fileTxt = new FileHandler(fileName); - } catch (IOException | SecurityException ex1) { - logger.log(Level.SEVERE, "Cannot initialize logging", ex); - } - } else { - logger.log(Level.SEVERE, "Cannot initialize logging", ex); - } - } - - Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { - @Override - public void uncaughtException(Thread t, Throwable e) { - logger.log(Level.SEVERE, "Uncaught exception in thread: " + t.getName(), e); - if (e instanceof OutOfMemoryError || !Helper.is64BitJre() && Helper.is64BitOs()) { - View.showMessageDialog(null, AppStrings.translate("message.warning.outOfMemory32BitJre"), AppStrings.translate("message.warning"), JOptionPane.WARNING_MESSAGE); - } - } - }); - - Formatter formatterTxt = new LogFormatter(); - if (fileTxt != null) { - fileTxt.setFormatter(formatterTxt); - logger.addHandler(fileTxt); - } - - if (!GraphicsEnvironment.isHeadless() && ErrorLogFrame.hasInstance()) { - ErrorLogFrame.getInstance().clearErrorState(); - } - - sdf = new SimpleDateFormat("yyyy-MM-dd"); - logger.log(Level.INFO, "Date: {0}", sdf.format(new Date())); - logger.log(Level.INFO, ApplicationInfo.applicationVerName); - logger.log(Level.INFO, "{0} {1} {2}", new Object[]{ - System.getProperty("os.name"), System.getProperty("os.version"), System.getProperty("os.arch")}); - logger.log(Level.INFO, "{0} {1} {2}", new Object[]{ - System.getProperty("java.version"), System.getProperty("java.vendor"), System.getProperty("os.arch")}); - } - - public static void initLogging(boolean debug) { - try { - Logger logger = Logger.getLogger(""); - logger.setLevel(Configuration.logLevel); - - Handler[] handlers = logger.getHandlers(); - for (int i = handlers.length - 1; i >= 0; i--) { - logger.removeHandler(handlers[i]); - } - - ConsoleHandler conHan = new ConsoleHandler(); - conHan.setLevel(debug ? Level.CONFIG : Level.WARNING); - SimpleFormatter formatterTxt = new SimpleFormatter(); - conHan.setFormatter(formatterTxt); - logger.addHandler(conHan); - clearLogFile(); - - } catch (Exception ex) { - throw new RuntimeException("Problems with creating the log files"); - } - } -} +/* + * Copyright (C) 2010-2016 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; + +import com.jpexs.debugger.flash.Debugger; +import com.jpexs.debugger.flash.DebuggerCommands; +import com.jpexs.debugger.flash.Variable; +import com.jpexs.debugger.flash.VariableType; +import com.jpexs.debugger.flash.messages.in.InCallFunction; +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.SwfOpenException; +import com.jpexs.decompiler.flash.UrlResolver; +import com.jpexs.decompiler.flash.Version; +import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; +import com.jpexs.decompiler.flash.abc.avm2.parser.script.Reference; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.configuration.SwfSpecificConfiguration; +import com.jpexs.decompiler.flash.console.CommandLineArgumentParser; +import com.jpexs.decompiler.flash.console.ContextMenuTools; +import com.jpexs.decompiler.flash.exporters.modes.ExeExportMode; +import com.jpexs.decompiler.flash.gui.debugger.DebugListener; +import com.jpexs.decompiler.flash.gui.debugger.DebuggerTools; +import com.jpexs.decompiler.flash.gui.pipes.FirstInstance; +import com.jpexs.decompiler.flash.gui.proxy.ProxyFrame; +import com.jpexs.decompiler.flash.helpers.SWFDecompilerPlugin; +import com.jpexs.decompiler.flash.tags.Tag; +import com.jpexs.decompiler.flash.tags.base.FontTag; +import com.jpexs.decompiler.flash.tags.base.ImportTag; +import com.jpexs.decompiler.flash.treeitems.SWFList; +import com.jpexs.helpers.Cache; +import com.jpexs.helpers.CancellableWorker; +import com.jpexs.helpers.Helper; +import com.jpexs.helpers.Path; +import com.jpexs.helpers.ProgressListener; +import com.jpexs.helpers.Stopwatch; +import com.jpexs.helpers.streams.SeekableInputStream; +import com.sun.jna.Platform; +import com.sun.jna.platform.win32.Advapi32Util; +import com.sun.jna.platform.win32.Kernel32; +import com.sun.jna.platform.win32.WinReg; +import java.awt.AWTException; +import java.awt.Frame; +import java.awt.GraphicsEnvironment; +import java.awt.MenuItem; +import java.awt.PopupMenu; +import java.awt.SystemTray; +import java.awt.TrayIcon; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.lang.reflect.Field; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.URL; +import java.net.URLConnection; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; +import java.util.logging.ConsoleHandler; +import java.util.logging.FileHandler; +import java.util.logging.Formatter; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.logging.SimpleFormatter; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.swing.JFileChooser; +import javax.swing.JFrame; +import javax.swing.JOptionPane; +import javax.swing.SwingWorker; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; +import javax.swing.filechooser.FileFilter; +import org.pushingpixels.substance.api.SubstanceLookAndFeel; + +/** + * Main executable class + * + * @author JPEXS + */ +public class Main { + + protected static ProxyFrame proxyFrame; + + private static List sourceInfos = new ArrayList<>(); + + public static LoadingDialog loadingDialog; + + private static boolean working = false; + + private static TrayIcon trayIcon; + + private static MenuItem stopMenuItem; + + private static volatile MainFrame mainFrame; + + public static final int UPDATE_SYSTEM_MAJOR = 1; + + public static final int UPDATE_SYSTEM_MINOR = 3; + + private static LoadFromMemoryFrame loadFromMemoryFrame; + + private static LoadFromCacheFrame loadFromCacheFrame; + + private static final Logger logger = Logger.getLogger(Main.class.getName()); + + public static DebugLogDialog debugDialog; + + public static boolean shouldCloseWhenClosingLoadingDialog; + + private static Debugger flashDebugger; + + private static DebuggerHandler debugHandler = null; + + //private static int ip = 0; + //private static String ipClass = null; + private static Process runProcess; + + private static boolean runProcessDebug; + + private static boolean runProcessDebugPCode; + + private static boolean inited = false; + + private static File runTempFile; + + private static List runTempFiles = new ArrayList<>(); + + public static void freeRun() { + synchronized (Main.class) { + if (runTempFile != null) { + runTempFile.delete(); + runTempFile = null; + } + for (File f : runTempFiles) { + f.delete(); + } + runTempFiles.clear(); + + runProcess = null; + } + if (mainFrame != null && mainFrame.getPanel() != null) { + mainFrame.getPanel().clearDebuggerColors(); + } + if (runProcessDebug) { + Main.getDebugHandler().disconnect(); + } + } + + public static synchronized boolean isDebugPaused() { + return runProcess != null && runProcessDebug && getDebugHandler().isPaused(); + } + + public static synchronized boolean isDebugRunning() { + return runProcess != null && runProcessDebug; + } + + public static synchronized boolean isDebugPCode() { + return runProcessDebugPCode; + } + + public static synchronized boolean isDebugConnected() { + return getDebugHandler().isConnected(); + } + + public static synchronized boolean isRunning() { + return runProcess != null && !runProcessDebug; + } + + /** + * FIXME! + * + * @param v + */ + public static synchronized void dumpBytes(Variable v) { + InCallFunction icf; + try { + long objectId = 0l; + if ((v.vType == VariableType.OBJECT || v.vType == VariableType.MOVIECLIP)) { + objectId = (Long) v.value; + } + Object oldPos = getDebugHandler().getVariable(objectId, "position", true).parent.value; + getDebugHandler().setVariable(objectId, "position", VariableType.NUMBER, 0); + icf = getDebugHandler().callFunction(false, "readUTF", v, new ArrayList<>()); + System.out.println("Result=" + icf.variables.get(0).value); + getDebugHandler().setVariable(objectId, "position", VariableType.NUMBER, oldPos); + } catch (DebuggerHandler.ActionScriptException ex) { + Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); + } + + } + + public static synchronized boolean addWatch(Variable v, long v_id, boolean watchRead, boolean watchWrite) { + DebuggerCommands.Watch w = getDebugHandler().addWatch(v, v_id, watchRead, watchWrite); + return w != null; + } + + public static void runPlayer(String title, final String exePath, String file, String flashVars) { + if (!new File(file).exists()) { + return; + } + if (flashVars != null && !flashVars.isEmpty()) { + file += "?" + flashVars; + } + final String ffile = file; + + CancellableWorker runWorker = new CancellableWorker() { + @Override + protected Object doInBackground() throws Exception { + Process proc; + try { + proc = Runtime.getRuntime().exec(new String[]{exePath, ffile}); + } catch (IOException ex) { + logger.log(Level.SEVERE, null, ex); + return null; + } + boolean isDebug; + + synchronized (Main.class) { + runProcess = proc; + isDebug = runProcessDebug; + } + if (isDebug) { + mainFrame.getMenu().hilightPath("/debugging"); + } + mainFrame.getMenu().updateComponents(); + try { + if (proc != null) { + proc.waitFor(); + } + } catch (InterruptedException ex) { + if (proc != null) { + try { + proc.destroy(); + } catch (Exception ex2) { + //ignore + } + } + } + freeRun(); + stopDebugger(); + mainFrame.getMenu().updateComponents(); + return null; + } + + @Override + protected void done() { + Main.stopWork(); + } + + @Override + public void workerCancelled() { + Main.stopWork(); + synchronized (Main.class) { + if (runProcess != null) { + try { + runProcess.destroy(); + } catch (Exception ex) { + + } + } + } + freeRun(); + mainFrame.getMenu().updateComponents(); + } + }; + + mainFrame.getMenu().updateComponents(); + Main.startWork(title + "...", runWorker); + runWorker.execute(); + } + + public static void stopRun() { + + synchronized (Main.class) { + if (runProcess != null) { + runProcess.destroy(); + } + } + freeRun(); + stopDebugger(); + mainFrame.getMenu().updateComponents(); + } + + private static interface SwfPreparation { + + public SWF prepare(SWF swf); + } + + private static class SwfRunPrepare implements SwfPreparation { + + @Override + public SWF prepare(SWF swf) { + if (Configuration.autoOpenLoadedSWFs.get()) { + if (!DebuggerTools.hasDebugger(swf)) { + DebuggerTools.switchDebugger(swf); + } + DebuggerTools.injectDebugLoader(swf); + } + return swf; + } + } + + private static class SwfDebugPrepare extends SwfRunPrepare { + + private boolean doPCode; + + public SwfDebugPrepare(boolean doPCode) { + this.doPCode = doPCode; + } + + @Override + public SWF prepare(SWF instrSWF) { + instrSWF = super.prepare(instrSWF); + try { + File fTempFile = new File(instrSWF.getFile()); + instrSWF.enableDebugging(true, new File("."), true, doPCode); + FileOutputStream fos = new FileOutputStream(fTempFile); + instrSWF.saveTo(fos); + fos.close(); + if (!instrSWF.isAS3()) { + //Read again, because line file offsets changed with adding debug tags + //TODO: handle somehow without rereading? + instrSWF = null; + try (FileInputStream fis = new FileInputStream(fTempFile)) { + instrSWF = new SWF(fis, false, false); + } catch (InterruptedException ex) { + logger.log(Level.SEVERE, null, ex); + } + if (instrSWF != null) { + String swfFileName = fTempFile.getAbsolutePath(); + if (swfFileName.toLowerCase().endsWith(".swf")) { + swfFileName = swfFileName.substring(0, swfFileName.length() - 4) + ".swd"; + } else { + swfFileName = swfFileName + ".swd"; + } + File swdFile = new File(swfFileName); + if (doPCode) { + instrSWF.generatePCodeSwdFile(swdFile, getPackBreakPoints(true)); + } else { + instrSWF.generateSwdFile(swdFile, getPackBreakPoints(true)); + } + } + } + } catch (IOException ex) { + //ignore, return instrSWF + } + return instrSWF; + } + } + + private static void prepareSwf(SwfPreparation prep, File toPrepareFile, File origFile, List tempFiles) throws IOException { + SWF instrSWF = null; + try (FileInputStream fis = new FileInputStream(toPrepareFile)) { + instrSWF = new SWF(fis, toPrepareFile.getAbsolutePath(), origFile.getName(), false); + } catch (InterruptedException ex) { + logger.log(Level.SEVERE, null, ex); + } + if (instrSWF != null) { + for (Tag t : instrSWF.getLocalTags()) { + if (t instanceof ImportTag) { + ImportTag it = (ImportTag) t; + String url = it.getUrl(); + File importedFile = new File(origFile.getParentFile(), url); + if (importedFile.exists()) { + File newTempFile = File.createTempFile("ffdec_run_import_", ".swf"); + it.setUrl("./" + newTempFile.getName()); + byte[] impData = Helper.readFile(importedFile.getAbsolutePath()); + Helper.writeFile(newTempFile.getAbsolutePath(), impData); + tempFiles.add(newTempFile); + prepareSwf(prep, newTempFile, importedFile, tempFiles); + } + } + } + if (prep != null) { + instrSWF = prep.prepare(instrSWF); + } + try (FileOutputStream fos = new FileOutputStream(toPrepareFile)) { + instrSWF.saveTo(fos); + } + } + } + + public static void run(SWF swf) { + String flashVars = "";//key=val&key2=val2 + String playerLocation = Configuration.playerLocation.get(); + if (playerLocation.isEmpty() || (!new File(playerLocation).exists())) { + View.showMessageDialog(null, AppStrings.translate("message.playerpath.notset"), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE); + advancedSettings("paths"); + return; + } + if (swf == null) { + return; + } + File tempFile; + List tempFiles = new ArrayList<>(); + try { + tempFile = File.createTempFile("ffdec_run_", ".swf"); + + try (FileOutputStream fos = new FileOutputStream(tempFile)) { + swf.saveTo(fos); + } + + prepareSwf(new SwfRunPrepare(), tempFile, new File(swf.getFile()), tempFiles); + + } catch (IOException ex) { + return; + + } + if (tempFile != null) { + synchronized (Main.class) { + runTempFile = tempFile; + runTempFiles = tempFiles; + runProcessDebug = false; + } + runPlayer(AppStrings.translate("work.running"), playerLocation, tempFile.getAbsolutePath(), flashVars); + } + } + + public static void runDebug(SWF swf, final boolean doPCode) { + String flashVars = "";//key=val&key2=val2 + String playerLocation = Configuration.playerDebugLocation.get(); + if (playerLocation.isEmpty() || (!new File(playerLocation).exists())) { + View.showMessageDialog(null, AppStrings.translate("message.playerpath.debug.notset"), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE); + Main.advancedSettings("paths"); + return; + } + if (swf == null) { + return; + } + File tempFile = null; + + try { + tempFile = File.createTempFile("ffdec_debug_", ".swf"); + } catch (Exception ex) { + + } + + if (tempFile != null) { + final File fTempFile = tempFile; + final List tempFiles = new ArrayList<>(); + CancellableWorker instrumentWorker = new CancellableWorker() { + @Override + protected Object doInBackground() throws Exception { + + try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(fTempFile))) { + swf.saveTo(fos); + } + prepareSwf(new SwfDebugPrepare(doPCode), fTempFile, new File(swf.getFile()), tempFiles); + return null; + } + + @Override + public void workerCancelled() { + Main.stopWork(); + } + + @Override + protected void done() { + synchronized (Main.class) { + runTempFile = fTempFile; + runProcessDebug = true; + runProcessDebugPCode = doPCode; + runTempFiles = tempFiles; + } + Main.stopWork(); + Main.startDebugger(); + runPlayer(AppStrings.translate("work.debugging.wait"), playerLocation, fTempFile.getAbsolutePath(), flashVars); + } + }; + + Main.startWork(AppStrings.translate("work.debugging.instrumenting"), instrumentWorker); + instrumentWorker.execute(); + } + } + + /* public static void debuggerNotSuspended() { + + }*/ + public static boolean isDebugging() { + return isDebugRunning(); + } + + public synchronized static int getIp(Object pack) { + return getDebugHandler().getBreakIp(); + } + + public synchronized static String getIpClass() { + return getDebugHandler().getBreakScriptName(); + } + + public static synchronized boolean isBreakPointValid(String scriptName, int line) { + return !getDebugHandler().isBreakpointInvalid(scriptName, line); + } + + public synchronized static void addBreakPoint(String scriptName, int line) { + getDebugHandler().addBreakPoint(scriptName, line); + } + + public synchronized static void removeBreakPoint(String scriptName, int line) { + getDebugHandler().removeBreakPoint(scriptName, line); + } + + public synchronized static boolean toggleBreakPoint(String scriptName, int line) { + if (getDebugHandler().isBreakpointToAdd(scriptName, line) || getDebugHandler().isBreakpointConfirmed(scriptName, line) || getDebugHandler().isBreakpointInvalid(scriptName, line)) { + getDebugHandler().removeBreakPoint(scriptName, line); + return false; + } else { + getDebugHandler().addBreakPoint(scriptName, line); + return true; + } + } + + public synchronized static Map> getPackBreakPoints(boolean validOnly) { + return getDebugHandler().getAllBreakPoints(validOnly); + } + + public synchronized static Set getScriptBreakPoints(String pack, boolean onlyValid) { + return getDebugHandler().getBreakPoints(pack, onlyValid); + } + + public static DebuggerHandler getDebugHandler() { + return debugHandler; + } + + public static void ensureMainFrame() { + if (mainFrame == null) { + synchronized (Main.class) { + if (mainFrame == null) { + MainFrame frame; + if (Configuration.useRibbonInterface.get()) { + frame = new MainFrameRibbon(); + } else { + frame = new MainFrameClassic(); + } + frame.getPanel().setErrorState(ErrorLogFrame.getInstance().getErrorState()); + mainFrame = frame; + } + } + } + } + + public static MainFrame getMainFrame() { + return mainFrame; + } + + public static void loadFromCache() { + if (loadFromCacheFrame == null) { + loadFromCacheFrame = new LoadFromCacheFrame(); + } + loadFromCacheFrame.setVisible(true); + } + + public static void loadFromMemory() { + if (loadFromMemoryFrame == null) { + loadFromMemoryFrame = new LoadFromMemoryFrame(mainFrame); + } + loadFromMemoryFrame.setVisible(true); + } + + public static void setVariable(long parentId, String varName, int valueType, Object value) { + getDebugHandler().setVariable(parentId, varName, valueType, value); + } + + public static void setSubLimiter(boolean value) { + if (value) { + AVM2Code.toSourceLimit = Configuration.sublimiter.get(); + } else { + AVM2Code.toSourceLimit = -1; + } + } + + public synchronized static boolean isInited() { + return inited; + } + + public synchronized static void setSessionLoaded(boolean v) { + inited = v; + } + + public static boolean isWorking() { + return working; + } + + public static void startProxy(int port) { + if (proxyFrame == null) { + proxyFrame = new ProxyFrame(mainFrame); + } + + proxyFrame.setPort(port); + addTrayIcon(); + switchProxy(); + } + + public static void showProxy() { + if (proxyFrame == null) { + proxyFrame = new ProxyFrame(mainFrame); + } + proxyFrame.setVisible(true); + proxyFrame.setState(Frame.NORMAL); + } + + public static void startWork(String name, CancellableWorker worker) { + startWork(name, -1, worker); + } + + public static void startWork(final String name, final int percent, final CancellableWorker worker) { + working = true; + View.execInEventDispatchLater(() -> { + if (mainFrame != null) { + mainFrame.getPanel().setWorkStatus(name, worker); + if (percent == -1) { + mainFrame.getPanel().hidePercent(); + } else { + mainFrame.getPanel().setPercent(percent); + } + } + if (loadingDialog != null) { + loadingDialog.setDetail(name); + loadingDialog.setPercent(percent); + } + if (CommandLineArgumentParser.isCommandLineMode()) { + System.out.println(name); + } + }); + } + + public static void stopWork() { + working = false; + View.execInEventDispatchLater(() -> { + if (mainFrame != null) { + mainFrame.getPanel().setWorkStatus("", null); + } + if (loadingDialog != null) { + loadingDialog.setDetail(""); + } + }); + } + + public static SWFList parseSWF(SWFSourceInfo sourceInfo) throws Exception { + SWFList result = new SWFList(); + + InputStream inputStream = sourceInfo.getInputStream(); + SWFBundle bundle = null; + FileInputStream fis = null; + if (inputStream == null) { + inputStream = new BufferedInputStream(fis = new FileInputStream(sourceInfo.getFile())); + bundle = sourceInfo.getBundle(false, SearchMode.ALL); + logger.log(Level.INFO, "Load file: {0}", sourceInfo.getFile()); + } else if (inputStream instanceof SeekableInputStream + || inputStream instanceof BufferedInputStream) { + try { + inputStream.reset(); + } catch (IOException ex) { + logger.log(Level.SEVERE, null, ex); + } + logger.log(Level.INFO, "Load stream: {0}", sourceInfo.getFileTitle()); + } + + Stopwatch sw = Stopwatch.startNew(); + if (bundle != null) { + result.bundle = bundle; + result.name = new File(sourceInfo.getFileTitleOrName()).getName(); + for (Entry streamEntry : bundle.getAll().entrySet()) { + InputStream stream = streamEntry.getValue(); + stream.reset(); + CancellableWorker worker = new CancellableWorker() { + @Override + public SWF doInBackground() throws Exception { + final CancellableWorker worker = this; + SWF swf = new SWF(stream, null, streamEntry.getKey(), new ProgressListener() { + @Override + public void progress(int p) { + startWork(AppStrings.translate("work.reading.swf"), p, worker); + } + }, Configuration.parallelSpeedUp.get()); + return swf; + } + }; + loadingDialog.setWroker(worker); + worker.execute(); + + try { + result.add(worker.get()); + } catch (CancellationException ex) { + logger.log(Level.WARNING, "Loading SWF {0} was cancelled.", streamEntry.getKey()); + } + } + } else { + InputStream fInputStream = inputStream; + + final String[] yesno = new String[]{AppStrings.translate("button.yes"), AppStrings.translate("button.no"), AppStrings.translate("button.yes.all"), AppStrings.translate("button.no.all")}; + + CancellableWorker worker = new CancellableWorker() { + private boolean yestoall = false; + + private boolean notoall = false; + + private SWF open(InputStream is, String file, String fileTitle) throws IOException, InterruptedException { + final CancellableWorker worker = this; + + SWF swf = new SWF(is, file, fileTitle, new ProgressListener() { + @Override + public void progress(int p) { + startWork(AppStrings.translate("work.reading.swf"), p, worker); + } + }, Configuration.parallelSpeedUp.get(), false, true, new UrlResolver() { + @Override + public SWF resolveUrl(final String url) { + int opt = -1; + if (!(yestoall || notoall)) { + opt = View.showOptionDialog(null, AppStrings.translate("message.imported.swf").replace("%url%", url), AppStrings.translate("message.warning"), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, yesno, AppStrings.translate("button.yes")); + if (opt == 2) { + yestoall = true; + } + if (opt == 3) { + notoall = true; + } + } + + if (yestoall) { + opt = 0; // yes + } else if (notoall) { + opt = 1; // no + } + + if (opt == 1) //no + { + return null; + } + + if (url.startsWith("http://") || url.startsWith("https://")) { + try { + URL u = new URL(url); + return open(u.openStream(), null, url); //? + } catch (Exception ex) { + //ignore + } + } else { + File f = new File(new File(file).getParentFile(), url); + if (f.exists()) { + try { + return open(new FileInputStream(f), f.getAbsolutePath(), f.getName()); + } catch (Exception ex) { + //ignore + } + } + } + Reference ret = new Reference<>(null); + View.execInEventDispatch(new Runnable() { + @Override + public void run() { + + while (JOptionPane.YES_OPTION == View.showConfirmDialog(null, AppStrings.translate("message.imported.swf.manually").replace("%url%", url), AppStrings.translate("error"), JOptionPane.YES_NO_OPTION, JOptionPane.ERROR_MESSAGE)) { + + JFileChooser fc = new JFileChooser(); + fc.setCurrentDirectory(new File(Configuration.lastOpenDir.get())); + FileFilter allSupportedFilter = new FileFilter() { + private final String[] supportedExtensions = new String[]{".swf", ".gfx"}; + + @Override + public boolean accept(File f) { + String name = f.getName().toLowerCase(); + for (String ext : supportedExtensions) { + if (name.endsWith(ext)) { + return true; + } + } + return f.isDirectory(); + } + + @Override + public String getDescription() { + String exts = Helper.joinStrings(supportedExtensions, "*%s", "; "); + return AppStrings.translate("filter.supported") + " (" + exts + ")"; + } + }; + fc.setFileFilter(allSupportedFilter); + FileFilter swfFilter = new FileFilter() { + @Override + public boolean accept(File f) { + return (f.getName().toLowerCase().endsWith(".swf")) || (f.isDirectory()); + } + + @Override + public String getDescription() { + return AppStrings.translate("filter.swf"); + } + }; + fc.addChoosableFileFilter(swfFilter); + + FileFilter gfxFilter = new FileFilter() { + @Override + public boolean accept(File f) { + return (f.getName().toLowerCase().endsWith(".gfx")) || (f.isDirectory()); + } + + @Override + public String getDescription() { + return AppStrings.translate("filter.gfx"); + } + }; + fc.addChoosableFileFilter(gfxFilter); + fc.setAcceptAllFileFilterUsed(false); + JFrame f = new JFrame(); + View.setWindowIcon(f); + int returnVal = fc.showOpenDialog(f); + if (returnVal == JFileChooser.APPROVE_OPTION) { + Configuration.lastOpenDir.set(Helper.fixDialogFile(fc.getSelectedFile()).getParentFile().getAbsolutePath()); + File selFile = Helper.fixDialogFile(fc.getSelectedFile()); + try { + ret.setVal(open(new FileInputStream(selFile), selFile.getAbsolutePath(), selFile.getName())); + break; + } catch (Exception ex) { + //ignore; + } + } else { + break; + } + } + } + }); + return ret.getVal(); + } + }); + return swf; + } + + @Override + public SWF doInBackground() throws Exception { + return open(fInputStream, sourceInfo.getFile(), sourceInfo.getFileTitle()); + } + }; + if (loadingDialog != null) { + loadingDialog.setWroker(worker); + } + worker.execute(); + + try { + result.add(worker.get()); + } catch (CancellationException ex) { + logger.log(Level.WARNING, "Loading SWF {0} was cancelled.", sourceInfo.getFileTitleOrName()); + } + } + + if (fis != null) { + logger.log(Level.INFO, "File loaded in {0} seconds.", (sw.getElapsedMilliseconds() / 1000)); + fis.close(); + } else { + logger.log(Level.INFO, "Stream loaded in {0} seconds.", (sw.getElapsedMilliseconds() / 1000)); + } + + result.sourceInfo = sourceInfo; + for (SWF swf : result) { + logger.log(Level.INFO, ""); + logger.log(Level.INFO, "== File information =="); + logger.log(Level.INFO, "Size: {0}", Helper.formatFileSize(swf.fileSize)); + logger.log(Level.INFO, "Flash version: {0}", swf.version); + int width = (int) ((swf.displayRect.Xmax - swf.displayRect.Xmin) / SWF.unitDivisor); + int height = (int) ((swf.displayRect.Ymax - swf.displayRect.Ymin) / SWF.unitDivisor); + logger.log(Level.INFO, "Width: {0}", width); + logger.log(Level.INFO, "Height: {0}", height); + + swf.swfList = result; + swf.addEventListener(new EventListener() { + @Override + public void handleExportingEvent(String type, int index, int count, Object data) { + String text = AppStrings.translate("work.exporting"); + if (type != null && type.length() > 0) { + text += " " + type; + } + + startWork(text + " " + index + "/" + count + " " + data, null); + } + + @Override + public void handleExportedEvent(String type, int index, int count, Object data) { + String text = AppStrings.translate("work.exported"); + if (type != null && type.length() > 0) { + text += " " + type; + } + + startWork(text + " " + index + "/" + count + " " + data, null); + } + + @Override + public void handleEvent(String event, Object data) { + if (event.equals("exporting") || event.equals("exported")) { + throw new Error("Event is not supported by this handler."); + } + if (event.equals("getVariables")) { + startWork(AppStrings.translate("work.gettingvariables") + "..." + (String) data, null); + } + if (event.equals("deobfuscate")) { + startWork(AppStrings.translate("work.deobfuscating") + "..." + (String) data, null); + } + if (event.equals("rename")) { + startWork(AppStrings.translate("work.renaming") + "..." + (String) data, null); + } + } + }); + } + + return result; + } + + public static void saveFile(SWF swf, String outfile) throws IOException { + saveFile(swf, outfile, SaveFileMode.SAVE, null); + } + + public static void saveFile(SWF swf, String outfile, SaveFileMode mode, ExeExportMode exeExportMode) throws IOException { + if (mode == SaveFileMode.SAVEAS && !swf.swfList.isBundle()) { + swf.setFile(outfile); + swf.swfList.sourceInfo.setFile(outfile); + } + File outfileF = new File(outfile); + File tmpFile = new File(outfile + ".tmp"); + try (FileOutputStream fos = new FileOutputStream(tmpFile); + BufferedOutputStream bos = new BufferedOutputStream(fos)) { + if (mode == SaveFileMode.EXE) { + switch (exeExportMode) { + case WRAPPER: + InputStream exeStream = View.class.getClassLoader().getResourceAsStream("com/jpexs/helpers/resource/Swf2Exe.bin"); + Helper.copyStream(exeStream, bos); + int width = swf.displayRect.Xmax - swf.displayRect.Xmin; + int height = swf.displayRect.Ymax - swf.displayRect.Ymin; + bos.write(width & 0xff); + bos.write((width >> 8) & 0xff); + bos.write((width >> 16) & 0xff); + bos.write((width >> 24) & 0xff); + bos.write(height & 0xff); + bos.write((height >> 8) & 0xff); + bos.write((height >> 16) & 0xff); + bos.write((height >> 24) & 0xff); + bos.write(Configuration.saveAsExeScaleMode.get()); + break; + case PROJECTOR_WIN: + case PROJECTOR_MAC: + case PROJECTOR_LINUX: + File projectorFile = Configuration.getProjectorFile(exeExportMode); + if (projectorFile == null) { + String message = "Projector not found, please place it to " + Configuration.getProjectorPath(); + logger.log(Level.SEVERE, message); + throw new IOException(message); + } + Helper.copyStream(new FileInputStream(projectorFile), bos); + bos.flush(); + break; + } + } + + long pos = fos.getChannel().position(); + swf.saveTo(bos); + + if (mode == SaveFileMode.EXE) { + switch (exeExportMode) { + case PROJECTOR_WIN: + case PROJECTOR_MAC: + case PROJECTOR_LINUX: + bos.flush(); + int swfSize = (int) (fos.getChannel().position() - pos); + + // write magic number + bos.write(0x56); + bos.write(0x34); + bos.write(0x12); + bos.write(0xfa); + + bos.write(swfSize & 0xff); + bos.write((swfSize >> 8) & 0xff); + bos.write((swfSize >> 16) & 0xff); + bos.write((swfSize >> 24) & 0xff); + } + } + } + if (tmpFile.exists()) { + if (tmpFile.length() > 0) { + outfileF.delete(); + if (!tmpFile.renameTo(outfileF)) { + tmpFile.delete(); + throw new IOException("Cannot access " + outfile); + } + } else { + throw new IOException("Output is empty"); + } + } else { + throw new IOException("Output not found"); + } + } + + private static class OpenFileWorker extends SwingWorker { + + private final SWFSourceInfo[] sourceInfos; + + private final Runnable executeAfterOpen; + + private final int[] reloadIndices; + + public OpenFileWorker(SWFSourceInfo sourceInfo) { + this(sourceInfo, -1); + } + + public OpenFileWorker(SWFSourceInfo sourceInfo, int reloadIndex) { + this(sourceInfo, null, reloadIndex); + } + + public OpenFileWorker(SWFSourceInfo sourceInfo, Runnable executeAfterOpen) { + this(sourceInfo, executeAfterOpen, -1); + } + + public OpenFileWorker(SWFSourceInfo sourceInfo, Runnable executeAfterOpen, int reloadIndex) { + this.sourceInfos = new SWFSourceInfo[]{sourceInfo}; + this.executeAfterOpen = executeAfterOpen; + this.reloadIndices = new int[]{reloadIndex}; + } + + public OpenFileWorker(SWFSourceInfo[] sourceInfos) { + this(sourceInfos, null, null); + } + + public OpenFileWorker(SWFSourceInfo[] sourceInfos, Runnable executeAfterOpen) { + this(sourceInfos, executeAfterOpen, null); + } + + public OpenFileWorker(SWFSourceInfo[] sourceInfos, Runnable executeAfterOpen, int[] reloadIndices) { + this.sourceInfos = sourceInfos; + this.executeAfterOpen = executeAfterOpen; + int[] indices = new int[sourceInfos.length]; + for (int i = 0; i < indices.length; i++) { + indices[i] = -1; + } + this.reloadIndices = reloadIndices == null ? indices : reloadIndices; + } + + @Override + protected Object doInBackground() throws Exception { + boolean first = true; + SWF firstSWF = null; + for (int index = 0; index < sourceInfos.length; index++) { + SWFSourceInfo sourceInfo = sourceInfos[index]; + SWFList swfs = null; + try { + Main.startWork(AppStrings.translate("work.reading.swf") + "...", null); + try { + swfs = parseSWF(sourceInfo); + } catch (ExecutionException ex) { + Throwable cause = ex.getCause(); + if (cause instanceof SwfOpenException) { + throw (SwfOpenException) cause; + } + + throw ex; + } + } catch (OutOfMemoryError ex) { + logger.log(Level.SEVERE, null, ex); + View.showMessageDialog(null, "Cannot load SWF file. Out of memory."); + continue; + } catch (SwfOpenException ex) { + logger.log(Level.SEVERE, null, ex); + View.showMessageDialog(null, ex.getMessage()); + continue; + } catch (Exception ex) { + logger.log(Level.SEVERE, null, ex); + View.showMessageDialog(null, "Cannot load SWF file."); + continue; + } + + final SWFList swfs1 = swfs; + final boolean first1 = first; + first = false; + if (firstSWF == null && swfs1.size() > 0) { + firstSWF = swfs1.get(0); + } + + final int findex = index; + try { + View.execInEventDispatch(() -> { + Main.startWork(AppStrings.translate("work.creatingwindow") + "...", null); + ensureMainFrame(); + if (reloadIndices[findex] > -1) { + mainFrame.getPanel().loadSwfAtPos(swfs1, reloadIndices[findex]); + } else { + mainFrame.getPanel().load(swfs1, first1); + } + }); + } catch (Exception ex) { + logger.log(Level.SEVERE, null, ex); + } + } + + loadingDialog.setVisible(false); + shouldCloseWhenClosingLoadingDialog = false; + + final SWF fswf = firstSWF; + View.execInEventDispatch(() -> { + if (mainFrame != null) { + mainFrame.setVisible(true); + } + + Main.stopWork(); + + if (mainFrame != null && Configuration.gotoMainClassOnStartup.get()) { + mainFrame.getPanel().gotoDocumentClass(fswf); + } + + if (mainFrame != null && fswf != null) { + SwfSpecificConfiguration swfConf = Configuration.getSwfSpecificConfiguration(fswf.getShortFileName()); + if (swfConf != null) { + String pathStr = swfConf.lastSelectedPath; + mainFrame.getPanel().tagTree.setSelectionPathString(pathStr); + } + } + + if (executeAfterOpen != null) { + executeAfterOpen.run(); + } + }); + + return true; + } + } + + public static boolean reloadSWFs() { + CancellableWorker.cancelBackgroundThreads(); + if (Main.sourceInfos.isEmpty()) { + Helper.freeMem(); + showModeFrame(); + return true; + } else { + SWFSourceInfo[] sourceInfosCopy = new SWFSourceInfo[sourceInfos.size()]; + sourceInfos.toArray(sourceInfosCopy); + sourceInfos.clear(); + openFile(sourceInfosCopy); + return true; + } + } + + public static void reloadApp() { + if (debugDialog != null) { + debugDialog.setVisible(false); + debugDialog.dispose(); + debugDialog = null; + } + if (loadingDialog != null) { + synchronized (Main.class) { + if (loadingDialog != null) { + loadingDialog.setVisible(false); + loadingDialog.dispose(); + loadingDialog = null; + } + } + } + if (proxyFrame != null) { + proxyFrame.setVisible(false); + proxyFrame.dispose(); + proxyFrame = null; + } + if (loadFromMemoryFrame != null) { + loadFromMemoryFrame.setVisible(false); + loadFromMemoryFrame.dispose(); + loadFromMemoryFrame = null; + } + if (loadFromCacheFrame != null) { + loadFromCacheFrame.setVisible(false); + loadFromCacheFrame.dispose(); + loadFromCacheFrame = null; + } + if (mainFrame != null) { + mainFrame.setVisible(false); + mainFrame.getPanel().closeAll(false); + mainFrame.dispose(); + mainFrame = null; + } + FontTag.reload(); + Cache.clearAll(); + initGui(); + reloadSWFs(); + } + + public static OpenFileResult openFile(String swfFile, String fileTitle) { + return openFile(swfFile, fileTitle, null); + } + + public static OpenFileResult openFile(String swfFile, String fileTitle, Runnable executeAfterOpen) { + try { + File file = new File(swfFile); + if (!file.exists()) { + View.showMessageDialog(null, AppStrings.translate("open.error.fileNotFound"), AppStrings.translate("open.error"), JOptionPane.ERROR_MESSAGE); + return OpenFileResult.NOT_FOUND; + } + swfFile = file.getCanonicalPath(); + SWFSourceInfo sourceInfo = new SWFSourceInfo(null, swfFile, fileTitle); + OpenFileResult openResult = openFile(sourceInfo); + return openResult; + } catch (IOException ex) { + View.showMessageDialog(null, AppStrings.translate("open.error.cannotOpen"), AppStrings.translate("open.error"), JOptionPane.ERROR_MESSAGE); + return OpenFileResult.ERROR; + } + } + + public static OpenFileResult openFile(SWFSourceInfo sourceInfo) { + return openFile(new SWFSourceInfo[]{sourceInfo}); + } + + public static OpenFileResult openFile(SWFSourceInfo sourceInfo, Runnable executeAfterOpen) { + return openFile(new SWFSourceInfo[]{sourceInfo}, executeAfterOpen); + } + + public static OpenFileResult openFile(SWFSourceInfo sourceInfo, Runnable executeAfterOpen, int reloadIndex) { + return openFile(new SWFSourceInfo[]{sourceInfo}, executeAfterOpen, new int[]{reloadIndex}); + } + + public static OpenFileResult openFile(SWFSourceInfo[] newSourceInfos) { + return openFile(newSourceInfos, null); + } + + public static OpenFileResult openFile(SWFSourceInfo[] newSourceInfos, Runnable executeAfterOpen) { + return openFile(newSourceInfos, executeAfterOpen, null); + } + + public static OpenFileResult openFile(SWFSourceInfo[] newSourceInfos, Runnable executeAfterOpen, int[] reloadIndices) { + if (mainFrame != null && !Configuration.openMultipleFiles.get()) { + sourceInfos.clear(); + mainFrame.getPanel().closeAll(false); + mainFrame.setVisible(false); + Helper.freeMem(); + reloadIndices = null; + } + + loadingDialog.setVisible(true); + + for (int i = 0; i < newSourceInfos.length; i++) { + SWFSourceInfo si = newSourceInfos[i]; + String fileName = si.getFile(); + if (fileName != null) { + Configuration.addRecentFile(fileName); + } + } + + OpenFileWorker wrk = new OpenFileWorker(newSourceInfos, executeAfterOpen, reloadIndices); + wrk.execute(); + if (reloadIndices == null) { + sourceInfos.addAll(Arrays.asList(newSourceInfos)); + } else { + for (int i = 0; i < reloadIndices.length; i++) { + sourceInfos.set(reloadIndices[i], newSourceInfos[i]); + } + } + return OpenFileResult.OK; + } + + public static void closeFile(SWFList swf) { + sourceInfos.remove(swf.sourceInfo); + mainFrame.getPanel().close(swf); + } + + public static void reloadFile(SWFList swf) { + //mainFrame.getPanel().close(swf); + openFile(swf.sourceInfo, null, sourceInfos.indexOf(swf.sourceInfo)); + } + + public static boolean closeAll() { + boolean closeResult = mainFrame.getPanel().closeAll(true); + if (closeResult) { + sourceInfos.clear(); + } + + return closeResult; + } + + public static boolean saveFileDialog(SWF swf, final SaveFileMode mode) { + JFileChooser fc = new JFileChooser(); + fc.setCurrentDirectory(new File(Configuration.lastSaveDir.get())); + String ext = ".swf"; + switch (mode) { + case SAVE: + case SAVEAS: + if (swf.getFile() != null) { + ext = Path.getExtension(swf.getFile()); + } + break; + case EXE: + ext = ".exe"; + break; + } + + FileFilter swfFilter = new FileFilter() { + @Override + public boolean accept(File f) { + return (f.getName().toLowerCase().endsWith(".swf")) || (f.isDirectory()); + } + + @Override + public String getDescription() { + return AppStrings.translate("filter.swf"); + } + }; + + FileFilter gfxFilter = new FileFilter() { + @Override + public boolean accept(File f) { + return (f.getName().toLowerCase().endsWith(".gfx")) || (f.isDirectory()); + } + + @Override + public String getDescription() { + return AppStrings.translate("filter.gfx"); + } + }; + + ExeExportMode exeExportMode = null; + if (mode == SaveFileMode.EXE) { + exeExportMode = Configuration.exeExportMode.get(); + if (exeExportMode == null) { + exeExportMode = ExeExportMode.WRAPPER; + } + String filterDescription = null; + switch (exeExportMode) { + case WRAPPER: + case PROJECTOR_WIN: + ext = ".exe"; + filterDescription = "filter.exe"; + break; + case PROJECTOR_MAC: + ext = ".dmg"; + filterDescription = "filter.dmg"; + break; + case PROJECTOR_LINUX: + // linux projector is compressed with tar.gz + // todo: decompress + ext = ""; + filterDescription = "filter.linuxExe"; + break; + } + + String fext = ext; + String ffilterDescription = filterDescription; + FileFilter exeFilter = new FileFilter() { + @Override + public boolean accept(File f) { + return (f.getName().toLowerCase().endsWith(fext)) || (f.isDirectory()); + } + + @Override + public String getDescription() { + return AppStrings.translate(ffilterDescription); + } + }; + fc.setFileFilter(exeFilter); + } else if (swf.gfx) { + fc.addChoosableFileFilter(swfFilter); + fc.setFileFilter(gfxFilter); + } else { + fc.setFileFilter(swfFilter); + fc.addChoosableFileFilter(gfxFilter); + } + final String extension = ext; + fc.setAcceptAllFileFilterUsed(false); + JFrame f = new JFrame(); + View.setWindowIcon(f); + if (fc.showSaveDialog(f) == JFileChooser.APPROVE_OPTION) { + File file = Helper.fixDialogFile(fc.getSelectedFile()); + FileFilter selFilter = fc.getFileFilter(); + try { + String fileName = file.getAbsolutePath(); + if (selFilter == swfFilter) { + if (!fileName.toLowerCase().endsWith(extension)) { + fileName += extension; + } + swf.gfx = false; + } + if (selFilter == gfxFilter) { + if (!fileName.toLowerCase().endsWith(".gfx")) { + fileName += ".gfx"; + } + swf.gfx = true; + } + Main.saveFile(swf, fileName, mode, exeExportMode); + Configuration.lastSaveDir.set(file.getParentFile().getAbsolutePath()); + return true; + } catch (IOException ex) { + View.showMessageDialog(null, AppStrings.translate("error.file.write")); + } + } + return false; + } + + public static boolean openFileDialog() { + JFileChooser fc = new JFileChooser(); + if (Configuration.openMultipleFiles.get()) { + fc.setMultiSelectionEnabled(true); + } + fc.setCurrentDirectory(new File(Configuration.lastOpenDir.get())); + FileFilter allSupportedFilter = new FileFilter() { + private final String[] supportedExtensions = new String[]{".swf", ".gfx", ".swc", ".zip", ".iggy"}; + + @Override + public boolean accept(File f) { + String name = f.getName().toLowerCase(); + for (String ext : supportedExtensions) { + if (name.endsWith(ext)) { + return true; + } + } + return f.isDirectory(); + } + + @Override + public String getDescription() { + String exts = Helper.joinStrings(supportedExtensions, "*%s", "; "); + return AppStrings.translate("filter.supported") + " (" + exts + ")"; + } + }; + fc.setFileFilter(allSupportedFilter); + FileFilter swfFilter = new FileFilter() { + @Override + public boolean accept(File f) { + return (f.getName().toLowerCase().endsWith(".swf")) || (f.isDirectory()); + } + + @Override + public String getDescription() { + return AppStrings.translate("filter.swf"); + } + }; + fc.addChoosableFileFilter(swfFilter); + + FileFilter swcFilter = new FileFilter() { + @Override + public boolean accept(File f) { + return (f.getName().toLowerCase().endsWith(".swc")) || (f.isDirectory()); + } + + @Override + public String getDescription() { + return AppStrings.translate("filter.swc"); + } + }; + fc.addChoosableFileFilter(swcFilter); + + FileFilter gfxFilter = new FileFilter() { + @Override + public boolean accept(File f) { + return (f.getName().toLowerCase().endsWith(".gfx")) || (f.isDirectory()); + } + + @Override + public String getDescription() { + return AppStrings.translate("filter.gfx"); + } + }; + fc.addChoosableFileFilter(gfxFilter); + + FileFilter iggyFilter = new FileFilter() { + @Override + public boolean accept(File f) { + return (f.getName().toLowerCase().endsWith(".iggy")) || (f.isDirectory()); + } + + @Override + public String getDescription() { + return AppStrings.translate("filter.iggy"); + } + }; + fc.addChoosableFileFilter(iggyFilter); + + FileFilter zipFilter = new FileFilter() { + @Override + public boolean accept(File f) { + return (f.getName().toLowerCase().endsWith(".zip")) || (f.isDirectory()); + } + + @Override + public String getDescription() { + return AppStrings.translate("filter.zip"); + } + }; + fc.addChoosableFileFilter(zipFilter); + + FileFilter binaryFilter = new FileFilter() { + @Override + public boolean accept(File f) { + return true; + } + + @Override + public String getDescription() { + return AppStrings.translate("filter.binary"); + } + }; + fc.addChoosableFileFilter(binaryFilter); + + fc.setAcceptAllFileFilterUsed(false); + JFrame f = new JFrame(); + View.setWindowIcon(f); + int returnVal = fc.showOpenDialog(f); + if (returnVal == JFileChooser.APPROVE_OPTION) { + Configuration.lastOpenDir.set(Helper.fixDialogFile(fc.getSelectedFile()).getParentFile().getAbsolutePath()); + File[] selFiles = fc.getSelectedFiles(); + for (File file : selFiles) { + File selfile = Helper.fixDialogFile(file); + Main.openFile(selfile.getAbsolutePath(), null); + } + return true; + } else { + return false; + } + } + + public static void displayErrorFrame() { + ErrorLogFrame.getInstance().setVisible(true); + } + + private static String md5(byte data[]) { + try { + java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5"); + byte[] array = md.digest(data); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < array.length; ++i) { + sb.append(Integer.toHexString((array[i] & 0xFF) | 0x100).substring(1, 3)); + } + return sb.toString(); + } catch (java.security.NoSuchAlgorithmException e) { + } + return null; + } + + private static void initGui() { + if (GraphicsEnvironment.isHeadless()) { + System.err.println("Error: Your system does not support Graphic User Interface"); + exit(); + } + + System.setProperty("sun.java2d.d3d", "false"); + System.setProperty("sun.java2d.noddraw", "true"); + + if (Configuration.hwAcceleratedGraphics.get()) { + System.setProperty("sun.java2d.opengl", Configuration._debugMode.get() ? "True" : "true"); + } else { + System.setProperty("sun.java2d.opengl", "false"); + } + + initUiLang(); + + if (Configuration.useRibbonInterface.get()) { + View.setLookAndFeel(); + } else { + try { + UIManager.put(SubstanceLookAndFeel.COLORIZATION_FACTOR, null); + UIManager.put("Tree.expandedIcon", null); + UIManager.put("Tree.collapsedIcon", null); + UIManager.put("ColorChooserUI", null); + UIManager.put("ColorChooser.swatchesRecentSwatchSize", null); + UIManager.put("ColorChooser.swatchesSwatchSize", null); + UIManager.put("RibbonApplicationMenuPopupPanelUI", null); + UIManager.put("RibbonApplicationMenuButtonUI", null); + UIManager.put("ProgressBarUI", null); + UIManager.put("TextField.background", null); + UIManager.put("FormattedTextField.background", null); + UIManager.put("CommandButtonUI", null); + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { + logger.log(Level.SEVERE, null, ex); + } + } + + View.execInEventDispatch(() -> { + ErrorLogFrame.createNewInstance(); + + autoCheckForUpdates(); + offerAssociation(); + loadingDialog = new LoadingDialog(); + + DebuggerTools.initDebugger().addMessageListener(new DebugListener() { + @Override + public void onMessage(String clientId, String msg) { + } + + @Override + public void onLoaderURL(String clientId, String url) { + } + + @Override + public void onLoaderBytes(String clientId, byte[] data) { + String hash = md5(data); + for (SWFList sl : Main.getMainFrame().getPanel().getSwfs()) { + for (int s = 0; s < sl.size(); s++) { + String t = sl.get(s).getFileTitle(); + if (t == null) { + t = ""; + } + if (t.endsWith(":" + hash)) { //this one is already opened + return; + } + } + } + SWF swf = Main.getMainFrame().getPanel().getCurrentSwf(); + + String title = swf == null ? "?" : swf.getFileTitle(); + title = title + ":" + hash; + String tfile; + try { + tfile = tempFile(title); + Helper.writeFile(tfile, data); + openFile(new SWFSourceInfo(null, tfile, title)); + } catch (IOException ex) { + logger.log(Level.SEVERE, "Cannot create tempfile"); + } + } + + @Override + public void onFinish(String clientId) { + } + }); + + try { + flashDebugger = new Debugger(); + debugHandler = new DebuggerHandler(); + debugHandler.addBreakListener(new DebuggerHandler.BreakListener() { + @Override + public void doContinue() { + mainFrame.getPanel().clearDebuggerColors(); + } + + @Override + public void breakAt(String scriptName, int line, final int classIndex, final int traitIndex, final int methodIndex) { + View.execInEventDispatch(new Runnable() { + @Override + public void run() { + mainFrame.getPanel().gotoScriptLine(getMainFrame().getPanel().getCurrentSwf(), scriptName, line, classIndex, traitIndex, methodIndex); + } + }); + } + }); + debugHandler.addConnectionListener(new DebuggerHandler.ConnectionListener() { + @Override + public void connected() { + Main.mainFrame.getMenu().updateComponents(); + } + + @Override + public void disconnected() { + if (Main.mainFrame != null && Main.mainFrame.getPanel() != null) { + Main.mainFrame.getPanel().refreshBreakPoints(); + } + } + }); + flashDebugger.addConnectionListener(debugHandler); + } catch (IOException ex) { + logger.log(Level.SEVERE, "eeex", ex); + } + }); + } + + public static void startDebugger() { + flashDebugger.startDebugger(); + } + + public static void stopDebugger() { + flashDebugger.stopDebugger(); + } + + public static void showModeFrame() { + ensureMainFrame(); + mainFrame.setVisible(true); + } + + private static void offerAssociation() { + boolean offered = Configuration.offeredAssociation.get(); + if (!offered) { + if (Platform.isWindows()) { + if ((!ContextMenuTools.isAddedToContextMenu()) && View.showConfirmDialog(null, "Do you want to add FFDec to context menu of SWF files?\n(Can be changed later from main menu)", "Context menu", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) { + ContextMenuTools.addToContextMenu(true, false); + } + } + + Configuration.offeredAssociation.set(true); + } + } + + public static void initUiLang() { + if (GraphicsEnvironment.isHeadless()) { //No GUI in OS + return; + } + try { + Class cl = Class.forName("org.pushingpixels.substance.api.SubstanceLookAndFeel"); + Field field = cl.getDeclaredField("LABEL_BUNDLE"); + field.setAccessible(true); + field.set(null, null); + } catch (Throwable ex) { + logger.log(Level.SEVERE, null, ex); + } + + UIManager.put("OptionPane.okButtonText", AppStrings.translate("button.ok")); + UIManager.put("OptionPane.yesButtonText", AppStrings.translate("button.yes")); + UIManager.put("OptionPane.noButtonText", AppStrings.translate("button.no")); + UIManager.put("OptionPane.cancelButtonText", AppStrings.translate("button.cancel")); + UIManager.put("OptionPane.messageDialogTitle", AppStrings.translate("dialog.message.title")); + UIManager.put("OptionPane.titleText", AppStrings.translate("dialog.select.title")); + + UIManager.put("FileChooser.acceptAllFileFilterText", AppStrings.translate("FileChooser.acceptAllFileFilterText")); + UIManager.put("FileChooser.lookInLabelText", AppStrings.translate("FileChooser.lookInLabelText")); + UIManager.put("FileChooser.cancelButtonText", AppStrings.translate("button.cancel")); + UIManager.put("FileChooser.cancelButtonToolTipText", AppStrings.translate("button.cancel")); + UIManager.put("FileChooser.openButtonText", AppStrings.translate("FileChooser.openButtonText")); + UIManager.put("FileChooser.openButtonToolTipText", AppStrings.translate("FileChooser.openButtonToolTipText")); + UIManager.put("FileChooser.filesOfTypeLabelText", AppStrings.translate("FileChooser.filesOfTypeLabelText")); + UIManager.put("FileChooser.fileNameLabelText", AppStrings.translate("FileChooser.fileNameLabelText")); + UIManager.put("FileChooser.listViewButtonToolTipText", AppStrings.translate("FileChooser.listViewButtonToolTipText")); + UIManager.put("FileChooser.listViewButtonAccessibleName", AppStrings.translate("FileChooser.listViewButtonAccessibleName")); + UIManager.put("FileChooser.detailsViewButtonToolTipText", AppStrings.translate("FileChooser.detailsViewButtonToolTipText")); + UIManager.put("FileChooser.detailsViewButtonAccessibleName", AppStrings.translate("FileChooser.detailsViewButtonAccessibleName")); + UIManager.put("FileChooser.upFolderToolTipText", AppStrings.translate("FileChooser.upFolderToolTipText")); + UIManager.put("FileChooser.upFolderAccessibleName", AppStrings.translate("FileChooser.upFolderAccessibleName")); + UIManager.put("FileChooser.homeFolderToolTipText", AppStrings.translate("FileChooser.homeFolderToolTipText")); + UIManager.put("FileChooser.homeFolderAccessibleName", AppStrings.translate("FileChooser.homeFolderAccessibleName")); + UIManager.put("FileChooser.fileNameHeaderText", AppStrings.translate("FileChooser.fileNameHeaderText")); + UIManager.put("FileChooser.fileSizeHeaderText", AppStrings.translate("FileChooser.fileSizeHeaderText")); + UIManager.put("FileChooser.fileTypeHeaderText", AppStrings.translate("FileChooser.fileTypeHeaderText")); + UIManager.put("FileChooser.fileDateHeaderText", AppStrings.translate("FileChooser.fileDateHeaderText")); + UIManager.put("FileChooser.fileAttrHeaderText", AppStrings.translate("FileChooser.fileAttrHeaderText")); + UIManager.put("FileChooser.openDialogTitleText", AppStrings.translate("FileChooser.openDialogTitleText")); + UIManager.put("FileChooser.directoryDescriptionText", AppStrings.translate("FileChooser.directoryDescriptionText")); + UIManager.put("FileChooser.directoryOpenButtonText", AppStrings.translate("FileChooser.directoryOpenButtonText")); + UIManager.put("FileChooser.directoryOpenButtonToolTipText", AppStrings.translate("FileChooser.directoryOpenButtonToolTipText")); + UIManager.put("FileChooser.fileDescriptionText", AppStrings.translate("FileChooser.fileDescriptionText")); + UIManager.put("FileChooser.fileNameLabelText", AppStrings.translate("FileChooser.fileNameLabelText")); + UIManager.put("FileChooser.helpButtonText", AppStrings.translate("FileChooser.helpButtonText")); + UIManager.put("FileChooser.helpButtonToolTipText", AppStrings.translate("FileChooser.helpButtonToolTipText")); + UIManager.put("FileChooser.newFolderAccessibleName", AppStrings.translate("FileChooser.newFolderAccessibleName")); + UIManager.put("FileChooser.newFolderErrorText", AppStrings.translate("FileChooser.newFolderErrorText")); + UIManager.put("FileChooser.newFolderToolTipText", AppStrings.translate("FileChooser.newFolderToolTipText")); + UIManager.put("FileChooser.other.newFolder", AppStrings.translate("FileChooser.other.newFolder")); + UIManager.put("FileChooser.other.newFolder.subsequent", AppStrings.translate("FileChooser.other.newFolder.subsequent")); + UIManager.put("FileChooser.win32.newFolder", AppStrings.translate("FileChooser.win32.newFolder")); + UIManager.put("FileChooser.win32.newFolder.subsequent", AppStrings.translate("FileChooser.win32.newFolder.subsequent")); + UIManager.put("FileChooser.saveButtonText", AppStrings.translate("FileChooser.saveButtonText")); + UIManager.put("FileChooser.saveButtonToolTipText", AppStrings.translate("FileChooser.saveButtonToolTipText")); + UIManager.put("FileChooser.saveDialogTitleText", AppStrings.translate("FileChooser.saveDialogTitleText")); + UIManager.put("FileChooser.saveInLabelText", AppStrings.translate("FileChooser.saveInLabelText")); + UIManager.put("FileChooser.updateButtonText", AppStrings.translate("FileChooser.updateButtonText")); + UIManager.put("FileChooser.updateButtonToolTipText", AppStrings.translate("FileChooser.updateButtonToolTipText")); + + UIManager.put("FileChooser.detailsViewActionLabel.textAndMnemonic", AppStrings.translate("FileChooser.detailsViewActionLabel.textAndMnemonic")); + UIManager.put("FileChooser.detailsViewButtonToolTip.textAndMnemonic", AppStrings.translate("FileChooser.detailsViewButtonToolTip.textAndMnemonic")); + UIManager.put("FileChooser.fileAttrHeader.textAndMnemonic", AppStrings.translate("FileChooser.fileAttrHeader.textAndMnemonic")); + UIManager.put("FileChooser.fileDateHeader.textAndMnemonic", AppStrings.translate("FileChooser.fileDateHeader.textAndMnemonic")); + UIManager.put("FileChooser.fileNameHeader.textAndMnemonic", AppStrings.translate("FileChooser.fileNameHeader.textAndMnemonic")); + UIManager.put("FileChooser.fileNameLabel.textAndMnemonic", AppStrings.translate("FileChooser.fileNameLabel.textAndMnemonic")); + UIManager.put("FileChooser.fileSizeHeader.textAndMnemonic", AppStrings.translate("FileChooser.fileSizeHeader.textAndMnemonic")); + UIManager.put("FileChooser.fileTypeHeader.textAndMnemonic", AppStrings.translate("FileChooser.fileTypeHeader.textAndMnemonic")); + UIManager.put("FileChooser.filesOfTypeLabel.textAndMnemonic", AppStrings.translate("FileChooser.filesOfTypeLabel.textAndMnemonic")); + UIManager.put("FileChooser.folderNameLabel.textAndMnemonic", AppStrings.translate("FileChooser.folderNameLabel.textAndMnemonic")); + UIManager.put("FileChooser.homeFolderToolTip.textAndMnemonic", AppStrings.translate("FileChooser.homeFolderToolTip.textAndMnemonic")); + UIManager.put("FileChooser.listViewActionLabel.textAndMnemonic", AppStrings.translate("FileChooser.listViewActionLabel.textAndMnemonic")); + UIManager.put("FileChooser.listViewButtonToolTip.textAndMnemonic", AppStrings.translate("FileChooser.listViewButtonToolTip.textAndMnemonic")); + UIManager.put("FileChooser.lookInLabel.textAndMnemonic", AppStrings.translate("FileChooser.lookInLabel.textAndMnemonic")); + UIManager.put("FileChooser.newFolderActionLabel.textAndMnemonic", AppStrings.translate("FileChooser.newFolderActionLabel.textAndMnemonic")); + UIManager.put("FileChooser.newFolderToolTip.textAndMnemonic", AppStrings.translate("FileChooser.newFolderToolTip.textAndMnemonic")); + UIManager.put("FileChooser.refreshActionLabel.textAndMnemonic", AppStrings.translate("FileChooser.refreshActionLabel.textAndMnemonic")); + UIManager.put("FileChooser.saveInLabel.textAndMnemonic", AppStrings.translate("FileChooser.saveInLabel.textAndMnemonic")); + UIManager.put("FileChooser.upFolderToolTip.textAndMnemonic", AppStrings.translate("FileChooser.upFolderToolTip.textAndMnemonic")); + UIManager.put("FileChooser.viewMenuButtonAccessibleName", AppStrings.translate("FileChooser.viewMenuButtonAccessibleName")); + UIManager.put("FileChooser.viewMenuButtonToolTipText", AppStrings.translate("FileChooser.viewMenuButtonToolTipText")); + UIManager.put("FileChooser.viewMenuLabel.textAndMnemonic", AppStrings.translate("FileChooser.viewMenuLabel.textAndMnemonic")); + UIManager.put("FileChooser.newFolderActionLabelText", AppStrings.translate("FileChooser.newFolderActionLabelText")); + UIManager.put("FileChooser.listViewActionLabelText", AppStrings.translate("FileChooser.listViewActionLabelText")); + UIManager.put("FileChooser.detailsViewActionLabelText", AppStrings.translate("FileChooser.detailsViewActionLabelText")); + UIManager.put("FileChooser.refreshActionLabelText", AppStrings.translate("FileChooser.refreshActionLabelText")); + UIManager.put("FileChooser.sortMenuLabelText", AppStrings.translate("FileChooser.sortMenuLabelText")); + UIManager.put("FileChooser.viewMenuLabelText", AppStrings.translate("FileChooser.viewMenuLabelText")); + UIManager.put("FileChooser.fileSizeKiloBytes", AppStrings.translate("FileChooser.fileSizeKiloBytes")); + UIManager.put("FileChooser.fileSizeMegaBytes", AppStrings.translate("FileChooser.fileSizeMegaBytes")); + UIManager.put("FileChooser.fileSizeGigaBytes", AppStrings.translate("FileChooser.fileSizeGigaBytes")); + UIManager.put("FileChooser.folderNameLabelText", AppStrings.translate("FileChooser.folderNameLabelText")); + + UIManager.put("ColorChooser.okText", AppStrings.translate("ColorChooser.okText")); + UIManager.put("ColorChooser.cancelText", AppStrings.translate("ColorChooser.cancelText")); + UIManager.put("ColorChooser.resetText", AppStrings.translate("ColorChooser.resetText")); + UIManager.put("ColorChooser.previewText", AppStrings.translate("ColorChooser.previewText")); + UIManager.put("ColorChooser.swatchesNameText", AppStrings.translate("ColorChooser.swatchesNameText")); + UIManager.put("ColorChooser.swatchesRecentText", AppStrings.translate("ColorChooser.swatchesRecentText")); + UIManager.put("ColorChooser.sampleText", AppStrings.translate("ColorChooser.sampleText")); + + } + + public static void initLang() { + if (!Configuration.locale.hasValue()) { + if (Platform.isWindows()) { + //Load from Installer + String uninstKey = "{E618D276-6596-41F4-8A98-447D442A77DB}_is1"; + uninstKey = "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\" + uninstKey; + try { + if (Advapi32Util.registryKeyExists(WinReg.HKEY_LOCAL_MACHINE, uninstKey)) { + if (Advapi32Util.registryValueExists(WinReg.HKEY_LOCAL_MACHINE, uninstKey, "NSIS: Language")) { + String installedLoc = Advapi32Util.registryGetStringValue(WinReg.HKEY_LOCAL_MACHINE, uninstKey, "NSIS: Language"); + int lcid = Integer.parseInt(installedLoc); + char[] buf = new char[9]; + int cnt = Kernel32.INSTANCE.GetLocaleInfo(lcid, Kernel32.LOCALE_SISO639LANGNAME, buf, 9); + String langCode = new String(buf, 0, cnt).trim().toLowerCase(); + + cnt = Kernel32.INSTANCE.GetLocaleInfo(lcid, Kernel32.LOCALE_SISO3166CTRYNAME, buf, 9); + String countryCode = new String(buf, 0, cnt).trim().toLowerCase(); + + List langs = Arrays.asList(SelectLanguageDialog.getAvailableLanguages()); + for (int i = 0; i < langs.size(); i++) { + langs.set(i, langs.get(i).toLowerCase()); + } + + String selectedLang = null; + + if (langs.contains(langCode + "-" + countryCode)) { + selectedLang = SelectLanguageDialog.getAvailableLanguages()[langs.indexOf(langCode + "-" + countryCode)]; + } else if (langs.contains(langCode)) { + selectedLang = SelectLanguageDialog.getAvailableLanguages()[langs.indexOf(langCode)]; + } + if (selectedLang != null) { + Configuration.locale.set(selectedLang); + } + } + } + } catch (Exception ex) { + //ignore + } + } + } + Locale.setDefault(Locale.forLanguageTag(Configuration.locale.get())); + AppStrings.updateLanguage(); + + Helper.decompilationErrorAdd = AppStrings.translate(Configuration.autoDeobfuscate.get() ? "deobfuscation.comment.failed" : "deobfuscation.comment.tryenable"); + } + + /** + * Clear old FFDec/JavactiveX temp files + */ + private static void clearTemp() { + String tempDirPath = System.getProperty("java.io.tmpdir"); + if (tempDirPath == null) { + return; + } + File tempDir = new File(tempDirPath); + if (!tempDir.exists()) { + return; + } + File[] delFiles = tempDir.listFiles(new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + return name.matches("ffdec_cache.*\\.tmp") || name.matches("javactivex_.*\\.exe") || name.matches("temp[0-9]+\\.swf") || name.matches("ffdec_view_.*\\.swf"); + } + }); + + if (delFiles != null) { + for (File f : delFiles) { + try { + f.delete(); + } catch (Exception ex) { + //ignore + } + } + } + } + + /** + * @param args the command line arguments + * @throws IOException On error + */ + public static void main(String[] args) throws IOException { + setSessionLoaded(false); + + clearTemp(); + + try { + SWFDecompilerPlugin.loadPlugins(); + } catch (Throwable ex) { + logger.log(Level.SEVERE, "Failed to load plugins", ex); + } + + AppStrings.setResourceClass(MainFrame.class); + initLogging(Configuration._debugMode.get()); + + initLang(); + + if (Configuration.cacheOnDisk.get()) { + Cache.setStorageType(Cache.STORAGE_FILES); + } else { + Cache.setStorageType(Cache.STORAGE_MEMORY); + } + + if (args.length == 0) { + initGui(); + checkLibraryVersion(); + View.execInEventDispatch(() -> { + if (Configuration.allowOnlyOneInstance.get() && FirstInstance.focus()) { //Try to focus first instance + Main.exit(); + } else { + showModeFrame(); + reloadLastSession(); + } + }); + } else { + checkLibraryVersion(); + setSessionLoaded(true); + String[] filesToOpen = CommandLineArgumentParser.parseArguments(args); + if (filesToOpen != null && filesToOpen.length > 0) { + View.execInEventDispatch(() -> { + initGui(); + shouldCloseWhenClosingLoadingDialog = true; + if (Configuration.allowOnlyOneInstance.get() && FirstInstance.openFiles(Arrays.asList(filesToOpen))) { //Try to open in first instance + Main.exit(); + } else { + for (String fileToOpen : filesToOpen) { + openFile(fileToOpen, null); + } + } + }); + } + } + } + + private static void checkLibraryVersion() { + if (!ApplicationInfo.version.equals("unknown") && !ApplicationInfo.libraryVersion.equals("unknown") + && !Objects.equals(ApplicationInfo.version, ApplicationInfo.libraryVersion)) { + logger.log(Level.WARNING, "Application version is different from library version. FFDec may not work properly."); + } + } + + private static void reloadLastSession() { + boolean openingFiles = false; + if (Configuration.saveSessionOnExit.get()) { + String lastSession = Configuration.lastSessionFiles.get(); + if (lastSession != null && lastSession.length() > 0) { + String[] filesToOpen = lastSession.split(File.pathSeparator, -1); + List exfiles = new ArrayList<>(); + List extitles = new ArrayList<>(); + String lastSessionTitles = Configuration.lastSessionFileTitles.get(); + String[] fileTitles = new String[0]; + if (lastSessionTitles != null && !lastSessionTitles.isEmpty()) { + fileTitles = lastSessionTitles.split(File.pathSeparator, -1); + } + for (int i = 0; i < filesToOpen.length; i++) { + if (new File(filesToOpen[i]).exists()) { + exfiles.add(filesToOpen[i]); + if (fileTitles.length > i) { + extitles.add(fileTitles[i]); + } else { + extitles.add(null); + } + } + } + SWFSourceInfo[] sourceInfos = new SWFSourceInfo[exfiles.size()]; + for (int i = 0; i < exfiles.size(); i++) { + String extitle = extitles.get(i); + sourceInfos[i] = new SWFSourceInfo(null, exfiles.get(i), extitle == null || extitle.isEmpty() ? null : extitle); + } + if (sourceInfos.length > 0) { + openingFiles = true; + openFile(sourceInfos, () -> { + mainFrame.getPanel().tagTree.setSelectionPathString(Configuration.lastSessionSelection.get()); + setSessionLoaded(true); + }); + } + } + } + + if (!openingFiles) { + setSessionLoaded(true); + } + } + + public static String tempFile(String url) throws IOException { + File f = new File(Configuration.getFFDecHome() + "saved" + File.separator); + Path.createDirectorySafe(f); + return Configuration.getFFDecHome() + "saved" + File.separator + "asdec_" + Integer.toHexString(url.hashCode()) + ".tmp"; + } + + public static void removeTrayIcon() { + if (SystemTray.isSupported()) { + SystemTray tray = SystemTray.getSystemTray(); + if (trayIcon != null) { + tray.remove(trayIcon); + trayIcon = null; + } + } + } + + public static void switchProxy() { + proxyFrame.switchState(); + if (stopMenuItem != null) { + if (proxyFrame.isRunning()) { + stopMenuItem.setLabel(AppStrings.translate("proxy.stop")); + } else { + stopMenuItem.setLabel(AppStrings.translate("proxy.start")); + } + } + } + + public static void addTrayIcon() { + if (trayIcon != null) { + return; + } + if (SystemTray.isSupported()) { + SystemTray tray = SystemTray.getSystemTray(); + trayIcon = new TrayIcon(View.loadImage("proxy16"), ApplicationInfo.VENDOR + " " + ApplicationInfo.SHORT_APPLICATION_NAME + " " + AppStrings.translate("proxy")); + trayIcon.setImageAutoSize(true); + PopupMenu trayPopup = new PopupMenu(); + + ActionListener trayListener = new ActionListener() { + /** + * Invoked when an action occurs. + */ + @Override + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().equals("EXIT")) { + Main.exit(); + } + if (e.getActionCommand().equals("SHOW")) { + Main.showProxy(); + } + if (e.getActionCommand().equals("SWITCH")) { + Main.switchProxy(); + } + } + }; + + MenuItem showMenuItem = new MenuItem(AppStrings.translate("proxy.show")); + showMenuItem.setActionCommand("SHOW"); + showMenuItem.addActionListener(trayListener); + trayPopup.add(showMenuItem); + stopMenuItem = new MenuItem(AppStrings.translate("proxy.start")); + stopMenuItem.setActionCommand("SWITCH"); + stopMenuItem.addActionListener(trayListener); + trayPopup.add(stopMenuItem); + trayPopup.addSeparator(); + MenuItem exitMenuItem = new MenuItem(AppStrings.translate("exit")); + exitMenuItem.setActionCommand("EXIT"); + exitMenuItem.addActionListener(trayListener); + trayPopup.add(exitMenuItem); + + trayIcon.setPopupMenu(trayPopup); + trayIcon.addMouseListener(new MouseAdapter() { + /** + * {@inheritDoc} + */ + @Override + public void mouseClicked(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON1) { + Main.showProxy(); + } + } + }); + try { + tray.add(trayIcon); + } catch (AWTException ex) { + } + } + } + + public static void exit() { + Configuration.saveConfig(); + if (mainFrame != null && mainFrame.getPanel() != null) { + mainFrame.getPanel().unloadFlashPlayer(); + mainFrame.dispose(); + } + if (fileTxt != null) { + try { + fileTxt.flush(); + fileTxt.close(); + } catch (Exception ex) { + //ignore + } + } + System.exit(0); + } + + public static void about() { + (new AboutDialog()).setVisible(true); + } + + public static void advancedSettings() { + advancedSettings(null); + } + + public static void advancedSettings(String category) { + (new AdvancedSettingsDialog(category)).setVisible(true); + } + + public static void autoCheckForUpdates() { + if (Configuration.checkForUpdatesAuto.get()) { + Calendar lastUpdatesCheckDate = Configuration.lastUpdatesCheckDate.get(); + if ((lastUpdatesCheckDate == null) || (lastUpdatesCheckDate.getTime().getTime() < Calendar.getInstance().getTime().getTime() - Configuration.checkForUpdatesDelay.get())) { + new SwingWorker() { + @Override + protected Object doInBackground() throws Exception { + checkForUpdates(); + return null; + } + }.execute(); + } + } + } + + public static boolean checkForUpdates() { + String currentVersion = ApplicationInfo.version; + if (currentVersion.equals("unknown")) { + // sometimes during development the version information is not available + return false; + } + + List accepted = new ArrayList<>(); + if (Configuration.checkForUpdatesStable.get()) { + accepted.add("stable"); + } + if (Configuration.checkForUpdatesNightly.get()) { + accepted.add("nightly"); + } + + if (accepted.isEmpty()) { + return false; + } + + String acceptVersions = String.join(",", accepted); + try { + String proxyAddress = Configuration.updateProxyAddress.get(); + URL url = new URL(ApplicationInfo.updateCheckUrl); + + URLConnection uc; + if (proxyAddress != null && !proxyAddress.isEmpty()) { + int port = 8080; + if (proxyAddress.contains(":")) { + String[] parts = proxyAddress.split(":"); + port = Integer.parseInt(parts[1]); + proxyAddress = parts[0]; + } + + uc = url.openConnection(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyAddress, port))); + } else { + uc = url.openConnection(); + } + uc.setRequestProperty("X-Accept-Versions", acceptVersions); + uc.setRequestProperty("X-Update-Major", "" + UPDATE_SYSTEM_MAJOR); + uc.setRequestProperty("X-Update-Minor", "" + UPDATE_SYSTEM_MINOR); + uc.setRequestProperty("User-Agent", ApplicationInfo.shortApplicationVerName); + String currentLoc = Configuration.locale.get("en"); + uc.setRequestProperty("Accept-Language", currentLoc + ("en".equals(currentLoc) ? "" : ", en;q=0.8")); + + uc.connect(); + + BufferedReader br = new BufferedReader(new InputStreamReader(uc.getInputStream())); + String s; + final java.util.List versions = new ArrayList<>(); + String header = ""; + Pattern headerPat = Pattern.compile("\\[([a-zA-Z0-9]+)\\]"); + int updateMajor; + int updateMinor; + Version ver = null; + while ((s = br.readLine()) != null) { + + Matcher m = headerPat.matcher(s); + if (m.matches()) { + header = m.group(1); + if (header.equals("version")) { + ver = new Version(); + versions.add(ver); + } + if (header.equals("noversion")) { + break; + } + } else if (s.contains("=")) { + String key = s.substring(0, s.indexOf('=')); + String val = s.substring(s.indexOf('=') + 1); + if ("updateSystem".equals(header)) { + if (key.equals("majorVersion")) { + updateMajor = Integer.parseInt(val); + if (updateMajor > UPDATE_SYSTEM_MAJOR) { + break; + } + } + if (key.equals("minorVersion")) { + updateMinor = Integer.parseInt(val); + } + } + if ("version".equals(header) && (ver != null)) { + if (key.equals("versionId")) { + ver.versionId = Integer.parseInt(val); + } + if (key.equals("versionName")) { + ver.versionName = val; + } + if (key.equals("nightly")) { + ver.nightly = val.equals("true"); + } + if (key.equals("revision")) { + ver.revision = val; + } + if (key.equals("build")) { + ver.build = Integer.parseInt(val); + } + if (key.equals("major")) { + ver.major = Integer.parseInt(val); + } + if (key.equals("minor")) { + ver.minor = Integer.parseInt(val); + } + if (key.equals("release")) { + ver.release = Integer.parseInt(val); + } + if (key.equals("longVersionName")) { + ver.longVersionName = val; + } + if (key.equals("releaseDate")) { + ver.releaseDate = val; + } + if (key.equals("appName")) { + ver.appName = val; + } + if (key.equals("appFullName")) { + ver.appFullName = val; + } + if (key.equals("updateLink")) { + ver.updateLink = val; + } + if (key.equals("change[]")) { + String changeType = val.substring(0, val.indexOf('|')); + String change = val.substring(val.indexOf('|') + 1); + if (!ver.changes.containsKey(changeType)) { + ver.changes.put(changeType, new ArrayList<>()); + } + List chlist = ver.changes.get(changeType); + chlist.add(change); + } + } + } + } + + if (!versions.isEmpty()) { + View.execInEventDispatch(() -> { + NewVersionDialog newVersionDialog = new NewVersionDialog(versions); + newVersionDialog.setVisible(true); + Configuration.lastUpdatesCheckDate.set(Calendar.getInstance()); + }); + + return true; + } + } catch (IOException | NumberFormatException ex) { + return false; + } + Configuration.lastUpdatesCheckDate.set(Calendar.getInstance()); + return false; + } + + private static FileHandler fileTxt; + + public static void clearLogFile() { + Logger logger = Logger.getLogger(""); + + FileHandler oldFileTxt = fileTxt; + fileTxt = null; + if (oldFileTxt != null) { + logger.removeHandler(fileTxt); + oldFileTxt.flush(); + oldFileTxt.close(); + } + + String fileName = null; + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-hh-mm-ss"); + + try { + fileName = Configuration.getFFDecHome() + "logs" + File.separator; + if (Configuration.useDetailedLogging.get()) { + fileName += "log-" + sdf.format(new Date()) + ".txt"; + } else { + fileName += "log.txt"; + } + File f = new File(fileName).getParentFile(); + if (!f.exists()) { + f.mkdir(); + } + fileTxt = new FileHandler(fileName); + } catch (IOException | SecurityException ex) { + //cannot get lock error + if (ex.getMessage().contains("lock for")) { + //remove all old log files and their .lck + for (int i = 0; i <= 100; i++) { + File flog = new File(fileName + (i == 0 ? "" : "." + i)); + File flog_lock = new File(fileName + (i == 0 ? "" : "." + i) + ".lck"); + flog.delete(); + flog_lock.delete(); + } + try { + fileTxt = new FileHandler(fileName); + } catch (IOException | SecurityException ex1) { + logger.log(Level.SEVERE, "Cannot initialize logging", ex); + } + } else { + logger.log(Level.SEVERE, "Cannot initialize logging", ex); + } + } + + Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { + @Override + public void uncaughtException(Thread t, Throwable e) { + logger.log(Level.SEVERE, "Uncaught exception in thread: " + t.getName(), e); + if (e instanceof OutOfMemoryError || !Helper.is64BitJre() && Helper.is64BitOs()) { + View.showMessageDialog(null, AppStrings.translate("message.warning.outOfMemory32BitJre"), AppStrings.translate("message.warning"), JOptionPane.WARNING_MESSAGE); + } + } + }); + + Formatter formatterTxt = new LogFormatter(); + if (fileTxt != null) { + fileTxt.setFormatter(formatterTxt); + logger.addHandler(fileTxt); + } + + if (!GraphicsEnvironment.isHeadless() && ErrorLogFrame.hasInstance()) { + ErrorLogFrame.getInstance().clearErrorState(); + } + + sdf = new SimpleDateFormat("yyyy-MM-dd"); + logger.log(Level.INFO, "Date: {0}", sdf.format(new Date())); + logger.log(Level.INFO, ApplicationInfo.applicationVerName); + logger.log(Level.INFO, "{0} {1} {2}", new Object[]{ + System.getProperty("os.name"), System.getProperty("os.version"), System.getProperty("os.arch")}); + logger.log(Level.INFO, "{0} {1} {2}", new Object[]{ + System.getProperty("java.version"), System.getProperty("java.vendor"), System.getProperty("os.arch")}); + } + + public static void initLogging(boolean debug) { + try { + Logger logger = Logger.getLogger(""); + logger.setLevel(Configuration.logLevel); + + Handler[] handlers = logger.getHandlers(); + for (int i = handlers.length - 1; i >= 0; i--) { + logger.removeHandler(handlers[i]); + } + + ConsoleHandler conHan = new ConsoleHandler(); + conHan.setLevel(debug ? Level.CONFIG : Level.WARNING); + SimpleFormatter formatterTxt = new SimpleFormatter(); + conHan.setFormatter(formatterTxt); + logger.addHandler(conHan); + clearLogFile(); + + } catch (Exception ex) { + throw new RuntimeException("Problems with creating the log files"); + } + } +}