Saving correct font data offsets

This commit is contained in:
Jindra Petřík
2016-12-04 18:57:10 +01:00
parent 0403e847f5
commit 1894606551
21 changed files with 890 additions and 618 deletions

View File

@@ -20,6 +20,11 @@ public class IggyCharAdvances implements StructureInterface {
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);

View File

@@ -25,6 +25,12 @@ public class IggyCharIndices implements StructureInterface {
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);

View File

@@ -36,6 +36,16 @@ public class IggyCharKerning implements StructureInterface {
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);

View File

@@ -38,15 +38,15 @@ public class IggyCharOffset implements StructureInterface {
readFromDataStream(stream);
}
public IggyCharOffset(long zero, int ischar1, int ischar2, long zero2, int xscale, int yscale, long zero3, long offset) {
this.zero = zero;
public IggyCharOffset(int ischar1, int ischar2, int xscale, int yscale) {
this.zero = 0;
this.ischar1 = ischar1;
this.ischar2 = ischar2;
this.zero2 = zero2;
this.zero2 = 0;
this.xscale = xscale;
this.yscale = yscale;
this.zero3 = zero3;
this.offset = offset;
this.zero3 = 0;
this.offset = 0;
}
@Override

View File

@@ -35,63 +35,25 @@ public class IggyFile implements StructureInterface {
final static Logger LOGGER = Logger.getLogger(IggyFile.class.getName());
private File originalFile;
private IggyHeader header;
private List<IggySubFileEntry> subFileEntries = new ArrayList<>();
private List<byte[]> subFileEntriesData = new ArrayList<>();
private List<IggySwf> iggySwfs = new ArrayList<>();
private IggySwf iggySwf;
public static final int FIRST_TAG_POSITION = 3;
public void replaceFontTag(int targetSwfIndex, int fontIndex, IggyFont newFont) throws IOException {
IggySwf iggySwf = iggySwfs.get(targetSwfIndex);
iggySwf.replaceFontTag(fontIndex, newFont);
IggyIndexBuilder indexStream = new IggyIndexBuilder();
DataStreamInterface flashStream = new TemporaryDataStream();
flashStream.setIndexing(indexStream);
iggySwf.writeToDataStream(flashStream);
byte flashData[] = flashStream.getAllBytes();
int swfIndex = 0;
int offsetChange = 0;
for (int i = 0; i < subFileEntries.size(); i++) {
IggySubFileEntry entry = subFileEntries.get(i);
entry.offset += offsetChange;
if (entry.type == IggySubFileEntry.TYPE_INDEX) {
if (swfIndex == targetSwfIndex) {
byte indexData[] = indexStream.getIndexBytes();
long newLen = indexData.length;
long oldLen = entry.size;
entry.size = newLen;
entry.size2 = newLen;
offsetChange += (newLen - oldLen);
subFileEntriesData.set(i, indexData);
}
swfIndex++;
}
if (entry.type == IggySubFileEntry.TYPE_FLASH) {
if (swfIndex == targetSwfIndex) {
long newLen = flashData.length;
long oldLen = entry.size;
entry.size = newLen;
entry.size2 = newLen;
offsetChange += (newLen - oldLen);
subFileEntriesData.set(i, flashData);
}
}
}
public IggySwf getSwf() {
return iggySwf;
}
public IggySwf getSwf(int swfIndex) {
return iggySwfs.get(swfIndex);
public int getFontCount() {
return iggySwf.fonts.size();
}
public int getFontCount(int swfIndex) {
return iggySwfs.get(swfIndex).fonts.size();
}
public IggyFont getFont(int swfIndex, int fontId) {
return iggySwfs.get(swfIndex).fonts.get(fontId);
public IggyFont getFont(int fontId) {
return iggySwf.fonts.get(fontId);
}
public IggyFile(String filePath) throws IOException {
@@ -99,11 +61,16 @@ public class IggyFile implements StructureInterface {
}
public IggyFile(File file) throws IOException {
this.originalFile = file;
try (ReadDataStreamInterface stream = new RandomAccessFileDataStream(file)) {
readFromDataStream(stream);
}
}
public File getOriginalFile() {
return originalFile;
}
public IggyHeader getHeader() {
return header;
}
@@ -200,8 +167,7 @@ public class IggyFile implements StructureInterface {
File outFile = new File(outFileName);
IggyFile iggyFile = new IggyFile(inFile);
extractIggyFile(inFile, extractDirOrig);
IggySwf iswf = iggyFile.getSwf(0);
iggyFile.replaceSwf(0, iswf);
iggyFile.updateFlashEntry();
outFile.delete();
try (RandomAccessFileDataStream outputStream = new RandomAccessFileDataStream(outFile)) {
iggyFile.writeToDataStream(outputStream);
@@ -620,32 +586,28 @@ public class IggyFile implements StructureInterface {
return null;
}
public int getSwfCount() {
return iggySwfs.size();
public String getSwfName() {
return iggySwf.getName();
}
public String getSwfName(int swfIndex) {
return iggySwfs.get(swfIndex).getName();
public long getSwfXMin() {
return iggySwf.getHdr().getXMin();
}
public long getSwfXMin(int swfIndex) {
return iggySwfs.get(swfIndex).getHdr().getXMin();
public long getSwfYMin() {
return iggySwf.getHdr().getYMin();
}
public long getSwfYMin(int swfIndex) {
return iggySwfs.get(swfIndex).getHdr().getYMin();
public long getSwfXMax() {
return iggySwf.getHdr().getXMax();
}
public long getSwfXMax(int swfIndex) {
return iggySwfs.get(swfIndex).getHdr().getXMax();
public long getSwfYMax() {
return iggySwf.getHdr().getYMax();
}
public long getSwfYMax(int swfIndex) {
return iggySwfs.get(swfIndex).getHdr().getYMax();
}
public float getSwfFrameRate(int swfIndex) {
return iggySwfs.get(swfIndex).getHdr().getFrameRate();
public float getSwfFrameRate() {
return iggySwf.getHdr().getFrameRate();
}
/**
@@ -667,11 +629,8 @@ public class IggyFile implements StructureInterface {
}
}
public boolean replaceSwf(int targetSwfIndex, IggySwf iggySwf) throws IOException {
public boolean updateFlashEntry() throws IOException {
if (targetSwfIndex < 0 || targetSwfIndex >= getSwfCount()) {
throw new ArrayIndexOutOfBoundsException("No such SWF file index");
}
byte replacementData[];
byte replacementIndexData[];
IggyIndexBuilder ib = new IggyIndexBuilder();
@@ -685,21 +644,17 @@ public class IggyFile implements StructureInterface {
return false;
}
//IggyIndexParser.parseIndex(true, new TemporaryDataStream(replacementIndexData), new ArrayList<>(), new ArrayList<>());
int swfIndex = 0;
long offsetsChange = 0;
for (int i = 0; i < subFileEntries.size(); i++) {
IggySubFileEntry entry = subFileEntries.get(i);
entry.offset += offsetsChange;
if (entry.type == IggySubFileEntry.TYPE_FLASH) {
if (swfIndex == targetSwfIndex) {
long oldSize = entry.size;
long newSize = replacementData.length;
entry.size = newSize;
entry.size2 = newSize;
offsetsChange = offsetsChange + (newSize - oldSize); //entries after this one will have modified offsets
subFileEntriesData.set(i, replacementData);
}
long oldSize = entry.size;
long newSize = replacementData.length;
entry.size = newSize;
entry.size2 = newSize;
offsetsChange = offsetsChange + (newSize - oldSize); //entries after this one will have modified offsets
subFileEntriesData.set(i, replacementData);
}
}
@@ -714,7 +669,8 @@ public class IggyFile implements StructureInterface {
for (int i = 0; i < subFileEntries.size(); i++) {
IggySubFileEntry entry = subFileEntries.get(i);
if (entry.type == IggySubFileEntry.TYPE_FLASH) {
iggySwfs.add(new IggySwf(new TemporaryDataStream(getEntryData(i))));
iggySwf = new IggySwf(new TemporaryDataStream(getEntryData(i)));
break;
}
/*if (entry.type == IggySubFileEntry.TYPE_INDEX) {
IggyIndexParser.parseIndex(true, new TemporaryDataStream(getEntryData(i)), new ArrayList<>(), new ArrayList<>());
@@ -736,6 +692,13 @@ public class IggyFile implements StructureInterface {
parseEntries();
}
public void saveChanges() throws IOException {
updateFlashEntry();
try (RandomAccessFileDataStream raf = new RandomAccessFileDataStream(originalFile)) {
writeToDataStream(raf);
}
}
@Override
public void writeToDataStream(WriteDataStreamInterface stream) throws IOException {
header.writeToDataStream(stream);

View File

@@ -99,6 +99,67 @@ public class IggyFlashHeader64 implements IggyFlashHeaderInterface {
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
*
@@ -146,6 +207,10 @@ public class IggyFlashHeader64 implements IggyFlashHeaderInterface {
}
public long getSequenceStartAddress2() {
return sequence_start_address2;
}
public long getSequenceStartAddress3() {
return sequence_start_address3;
}
@@ -175,21 +240,27 @@ public class IggyFlashHeader64 implements IggyFlashHeaderInterface {
@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;
@@ -209,23 +280,29 @@ public class IggyFlashHeader64 implements IggyFlashHeaderInterface {
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;

View File

@@ -108,9 +108,7 @@ public class IggyFont extends IggyTag {
IggyCharAdvances charScales;
IggyCharKerning charKernings;
byte[] padTo4byteBoundary;
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, byte[] padTo4byteBoundary) {
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;
@@ -149,7 +147,6 @@ public class IggyFont extends IggyTag {
this.codePoints = codePoints;
this.charScales = charScales;
this.charKernings = charKernings;
this.padTo4byteBoundary = padTo4byteBoundary;
}
public IggyFont(ReadDataStreamInterface stream) throws IOException {
@@ -276,8 +273,10 @@ public class IggyFont extends IggyTag {
}
glyphs = new ArrayList<>();
for (int i = 0; i < char_count; i++) {
//System.err.println("read char " + (i + 1) + "/" + char_count);
long addr = charAddresses.get(i);
if (addr != 0) {
//System.err.println("read chars at offset " + addr);
s.seek(addr, SeekMode.SET);
glyphs.add(new IggyShape(s));
} else {
@@ -506,4 +505,108 @@ public class IggyFont extends IggyTag {
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

@@ -15,7 +15,7 @@ public class IggyFontBinInfo implements StructureInterface {
public static final int STRUCT_SIZE = 96;
@IggyFieldType(DataType.uint64_t)
long size_of_this_info = 96;
long size_of_this_info = STRUCT_SIZE;
@IggyFieldType(value = DataType.uint16_t, count = 4)
int font_specific[];
@IggyFieldType(DataType.float_t)

View File

@@ -21,10 +21,10 @@ public class IggyFontTypeInfo implements StructureInterface {
@IggyFieldType(DataType.uint64_t)
long font_info_num;
private long local_name_address;
private long local_name_ofs_pos;
public long getLocal_name_address() {
return local_name_address;
public long getLocal_name_ofs_pos() {
return local_name_ofs_pos;
}
public IggyFontTypeInfo(ReadDataStreamInterface s) throws IOException {
@@ -34,39 +34,15 @@ public class IggyFontTypeInfo implements StructureInterface {
@Override
public void readFromDataStream(ReadDataStreamInterface s) throws IOException {
zero = s.readUI64();
local_name_ofs_pos = s.position();
ofs_local_name = s.readUI64();
local_name_address = ofs_local_name + s.position() - 8;
font_info_num = s.readUI64();
}
public String readFontInfo(ReadDataStreamInterface s) throws IOException {
long pos = s.position();
s.seek(local_name_address, SeekMode.SET);
StringBuilder inf_font_builder = new StringBuilder();
while (true) {
char c = (char) s.readUI16();
if (c == '\0') {
break;
}
inf_font_builder.append(c);
}
s.seek(pos, SeekMode.SET);
return inf_font_builder.toString();
}
public void writeFontInfo(String info_name, WriteDataStreamInterface s) throws IOException {
long pos = s.position();
s.seek(local_name_address, SeekMode.SET);
for (int i = 0; i < info_name.length(); i++) {
s.writeUI16(info_name.charAt(i));
}
s.writeUI16(0);
s.seek(pos, SeekMode.SET);
}
@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,71 +0,0 @@
package com.jpexs.decompiler.flash.iggy;
import static com.jpexs.decompiler.flash.iggy.IggyFontBinInfo.STRUCT_SIZE;
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 IggySequence implements StructureInterface {
public static final int STRUCT_SIZE = 16;
@IggyArrayFieldType(value = DataType.uint64_t, count = 2)
public long onepadd[];
@IggyFieldType(DataType.uint64_t)
public long local_seq_offset;
@IggyFieldType(DataType.uint64_t)
public long zero;
@IggyFieldType(DataType.wchar_t)
public String sequence_name;
@IggyFieldType(DataType.uint64_t)
public long zero2;
// wchar_t sequencname[(sequenceendaddress-sequencestartaddress-localseqoffset)/2];
// if((sequenceendaddress-sequencestartaddress)%8!=0) byte padd[((sequenceendaddress-sequencestartaddress)/8+1)*8-(sequenceendaddress-sequencestartaddress)];
public IggySequence(ReadDataStreamInterface stream) throws IOException {
readFromDataStream(stream);
}
@Override
public void readFromDataStream(ReadDataStreamInterface s) throws IOException {
onepadd = new long[2];
for (int i = 0; i < onepadd.length; i++) {
onepadd[i] = s.readUI64();
}
//sequence start
local_seq_offset = s.readUI64();
zero = s.readUI64();
sequence_name = s.readWChar();
s.pad8bytes();
zero2 = s.readUI64(); //zero2
}
@Override
public void writeToDataStream(WriteDataStreamInterface s) throws IOException {
IggyIndexBuilder ib = s.getIndexing();
ib.writeLengthCustom(16, new int[]{0x00}, new int[]{2});
for (int i = 0; i < onepadd.length; i++) {
s.writeUI64(onepadd[i]);
}
ib.writeConstLength(IggyIndexBuilder.CONST_SEQUENCE_SIZE);
s.writeUI64(local_seq_offset);
s.writeUI64(zero);
ib.write16bitArray(sequence_name.length() + 1);
s.writeWChar(sequence_name);
s.pad8bytes();
ib.pad8bytes();
s.writeUI64(zero2);
}
}

View File

@@ -69,18 +69,18 @@ public class IggyShape implements StructureInterface {
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) {
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 = advance;
this.count = count;
this.one = one;
this.one2 = one2;
this.one3 = one3;
this.one4 = one4;
this.two1 = two1;
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;
}

View File

@@ -45,16 +45,17 @@ public class IggyShapeNode implements StructureInterface {
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;
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 = zer1;
this.zer2 = zer2;
this.isstart = isstart;
this.zer1 = 0;
this.zer2 = 0;
this.first = first;
this.isstart = first ? 0 : 1;
}
public IggyShapeNode(ReadDataStreamInterface s, boolean first) throws IOException {
@@ -98,19 +99,19 @@ public class IggyShapeNode implements StructureInterface {
s.writeUI32(isstart);
}
public float getX1() {
public float getTargetX() {
return targetX;
}
public float getY1() {
public float getTargetY() {
return targetY;
}
public float getX2() {
public float getControlX() {
return controlX;
}
public float getY2() {
public float getControlY() {
return controlY;
}

View File

@@ -28,9 +28,9 @@ public class IggySwf implements StructureInterface {
String name;
List<IggyFont> fonts = new ArrayList<>();
private List<Long> font_data_addresses = 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 List<Long> add_font_data_addresses = new ArrayList<>();
private IggyFlashHeader64 hdr;
@@ -38,14 +38,16 @@ public class IggySwf implements StructureInterface {
readFromDataStream(stream);
}
private List<IggyText> texts = new ArrayList<>();
private List<Long> text_data_addresses = 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 List<Long> add_text_data_addresses = new ArrayList<>();
private byte font_add_data[];
private List<Long> font_additional_size = new ArrayList<>();
//private byte font_add_data[];
//private List<Long> font_additional_size = new ArrayList<>();
private IggyFontBinInfo font_bin_info[];
private IggySequence sequence;
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;
@@ -56,36 +58,6 @@ public class IggySwf implements StructureInterface {
return hdr;
}
public void replaceFontTag(int fontIndex, IggyFont newFont) throws IOException {
/*long newLen;
byte newData[];
try (WriteDataStreamInterface stream = new TemporaryDataStream()) {
newFont.writeToDataStream(stream);
newData = stream.getAllBytes();
newLen = newData.length;
}
//FIXME
Helper.writeFile("d:\\Dropbox\\jpexs-laptop\\iggi\\extraxtdir_new\\font" + fontIndex + ".bin", newData);
long oldLen = font_data_sizes[fontIndex];
long diff = newLen - oldLen;
if (diff != 0) {
font_data_sizes[fontIndex] = newLen;
for (int i = fontIndex; i < hdr.font_count; i++) {
font_data_addresses[i] += diff;
}
for (int i = 0; i < text_addresses.size(); i++) {
text_addresses.set(i, text_addresses.get(i) + diff);
}
for (int i = 0; i < font_add_off.size(); i++) {
font_add_off.set(i, font_add_off.get(i) + diff);
}
}
hdr.insertGapAfter(font_data_addresses[fontIndex], diff);
*/
}
@Override
public void readFromDataStream(ReadDataStreamInterface s) throws IOException {
this.hdr = new IggyFlashHeader64(s);
@@ -97,7 +69,7 @@ public class IggySwf implements StructureInterface {
if (pad8 > 8) {
s.seek(pad8, SeekMode.CUR);
}
//here is offset [2] - 232
//here is offset [2] - 232
s.seek(hdr.getBaseAddress(), SeekMode.SET);
s.readUI64(); //pad 1
@@ -121,12 +93,12 @@ public class IggySwf implements StructureInterface {
switch (kind) {
case 22 /*FONT*/:
IggyFont font = new IggyFont(s);
font_data_addresses.add(addr);
//font_data_addresses.add(addr);
fonts.add(font);
break;
case 6 /*TEXT*/:
IggyText text = new IggyText(s);
text_data_addresses.add(addr);
//text_data_addresses.add(addr);
texts.add(text);
break;
default:
@@ -151,12 +123,12 @@ public class IggySwf implements StructureInterface {
switch (kind) {
case 22 /*FONT*/:
IggyFont font = new IggyFont(s);
add_font_data_addresses.add(addr);
//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_text_data_addresses.add(addr);
add_texts.add(text);
break;
default:
@@ -164,91 +136,6 @@ public class IggySwf implements StructureInterface {
}
}
}
/*
for (int i = 0; i < hdr.font_count; i++) {
long offset = s.readUI64();
font_data_addresses[i] = offset + s.position() - 8;
long next_offset = s.readUI64();
s.seek(-8, SeekMode.CUR);
if (next_offset == 1) {
font_data_sizes[i] = hdr.getFontEndAddress() - font_data_addresses[i];
} else {
font_data_sizes[i] = next_offset - offset + 8;
}
}
while (true) {
long offset = s.readUI64();
if (offset == 1) {
break;
}
long text_addr = offset + s.position() - 8;
text_addresses.add(text_addr);
long next_offset = s.readUI64();
s.seek(-8, SeekMode.CUR);
if (next_offset == 1) {
text_data_sizes.add(hdr.getFontEndAddress() - text_addr);
break;
} else {
text_data_sizes.add(next_offset - offset + 8);
}
}
s.readUI64(); //1
if (hdr.getImported_guid() != 0) {
ofs_additional = s.readUI64();
additional_address = ofs_additional + s.position() - 8;
font_additional_addresses.add(additional_address);
font_additional_size.add(hdr.getFontEndAddress() - font_additional_addresses.get(0));
if (s.readUI8(font_additional_addresses.get(0)) != 22) { //additional is not text
// font je hozen mezi infa...
for (int i = 0; i < text_addresses.size(); i++) { //walk all already read texts
if (s.readUI8(text_addresses.get(i)) == 22) { //check if it's text
long pomoff;
long pomsize;
pomoff = text_addresses.get(i);
pomsize = text_data_sizes.get(i);
text_addresses.set(i, font_additional_addresses.get(0));
text_data_sizes.set(i, font_additional_size.get(0));
font_additional_addresses.set(0, pomoff);
font_additional_size.set(0, pomsize);
}
}
}
}*/
/* if (s.readUI8(s.position()) == 22) { //22 = Text
byte[] textHdr = s.readBytes(IggyText.STRUCT_SIZE);
String textStr = s.readWChar();
s.pad8bytes();
}*/
//here is offset [3] - 744
/* fonts = new ArrayList<>();
for (int i = 0; i < hdr.font_count; i++) {
s.seek(font_data_addresses[i], SeekMode.SET);
byte font_data[] = s.readBytes((int) font_data_sizes[i]);
//FIXME
//Helper.writeFile("d:\\Dropbox\\jpexs-laptop\\iggi\\extraxtdir_orig\\font" + i + ".bin", font_data);
s.seek(-font_data_sizes[i], SeekMode.CUR);
IggyFont font = new IggyFont(s);
fonts.add(font);
}
for (int i = 0;
i < text_addresses.size();
i++) {
s.seek(text_addresses.get(i), SeekMode.SET);
texts.add(new IggyText(s));
//byte text_data[] = s.readBytes((int) (long) text_data_sizes.get(i));
//text_data_bytes.add(text_data);
}
if (hdr.getImported_guid()
!= 0) {
s.seek(font_additional_addresses.get(0), SeekMode.SET);
font_add_data = s.readBytes((int) (long) font_additional_size.get(0));
}*/
s.seek(hdr.getFontEndAddress(), SeekMode.SET);
//here is offset [4] - 856 ?
font_bin_info = new IggyFontBinInfo[(int) hdr.font_count];
@@ -256,9 +143,33 @@ public class IggySwf implements StructureInterface {
font_bin_info[i] = new IggyFontBinInfo(s);
}
s.seek(hdr.getSequenceStartAddress1(), SeekMode.SET);
sequence = new IggySequence(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];
@@ -266,7 +177,8 @@ public class IggySwf implements StructureInterface {
type_info[i] = new IggyFontTypeInfo(s);
}
for (int i = 0; i < hdr.font_count; i++) {
type_info_name[i] = type_info[i].readFontInfo(s);
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);
@@ -290,64 +202,114 @@ public class IggySwf implements StructureInterface {
ib.write16bitArray(name.length() + 1);
ib.writeTwoPaddingBytes();
ib.write64bitPointerArray(64);
for (int i = 0; i < font_data_addresses.size(); i++) {
long offset = font_data_addresses.get(i) - s.position();
s.writeUI64(offset);
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);
}
for (int i = 0; i < text_data_addresses.size(); i++) {
long offset = text_data_addresses.get(i) - s.position();
s.writeUI64(offset);
List<Long> textPosFillLater = new ArrayList<>();
for (int i = 0; i < texts.size(); i++) {
textPosFillLater.add(s.position());
s.writeUI64(FILL_LATER);
}
s.writeUI64(1);
if (additional_address != 0) {
long ofs_additional = additional_address - s.position();
s.writeUI64(ofs_additional);
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);
}
while (s.position() < font_data_addresses.get(0)) {
s.writeUI64(1);
}
for (int i = 0; i < fonts.size(); i++) {
s.seek(font_data_addresses.get(i), SeekMode.SET);
s.setOlderOffsetToThisPos(fontPosFillLater.get(i));
fonts.get(i).writeToDataStream(s);
}
for (int i = 0; i < texts.size(); i++) {
s.seek(text_data_addresses.get(i), SeekMode.SET);
s.setOlderOffsetToThisPos(textPosFillLater.get(i));
texts.get(i).writeToDataStream(s);
}
if (hdr.getImported_guid() != 0) {
if (!add_fonts.isEmpty() || !add_texts.isEmpty()) {
s.setOlderOffsetToThisPos(addPosFillLater);
List<Long> addFontPosFillLater = new ArrayList<>();
for (int i = 0; i < add_fonts.size(); i++) {
s.seek(add_font_data_addresses.get(i), SeekMode.SET);
fonts.get(i).writeToDataStream(s);
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.seek(add_text_data_addresses.get(i), SeekMode.SET);
texts.get(i).writeToDataStream(s);
s.setOlderOffsetToThisPos(addTextPosFillLater.get(i));
add_texts.get(i).writeToDataStream(s);
}
}
s.seek(hdr.getFontEndAddress(), SeekMode.SET);
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);
}
s.seek(hdr.getSequenceStartAddress1(), SeekMode.SET);
sequence.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.seek(hdr.getTypeFontsAddress(), SeekMode.SET);
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);
type_info[i].writeFontInfo(type_info_name[i], s);
s.setOlderOffsetToThisPos(type_info[i].getLocal_name_ofs_pos());
s.writeWChar(type_info_name[i]);
}
s.pad8bytes();
ib.pad8bytes();
s.seek(hdr.getDeclStringsAddress(), SeekMode.SET);
s.setOlderOffsetToThisPos(hdr.getDecl_strings_ofs_pos());
//s.seek(hdr.getDeclStringsAddress(), SeekMode.SET);
decl_strings.writeToDataStream(s);
}

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

@@ -9,6 +9,7 @@ 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;
@@ -44,56 +45,42 @@ import java.util.Set;
*/
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);
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 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 {
public static void exportSwfToFile(IggyFile file, File outputFile) throws IOException {
try (FileOutputStream fos = new FileOutputStream(outputFile)) {
exportSwf(file, swfIndex, fos);
exportSwf(file, fos);
}
}
public static void exportSwf(IggyFile file, int swfIndex, OutputStream output) throws IOException {
SWF swf = getSwf(file, swfIndex);
public static void exportSwf(IggyFile file, OutputStream output) throws IOException {
SWF swf = getSwf(file);
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) {
public static SWF getSwf(IggyFile file) {
SWF swf = new SWF();
swf.compression = SWFCompression.NONE;
swf.frameCount = 1; //FIXME!!
swf.frameRate = file.getSwfFrameRate(swfIndex);
swf.frameRate = file.getSwfFrameRate();
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));
(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);
@@ -101,15 +88,14 @@ public class IggyToSwfConvertor {
fat.hasMetadata = false;
fat.useNetwork = false;
swf.addTag(fat);
//Set<Integer> fontIndices = file.getFontIds(swfIndex);
int fontCount = file.getFontCount(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(swfIndex, fontIndex);
IggyFont iggyFont = file.getFont(fontIndex);
DefineFont2Tag fontTag = new DefineFont2Tag(swf);
currentCharId++;
fontIndex2CharId.put(fontIndex, currentCharId);

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

@@ -227,4 +227,15 @@ public abstract class AbstractDataStream implements DataStreamInterface {
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

@@ -4,20 +4,14 @@ 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.IggySequence;
import com.jpexs.decompiler.flash.iggy.IggyShape;
import com.jpexs.decompiler.flash.iggy.IggyShapeNode;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
/**
@@ -73,7 +67,7 @@ public class IggyIndexBuilder {
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 = IggySequence.STRUCT_SIZE;
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;
@@ -175,8 +169,12 @@ public class IggyIndexBuilder {
long ret = 0;
long rem = cnt;
while (true) {
if (rem == 0) {
break;
}
if (rem == 1) {
return writeIndex(constIndex, false, 0);
ret += writeIndex(constIndex, false, 0);
break;
}
if (rem <= 64) {
ret += writeIndex(0x80 + (int) rem - 1, false, constIndex);
@@ -307,10 +305,7 @@ public class IggyIndexBuilder {
int index;
indexStream.writeUI8((int) val);
if ((index = (int) val) < 0) {
LOGGER.severe(String.format("< 0xC0: Cannot read index."));
return 0;
}
index = (int) val;
if (index >= constTable.size()) {
LOGGER.severe(String.format("< 0xC0: index is greater than index_table_size. %x > %x", index, constTable.size()));

View File

@@ -21,6 +21,8 @@ public interface WriteDataStreamInterface extends AutoCloseable {
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;