Merge pull request #45 from jindrapetrik/iggyplus

Editing fonts in Iggy files
This commit is contained in:
Jindra Petřík
2016-12-04 19:17:04 +01:00
committed by GitHub
42 changed files with 5515 additions and 3326 deletions

View File

@@ -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
}
}

View File

@@ -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);
}
}

View File

@@ -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
}

View File

@@ -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<Float> advances;
private long charCount;
public List<Float> 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<Float> advances;
private long charCount;
public List<Float> getScales() {
return advances;
}
public IggyCharAdvances(List<Float> 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));
}
}
}

View File

@@ -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<Character> chars;
@IggyFieldType(DataType.uint32_t)
long padd;
public List<Character> 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<Character> chars;
@IggyFieldType(DataType.uint32_t)
long padd;
public List<Character> getChars() {
return chars;
}
private long charCount;
public IggyCharIndices(List<Character> 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);
}
}

View File

@@ -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<Character> charsA;
List<Character> charsB;
List<Short> kerningOffsets;
long pad;
public long getKernCount() {
return kernCount;
}
public List<Character> getCharsA() {
return charsA;
}
public List<Character> getCharsB() {
return charsB;
}
public List<Short> 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<Character> charsA;
List<Character> charsB;
List<Short> kerningOffsets;
public long getKernCount() {
return kernCount;
}
public List<Character> getCharsA() {
return charsA;
}
public List<Character> getCharsB() {
return charsB;
}
public List<Short> getKerningOffsets() {
return kerningOffsets;
}
public IggyCharKerning(List<Character> charsA, List<Character> charsB, List<Short> 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));
}
}
}

View File

@@ -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;
}
}

View File

@@ -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<Integer, IggyFont> fonts;
Map<Integer, IggyText> texts;
Map<Integer, Integer> text2Font;
private IggyFlashHeader64 header;
private Map<Long, Long> sizesOfOffsets;
private List<Long> allOffsets;
public IggyDataReader(IggyFlashHeader64 header, AbstractDataStream stream, List<Long> 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();
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}

View File

@@ -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<IggyCharOffset> charOffsets;
List<IggyShape> 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<IggyCharOffset> charOffsets, List<IggyShape> 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<IggyShape> 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<IggyCharOffset> 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<IggyCharOffset> charOffsets;
List<IggyShape> 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<IggyCharOffset> charOffsets, List<IggyShape> 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<Long> 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<Long> 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<IggyShape> 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<IggyCharOffset> 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<IggyCharOffset> charOffsets) {
this.charOffsets = charOffsets;
}
public void setGlyphs(List<IggyShape> 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;
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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<Integer> indexTableEntry, List<Long> 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);
}
}
}

View File

@@ -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<IggyShapeNode> 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<IggyShapeNode> 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<IggyShapeNode> 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<IggyShapeNode> nodes;
public IggyShape(ReadDataStreamInterface stream) throws IOException {
readFromDataStream(stream);
}
public IggyShape(float minx, float miny, float maxx, float maxy, List<IggyShapeNode> 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<IggyShapeNode> getNodes() {
return nodes;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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<IggyFont> fonts = new ArrayList<>();
// private List<Long> font_data_addresses = new ArrayList<>();
List<IggyFont> add_fonts = new ArrayList<>();
// private List<Long> add_font_data_addresses = new ArrayList<>();
private IggyFlashHeader64 hdr;
public IggySwf(ReadDataStreamInterface stream) throws IOException {
readFromDataStream(stream);
}
private List<IggyText> texts = new ArrayList<>();
//private List<Long> text_data_addresses = new ArrayList<>();
private List<IggyText> add_texts = new ArrayList<>();
//private List<Long> add_text_data_addresses = new ArrayList<>();
//private byte font_add_data[];
//private List<Long> font_additional_size = new ArrayList<>();
private IggyFontBinInfo font_bin_info[];
private List<String> sequenceNames = new ArrayList<>();
//private List<Long> 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<Long> 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<Long> 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<Long> fontPosFillLater = new ArrayList<>();
for (int i = 0; i < fonts.size(); i++) {
fontPosFillLater.add(s.position());
s.writeUI64(FILL_LATER);
}
List<Long> 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<Long> addFontPosFillLater = new ArrayList<>();
for (int i = 0; i < add_fonts.size(); i++) {
addFontPosFillLater.add(s.position());
s.writeUI64(FILL_LATER);
}
List<Long> 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();
}
}

View File

@@ -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());
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}

View File

@@ -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();
}
}

View File

@@ -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<SHAPERECORD> retList = new ArrayList<>();
List<IggyShapeNode> 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<SHAPERECORD> retList = new ArrayList<>();
List<IggyShapeNode> 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;
}
}

View File

@@ -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<String> getKeys() {
Set<String> 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<String, SeekableInputStream> getAll() throws IOException {
Map<String, SeekableInputStream> 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<String> getKeys() {
Set<String> 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<String, SeekableInputStream> getAll() throws IOException {
Map<String, SeekableInputStream> 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<DefineFont2Tag> 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;
}
}
}

View File

@@ -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<Integer> fontIndices = file.getFontIds(swfIndex);
int currentCharId = 0;
Map<Integer, Integer> 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<Integer, Integer> textIndex2CharId = new HashMap<>();
Set<Integer> 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<Integer> fontIndices = file.getFontIds(swfIndex);
int fontCount = file.getFontCount();
int currentCharId = 0;
Map<Integer, Integer> 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<Integer, Integer> textIndex2CharId = new HashMap<>();
Set<Integer> 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);
}
}
}

View File

@@ -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<IggyShapeNode> 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;
}
}

View File

@@ -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<IggyCharOffset> charOffsets = new ArrayList<>();
List<IggyShape> glyphs = new ArrayList<>();
for (SHAPE s : fontTag.glyphShapeTable) {
glyphs.add(SwfShapeToIggyConvertor.convertShape(s));
}
List<Character> chars = new ArrayList<>();
for (int code : fontTag.codeTable) {
chars.add((char) code);
}
IggyCharIndices codePoints = new IggyCharIndices(chars);
List<Float> scales = new ArrayList<>();
for (int adv : fontTag.fontAdvanceTable) {
scales.add(normalizeLengths(adv));
}
IggyCharAdvances charScales = new IggyCharAdvances(scales);
List<Character> charA = new ArrayList<>();
List<Character> charB = new ArrayList<>();
List<Short> 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<IggyCharOffset> charOffsets = new ArrayList<>();
List<IggyShape> glyphs = new ArrayList<>();
List<Character> chars = new ArrayList<>();
for (int code : fontTag.codeTable) {
chars.add((char) code);
}
IggyCharIndices codePoints = new IggyCharIndices(chars);
List<Float> scales = new ArrayList<>();
for (int adv : fontTag.fontAdvanceTable) {
scales.add((float) adv);
}
IggyCharAdvances charScales = new IggyCharAdvances(scales);
List<Character> charA = new ArrayList<>();
List<Character> charB = new ArrayList<>();
List<Short> 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;
}
}

View File

@@ -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));
}
}
}

View File

@@ -0,0 +1,9 @@
package com.jpexs.decompiler.flash.iggy.streams;
/**
*
* @author JPEXS
*/
public interface DataStreamInterface extends ReadDataStreamInterface, WriteDataStreamInterface {
}

View File

@@ -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<Integer> constTable = new ArrayList<>();
private Map<Integer, List<Integer>> constTableOffsets = new HashMap<>();
private Map<Integer, List<Integer>> 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<Integer> localOffsetsList = new ArrayList<>();
for (int t : localOffsets) {
localOffsetsList.add(t);
}
List<Integer> 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;
}
}
}

View File

@@ -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<Integer> indexTableEntry, List<Long> 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);
}
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}

View File

@@ -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
}

View File

@@ -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;
}

View File

@@ -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
}
}
}

View File

@@ -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();
}