diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/AbstractDataStream.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/AbstractDataStream.java deleted file mode 100644 index 66b21399a..000000000 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/AbstractDataStream.java +++ /dev/null @@ -1,110 +0,0 @@ -package com.jpexs.decompiler.flash.iggy; - -import java.io.EOFException; -import java.io.IOException; - -/** - * - * @author JPEXS - */ -public abstract class AbstractDataStream { - - /** - * Available bytes - * - * @return null if unknown, long value otherwise - */ - public abstract Long available(); - - public abstract long position(); - - public abstract boolean is64(); - - protected long readUI64() throws IOException { - try { - return (readUI32() + (readUI32() << 32)) & 0xffffffffffffffffL; - } catch (EOFException ex) { - return -1; - } - } - - protected 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; - } - - protected long readUI32() throws IOException { - try { - return (readUI8() + (readUI8() << 8) + (readUI8() << 16) + (readUI8() << 24)); - } catch (EOFException ex) { - return -1; - } - } - - protected 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; - } - - protected int readUI16() throws IOException { - try { - return (readUI8() + (readUI8() << 8)) & 0xffff; - } catch (EOFException ex) { - return -1; - } - } - - protected boolean writeUI16(int val) throws IOException { - write(val & 0xff); - write((val >> 8) & 0xff); - return true; - } - - protected int readUI8() throws IOException { - try { - return read() & 0xff; - } catch (EOFException ex) { - return -1; - } - } - - protected boolean writeUI8(int val) throws IOException { - write(val); - return true; - } - - protected float readFloat() throws IOException { - return Float.intBitsToFloat((int) readUI32()); - } - - protected boolean writeFloat(float val) throws IOException { - return writeUI32(Float.floatToIntBits(val)); - } - - protected byte[] readBytes(int numBytes) throws IOException { - byte[] ret = new byte[numBytes]; - for (int i = 0; i < numBytes; i++) { - ret[i] = (byte) read(); - } - return ret; - } - - protected abstract int read() throws IOException; - - protected abstract void seek(long pos, SeekMode mode) throws IOException; - - protected void write(int val) throws IOException { - //nothing - } -} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/ByteArrayDataStream.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/ByteArrayDataStream.java deleted file mode 100644 index b8327fb52..000000000 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/ByteArrayDataStream.java +++ /dev/null @@ -1,85 +0,0 @@ -package com.jpexs.decompiler.flash.iggy; - -import java.io.EOFException; -import java.io.IOException; -import java.util.Arrays; - -/** - * - * @author JPEXS - */ -public class ByteArrayDataStream extends AbstractDataStream { - - private byte[] data; - private long pos; - private boolean use64bit; - - public ByteArrayDataStream(int initialSize, boolean use64bit) { - this(new byte[initialSize], use64bit); - } - - @Override - public long position() { - return pos; - } - - public ByteArrayDataStream(byte data[], boolean use64bit) { - this.data = data; - pos = 0; - this.use64bit = use64bit; - } - - @Override - public boolean is64() { - return use64bit; - } - - @Override - protected int read() throws IOException { - if (pos >= data.length) { - throw new EOFException("End of stream reached"); - } - int ret = data[(int) pos] & 0xff; - pos++; - return ret; - } - - public void resize(int newsize) { - data = Arrays.copyOf(data, newsize); - if (pos > data.length) { - pos = data.length; - } - } - - @Override - protected void write(int val) throws IOException { - if (pos >= data.length) { - throw new EOFException("End of stream reached"); - } - data[(int) pos] = (byte) val; - pos++; - } - - @Override - protected void seek(long pos, SeekMode mode) throws IOException { - long newpos = pos; - if (mode == SeekMode.CUR) { - newpos = this.pos + pos; - } else if (mode == SeekMode.END) { - newpos = data.length - pos; - } - if (newpos > data.length) { - throw new ArrayIndexOutOfBoundsException("Position outside bounds accessed: " + pos + ". Size: " + data.length); - } else if (newpos < 0) { - throw new ArrayIndexOutOfBoundsException("Negative position accessed: " + pos); - } else { - this.pos = (int) newpos; - } - } - - @Override - public Long available() { - return (long) (data.length - pos); - } - -} 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 e3fd968cd..b5f1fc8cc 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, - widechar_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 7e5a4b864..b7a5e7fce 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,37 +1,47 @@ -package com.jpexs.decompiler.flash.iggy; - -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(AbstractDataStream stream, long charCount) throws IOException { - this.charCount = charCount; - readFromDataStream(stream); - } - - @Override - public void readFromDataStream(AbstractDataStream stream) throws IOException { - advances = new ArrayList<>(); - for (int i = 0; i < charCount; i++) { - advances.add(stream.readFloat()); - } - } - - @Override - public void writeToDataStream(AbstractDataStream stream) throws IOException { - throw new UnsupportedOperationException("Not supported yet."); - } -} +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 6c57824df..cf3d28e95 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,44 +1,56 @@ -package com.jpexs.decompiler.flash.iggy; - -import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -/** - * - * @author JPEXS - */ -public class IggyCharIndices implements StructureInterface { - - @IggyFieldType(value = DataType.widechar_t) - List chars; - @IggyFieldType(DataType.uint32_t) - long padd; - - public List getChars() { - return chars; - } - - private long charCount; - - public IggyCharIndices(AbstractDataStream stream, long charCount) throws IOException { - this.charCount = charCount; - readFromDataStream(stream); - } - - @Override - public void readFromDataStream(AbstractDataStream 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(AbstractDataStream stream) throws IOException { - throw new UnsupportedOperationException("Not supported yet."); - } - -} +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 ee00e2c84..6b60bdd20 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,58 +1,75 @@ -package com.jpexs.decompiler.flash.iggy; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -/** - * - * @author JPEXS - */ -public class IggyCharKerning implements StructureInterface { - - private long kernCount; - List charsA; - List charsB; - List kerningOffsets; - long pad; - - public long getKernCount() { - return kernCount; - } - - public List getCharsA() { - return charsA; - } - - public List getCharsB() { - return charsB; - } - - public List getKerningOffsets() { - return kerningOffsets; - } - - public IggyCharKerning(AbstractDataStream stream, long kernCount) throws IOException { - this.kernCount = kernCount; - readFromDataStream(stream); - } - - @Override - public void readFromDataStream(AbstractDataStream 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()); - } - pad = stream.readUI32(); - } - - @Override - public void writeToDataStream(AbstractDataStream stream) throws IOException { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - -} +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 0899925ac..b3632d94e 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,99 +1,108 @@ -package com.jpexs.decompiler.flash.iggy; - -import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType; -import java.io.IOException; -import java.util.logging.Logger; - -/** - * - * @author JPEXS - */ -public class IggyCharOffset implements StructureInterface { - - 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(AbstractDataStream stream) throws IOException { - readFromDataStream(stream); - } - - public IggyCharOffset(long zero, int ischar1, int ischar2, long zero2, int xscale, int yscale, long zero3, long offset) { - this.zero = zero; - this.ischar1 = ischar1; - this.ischar2 = ischar2; - this.zero2 = zero2; - this.xscale = xscale; - this.yscale = yscale; - this.zero3 = zero3; - this.offset = offset; - } - - @Override - public void readFromDataStream(AbstractDataStream stream) throws IOException { - zero = stream.readUI64(); - ischar1 = stream.readUI16(); - ischar2 = stream.readUI16(); - zero2 = stream.readUI32(); - xscale = stream.readUI16(); - yscale = stream.readUI16(); - zero3 = stream.readUI32(); - long cur_position = stream.position(); - long relative_offset = stream.readUI64(); - if (ischar1 > 0) { - offset = cur_position + relative_offset; - } else { - offset = 0; - LOGGER.finer(String.format("Empty char")); - } - } - - @Override - public void writeToDataStream(AbstractDataStream stream) throws IOException { - throw new UnsupportedOperationException("Not supported yet."); - } - - 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/IggyDataReader.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyDataReader.java deleted file mode 100644 index 179062ea9..000000000 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyDataReader.java +++ /dev/null @@ -1,89 +0,0 @@ -package com.jpexs.decompiler.flash.iggy; - -import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType; -import java.io.IOException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * - * @author JPEXS - */ -public class IggyDataReader implements StructureInterface { - - final static int NO_OFFSET = 1; - - @IggyFieldType(value = DataType.widechar_t, count = 48) - String name; - - Map fonts; - Map texts; - Map text2Font; - - private IggyFlashHeader64 header; - private Map sizesOfOffsets; - private List allOffsets; - - public IggyDataReader(IggyFlashHeader64 header, AbstractDataStream stream, List offsets) throws IOException { - this.header = header; - sizesOfOffsets = new HashMap<>(); - for (int i = 0; i < offsets.size() - 1; i++) { - sizesOfOffsets.put(offsets.get(i), offsets.get(i + 1) - offsets.get(i)); - } - sizesOfOffsets.put(offsets.get(offsets.size() - 1), 0L); //Last offset has 0L length? - this.allOffsets = offsets; - readFromDataStream(stream); - } - - @Override - public void readFromDataStream(AbstractDataStream stream) throws IOException { - //here is offset[0] - StringBuilder nameBuilder = new StringBuilder(); - do { - char c = (char) stream.readUI16(); - if (c == '\0') { - break; - } - nameBuilder.append(c); - } while (true); - name = nameBuilder.toString(); - //here is offset[1] - int pad8 = 8 - (int) (stream.position() % 8); - stream.seek(pad8, SeekMode.CUR); - //here is offset [2] - fonts = new HashMap<>(); - int fontIndex = 0; - for (int i = 2; i < allOffsets.size(); i++) { - long offset = allOffsets.get(i); - stream.seek(offset, SeekMode.SET); - int type = stream.readUI16(); - stream.seek(-2, SeekMode.CUR); - if (type == IggyFont.ID) { - IggyFont font = new IggyFont(stream); - fonts.put(fontIndex++, font); - } - if (type == IggyText.ID) { - //TODO: Texts - incomplete - } - } - } - - public String getName() { - return name; - } - - @Override - public void writeToDataStream(AbstractDataStream stream) throws IOException { - throw new UnsupportedOperationException("Not supported yet."); - } - - @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/IggyDeclStrings.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyDeclStrings.java new file mode 100644 index 000000000..c9c21b2c8 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyDeclStrings.java @@ -0,0 +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); + } + +} 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 fb1a9f239..4b248ef66 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,715 +1,718 @@ -package com.jpexs.decompiler.flash.iggy; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.EOFException; -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.io.RandomAccessFile; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - * @author JPEXS - * - * Based of works of somebody called eternity. - * - */ -public class IggyFile extends AbstractDataStream implements AutoCloseable { - - final static Logger LOGGER = Logger.getLogger(IggyFile.class.getName()); - - private RandomAccessFile raf; - private IggyHeader header; - private List subFileEntries = new ArrayList<>(); - - private List headers = new ArrayList<>(); - private List flashDataReaders = new ArrayList<>(); - - public Set getFontIds(int swfIndex) { - return flashDataReaders.get(swfIndex).fonts.keySet(); - } - - public IggyFont getFont(int swfIndex, int fontId) { - return flashDataReaders.get(swfIndex).fonts.get(fontId); - } - - public IggyText getText(int swfIndex, int textId) { - return flashDataReaders.get(swfIndex).texts.get(textId); - } - - public Set getTextIds(int swfIndex) { - return flashDataReaders.get(swfIndex).texts.keySet(); - } - - @Override - public long position() { - try { - return raf.getFilePointer(); - } catch (IOException ex) { - return -1; - } - } - - public IggyFile(File file) throws IOException { - raf = new RandomAccessFile(file, "r"); - header = new IggyHeader(this); - for (int i = 0; i < header.getNumSubfiles(); i++) { - subFileEntries.add(new IggySubFileEntry(this)); - } - - List> indexTables = new ArrayList<>(); //TODO: use this two for something ?? - List> offsetTables = new ArrayList<>(); - List flashDataStreams = new ArrayList<>(); - - for (int i = 0; i < subFileEntries.size(); i++) { - IggySubFileEntry entry = subFileEntries.get(i); - ByteArrayDataStream dataStream = getEntryDataStream(i); - if (entry.type == IggySubFileEntry.TYPE_INDEX) { - List indexTable = new ArrayList<>(); - List offsets = new ArrayList<>(); - IggyIndexParser.parseIndex(dataStream, indexTable, offsets); - indexTables.add(indexTable); - offsetTables.add(offsets); - } else if (entry.type == IggySubFileEntry.TYPE_FLASH) { - IggyFlashHeaderInterface hdr; - if (is64()) { - hdr = new IggyFlashHeader64(dataStream); - } else { - hdr = new IggyFlashHeader32(dataStream); - } - headers.add(hdr); - flashDataStreams.add(dataStream); - } - } - - for (int swfIndex = 0; swfIndex < headers.size(); swfIndex++) { - IggyFlashHeaderInterface hdr = headers.get(swfIndex); - IggyDataReader dataReader = new IggyDataReader((IggyFlashHeader64) hdr /*FIXME for 32*/, flashDataStreams.get(swfIndex), offsetTables.get(swfIndex)); - flashDataReaders.add(dataReader); - } - } - - @Override - public boolean is64() { - return header.is64(); - } - - 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) throws IOException { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - InputStream is = getEntryInputStream(entryIndex); - byte buf[] = new byte[1024]; - int cnt; - while ((cnt = is.read(buf)) > 0) { - baos.write(buf, 0, cnt); - } - return baos.toByteArray(); - } - - public ByteArrayDataStream getEntryDataStream(int entryIndex) throws IOException { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - InputStream is = getEntryInputStream(entryIndex); - byte buf[] = new byte[1024]; - int cnt; - while ((cnt = is.read(buf)) > 0) { - baos.write(buf, 0, cnt); - } - byte data[] = baos.toByteArray(); - return new ByteArrayDataStream(data, is64()); - } - - public InputStream getEntryInputStream(int entryIndex) { - IggySubFileEntry entry = getSubFileEntry(entryIndex); - - return new InputStream() { - long offset = entry.offset; - long maxOffset = entry.offset + entry.size; - - @Override - public synchronized int read() throws IOException { - if (offset < maxOffset) { - raf.seek(offset); - offset++; - return raf.read(); - } - return -1; - } - }; - } - - @Override - protected int read() throws IOException { - int val = raf.read(); - if (val == -1) { - throw new EOFException(); - } - return val; - } - - @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"; - try (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 { - System.out.println("Iggy file splitter"); - if (args.length == 0) { - System.err.println("No file specified"); - System.exit(1); - } - - for (String s : args) { - File f = new File(s); - if (!f.exists()) { - System.err.println("File " + f + " does not exists"); - System.exit(1); - } - processFile(f); - - } - 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 - } - } - - @Override - public void close() { - try { - raf.close(); - } catch (IOException ex) { - //ignore - } - } - - @Override - protected 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()) { - throw new ArrayIndexOutOfBoundsException("Position outside bounds accessed: " + pos + ". Size: " + raf.length()); - } else if (newpos < 0) { - throw new ArrayIndexOutOfBoundsException("Negative position accessed: " + pos); - } else { - raf.seek(newpos); - } - } - - private static boolean updateIndex(long item_offset /*uint32_t*/, boolean is_64, byte index_bytes[], long item_size_change /*int32_t*/) throws IOException { - ByteArrayDataStream stream = new ByteArrayDataStream(index_bytes, is_64); - - /* - 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 { - ByteArrayDataStream stream = new ByteArrayDataStream(index_bytes, is_64); - - /* - 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; - } - - @Override - public Long available() { - try { - return raf.length() - raf.getFilePointer(); - } catch (IOException ex) { - return null; - } - } - - public int getSwfCount() { - return flashDataReaders.size(); - } - - public String getSwfName(int swfIndex) { - return flashDataReaders.get(swfIndex).getName(); - } - - public long getSwfXMin(int swfIndex) { - return headers.get(swfIndex).getXMin(); - } - - public long getSwfYMin(int swfIndex) { - return headers.get(swfIndex).getYMin(); - } - - public long getSwfXMax(int swfIndex) { - return headers.get(swfIndex).getXMax(); - } - - public long getSwfYMax(int swfIndex) { - return headers.get(swfIndex).getYMax(); - } - - public float getSwfFrameRate(int swfIndex) { - return headers.get(swfIndex).getFrameRate(); - } -} +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 433900e90..55178b372 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,195 +1,197 @@ -package com.jpexs.decompiler.flash.iggy; - -import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType; -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(AbstractDataStream stream) throws IOException { - readFromDataStream(stream); - } - - @Override - public void readFromDataStream(AbstractDataStream 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(AbstractDataStream 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 bebb70cd5..ecf77100c 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,211 +1,393 @@ -package com.jpexs.decompiler.flash.iggy; - -import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType; -import java.io.IOException; - -/** - * - * @author Jindra - * - * Based of works of somebody called eternity. - */ -public class IggyFlashHeader64 implements IggyFlashHeaderInterface { - - @IggyFieldType(DataType.uint64_t) - long main_offset; // 0 Relative offset to first section (matches sizeof header); - @IggyFieldType(DataType.uint64_t) - long as3_section_offset; // 8 Relative offset to as3 file names table... - @IggyFieldType(DataType.uint64_t) - long unk_offset; // 0x10 relative offset to something - @IggyFieldType(DataType.uint64_t) - long unk_offset2; // 0x18 relative offset to something - @IggyFieldType(DataType.uint64_t) - long unk_offset3; // 0x20 relative offset to something - @IggyFieldType(DataType.uint64_t) - long unk_offset4; // 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 fonts_offset; - @IggyFieldType(DataType.uint64_t) - long unk_68; - @IggyFieldType(DataType.uint64_t) - long names_offset; // 0x70 relative offset to the names/import section of the file - end of fonts - @IggyFieldType(DataType.uint64_t) - long unk_offset5; // 0x78 relative offset to something - @IggyFieldType(DataType.uint64_t) - long unk_80; // Maybe number of imports/names pointed by names_offset - @IggyFieldType(DataType.uint64_t) - long last_section_offset; // 0x88 relative offset, points to the small last section of the file - @IggyFieldType(DataType.uint64_t) - long unk_offset6; // 0x90 relative offset to something - @IggyFieldType(DataType.uint64_t) - long as3_code_offset; // 0x98 relative offset to as3 code (16 bytes header + abc blob) - @IggyFieldType(DataType.uint64_t) - long as3_names_offset; // 0xA0 relative offset to as3 file names table (or classes names or whatever) - @IggyFieldType(DataType.uint32_t) - long unk_A8; - @IggyFieldType(DataType.uint32_t) //font_main_off - long unk_AC; //font_main_size - @IggyFieldType(DataType.uint32_t) //font_info_off - long font_count; // Maybe number of classes / as3 names //font_info_size - @IggyFieldType(DataType.uint32_t) - long unk_B4; //zero (?) - - // 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(AbstractDataStream stream) throws IOException { - readFromDataStream(stream); - } - - @Override - public void readFromDataStream(AbstractDataStream stream) throws IOException { - main_offset = stream.readUI64(); - as3_section_offset = stream.readUI64(); - unk_offset = stream.readUI64(); - unk_offset2 = stream.readUI64(); - unk_offset3 = stream.readUI64(); - unk_offset4 = stream.readUI64(); - xmin = stream.readUI32(); - ymin = stream.readUI32(); - xmax = stream.readUI32(); - ymax = stream.readUI32(); - unk_40 = stream.readUI32(); - 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(); - fonts_offset = stream.readUI64(); - unk_68 = stream.readUI64(); - names_offset = stream.readUI64(); - unk_offset5 = stream.readUI64(); - unk_80 = stream.readUI64(); - last_section_offset = stream.readUI64(); - unk_offset6 = stream.readUI64(); - as3_code_offset = stream.readUI64(); - as3_names_offset = stream.readUI64(); - unk_A8 = stream.readUI32(); - unk_AC = stream.readUI32(); - font_count = stream.readUI32(); - unk_B4 = stream.readUI32(); - - } - - @Override - public void writeToDataStream(AbstractDataStream 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); - sb.append(" global: ").append(main_offset + as3_section_offset); - sb.append("\r\n"); - sb.append("unk_offset ").append(unk_offset); - if (unk_offset != 1) { - sb.append(" global: ").append(main_offset + unk_offset); - } - sb.append("\r\n"); - sb.append("unk_offset2 ").append(unk_offset2); - if (unk_offset2 != 1) { - sb.append(" global: ").append(main_offset + unk_offset2); - } - sb.append("\r\n"); - sb.append("unk_offset3 ").append(unk_offset3); - if (unk_offset3 != 1) { - sb.append(" global: ").append(main_offset + unk_offset3); - } - sb.append("\r\n"); - sb.append("unk_offset4 ").append(unk_offset4); - if (unk_offset4 != 1) { - sb.append(" global: ").append(main_offset + unk_offset4); - } - sb.append("\r\n"); - sb.append("xmin ").append(xmin).append("\r\n"); - sb.append("ymin ").append(ymin).append("\r\n"); - sb.append("xmax ").append(ymax).append("\r\n"); - sb.append("ymax ").append(ymax).append("\r\n"); - sb.append("unk_40 ").append(unk_40).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("unk_50 ").append(unk_50).append("\r\n"); - sb.append("unk_54 ").append(unk_54).append("\r\n"); - sb.append("frame_rate ").append(frame_rate).append("\r\n"); - sb.append("unk_5C ").append(unk_5C).append("\r\n"); - sb.append("fonts_offset ").append(fonts_offset).append("\r\n"); - sb.append("unk_68 ").append(unk_68).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_80 ").append(unk_80).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_A8 ").append(unk_A8).append("\r\n"); - sb.append("unk_AC ").append(unk_AC).append("\r\n"); - sb.append("font_count ").append(font_count).append("\r\n"); - sb.append("unk_B4 ").append(unk_B4).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 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 0cde6ac8a..42dabf338 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,18 +1,20 @@ -package com.jpexs.decompiler.flash.iggy; - -/** - * - * @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 bd9def55c..978d05c8e 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,316 +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 java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -/** - * - * @author JPEXS - */ -public class IggyFont implements StructureInterface { - - 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.uint8_t, count = 272) - byte[] zeroes; - @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.widechar_t, count = 16) - String name; - - List charOffsets; - List glyphs; - IggyCharIndices codePoints; - IggyCharAdvances charScales; - IggyCharKerning charKernings; - - byte[] padTo4byteBoundary; - - public IggyFont(int type, int order_in_iggy_file, byte[] zeroone, int char_count2, int ascent, int descent, int leading, long flags, long start_of_char_struct, long start_of_char_index, long start_of_scale, long kern_count, float[] unk_float, long start_of_kern, long zero_padd, long what_2, long zero_padd_2, long start_of_name, 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[] zeroes, 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 chars, IggyCharIndices charIndices, IggyCharAdvances charScales, IggyCharKerning charKernings, byte[] padTo4byteBoundary) { - this.type = type; - this.fontId = order_in_iggy_file; - this.zeroone = zeroone; - this.char_count2 = char_count2; - this.ascent = ascent; - this.descent = descent; - this.leading = leading; - this.flags = flags; - this.start_of_char_struct = start_of_char_struct; - this.start_of_char_index = start_of_char_index; - this.start_of_scale = start_of_scale; - this.kern_count = kern_count; - this.unk_float = unk_float; - this.start_of_kern = start_of_kern; - this.zero_padd = zero_padd; - this.what_2 = what_2; - this.zero_padd_2 = zero_padd_2; - this.start_of_name = start_of_name; - 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.zeroes = zeroes; - 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 = chars; - this.codePoints = charIndices; - this.charScales = charScales; - this.charKernings = charKernings; - this.padTo4byteBoundary = padTo4byteBoundary; - } - - public IggyFont(AbstractDataStream stream) throws IOException { - readFromDataStream(stream); - } - - private long readAbsoluteOffset(AbstractDataStream stream) throws IOException { - long offset = stream.readUI64(); - if (offset == 1) { - return 0; - } - return stream.position() - 8 + offset; - } - - @Override - public void readFromDataStream(AbstractDataStream stream) throws IOException { - ByteArrayDataStream s = new ByteArrayDataStream(stream.readBytes((int) (long) stream.available()), stream.is64()); - 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(); - start_of_char_struct = readAbsoluteOffset(s); - start_of_char_index = readAbsoluteOffset(s); - start_of_scale = readAbsoluteOffset(s); - kern_count = s.readUI32(); - unk_float = new float[5]; - for (int i = 0; i < unk_float.length; i++) { - unk_float[i] = s.readFloat(); - } - start_of_kern = readAbsoluteOffset(s); - zero_padd = s.readUI64(); - what_2 = s.readUI64(); - zero_padd_2 = s.readUI64(); - start_of_name = readAbsoluteOffset(s); - 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(); - s.seek(272, SeekMode.CUR); - 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(); - if (start_of_name != 0) { - s.seek(start_of_name, SeekMode.SET); - StringBuilder nameBuilder = new StringBuilder(); - int nameCharCnt = 0; - do { - char c = (char) s.readUI16(); - nameCharCnt++; - if (c == '\0') { - break; - } - nameBuilder.append(c); - } while (true); - s.seek(32 - nameCharCnt * 2, SeekMode.CUR); - name = nameBuilder.toString(); - } - s.readUI64(); //pad zero - if (start_of_char_struct != 0) { - s.seek(start_of_char_struct, SeekMode.SET); - charOffsets = new ArrayList<>(); - for (int i = 0; i < char_count; i++) { - charOffsets.add(new IggyCharOffset(s)); - } - glyphs = new ArrayList<>(); - for (int i = 0; i < char_count; i++) { - long offset = charOffsets.get(i).offset; - glyphs.add(new IggyShape(s, offset)); - } - } - if (start_of_char_index != 0) { - s.seek(start_of_char_index, SeekMode.SET); - codePoints = new IggyCharIndices(s, char_count); - } - if (start_of_scale != 0) { - s.seek(start_of_scale, SeekMode.SET); - charScales = new IggyCharAdvances(s, char_count); - } - if (start_of_kern != 0) { - s.seek(start_of_kern, SeekMode.SET); - charKernings = new IggyCharKerning(s, kern_count); - } - } - - @Override - public void writeToDataStream(AbstractDataStream stream) throws IOException { - throw new UnsupportedOperationException("Not supported yet."); - } - - 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; - } - -} +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 new file mode 100644 index 000000000..a76f2127b --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFontBinInfo.java @@ -0,0 +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); + } + +} 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 new file mode 100644 index 000000000..b326f6673 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFontTypeInfo.java @@ -0,0 +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); + } + +} 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 ca9b8f9a2..c6890e6a2 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,153 +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 java.io.IOException; - -/** - * - * @author JPEXS - * - * little endian all - * - * Based of works of somebody called eternity. - */ -public class IggyHeader implements StructureInterface { - - 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(AbstractDataStream 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(AbstractDataStream 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(AbstractDataStream stream) throws IOException { - throw new UnsupportedOperationException("Not supported yet."); - } - - 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/IggyIndexParser.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyIndexParser.java deleted file mode 100644 index f5c963b7f..000000000 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyIndexParser.java +++ /dev/null @@ -1,165 +0,0 @@ -package com.jpexs.decompiler.flash.iggy; - -import java.io.IOException; -import java.util.List; -import java.util.logging.Logger; - -/** - * - * @author Jindra - */ -public class IggyIndexParser { - - private static Logger LOGGER = Logger.getLogger(IggyIndexParser.class.getName()); - - /* - Offsets: - 1) name - 2) UI16 - zero - 3) tag list - 4) ... tag data offsets - - */ - /** - * 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(ByteArrayDataStream 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: %02x\n", offset)); - indexTable[i] = offset; - indexTableEntry.add(offset); - int num = indexStream.readUI8(); - indexStream.seek(num * 2, SeekMode.CUR); - } - - long offset = 0; - int code; - - while ((code = indexStream.readUI8()) > -1) { - LOGGER.finer(String.format("Code = %x\n", code)); - - if (code < 0x80) // 0-0x7F - { - // 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\n", code, indexTableSize)); - return; - } - - offset += indexTable[code]; - } else if (code < 0xC0) // 0x80-BF - { - int index; - - if ((index = indexStream.readUI8()) < 0) { - LOGGER.severe(String.format("< 0xC0: Cannot read index.\n")); - return; - } - - if (index >= indexTableSize) { - LOGGER.severe(String.format("< 0xC0: index is greater than index_table_size. %x > %x\n", index, indexTableSize)); - return; - } - - int n = code - 0x7F; - offset += indexTable[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; - int n8; - int n; - - if ((n8 = indexStream.readUI8()) < 0) { - LOGGER.severe(String.format("< 0xE0: Cannot read n.\n")); - return; - } - - n = n8 + 1; - - if (indexStream.is64()) { - 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.severe(String.format("< 0xE0: Invalid value for i (%x %x)\n", 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.severe(String.format("< 0xE0: invalid value for i (%x %x)\n", i, code)); - } - } - } else if (code == 0xFC) { - indexStream.seek(1, SeekMode.CUR); - } else if (code == 0xFD) { - int n, m; - - if ((n = indexStream.readUI8()) < 0) { - LOGGER.severe(String.format("0xFD: Cannot read n.\n")); - return; - } - - if ((m = indexStream.readUI8()) < 0) { - LOGGER.severe(String.format("0xFD: Cannot read m.\n")); - return; - } - - offset += n; - indexStream.seek(m * 2, SeekMode.CUR); - } else if (code == 0xFE) { - int n8; - int n; - - if ((n8 = indexStream.readUI8()) < 0) { - LOGGER.severe(String.format("0xFE: Cannot read n.\n")); - return; - } - - n = n8 + 1; - offset += n; - } else if (code == 0xFF) { - long n; - - if ((n = indexStream.readUI32()) < 0) { - LOGGER.severe(String.format("0xFF: Cannot read n.\n")); - return; - } - - offset += n; - } else { - LOGGER.warning(String.format("Unrecognized code: %x\n", code)); - } - - offsets.add(offset); - } - } -} 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 e5272877e..1cecf0e49 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,155 +1,174 @@ -package com.jpexs.decompiler.flash.iggy; - -import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Logger; - -/** - * - * @author JPEXS - */ -public class IggyShape implements StructureInterface { - - 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; - - private long offset; - - public IggyShape(AbstractDataStream stream, long offset) throws IOException { - this.offset = offset; - readFromDataStream(stream); - } - - public IggyShape(float minx, float miny, float maxx, float maxy, long advance, long count, long one, long one2, long one3, long one4, long two1, List nodes) { - this.minx = minx; - this.miny = miny; - this.maxx = maxx; - this.maxy = maxy; - this.unk = advance; - this.count = count; - this.one = one; - this.one2 = one2; - this.one3 = one3; - this.one4 = one4; - this.two1 = two1; - this.nodes = nodes; - } - - @Override - public void readFromDataStream(AbstractDataStream s) throws IOException { - s.seek(offset, SeekMode.SET); - 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 pos %d, one: %d, one2: %d, one3: %d, one4: %d, two1: %d\n", offset, 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(AbstractDataStream stream) throws IOException { - throw new UnsupportedOperationException("Not supported yet."); - } - - 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 d235c9562..0961f838e 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,122 +1,135 @@ -package com.jpexs.decompiler.flash.iggy; - -import com.jpexs.decompiler.flash.iggy.annotations.IggyFieldType; -import java.io.IOException; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - * @author JPEXS - */ -public class IggyShapeNode implements StructureInterface { - - 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 x1, float y1, float x2, float y2, int node_type, int node_subtype, int zer1, int zer2, long isstart) { - this.targetX = x1; - this.targetY = y1; - this.controlX = x2; - this.controlY = y2; - this.node_type = node_type; - this.node_subtype = node_subtype; - this.zer1 = zer1; - this.zer2 = zer2; - this.isstart = isstart; - } - - public IggyShapeNode(AbstractDataStream s, boolean first) throws IOException { - this.first = first; - readFromDataStream(s); - } - - @Override - public void readFromDataStream(AbstractDataStream 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(AbstractDataStream stream) throws IOException { - throw new UnsupportedOperationException("Not supported yet."); - } - - public float getX1() { - return targetX; - } - - public float getY1() { - return targetY; - } - - public float getX2() { - return controlX; - } - - public float getY2() { - 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 e08a16cf9..485789a04 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,70 +1,76 @@ -package com.jpexs.decompiler.flash.iggy; - -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -/** - * - * @author JPEXS - * - * Based of works of somebody called eternity. - */ -public class IggySubFileEntry implements StructureInterface { - - 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(AbstractDataStream 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(AbstractDataStream stream) throws IOException { - type = stream.readUI32(); - size = stream.readUI32(); - size2 = stream.readUI32(); - offset = stream.readUI32(); - } - - @Override - public void writeToDataStream(AbstractDataStream stream) throws IOException { - throw new UnsupportedOperationException("Not supported yet."); - } - -} +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 new file mode 100644 index 000000000..34fafba0f --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggySwf.java @@ -0,0 +1,318 @@ +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.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 new file mode 100644 index 000000000..eeae0f3cb --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyTag.java @@ -0,0 +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()); + } +} 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 9931df6ea..8aee23b66 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 java.io.IOException; - -/** - * - * @author JPEXS - */ -public class IggyText implements StructureInterface { - - 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 - @IggyArrayFieldType(value = DataType.widechar_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(AbstractDataStream stream) throws IOException { - this.readFromDataStream(stream); - } - - @Override - public void readFromDataStream(AbstractDataStream 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(); - - //flags - enum_hex = s.readUI16(); - - int en = enum_hex; - - //guessing - it could be like DefineEditText?... - hasText = ((en >> 0) & 1) == 1; - wordWrap = ((en >> 1) & 1) == 1; - multiline = ((en >> 2) & 1) == 1; - password = ((en >> 3) & 1) == 1; - readOnly = ((en >> 4) & 1) == 1; - hasTextColor = ((en >> 5) & 1) == 1; - hasMaxLength = ((en >> 6) & 1) == 1; - hasFont = ((en >> 7) & 1) == 1; - hasFontClass = ((en >> 8) & 1) == 1; - autosize = ((en >> 9) & 1) == 1; - hasLayout = ((en >> 10) & 1) == 1; - noSelect = ((en >> 11) & 1) == 1; - border = ((en >> 12) & 1) == 1; - wasStatic = ((en >> 13) & 1) == 1; - html = ((en >> 14) & 1) == 1; - useOutlines = ((en >> 15) & 1) == 1; - - //if hasFont? - fontIndex = s.readUI16(); //fontId - //if hasFontClass - readString? - //if hasFont || hasFontClass - readFontHeight? - //if hasTextColor....? - zero = s.readUI32(); - one = s.readUI64(); //01CB FF33 3333 - some = s.readBytes(32); // [6] => 40, [24] => 8 - StringBuilder textBuilder = new StringBuilder(); - do { - char c = (char) s.readUI16(); - if (c == '\0') { - break; - } - textBuilder.append(c); - } while (true); - initialText = textBuilder.toString(); - } - - @Override - public void writeToDataStream(AbstractDataStream stream) throws IOException { - throw new UnsupportedOperationException("Not supported yet."); - } - - 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 new file mode 100644 index 000000000..9f1e0aeaa --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/RawIggyPart.java @@ -0,0 +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); + } + +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/StructureInterface.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/StructureInterface.java deleted file mode 100644 index 8638c42e0..000000000 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/StructureInterface.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.jpexs.decompiler.flash.iggy; - -import java.io.IOException; -import java.util.List; - -/** - * - * @author JPEXS - */ -public interface StructureInterface { - - public void readFromDataStream(AbstractDataStream stream) throws IOException; - - public void writeToDataStream(AbstractDataStream stream) throws IOException; -} 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 new file mode 100644 index 000000000..9d3325283 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/annotations/FieldPrinter.java @@ -0,0 +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(); + } +} 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 8644c6882..00ab98dce 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.getX1()); - prevY = scr.moveDeltaY = makeLengthsEmY(ign.getY1()); - scr.fillStyles = new FILLSTYLEARRAY(); - scr.lineStyles = new LINESTYLEARRAY(); - scr.calculateBits(); - retList.add(scr); - } else { - - int curX1 = makeLengthsEmX(ign.getX1()); - int curY1 = makeLengthsEmY(ign.getY1()); - - int curX2 = makeLengthsEmX(ign.getX2()); - int curY2 = makeLengthsEmY(ign.getY2()); - - 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 330342129..058f010e1 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,104 +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.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.HashMap; -import java.util.Map; -import java.util.Set; -import java.util.TreeSet; - -/** - * - * @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 iggyFile.getSwfCount(); - } - - @Override - public Set getKeys() { - Set ret = new TreeSet<>(); - for (int i = 0; i < length(); i++) { - ret.add(iggyFile.getSwfName(i)); - } - return ret; - } - - private int keyToSwfIndex(String key) { - for (int i = 0; i < length(); i++) { - if (key.equals(iggyFile.getSwfName(i))) { - return i; - } - } - throw new IllegalArgumentException("Key " + key + " does not exist!"); - } - - @Override - public SeekableInputStream getSWF(String key) throws IOException { - SWF swf = IggyToSwfConvertor.getSwf(iggyFile, keyToSwfIndex(key)); - 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 true; //TODO: make writable - } - - @Override - public boolean putSWF(String key, InputStream is) throws IOException { - throw new UnsupportedOperationException("Not supported yet."); - } - -} +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 ee66d6c06..3fcaafad2 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,248 +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.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 SWF[] getAllSwfs(IggyFile file) { - SWF[] ret = new SWF[file.getSwfCount()]; - for (int i = 0; i < ret.length; i++) { - ret[i] = getSwf(file, i); - } - return ret; - } - - public static void exportAllSwfsToDir(IggyFile file, File outputDir) throws IOException { - for (int swfIndex = 0; swfIndex < file.getSwfCount(); swfIndex++) { - exportSwfToDir(file, swfIndex, outputDir); - } - } - - public static void exportSwfToDir(IggyFile file, int swfIndex, File outputDir) throws IOException { - try (FileOutputStream fos = new FileOutputStream(new File(outputDir, file.getSwfName(swfIndex)))) { - exportSwf(file, swfIndex, fos); - } - } - - public static void exportSwfToFile(IggyFile file, int swfIndex, File outputFile) throws IOException { - try (FileOutputStream fos = new FileOutputStream(outputFile)) { - exportSwf(file, swfIndex, fos); - } - } - - public static void exportSwf(IggyFile file, int swfIndex, OutputStream output) throws IOException { - SWF swf = getSwf(file, swfIndex); - swf.saveTo(output); - } - - private static int makeLengthsTwip(double val) { - return (int) (val * SWF.unitDivisor); - } - - private static int makeLengthsEm(double val) { - return (int) (val * 1024.0); - } - - public static SWF getSwf(IggyFile file, int swfIndex) { - SWF swf = new SWF(); - swf.compression = SWFCompression.NONE; - swf.frameCount = 1; //FIXME!! - swf.frameRate = file.getSwfFrameRate(swfIndex); - swf.gfx = false; - swf.displayRect = new RECT( - (int) (file.getSwfXMin(swfIndex) * SWF.unitDivisor), - (int) (file.getSwfXMax(swfIndex) * SWF.unitDivisor), - (int) (file.getSwfYMin(swfIndex) * SWF.unitDivisor), - (int) (file.getSwfYMax(swfIndex) * 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 currentCharId = 0; - Map fontIndex2CharId = new HashMap<>(); - - for (int fontIndex : fontIndices) { - IggyFont iggyFont = file.getFont(swfIndex, 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 = makeLengthsEm(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); - IggyShape glyph = iggyFont.getChars().get(i); - fontTag.codeTable.add(code); - SHAPE shp = IggyShapeToSwfConvertor.convertCharToShape(glyph); - fontTag.glyphShapeTable.add(shp); - fontTag.fontBoundsTable.add(shp.getBounds()); - 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 new file mode 100644 index 000000000..c23c6a009 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/conversion/SwfShapeToIggyConvertor.java @@ -0,0 +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; + } +} 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 new file mode 100644 index 000000000..649135c3b --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/conversion/SwfToIggyConvertor.java @@ -0,0 +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; + } +} 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 new file mode 100644 index 000000000..2cda5f443 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/AbstractDataStream.java @@ -0,0 +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)); + } + } +} 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 new file mode 100644 index 000000000..d3a4f2916 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/DataStreamInterface.java @@ -0,0 +1,9 @@ +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 new file mode 100644 index 000000000..49c6263be --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/IggyIndexBuilder.java @@ -0,0 +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; + } + } +} 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 new file mode 100644 index 000000000..87e7f02c8 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/IggyIndexParser.java @@ -0,0 +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); + } + } +} 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 new file mode 100644 index 000000000..4b0f613bd --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/RandomAccessFileDataStream.java @@ -0,0 +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(); + } + +} 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 new file mode 100644 index 000000000..7536e6aef --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/ReadDataStreamInterface.java @@ -0,0 +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(); +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/SeekMode.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/SeekMode.java similarity index 55% rename from libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/SeekMode.java rename to libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/SeekMode.java index 449abf4ea..237fb8c7f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/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; - -/** - * - * @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 new file mode 100644 index 000000000..526445ddd --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/StructureInterface.java @@ -0,0 +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; +} 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 new file mode 100644 index 000000000..adb99afdd --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/TemporaryDataStream.java @@ -0,0 +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 + } + } +} 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 new file mode 100644 index 000000000..079d53136 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/WriteDataStreamInterface.java @@ -0,0 +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(); +}