diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFile.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFile.java index 19ee321a6..30b7791f2 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFile.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFile.java @@ -43,30 +43,29 @@ public class IggyFile implements StructureInterface { public static final int FIRST_TAG_POSITION = 3; - public void replaceTag(int swfIndex, int tagIndex, IggyTag newTag) throws IOException { - WriteDataStreamInterface stream = new TemporaryDataStream(); - newTag.writeToDataStream(stream); + public void replaceFontTag(int targetSwfIndex, int fontIndex, IggyFont newFont) throws IOException { + IggySwf iggySwf = iggySwfs.get(targetSwfIndex); + iggySwf.replaceFontTag(fontIndex, newFont); - setSwfItemLength(swfIndex, FIRST_TAG_POSITION + tagIndex, stream.totalSize()); - } - - public void saveTag(int swfIndex, IggyTag newTag) throws IOException { - WriteDataStreamInterface stream = new TemporaryDataStream(); - newTag.writeToDataStream(stream); - - int tagIndex = 0; - List taglist = iggySwfs.get(swfIndex).getTags(); - for (IggyTag t : taglist) { - if (t == newTag) { - break; + DataStreamInterface flashStream = new TemporaryDataStream(); + 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_FLASH) { + if (swfIndex == targetSwfIndex) { + long newLen = flashData.length; + long oldLen = entry.size; + offsetChange += (newLen - oldLen); + } + swfIndex++; } - tagIndex++; - } - if (tagIndex < taglist.size()) { - setSwfItemLength(swfIndex, FIRST_TAG_POSITION + tagIndex, stream.totalSize()); - } else { - throw new IllegalArgumentException("Tag does not exists in this iggy file"); } + subFileEntriesData.set(targetSwfIndex, flashData); + //TODO: Update index } private boolean setSwfItemLength(int swfIndex, int itemindex, long newLength) { @@ -103,14 +102,6 @@ public class IggyFile implements StructureInterface { return iggySwfs.get(swfIndex).fonts.get(fontId); } - public IggyText getText(int swfIndex, int textId) { - return iggySwfs.get(swfIndex).texts.get(textId); - } - - public Set getTextIds(int swfIndex) { - return iggySwfs.get(swfIndex).texts.keySet(); - } - public IggyFile(String filePath) throws IOException { this(new File(filePath)); } @@ -202,7 +193,8 @@ public class IggyFile implements StructureInterface { File outFile = new File(outFileName); IggyFile iggyFile = new IggyFile(inFile); IggySwf iswf = iggyFile.getSwf(0); - iggyFile.replaceSwf(0, iswf); + IggyFont ifont = iswf.fonts.get(0); + iggyFile.replaceFontTag(0, 0, ifont); outFile.delete(); try (RandomAccessFileDataStream outputStream = new RandomAccessFileDataStream(outFile)) { iggyFile.writeToDataStream(outputStream); @@ -649,7 +641,9 @@ public class IggyFile implements StructureInterface { //WIP public boolean replaceSwf(int targetSwfIndex, IggySwf iggySwf) { - if (targetSwfIndex < 0 || targetSwfIndex >= getSwfCount()) { + return false; //Not working yet - need to make IggySWF.writeToDataStream work + + /*if (targetSwfIndex < 0 || targetSwfIndex >= getSwfCount()) { throw new ArrayIndexOutOfBoundsException("No such SWF file index"); } byte replacementData[]; @@ -680,7 +674,7 @@ public class IggyFile implements StructureInterface { } } subFileEntriesData.set(targetSwfIndex, replacementData); - return true; + return true;*/ } private void parseEntries() throws IOException { @@ -697,23 +691,9 @@ public class IggyFile implements StructureInterface { indexTables.add(indexTable); offsetTables.add(offsets); } else if (entry.type == IggySubFileEntry.TYPE_FLASH) { - IggyFlashHeaderInterface hdr; - if (header.is64()) { - hdr = new IggyFlashHeader64(dataStream); - } else { - hdr = new IggyFlashHeader32(dataStream); - throw new UnsupportedOperationException("Iggy 32bit files are not supported"); //TODO - } - headers.add(hdr); - flashDataStreams.add(dataStream); + iggySwfs.add(new IggySwf(dataStream)); } } - - for (int swfIndex = 0; swfIndex < headers.size(); swfIndex++) { - IggyFlashHeaderInterface hdr = headers.get(swfIndex); - IggySwf dataReader = new IggySwf((IggyFlashHeader64) hdr, flashDataStreams.get(swfIndex), offsetTables.get(swfIndex)); - iggySwfs.add(dataReader); - } } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFlashHeader64.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFlashHeader64.java index aa8cf2e96..71de61c57 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFlashHeader64.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggyFlashHeader64.java @@ -64,7 +64,7 @@ public class IggyFlashHeader64 implements IggyFlashHeaderInterface { @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_unk8C; // 0x78 relative offset to something + long off_unk78; // 0x78 relative offset to something @IggyFieldType(DataType.uint64_t) long off_unk80; @IggyFieldType(DataType.uint64_t) @@ -97,13 +97,35 @@ public class IggyFlashHeader64 implements IggyFlashHeaderInterface { private long font_end_address; private long sequence_start_address; private long names_address; - private long unk8C_address; + private long unk78_address; private long unk80_address; private long last_section_address; private long flash_filename_address; private long decl_strings_address; private long type_fonts_address; + /** + * 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 boolean isImported() { return imported == 1; } @@ -120,6 +142,10 @@ public class IggyFlashHeader64 implements IggyFlashHeaderInterface { return font_end_address; } + public void setFontEndAddress(long val) { + this.font_end_address = val; + } + public long getSequenceStartAddress() { return sequence_start_address; } @@ -128,8 +154,8 @@ public class IggyFlashHeader64 implements IggyFlashHeaderInterface { return names_address; } - public long getUnk8CAddress() { - return unk8C_address; + public long getUnk78Address() { + return unk78_address; } public long getUnk80Address() { @@ -191,8 +217,8 @@ public class IggyFlashHeader64 implements IggyFlashHeaderInterface { off_names = stream.readUI64(); names_address = off_names + stream.position() - 8; - off_unk8C = stream.readUI64(); - unk8C_address = off_unk8C + stream.position() - 8; + off_unk78 = stream.readUI64(); + unk78_address = off_unk78 + stream.position() - 8; off_unk80 = stream.readUI64(); unk80_address = off_unk80 + stream.position() - 8; off_last_section = stream.readUI64(); @@ -211,11 +237,16 @@ public class IggyFlashHeader64 implements IggyFlashHeaderInterface { @Override public void writeToDataStream(WriteDataStreamInterface stream) throws IOException { + off_start = base_address - stream.position(); stream.writeUI64(off_start); + off_seq_end = sequence_end_address - stream.position(); stream.writeUI64(off_seq_end); + off_font_end = font_end_address - stream.position(); stream.writeUI64(off_font_end); + off_seq_start1 = sequence_start_address - stream.position(); stream.writeUI64(off_seq_start1); stream.writeUI64(pad_to_match); + off_seq_start2 = sequence_start_address - stream.position(); stream.writeUI64(off_seq_start2); stream.writeUI32(xmin); stream.writeUI32(ymin); @@ -232,12 +263,19 @@ public class IggyFlashHeader64 implements IggyFlashHeaderInterface { stream.writeUI32(additional_import1); stream.writeUI32(zero1); stream.writeUI64(unk_guid); + off_names = names_address - stream.position(); stream.writeUI64(off_names); - stream.writeUI64(off_unk8C); + off_unk78 = unk78_address - stream.position(); + stream.writeUI64(off_unk78); + off_unk80 = unk80_address - stream.position(); stream.writeUI64(off_unk80); + off_last_section = last_section_address - stream.position(); stream.writeUI64(off_last_section); + off_flash_filename = flash_filename_address - stream.position(); stream.writeUI64(off_flash_filename); + off_decl_strings = decl_strings_address - stream.position(); stream.writeUI64(off_decl_strings); + off_type_of_fonts = type_fonts_address - stream.position(); stream.writeUI64(off_type_of_fonts); stream.writeUI64(flags); stream.writeUI32(font_count); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggySwf.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggySwf.java index c9b969e83..0eed741c1 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggySwf.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/IggySwf.java @@ -25,35 +25,57 @@ public class IggySwf implements StructureInterface { String name; Map fonts; - Map texts; - Map text2Font; private IggyFlashHeader64 hdr; - private Map sizesOfOffsets; - private List offsets; - private List tags = new ArrayList<>(); - public List getTags() { - return tags; - } + private byte[] allFontBytes; - public IggySwf(IggyFlashHeader64 header, ReadDataStreamInterface stream, List offsets) throws IOException { - this.hdr = header; - this.offsets = offsets; - calcSizesFromOffsets(); + public IggySwf(ReadDataStreamInterface stream) throws IOException { readFromDataStream(stream); } - private void calcSizesFromOffsets() { - sizesOfOffsets = new HashMap<>(); - for (int i = 0; i < offsets.size() - 1; i++) { - sizesOfOffsets.put(offsets.get(i), offsets.get(i + 1) - offsets.get(i)); + private long font_data_addresses[]; + private long font_data_sizes[]; + private List text_addresses = new ArrayList<>(); + private List text_data_sizes = new ArrayList<>(); + private List font_add_off = new ArrayList<>(); + private List font_add_size = new ArrayList<>(); + + 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; } - sizesOfOffsets.put(offsets.get(offsets.size() - 1), 0L); //Last offset has 0L length? + 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); + //Save all font bytes to buffer for later easy modification + long curPos = s.position(); + long maxPos = hdr.getFontEndAddress(); + allFontBytes = s.readBytes((int) (maxPos - curPos)); + s.seek(curPos, SeekMode.SET); + //here is offset[0] StringBuilder nameBuilder = new StringBuilder(); do { @@ -71,8 +93,8 @@ public class IggySwf implements StructureInterface { s.seek(hdr.getBaseAddress(), SeekMode.SET); s.readUI64(); //one pad - long font_data_addresses[] = new long[(int) hdr.font_count]; - long font_data_sizes[] = new long[(int) hdr.font_count]; + font_data_addresses = new long[(int) hdr.font_count]; + font_data_sizes = new long[(int) hdr.font_count]; for (int i = 0; i < hdr.font_count; i++) { long offset = s.readUI64(); @@ -85,8 +107,6 @@ public class IggySwf implements StructureInterface { font_data_sizes[i] = next_offset - offset; } } - List text_addresses = new ArrayList<>(); - List text_data_sizes = new ArrayList<>(); while (true) { long offset = s.readUI64(); long text_addr = offset + s.position() - 8; @@ -101,8 +121,6 @@ public class IggySwf implements StructureInterface { } } - List font_add_off = new ArrayList<>(); - List font_add_size = new ArrayList<>(); if (hdr.isImported()) { // tohle muze narusit iggy order, ale oni to pak stejne pocitaji dle infa long additionalOffset = s.readUI64(); font_add_off.add(additionalOffset + s.position() - 8); @@ -129,7 +147,6 @@ public class IggySwf implements StructureInterface { s.seek(font_data_addresses[i], SeekMode.SET); //byte font_data[] = s.readBytes((int) font_data_sizes[i]); IggyFont font = new IggyFont(s); - tags.add(font); fonts.put(i/*??*/, font); } @@ -151,30 +168,26 @@ public class IggySwf implements StructureInterface { } @Override - public void writeToDataStream(WriteDataStreamInterface stream) throws IOException { - List newOffsets = new ArrayList<>(); - - try { - newOffsets.add(stream.position()); - for (int i = 0; i < name.length(); i++) { - stream.writeUI16(name.charAt(i)); + public void writeToDataStream(WriteDataStreamInterface st) throws IOException { + try (DataStreamInterface s = new TemporaryDataStream(allFontBytes)) { + hdr.writeToDataStream(s); + s.writeUI64(1); + for (int i = 0; i < font_data_addresses.length; i++) { + long offset = font_data_addresses[i] - s.position() + 8; + s.writeUI64(offset); } - stream.writeUI16(0); - newOffsets.add(stream.position()); - long pad8 = 8 - (stream.position() % 8); - for (int i = 0; i < pad8; i++) { - stream.write(0); + s.writeUI64(1); + for (int i = 0; i < text_addresses.size(); i++) { + long offset = text_addresses.get(i) - s.position() + 8; + s.writeUI64(offset); } - newOffsets.add(stream.position()); - for (IggyTag tag : tags) { - tag.writeToDataStream(stream); - newOffsets.add(stream.position()); + s.writeUI64(1); + s.seek(840, SeekMode.SET); + for (int i = 0; i < hdr.font_count; i++) { + fonts.get(i).writeToDataStream(s); } - } catch (IOException ex) { - //ignore + st.writeBytes(s.getAllBytes()); } - this.offsets = newOffsets; - calcSizesFromOffsets(); } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/WriteDataStreamInterface.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/WriteDataStreamInterface.java index 1b3e47e61..1e087fd1b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/WriteDataStreamInterface.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/iggy/streams/WriteDataStreamInterface.java @@ -35,6 +35,8 @@ public interface WriteDataStreamInterface extends AutoCloseable { public void seek(long pos, SeekMode mode) throws IOException; + public byte[] getAllBytes() throws IOException; + @Override public void close(); }